URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [libnetworking/] [pppd/] [options.c] - Rev 1026
Go to most recent revision | Compare with Previous | Blame | View Log
/* * options.c - handles option processing for PPP. * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Carnegie Mellon University. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #define RCSID "options.c,v 1.4 2002/01/31 21:40:47 joel Exp" #include <ctype.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <termios.h> #include <string.h> #include <netdb.h> #include <pwd.h> #include <sys/types.h> #include <sys/stat.h> #include <netinet/in.h> #include <arpa/inet.h> #ifdef PLUGIN #include <dlfcn.h> #endif #ifdef PPP_FILTER #include <pcap.h> #include <pcap-int.h> /* XXX: To get struct pcap */ #endif #include "pppd.h" #include "pathnames.h" #include "patchlevel.h" #include "fsm.h" #include "lcp.h" #include "ipcp.h" #include "upap.h" #include "chap.h" #include "ccp.h" #include <net/ppp-comp.h> #if defined(ultrix) || defined(NeXT) char *strdup __P((char *)); #endif static const char rcsid[] = RCSID; /* * Option variables and default values. */ #ifdef PPP_FILTER int dflag = 0; /* Tell libpcap we want debugging */ #endif int debug = 0; /* Debug flag */ int kdebugflag = 0; /* Tell kernel to print debug messages */ int default_device = 1; /* Using /dev/tty or equivalent */ char devnam[MAXPATHLEN]; /* Device name */ int crtscts = 0; /* Use hardware flow control */ bool modem = 1; /* Use modem control lines */ int inspeed = 0; /* Input/Output speed requested */ u_int32_t netmask = 0; /* IP netmask to set on interface */ bool lockflag = 0; /* Create lock file to lock the serial dev */ bool nodetach = 0; /* Don't detach from controlling tty */ bool updetach = 0; /* Detach once link is up */ char *initializer = NULL; /* Script to initialize physical link */ char *connect_script = NULL; /* Script to establish physical link */ char *disconnect_script = NULL; /* Script to disestablish physical link */ char *welcomer = NULL; /* Script to run after phys link estab. */ char *ptycommand = NULL; /* Command to run on other side of pty */ int maxconnect = 0; /* Maximum connect time */ char user[MAXNAMELEN]; /* Username for PAP */ char passwd[MAXSECRETLEN]; /* Password for PAP */ bool persist = 0; /* Reopen link after it goes down */ char our_name[MAXNAMELEN]; /* Our name for authentication purposes */ bool demand = 0; /* do dial-on-demand */ char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ int idle_time_limit = 0; /* Disconnect if idle for this many seconds */ int holdoff = 30; /* # seconds to pause before reconnecting */ bool holdoff_specified; /* true if a holdoff value has been given */ bool notty = 0; /* Stdin/out is not a tty */ char *record_file = NULL; /* File to record chars sent/received */ int using_pty = 0; bool sync_serial = 0; /* Device is synchronous serial device */ int log_to_fd = 1; /* send log messages to this fd too */ int maxfail = 10; /* max # of unsuccessful connection attempts */ char linkname[MAXPATHLEN]; /* logical name for link */ bool tune_kernel; /* may alter kernel settings */ int connect_delay = 1000; /* wait this many ms after connect script */ extern option_t auth_options[]; extern struct stat devstat; extern int prepass; /* Doing pre-pass to find device name */ struct option_info initializer_info; struct option_info connect_script_info; struct option_info disconnect_script_info; struct option_info welcomer_info; struct option_info devnam_info; struct option_info ptycommand_info; #ifdef PPP_FILTER struct bpf_program pass_filter;/* Filter program for packets to pass */ struct bpf_program active_filter; /* Filter program for link-active pkts */ pcap_t pc; /* Fake struct pcap so we can compile expr */ #endif char *current_option; /* the name of the option being parsed */ int privileged_option; /* set iff the current option came from root */ char *option_source; /* string saying where the option came from */ bool log_to_file; /* log_to_fd is a file opened by us */ /* * Prototypes */ static int setdevname __P((char *)); static int setipaddr __P((char *)); static int setspeed __P((char *)); static int noopt __P((char **)); static int setdomain __P((char **)); static int setnetmask __P((char **)); static int setxonxoff __P((char **)); static int readfile __P((char **)); static int callfile __P((char **)); static void usage __P((void)); static int setlogfile __P((char **)); #ifdef PLUGIN static int loadplugin __P((char **)); #endif #ifdef PPP_FILTER static int setpassfilter __P((char **)); static int setactivefilter __P((char **)); #endif static option_t *find_option __P((char *name)); static int process_option __P((option_t *, char **)); static int n_arguments __P((option_t *)); static int number_option __P((char *, u_int32_t *, int)); /* * Structure to store extra lists of options. */ struct option_list { option_t *options; struct option_list *next; }; static struct option_list *extra_options = NULL; /* * Valid arguments. */ option_t general_options[] = { { "debug", o_int, &debug, "Increase debugging level", OPT_INC|OPT_NOARG|1 }, { "-d", o_int, &debug, "Increase debugging level", OPT_INC|OPT_NOARG|1 }, { "kdebug", o_int, &kdebugflag, "Set kernel driver debug level" }, { "nodetach", o_bool, &nodetach, "Don't detach from controlling tty", 1 }, { "-detach", o_bool, &nodetach, "Don't detach from controlling tty", 1 }, { "updetach", o_bool, &updetach, "Detach from controlling tty once link is up", 1 }, { "holdoff", o_int, &holdoff, "Set time in seconds before retrying connection" }, { "idle", o_int, &idle_time_limit, "Set time in seconds before disconnecting idle link" }, { "lock", o_bool, &lockflag, "Lock serial device with UUCP-style lock file", 1 }, { "-all", o_special_noarg, noopt, "Don't request/allow any LCP or IPCP options (useless)" }, { "init", o_string, &initializer, "A program to initialize the device", OPT_A2INFO | OPT_PRIVFIX, &initializer_info }, { "connect", o_string, &connect_script, "A program to set up a connection", OPT_A2INFO | OPT_PRIVFIX, &connect_script_info }, { "disconnect", o_string, &disconnect_script, "Program to disconnect serial device", OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info }, { "welcome", o_string, &welcomer, "Script to welcome client", OPT_A2INFO | OPT_PRIVFIX, &welcomer_info }, { "pty", o_string, &ptycommand, "Script to run on pseudo-tty master side", OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info }, { "notty", o_bool, ¬ty, "Input/output is not a tty", OPT_DEVNAM | 1 }, { "record", o_string, &record_file, "Record characters sent/received to file" }, { "maxconnect", o_int, &maxconnect, "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF }, { "crtscts", o_int, &crtscts, "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) }, { "nocrtscts", o_int, &crtscts, "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, { "-crtscts", o_int, &crtscts, "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, { "cdtrcts", o_int, &crtscts, "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) }, { "nocdtrcts", o_int, &crtscts, "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, { "xonxoff", o_special_noarg, setxonxoff, "Set software (XON/XOFF) flow control" }, { "domain", o_special, setdomain, "Add given domain name to hostname" }, { "mtu", o_int, &lcp_allowoptions[0].mru, "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU }, { "netmask", o_special, setnetmask, "set netmask" }, { "modem", o_bool, &modem, "Use modem control lines", 1 }, { "local", o_bool, &modem, "Don't use modem control lines" }, { "file", o_special, readfile, "Take options from a file", OPT_PREPASS }, { "call", o_special, callfile, "Take options from a privileged file", OPT_PREPASS }, { "persist", o_bool, &persist, "Keep on reopening connection after close", 1 }, { "nopersist", o_bool, &persist, "Turn off persist option" }, { "demand", o_bool, &demand, "Dial on demand", OPT_INITONLY | 1, &persist }, { "sync", o_bool, &sync_serial, "Use synchronous HDLC serial encoding", 1 }, { "logfd", o_int, &log_to_fd, "Send log messages to this file descriptor" }, { "logfile", o_special, setlogfile, "Append log messages to this file" }, { "nolog", o_int, &log_to_fd, "Don't send log messages to any file", OPT_NOARG | OPT_VAL(-1) }, { "nologfd", o_int, &log_to_fd, "Don't send log messages to any file descriptor", OPT_NOARG | OPT_VAL(-1) }, { "linkname", o_string, linkname, "Set logical name for link", OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, { "maxfail", o_int, &maxfail, "Maximum number of unsuccessful connection attempts to allow" }, { "ktune", o_bool, &tune_kernel, "Alter kernel settings as necessary", 1 }, { "noktune", o_bool, &tune_kernel, "Don't alter kernel settings", 0 }, { "connect-delay", o_int, &connect_delay, "Maximum time (in ms) to wait after connect script finishes" }, #ifdef PLUGIN { "plugin", o_special, loadplugin, "Load a plug-in module into pppd", OPT_PRIV }, #endif #ifdef PPP_FILTER { "pdebug", o_int, &dflag, "libpcap debugging" }, { "pass-filter", 1, setpassfilter, "set filter for packets to pass" }, { "active-filter", 1, setactivefilter, "set filter for active pkts" }, #endif { NULL } }; #ifndef IMPLEMENTATION #define IMPLEMENTATION "" #endif static char *usage_string = "\ pppd version %s.%d%s\n\ Usage: %s [ options ], where options are:\n\ <device> Communicate over the named device\n\ <speed> Set the baud rate to <speed>\n\ <loc>:<rem> Set the local and/or remote interface IP\n\ addresses. Either one may be omitted.\n\ asyncmap <n> Set the desired async map to hex <n>\n\ auth Require authentication from peer\n\ connect <p> Invoke shell command <p> to set up the serial line\n\ crtscts Use hardware RTS/CTS flow control\n\ defaultroute Add default route through interface\n\ file <f> Take options from file <f>\n\ modem Use modem control lines\n\ mru <n> Set MRU value to <n> for negotiation\n\ See pppd(8) for more options.\n\ "; /* * parse_args - parse a string of arguments from the command line. * If prepass is true, we are scanning for the device name and only * processing a few options, so error messages are suppressed. */ int parse_args(argc, argv) int argc; char **argv; { char *arg; option_t *opt; int ret; privileged_option = privileged; option_source = "command line"; while (argc > 0) { arg = *argv++; --argc; /* * First see if it's an option in the new option list. */ opt = find_option(arg); if (opt != NULL) { int n = n_arguments(opt); if (argc < n) { option_error("too few parameters for option %s", arg); return 0; } current_option = arg; if (!process_option(opt, argv)) return 0; argc -= n; argv += n; continue; } /* * Maybe a tty name, speed or IP address? */ if ((ret = setdevname(arg)) == 0 && (ret = setspeed(arg)) == 0 && (ret = setipaddr(arg)) == 0 && !prepass) { option_error("unrecognized option '%s'", arg); usage(); return 0; } if (ret < 0) /* error */ return 0; } return 1; } #if 0 /* * scan_args - scan the command line arguments to get the tty name, * if specified. Also checks whether the notty or pty option was given. */ void scan_args(argc, argv) int argc; char **argv; { char *arg; option_t *opt; privileged_option = privileged; while (argc > 0) { arg = *argv++; --argc; if (strcmp(arg, "notty") == 0 || strcmp(arg, "pty") == 0) using_pty = 1; /* Skip options and their arguments */ opt = find_option(arg); if (opt != NULL) { int n = n_arguments(opt); argc -= n; argv += n; continue; } /* Check if it's a tty name and copy it if so */ (void) setdevname(arg, 1); } } #endif /* * options_from_file - Read a string of options from a file, * and interpret them. */ int options_from_file(filename, must_exist, check_prot, priv) char *filename; int must_exist; int check_prot; int priv; { FILE *f; int i, newline, ret, err; option_t *opt; int oldpriv; char *oldsource; char *argv[MAXARGS]; char args[MAXARGS][MAXWORDLEN]; char cmd[MAXWORDLEN]; f = fopen(filename, "r"); err = errno; if (f == NULL) { if (!must_exist && err == ENOENT) return 1; errno = err; option_error("Can't open options file %s: %m", filename); return 0; } oldpriv = privileged_option; privileged_option = priv; oldsource = option_source; option_source = strdup(filename); if (option_source == NULL) option_source = "file"; ret = 0; while (getword(f, cmd, &newline, filename)) { /* * First see if it's a command. */ opt = find_option(cmd); if (opt != NULL) { int n = n_arguments(opt); for (i = 0; i < n; ++i) { if (!getword(f, args[i], &newline, filename)) { option_error( "In file %s: too few parameters for option '%s'", filename, cmd); goto err; } argv[i] = args[i]; } current_option = cmd; if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) { option_error("the %s option may not be used in the %s file", cmd, filename); goto err; } if (!process_option(opt, argv)) goto err; continue; } /* * Maybe a tty name, speed or IP address? */ if ((i = setdevname(cmd)) == 0 && (i = setspeed(cmd)) == 0 && (i = setipaddr(cmd)) == 0) { option_error("In file %s: unrecognized option '%s'", filename, cmd); goto err; } if (i < 0) /* error */ goto err; } ret = 1; err: fclose(f); privileged_option = oldpriv; option_source = oldsource; return ret; } /* * options_from_user - See if the use has a ~/.ppprc file, * and if so, interpret options from it. */ int options_from_user() { return 0; } /* * options_for_tty - See if an options file exists for the serial * device, and if so, interpret options from it. */ int options_for_tty() { char *dev, *path, *p; int ret; size_t pl; dev = devnam; if (strncmp(dev, "/dev/", 5) == 0) dev += 5; if (dev[0] == 0 || strcmp(dev, "tty") == 0) return 1; /* don't look for /etc/ppp/options.tty */ pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1; path = malloc(pl); if (path == NULL) novm("tty init file name"); slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev); /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */ for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p) if (*p == '/') *p = '.'; ret = options_from_file(path, 0, 0, 1); free(path); return ret; } /* * options_from_list - process a string of options in a wordlist. */ int options_from_list(w, priv) struct wordlist *w; int priv; { char *argv[MAXARGS]; option_t *opt; int i, ret = 0; privileged_option = priv; option_source = "secrets file"; while (w != NULL) { /* * First see if it's a command. */ opt = find_option(w->word); if (opt != NULL) { int n = n_arguments(opt); struct wordlist *w0 = w; for (i = 0; i < n; ++i) { w = w->next; if (w == NULL) { option_error( "In secrets file: too few parameters for option '%s'", w0->word); goto err; } argv[i] = w->word; } current_option = w0->word; if (!process_option(opt, argv)) goto err; w = w->next; continue; } /* * Maybe a tty name, speed or IP address? */ if ((i = setdevname(w->word)) == 0 && (i = setspeed(w->word)) == 0 && (i = setipaddr(w->word)) == 0) { option_error("In secrets file: unrecognized option '%s'", w->word); goto err; } if (i < 0) /* error */ goto err; w = w->next; } ret = 1; err: return ret; } /* * find_option - scan the option lists for the various protocols * looking for an entry with the given name. * This could be optimized by using a hash table. */ static option_t * find_option(name) char *name; { option_t *opt; struct option_list *list; int i; for (list = extra_options; list != NULL; list = list->next) for (opt = list->options; opt->name != NULL; ++opt) if (strcmp(name, opt->name) == 0) return opt; for (opt = general_options; opt->name != NULL; ++opt) if (strcmp(name, opt->name) == 0) return opt; for (opt = auth_options; opt->name != NULL; ++opt) if (strcmp(name, opt->name) == 0) return opt; for (i = 0; protocols[i] != NULL; ++i) if ((opt = protocols[i]->options) != NULL) for (; opt->name != NULL; ++opt) if (strcmp(name, opt->name) == 0) return opt; return NULL; } /* * process_option - process one new-style option. */ static int process_option(opt, argv) option_t *opt; char **argv; { u_int32_t v; int iv, a; char *sv; int (*parser) __P((char **)); if ((opt->flags & OPT_PREPASS) == 0 && prepass) return 1; if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) { option_error("it's too late to use the %s option", opt->name); return 0; } if ((opt->flags & OPT_PRIV) && !privileged_option) { option_error("using the %s option requires root privilege", opt->name); return 0; } if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) { option_error("%s option is disabled", opt->name); return 0; } if ((opt->flags & OPT_PRIVFIX) && !privileged_option) { struct option_info *ip = (struct option_info *) opt->addr2; if (ip && ip->priv) { option_error("%s option cannot be overridden", opt->name); return 0; } } switch (opt->type) { case o_bool: v = opt->flags & OPT_VALUE; *(bool *)(opt->addr) = v; if (opt->addr2 && (opt->flags & OPT_A2COPY)) *(bool *)(opt->addr2) = v; break; case o_int: iv = 0; if ((opt->flags & OPT_NOARG) == 0) { if (!int_option(*argv, &iv)) return 0; if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit) || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit)) && !((opt->flags & OPT_ZEROOK && iv == 0))) { char *zok = (opt->flags & OPT_ZEROOK)? " zero or": ""; switch (opt->flags & OPT_LIMITS) { case OPT_LLIMIT: option_error("%s value must be%s >= %d", opt->name, zok, opt->lower_limit); break; case OPT_ULIMIT: option_error("%s value must be%s <= %d", opt->name, zok, opt->upper_limit); break; case OPT_LIMITS: option_error("%s value must be%s between %d and %d", opt->name, opt->lower_limit, opt->upper_limit); break; } return 0; } } a = opt->flags & OPT_VALUE; if (a >= 128) a -= 256; /* sign extend */ iv += a; if (opt->flags & OPT_INC) iv += *(int *)(opt->addr); if ((opt->flags & OPT_NOINCR) && !privileged_option) { int oldv = *(int *)(opt->addr); if ((opt->flags & OPT_ZEROINF) ? (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) { option_error("%s value cannot be increased", opt->name); return 0; } } *(int *)(opt->addr) = iv; if (opt->addr2 && (opt->flags & OPT_A2COPY)) *(int *)(opt->addr2) = iv; break; case o_uint32: if (opt->flags & OPT_NOARG) { v = opt->flags & OPT_VALUE; } else if (!number_option(*argv, &v, 16)) return 0; if (opt->flags & OPT_OR) v |= *(u_int32_t *)(opt->addr); *(u_int32_t *)(opt->addr) = v; if (opt->addr2 && (opt->flags & OPT_A2COPY)) *(u_int32_t *)(opt->addr2) = v; break; case o_string: if (opt->flags & OPT_STATIC) { strlcpy((char *)(opt->addr), *argv, opt->upper_limit); } else { sv = strdup(*argv); if (sv == NULL) novm("option argument"); if ( *(char **)(opt->addr) != NULL ) { free((void *)*(char **)(opt->addr)); *(char **)(opt->addr) = NULL; } *(char **)(opt->addr) = sv; } break; case o_special_noarg: case o_special: parser = (int (*) __P((char **))) opt->addr; if (!(*parser)(argv)) return 0; break; } if (opt->addr2) { if (opt->flags & OPT_A2INFO) { struct option_info *ip = (struct option_info *) opt->addr2; ip->priv = privileged_option; ip->source = option_source; } else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0) *(bool *)(opt->addr2) = 1; } return 1; } /* * n_arguments - tell how many arguments an option takes */ static int n_arguments(opt) option_t *opt; { return (opt->type == o_bool || opt->type == o_special_noarg || (opt->flags & OPT_NOARG))? 0: 1; } /* * add_options - add a list of options to the set we grok. */ void add_options(opt) option_t *opt; { struct option_list *list; list = malloc(sizeof(*list)); if (list == 0) novm("option list entry"); list->options = opt; list->next = extra_options; extra_options = list; } /* * usage - print out a message telling how to use the program. */ static void usage() { if (phase == PHASE_INITIALIZE) fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION, progname); } /* * option_error - print a message about an error in an option. * The message is logged, and also sent to * stderr if phase == PHASE_INITIALIZE. */ void option_error __V((char *fmt, ...)) { va_list args; char buf[256]; #if defined(__STDC__) va_start(args, fmt); #else char *fmt; va_start(args); fmt = va_arg(args, char *); #endif if (prepass) { va_end(args); return; } vslprintf(buf, sizeof(buf), fmt, args); va_end(args); fprintf(stderr, "pppd: %s\n", buf); } /* * Read a word from a file. * Words are delimited by white-space or by quotes (" or '). * Quotes, white-space and \ may be escaped with \. * \<newline> is ignored. */ int getword(f, word, newlinep, filename) FILE *f; char *word; int *newlinep; char *filename; { int c, len, escape; int quoted, comment; int value, digit, got, n; #define isoctal(c) ((c) >= '0' && (c) < '8') *newlinep = 0; len = 0; escape = 0; comment = 0; /* * First skip white-space and comments. */ for (;;) { c = getc(f); if (c == EOF) break; /* * A newline means the end of a comment; backslash-newline * is ignored. Note that we cannot have escape && comment. */ if (c == '\n') { if (!escape) { *newlinep = 1; comment = 0; } else escape = 0; continue; } /* * Ignore characters other than newline in a comment. */ if (comment) continue; /* * If this character is escaped, we have a word start. */ if (escape) break; /* * If this is the escape character, look at the next character. */ if (c == '\\') { escape = 1; continue; } /* * If this is the start of a comment, ignore the rest of the line. */ if (c == '#') { comment = 1; continue; } /* * A non-whitespace character is the start of a word. */ if (!isspace(c)) break; } /* * Save the delimiter for quoted strings. */ if (!escape && (c == '"' || c == '\'')) { quoted = c; c = getc(f); } else quoted = 0; /* * Process characters until the end of the word. */ while (c != EOF) { if (escape) { /* * This character is escaped: backslash-newline is ignored, * various other characters indicate particular values * as for C backslash-escapes. */ escape = 0; if (c == '\n') { c = getc(f); continue; } got = 0; switch (c) { case 'a': value = '\a'; break; case 'b': value = '\b'; break; case 'f': value = '\f'; break; case 'n': value = '\n'; break; case 'r': value = '\r'; break; case 's': value = ' '; break; case 't': value = '\t'; break; default: if (isoctal(c)) { /* * \ddd octal sequence */ value = 0; for (n = 0; n < 3 && isoctal(c); ++n) { value = (value << 3) + (c & 07); c = getc(f); } got = 1; break; } if (c == 'x') { /* * \x<hex_string> sequence */ value = 0; c = getc(f); for (n = 0; n < 2 && isxdigit(c); ++n) { digit = toupper(c) - '0'; if (digit > 10) digit += '0' + 10 - 'A'; value = (value << 4) + digit; c = getc (f); } got = 1; break; } /* * Otherwise the character stands for itself. */ value = c; break; } /* * Store the resulting character for the escape sequence. */ if (len < MAXWORDLEN-1) word[len] = value; ++len; if (!got) c = getc(f); continue; } /* * Not escaped: see if we've reached the end of the word. */ if (quoted) { if (c == quoted) break; } else { if (isspace(c) || c == '#') { ungetc (c, f); break; } } /* * Backslash starts an escape sequence. */ if (c == '\\') { escape = 1; c = getc(f); continue; } /* * An ordinary character: store it in the word and get another. */ if (len < MAXWORDLEN-1) word[len] = c; ++len; c = getc(f); } /* * End of the word: check for errors. */ if (c == EOF) { if (ferror(f)) { if (errno == 0) errno = EIO; option_error("Error reading %s: %m", filename); die(1); } /* * If len is zero, then we didn't find a word before the * end of the file. */ if (len == 0) return 0; } /* * Warn if the word was too long, and append a terminating null. */ if (len >= MAXWORDLEN) { option_error("warning: word in file %s too long (%.20s...)", filename, word); len = MAXWORDLEN - 1; } word[len] = 0; return 1; #undef isoctal } /* * number_option - parse an unsigned numeric parameter for an option. */ static int number_option(str, valp, base) char *str; u_int32_t *valp; int base; { char *ptr; *valp = strtoul(str, &ptr, base); if (ptr == str) { option_error("invalid numeric parameter '%s' for %s option", str, current_option); return 0; } return 1; } /* * int_option - like number_option, but valp is int *, * the base is assumed to be 0, and *valp is not changed * if there is an error. */ int int_option(str, valp) char *str; int *valp; { u_int32_t v; if (!number_option(str, &v, 0)) return 0; *valp = (int) v; return 1; } /* * The following procedures parse options. */ /* * readfile - take commands from a file. */ static int readfile(argv) char **argv; { return options_from_file(*argv, 1, 1, privileged_option); } /* * callfile - take commands from /etc/ppp/peers/<name>. * Name may not contain /../, start with / or ../, or end in /.. */ static int callfile(argv) char **argv; { char *fname, *arg, *p; int l, ok; arg = *argv; ok = 1; if (arg[0] == '/' || arg[0] == 0) ok = 0; else { for (p = arg; *p != 0; ) { if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) { ok = 0; break; } while (*p != '/' && *p != 0) ++p; if (*p == '/') ++p; } } if (!ok) { option_error("call option value may not contain .. or start with /"); return 0; } l = strlen(arg) + strlen(_PATH_PEERFILES) + 1; if ((fname = (char *) malloc(l)) == NULL) novm("call file name"); slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg); ok = options_from_file(fname, 1, 1, 1); free(fname); return ok; } #ifdef PPP_FILTER /* * setpdebug - Set libpcap debugging level. */ static int setpdebug(argv) char **argv; { return int_option(*argv, &dflag); } /* * setpassfilter - Set the pass filter for packets */ static int setpassfilter(argv) char **argv; { pc.linktype = DLT_PPP; pc.snapshot = PPP_HDRLEN; if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0) return 1; option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc)); return 0; } /* * setactivefilter - Set the active filter for packets */ static int setactivefilter(argv) char **argv; { pc.linktype = DLT_PPP; pc.snapshot = PPP_HDRLEN; if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0) return 1; option_error("error in active-filter expression: %s\n", pcap_geterr(&pc)); return 0; } #endif /* * noopt - Disable all options. */ static int noopt(argv) char **argv; { BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options)); BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options)); return (1); } /* * setdomain - Set domain name to append to hostname */ static int setdomain(argv) char **argv; { if (!privileged_option) { option_error("using the domain option requires root privilege"); return 0; } gethostname(hostname, MAXNAMELEN); if (**argv != 0) { if (**argv != '.') strncat(hostname, ".", MAXNAMELEN - strlen(hostname)); strncat(hostname, *argv, MAXNAMELEN - strlen(hostname)); } hostname[MAXNAMELEN-1] = 0; return (1); } /* * setspeed - Set the speed. */ static int setspeed(arg) char *arg; { int spd; int ret = (int )1; speed_t spdValue = (speed_t)0; char *ptr; if ( !prepass ) { spd = strtol(arg, &ptr, 0); if (ptr == arg || *ptr != 0 || spd == 0) { ret = (int)0; } else { switch ( spd ) { case 2400: spdValue = B2400; break; case 4800: spdValue = B4800; break; case 9600: spdValue = B9600; break; case 19200: spdValue = B19200; break; case 38400: spdValue = B38400; break; case 57600: spdValue = B57600; break; case 115200: spdValue = B115200; break; default: ret = (int)0; break; } if ( spdValue ) { inspeed = spdValue; } } } return ( ret ); } /* * setdevname - Set the device name. */ static int setdevname(cp) char *cp; { struct stat statbuf; char dev[MAXPATHLEN]; if (*cp == 0) return 0; if (strncmp("/dev/", cp, 5) != 0) { strlcpy(dev, "/dev/", sizeof(dev)); strlcat(dev, cp, sizeof(dev)); cp = dev; } /* * Check if there is a character device by this name. */ if (stat(cp, &statbuf) < 0) { if (errno == ENOENT) return 0; option_error("Couldn't stat %s: %m", cp); return -1; } if (!S_ISCHR(statbuf.st_mode)) { option_error("%s is not a character device", cp); return -1; } if (phase != PHASE_INITIALIZE) { option_error("device name cannot be changed after initialization"); return -1; } else if (devnam_fixed) { option_error("per-tty options file may not specify device name"); return -1; } if (devnam_info.priv && !privileged_option) { option_error("device name cannot be overridden"); return -1; } strlcpy(devnam, cp, sizeof(devnam)); devstat = statbuf; default_device = 0; devnam_info.priv = privileged_option; devnam_info.source = option_source; return 1; } /* * setipaddr - Set the IP address */ static int setipaddr(arg) char *arg; { struct hostent *hp; char *colon; u_int32_t local, remote; ipcp_options *wo = &ipcp_wantoptions[0]; /* * IP address pair separated by ":". */ if ((colon = strchr(arg, ':')) == NULL) return 0; if (prepass) return 1; /* * If colon first character, then no local addr. */ if (colon != arg) { *colon = '\0'; if ((local = inet_addr(arg)) == (u_int32_t) -1) { if ((hp = gethostbyname(arg)) == NULL) { option_error("unknown host: %s", arg); return -1; } else { local = *(u_int32_t *)hp->h_addr; } } if (bad_ip_adrs(local)) { option_error("bad local IP address %s", ip_ntoa(local)); return -1; } if (local != 0) wo->ouraddr = local; *colon = ':'; } /* * If colon last character, then no remote addr. */ if (*++colon != '\0') { if ((remote = inet_addr(colon)) == (u_int32_t) -1) { if ((hp = gethostbyname(colon)) == NULL) { option_error("unknown host: %s", colon); return -1; } else { remote = *(u_int32_t *)hp->h_addr; if (remote_name[0] == 0) strlcpy(remote_name, colon, sizeof(remote_name)); } } if (bad_ip_adrs(remote)) { option_error("bad remote IP address %s", ip_ntoa(remote)); return -1; } if (remote != 0) wo->hisaddr = remote; } return 1; } /* * setnetmask - set the netmask to be used on the interface. */ static int setnetmask(argv) char **argv; { u_int32_t mask, b; int n, ok; char *p, *endp; /* * Unfortunately, if we use inet_addr, we can't tell whether * a result of all 1s is an error or a valid 255.255.255.255. */ p = *argv; ok = 0; mask = 0; for (n = 3;; --n) { b = strtoul(p, &endp, 0); if (endp == p) break; if (b > 255) { if (n == 3) { /* accept e.g. 0xffffff00 */ p = endp; mask = b; } break; } mask |= b << (n * 8); p = endp; if (*p != '.' || n == 0) break; ++p; } mask = htonl(mask); if (*p != 0 || (netmask & ~mask) != 0) { option_error("invalid netmask value '%s'", *argv); return 0; } netmask = mask; return (1); } static int setxonxoff(argv) char **argv; { lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */ lcp_wantoptions[0].neg_asyncmap = 1; crtscts = -2; return (1); } static int setlogfile(argv) char **argv; { int fd, err; fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644); if (fd < 0 && errno == EEXIST) fd = open(*argv, O_WRONLY | O_APPEND); err = errno; if (fd < 0) { errno = err; option_error("Can't open log file %s: %m", *argv); return 0; } if (log_to_file && log_to_fd >= 0) close(log_to_fd); log_to_fd = fd; log_to_file = 1; return 1; } #ifdef PLUGIN static int loadplugin(argv) char **argv; { char *arg = *argv; void *handle; const char *err; void (*init) __P((void)); handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW); if (handle == 0) { err = dlerror(); if (err != 0) option_error("%s", err); option_error("Couldn't load plugin %s", arg); return 0; } init = dlsym(handle, "plugin_init"); if (init == 0) { option_error("%s has no initialization entry point", arg); dlclose(handle); return 0; } info("Plugin %s loaded.", arg); (*init)(); return 1; } #endif /* PLUGIN */
Go to most recent revision | Compare with Previous | Blame | View Log