Home | History | Annotate | Download | only in pppd
      1 /*
      2  * options.c - handles option processing for PPP.
      3  *
      4  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  *
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *
     18  * 3. The name "Carnegie Mellon University" must not be used to
     19  *    endorse or promote products derived from this software without
     20  *    prior written permission. For permission or any legal
     21  *    details, please contact
     22  *      Office of Technology Transfer
     23  *      Carnegie Mellon University
     24  *      5000 Forbes Avenue
     25  *      Pittsburgh, PA  15213-3890
     26  *      (412) 268-4387, fax: (412) 268-7395
     27  *      tech-transfer (at) andrew.cmu.edu
     28  *
     29  * 4. Redistributions of any form whatsoever must retain the following
     30  *    acknowledgment:
     31  *    "This product includes software developed by Computing Services
     32  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     33  *
     34  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     35  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     36  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     37  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     39  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     40  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     41  */
     42 
     43 #define RCSID	"$Id: options.c,v 1.95 2004/11/09 22:33:35 paulus Exp $"
     44 
     45 #include <ctype.h>
     46 #include <stdio.h>
     47 #include <errno.h>
     48 #include <unistd.h>
     49 #include <fcntl.h>
     50 #include <stdlib.h>
     51 #include <syslog.h>
     52 #include <string.h>
     53 #include <pwd.h>
     54 #ifdef PLUGIN
     55 #include <dlfcn.h>
     56 #endif
     57 
     58 #ifdef PPP_FILTER
     59 #include <pcap.h>
     60 
     61 /*
     62  * DLT_PPP_WITH_DIRECTION is in current libpcap cvs, and should be in
     63  * libpcap-0.8.4.  Until that is released, use DLT_PPP - but that means
     64  * we lose the inbound and outbound qualifiers.
     65  */
     66 #ifndef DLT_PPP_WITH_DIRECTION
     67 #define DLT_PPP_WITH_DIRECTION	DLT_PPP
     68 #endif
     69 #endif
     70 
     71 #include "pppd.h"
     72 #include "pathnames.h"
     73 
     74 #if defined(ultrix) || defined(NeXT)
     75 char *strdup __P((char *));
     76 #endif
     77 
     78 static const char rcsid[] = RCSID;
     79 
     80 struct option_value {
     81     struct option_value *next;
     82     const char *source;
     83     char value[1];
     84 };
     85 
     86 /*
     87  * Option variables and default values.
     88  */
     89 int	debug = 0;		/* Debug flag */
     90 int	kdebugflag = 0;		/* Tell kernel to print debug messages */
     91 int	default_device = 1;	/* Using /dev/tty or equivalent */
     92 char	devnam[MAXPATHLEN];	/* Device name */
     93 bool	nodetach = 0;		/* Don't detach from controlling tty */
     94 bool	updetach = 0;		/* Detach once link is up */
     95 int	maxconnect = 0;		/* Maximum connect time */
     96 char	user[MAXNAMELEN];	/* Username for PAP */
     97 char	passwd[MAXSECRETLEN];	/* Password for PAP */
     98 bool	persist = 0;		/* Reopen link after it goes down */
     99 char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
    100 bool	demand = 0;		/* do dial-on-demand */
    101 char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
    102 int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
    103 int	holdoff = 30;		/* # seconds to pause before reconnecting */
    104 bool	holdoff_specified;	/* true if a holdoff value has been given */
    105 int	log_to_fd = 1;		/* send log messages to this fd too */
    106 bool	log_default = 1;	/* log_to_fd is default (stdout) */
    107 int	maxfail = 10;		/* max # of unsuccessful connection attempts */
    108 char	linkname[MAXPATHLEN];	/* logical name for link */
    109 bool	tune_kernel;		/* may alter kernel settings */
    110 int	connect_delay = 1000;	/* wait this many ms after connect script */
    111 int	req_unit = -1;		/* requested interface unit */
    112 bool	multilink = 0;		/* Enable multilink operation */
    113 char	*bundle_name = NULL;	/* bundle name for multilink */
    114 bool	dump_options;		/* print out option values */
    115 bool	dryrun;			/* print out option values and exit */
    116 char	*domain;		/* domain name set by domain option */
    117 int	child_wait = 5;		/* # seconds to wait for children at exit */
    118 
    119 #ifdef MAXOCTETS
    120 unsigned int  maxoctets = 0;    /* default - no limit */
    121 int maxoctets_dir = 0;       /* default - sum of traffic */
    122 int maxoctets_timeout = 1;   /* default 1 second */
    123 #endif
    124 
    125 
    126 extern option_t auth_options[];
    127 extern struct stat devstat;
    128 
    129 #ifdef PPP_FILTER
    130 struct	bpf_program pass_filter;/* Filter program for packets to pass */
    131 struct	bpf_program active_filter; /* Filter program for link-active pkts */
    132 #endif
    133 
    134 char *current_option;		/* the name of the option being parsed */
    135 int  privileged_option;		/* set iff the current option came from root */
    136 char *option_source;		/* string saying where the option came from */
    137 int  option_priority = OPRIO_CFGFILE; /* priority of the current options */
    138 bool devnam_fixed;		/* can no longer change device name */
    139 
    140 static int logfile_fd = -1;	/* fd opened for log file */
    141 static char logfile_name[MAXPATHLEN];	/* name of log file */
    142 
    143 /*
    144  * Prototypes
    145  */
    146 static int setdomain __P((char **));
    147 static int readfile __P((char **));
    148 static int callfile __P((char **));
    149 static int showversion __P((char **));
    150 static int showhelp __P((char **));
    151 static void usage __P((void));
    152 static int setlogfile __P((char **));
    153 #ifdef PLUGIN
    154 static int loadplugin __P((char **));
    155 #endif
    156 
    157 #ifdef PPP_FILTER
    158 static int setpassfilter __P((char **));
    159 static int setactivefilter __P((char **));
    160 #endif
    161 
    162 #ifdef MAXOCTETS
    163 static int setmodir __P((char **));
    164 #endif
    165 
    166 static option_t *find_option __P((const char *name));
    167 static int process_option __P((option_t *, char *, char **));
    168 static int n_arguments __P((option_t *));
    169 static int number_option __P((char *, u_int32_t *, int));
    170 
    171 /*
    172  * Structure to store extra lists of options.
    173  */
    174 struct option_list {
    175     option_t *options;
    176     struct option_list *next;
    177 };
    178 
    179 static struct option_list *extra_options = NULL;
    180 
    181 /*
    182  * Valid arguments.
    183  */
    184 option_t general_options[] = {
    185     { "debug", o_int, &debug,
    186       "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
    187     { "-d", o_int, &debug,
    188       "Increase debugging level",
    189       OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
    190 
    191     { "kdebug", o_int, &kdebugflag,
    192       "Set kernel driver debug level", OPT_PRIO },
    193 
    194     { "nodetach", o_bool, &nodetach,
    195       "Don't detach from controlling tty", OPT_PRIO | 1 },
    196     { "-detach", o_bool, &nodetach,
    197       "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
    198     { "updetach", o_bool, &updetach,
    199       "Detach from controlling tty once link is up",
    200       OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
    201 
    202     { "holdoff", o_int, &holdoff,
    203       "Set time in seconds before retrying connection",
    204       OPT_PRIO, &holdoff_specified },
    205 
    206     { "idle", o_int, &idle_time_limit,
    207       "Set time in seconds before disconnecting idle link", OPT_PRIO },
    208 
    209     { "maxconnect", o_int, &maxconnect,
    210       "Set connection time limit",
    211       OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
    212 
    213     { "domain", o_special, (void *)setdomain,
    214       "Add given domain name to hostname",
    215       OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
    216 
    217     { "file", o_special, (void *)readfile,
    218       "Take options from a file", OPT_NOPRINT },
    219     { "call", o_special, (void *)callfile,
    220       "Take options from a privileged file", OPT_NOPRINT },
    221 
    222     { "persist", o_bool, &persist,
    223       "Keep on reopening connection after close", OPT_PRIO | 1 },
    224     { "nopersist", o_bool, &persist,
    225       "Turn off persist option", OPT_PRIOSUB },
    226 
    227     { "demand", o_bool, &demand,
    228       "Dial on demand", OPT_INITONLY | 1, &persist },
    229 
    230     { "--version", o_special_noarg, (void *)showversion,
    231       "Show version number" },
    232     { "--help", o_special_noarg, (void *)showhelp,
    233       "Show brief listing of options" },
    234     { "-h", o_special_noarg, (void *)showhelp,
    235       "Show brief listing of options", OPT_ALIAS },
    236 
    237     { "logfile", o_special, (void *)setlogfile,
    238       "Append log messages to this file",
    239       OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
    240     { "logfd", o_int, &log_to_fd,
    241       "Send log messages to this file descriptor",
    242       OPT_PRIOSUB | OPT_A2CLR, &log_default },
    243     { "nolog", o_int, &log_to_fd,
    244       "Don't send log messages to any file",
    245       OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
    246     { "nologfd", o_int, &log_to_fd,
    247       "Don't send log messages to any file descriptor",
    248       OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
    249 
    250     { "linkname", o_string, linkname,
    251       "Set logical name for link",
    252       OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
    253 
    254     { "maxfail", o_int, &maxfail,
    255       "Maximum number of unsuccessful connection attempts to allow",
    256       OPT_PRIO },
    257 
    258     { "ktune", o_bool, &tune_kernel,
    259       "Alter kernel settings as necessary", OPT_PRIO | 1 },
    260     { "noktune", o_bool, &tune_kernel,
    261       "Don't alter kernel settings", OPT_PRIOSUB },
    262 
    263     { "connect-delay", o_int, &connect_delay,
    264       "Maximum time (in ms) to wait after connect script finishes",
    265       OPT_PRIO },
    266 
    267     { "unit", o_int, &req_unit,
    268       "PPP interface unit number to use if possible",
    269       OPT_PRIO | OPT_LLIMIT, 0, 0 },
    270 
    271     { "dump", o_bool, &dump_options,
    272       "Print out option values after parsing all options", 1 },
    273     { "dryrun", o_bool, &dryrun,
    274       "Stop after parsing, printing, and checking options", 1 },
    275 
    276     { "child-timeout", o_int, &child_wait,
    277       "Number of seconds to wait for child processes at exit",
    278       OPT_PRIO },
    279 
    280 #ifdef HAVE_MULTILINK
    281     { "multilink", o_bool, &multilink,
    282       "Enable multilink operation", OPT_PRIO | 1 },
    283     { "mp", o_bool, &multilink,
    284       "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
    285     { "nomultilink", o_bool, &multilink,
    286       "Disable multilink operation", OPT_PRIOSUB | 0 },
    287     { "nomp", o_bool, &multilink,
    288       "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
    289 
    290     { "bundle", o_string, &bundle_name,
    291       "Bundle name for multilink", OPT_PRIO },
    292 #endif /* HAVE_MULTILINK */
    293 
    294 #ifdef PLUGIN
    295     { "plugin", o_special, (void *)loadplugin,
    296       "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
    297 #endif
    298 
    299 #ifdef PPP_FILTER
    300     { "pass-filter", 1, setpassfilter,
    301       "set filter for packets to pass", OPT_PRIO },
    302 
    303     { "active-filter", 1, setactivefilter,
    304       "set filter for active pkts", OPT_PRIO },
    305 #endif
    306 
    307 #ifdef MAXOCTETS
    308     { "maxoctets", o_int, &maxoctets,
    309       "Set connection traffic limit",
    310       OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
    311     { "mo", o_int, &maxoctets,
    312       "Set connection traffic limit",
    313       OPT_ALIAS | OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
    314     { "mo-direction", o_special, setmodir,
    315       "Set direction for limit traffic (sum,in,out,max)" },
    316     { "mo-timeout", o_int, &maxoctets_timeout,
    317       "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
    318 #endif
    319 
    320     { NULL }
    321 };
    322 
    323 #ifndef IMPLEMENTATION
    324 #define IMPLEMENTATION ""
    325 #endif
    326 
    327 static char *usage_string = "\
    328 pppd version %s\n\
    329 Usage: %s [ options ], where options are:\n\
    330 	<device>	Communicate over the named device\n\
    331 	<speed>		Set the baud rate to <speed>\n\
    332 	<loc>:<rem>	Set the local and/or remote interface IP\n\
    333 			addresses.  Either one may be omitted.\n\
    334 	asyncmap <n>	Set the desired async map to hex <n>\n\
    335 	auth		Require authentication from peer\n\
    336         connect <p>     Invoke shell command <p> to set up the serial line\n\
    337 	crtscts		Use hardware RTS/CTS flow control\n\
    338 	defaultroute	Add default route through interface\n\
    339 	file <f>	Take options from file <f>\n\
    340 	modem		Use modem control lines\n\
    341 	mru <n>		Set MRU value to <n> for negotiation\n\
    342 See pppd(8) for more options.\n\
    343 ";
    344 
    345 /*
    346  * parse_args - parse a string of arguments from the command line.
    347  */
    348 int
    349 parse_args(argc, argv)
    350     int argc;
    351     char **argv;
    352 {
    353     char *arg;
    354     option_t *opt;
    355     int n;
    356 
    357     privileged_option = privileged;
    358     option_source = "command line";
    359     option_priority = OPRIO_CMDLINE;
    360     while (argc > 0) {
    361 	arg = *argv++;
    362 	--argc;
    363 	opt = find_option(arg);
    364 	if (opt == NULL) {
    365 	    option_error("unrecognized option '%s'", arg);
    366 	    usage();
    367 	    return 0;
    368 	}
    369 	n = n_arguments(opt);
    370 	if (argc < n) {
    371 	    option_error("too few parameters for option %s", arg);
    372 	    return 0;
    373 	}
    374 	if (!process_option(opt, arg, argv))
    375 	    return 0;
    376 	argc -= n;
    377 	argv += n;
    378     }
    379     return 1;
    380 }
    381 
    382 /*
    383  * options_from_file - Read a string of options from a file,
    384  * and interpret them.
    385  */
    386 int
    387 options_from_file(filename, must_exist, check_prot, priv)
    388     char *filename;
    389     int must_exist;
    390     int check_prot;
    391     int priv;
    392 {
    393     FILE *f;
    394     int i, newline, ret, err;
    395     option_t *opt;
    396     int oldpriv, n;
    397     char *oldsource;
    398     char *argv[MAXARGS];
    399     char args[MAXARGS][MAXWORDLEN];
    400     char cmd[MAXWORDLEN];
    401 
    402     if (check_prot)
    403 	seteuid(getuid());
    404     f = fopen(filename, "r");
    405     err = errno;
    406     if (check_prot)
    407 	seteuid(0);
    408     if (f == NULL) {
    409 	errno = err;
    410 	if (!must_exist) {
    411 	    if (err != ENOENT && err != ENOTDIR)
    412 		warn("Warning: can't open options file %s: %m", filename);
    413 	    return 1;
    414 	}
    415 	option_error("Can't open options file %s: %m", filename);
    416 	return 0;
    417     }
    418 
    419     oldpriv = privileged_option;
    420     privileged_option = priv;
    421     oldsource = option_source;
    422     option_source = strdup(filename);
    423     if (option_source == NULL)
    424 	option_source = "file";
    425     ret = 0;
    426     while (getword(f, cmd, &newline, filename)) {
    427 	opt = find_option(cmd);
    428 	if (opt == NULL) {
    429 	    option_error("In file %s: unrecognized option '%s'",
    430 			 filename, cmd);
    431 	    goto err;
    432 	}
    433 	n = n_arguments(opt);
    434 	for (i = 0; i < n; ++i) {
    435 	    if (!getword(f, args[i], &newline, filename)) {
    436 		option_error(
    437 			"In file %s: too few parameters for option '%s'",
    438 			filename, cmd);
    439 		goto err;
    440 	    }
    441 	    argv[i] = args[i];
    442 	}
    443 	if (!process_option(opt, cmd, argv))
    444 	    goto err;
    445     }
    446     ret = 1;
    447 
    448 err:
    449     fclose(f);
    450     privileged_option = oldpriv;
    451     option_source = oldsource;
    452     return ret;
    453 }
    454 
    455 /*
    456  * options_from_user - See if the use has a ~/.ppprc file,
    457  * and if so, interpret options from it.
    458  */
    459 int
    460 options_from_user()
    461 {
    462     char *user, *path, *file;
    463     int ret;
    464     struct passwd *pw;
    465     size_t pl;
    466 
    467     pw = getpwuid(getuid());
    468     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
    469 	return 1;
    470     file = _PATH_USEROPT;
    471     pl = strlen(user) + strlen(file) + 2;
    472     path = malloc(pl);
    473     if (path == NULL)
    474 	novm("init file name");
    475     slprintf(path, pl, "%s/%s", user, file);
    476     option_priority = OPRIO_CFGFILE;
    477     ret = options_from_file(path, 0, 1, privileged);
    478     free(path);
    479     return ret;
    480 }
    481 
    482 /*
    483  * options_for_tty - See if an options file exists for the serial
    484  * device, and if so, interpret options from it.
    485  * We only allow the per-tty options file to override anything from
    486  * the command line if it is something that the user can't override
    487  * once it has been set by root; this is done by giving configuration
    488  * files a lower priority than the command line.
    489  */
    490 int
    491 options_for_tty()
    492 {
    493     char *dev, *path, *p;
    494     int ret;
    495     size_t pl;
    496 
    497     dev = devnam;
    498     if ((p = strstr(dev, "/dev/")) != NULL)
    499 	dev = p + 5;
    500     if (dev[0] == 0 || strcmp(dev, "tty") == 0)
    501 	return 1;		/* don't look for /etc/ppp/options.tty */
    502     pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
    503     path = malloc(pl);
    504     if (path == NULL)
    505 	novm("tty init file name");
    506     slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
    507     /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
    508     for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
    509 	if (*p == '/')
    510 	    *p = '.';
    511     option_priority = OPRIO_CFGFILE;
    512     ret = options_from_file(path, 0, 0, 1);
    513     free(path);
    514     return ret;
    515 }
    516 
    517 /*
    518  * options_from_list - process a string of options in a wordlist.
    519  */
    520 int
    521 options_from_list(w, priv)
    522     struct wordlist *w;
    523     int priv;
    524 {
    525     char *argv[MAXARGS];
    526     option_t *opt;
    527     int i, n, ret = 0;
    528     struct wordlist *w0;
    529 
    530     privileged_option = priv;
    531     option_source = "secrets file";
    532     option_priority = OPRIO_SECFILE;
    533 
    534     while (w != NULL) {
    535 	opt = find_option(w->word);
    536 	if (opt == NULL) {
    537 	    option_error("In secrets file: unrecognized option '%s'",
    538 			 w->word);
    539 	    goto err;
    540 	}
    541 	n = n_arguments(opt);
    542 	w0 = w;
    543 	for (i = 0; i < n; ++i) {
    544 	    w = w->next;
    545 	    if (w == NULL) {
    546 		option_error(
    547 			"In secrets file: too few parameters for option '%s'",
    548 			w0->word);
    549 		goto err;
    550 	    }
    551 	    argv[i] = w->word;
    552 	}
    553 	if (!process_option(opt, w0->word, argv))
    554 	    goto err;
    555 	w = w->next;
    556     }
    557     ret = 1;
    558 
    559 err:
    560     return ret;
    561 }
    562 
    563 /*
    564  * match_option - see if this option matches an option_t structure.
    565  */
    566 static int
    567 match_option(name, opt, dowild)
    568     char *name;
    569     option_t *opt;
    570     int dowild;
    571 {
    572 	int (*match) __P((char *, char **, int));
    573 
    574 	if (dowild != (opt->type == o_wild))
    575 		return 0;
    576 	if (!dowild)
    577 		return strcmp(name, opt->name) == 0;
    578 	match = (int (*) __P((char *, char **, int))) opt->addr;
    579 	return (*match)(name, NULL, 0);
    580 }
    581 
    582 /*
    583  * find_option - scan the option lists for the various protocols
    584  * looking for an entry with the given name.
    585  * This could be optimized by using a hash table.
    586  */
    587 static option_t *
    588 find_option(name)
    589     const char *name;
    590 {
    591 	option_t *opt;
    592 	struct option_list *list;
    593 	int i, dowild;
    594 
    595 	for (dowild = 0; dowild <= 1; ++dowild) {
    596 		for (opt = general_options; opt->name != NULL; ++opt)
    597 			if (match_option(name, opt, dowild))
    598 				return opt;
    599 		for (opt = auth_options; opt->name != NULL; ++opt)
    600 			if (match_option(name, opt, dowild))
    601 				return opt;
    602 		for (list = extra_options; list != NULL; list = list->next)
    603 			for (opt = list->options; opt->name != NULL; ++opt)
    604 				if (match_option(name, opt, dowild))
    605 					return opt;
    606 		for (opt = the_channel->options; opt->name != NULL; ++opt)
    607 			if (match_option(name, opt, dowild))
    608 				return opt;
    609 		for (i = 0; protocols[i] != NULL; ++i)
    610 			if ((opt = protocols[i]->options) != NULL)
    611 				for (; opt->name != NULL; ++opt)
    612 					if (match_option(name, opt, dowild))
    613 						return opt;
    614 	}
    615 	return NULL;
    616 }
    617 
    618 /*
    619  * process_option - process one new-style option.
    620  */
    621 static int
    622 process_option(opt, cmd, argv)
    623     option_t *opt;
    624     char *cmd;
    625     char **argv;
    626 {
    627     u_int32_t v;
    628     int iv, a;
    629     char *sv;
    630     int (*parser) __P((char **));
    631     int (*wildp) __P((char *, char **, int));
    632     char *optopt = (opt->type == o_wild)? "": " option";
    633     int prio = option_priority;
    634     option_t *mainopt = opt;
    635 
    636     current_option = opt->name;
    637     if ((opt->flags & OPT_PRIVFIX) && privileged_option)
    638 	prio += OPRIO_ROOT;
    639     while (mainopt->flags & OPT_PRIOSUB)
    640 	--mainopt;
    641     if (mainopt->flags & OPT_PRIO) {
    642 	if (prio < mainopt->priority) {
    643 	    /* new value doesn't override old */
    644 	    if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
    645 		option_error("%s%s set in %s cannot be overridden\n",
    646 			     opt->name, optopt, mainopt->source);
    647 		return 0;
    648 	    }
    649 	    return 1;
    650 	}
    651 	if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
    652 	    warn("%s%s from %s overrides command line",
    653 		 opt->name, optopt, option_source);
    654     }
    655 
    656     if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
    657 	option_error("%s%s cannot be changed after initialization",
    658 		     opt->name, optopt);
    659 	return 0;
    660     }
    661     if ((opt->flags & OPT_PRIV) && !privileged_option) {
    662 	option_error("using the %s%s requires root privilege",
    663 		     opt->name, optopt);
    664 	return 0;
    665     }
    666     if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
    667 	option_error("%s%s is disabled", opt->name, optopt);
    668 	return 0;
    669     }
    670     if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
    671 	option_error("the %s%s may not be changed in %s",
    672 		     opt->name, optopt, option_source);
    673 	return 0;
    674     }
    675 
    676     switch (opt->type) {
    677     case o_bool:
    678 	v = opt->flags & OPT_VALUE;
    679 	*(bool *)(opt->addr) = v;
    680 	if (opt->addr2 && (opt->flags & OPT_A2COPY))
    681 	    *(bool *)(opt->addr2) = v;
    682 	else if (opt->addr2 && (opt->flags & OPT_A2CLR))
    683 	    *(bool *)(opt->addr2) = 0;
    684 	else if (opt->addr2 && (opt->flags & OPT_A2CLRB))
    685 	    *(u_char *)(opt->addr2) &= ~v;
    686 	else if (opt->addr2 && (opt->flags & OPT_A2OR))
    687 	    *(u_char *)(opt->addr2) |= v;
    688 	break;
    689 
    690     case o_int:
    691 	iv = 0;
    692 	if ((opt->flags & OPT_NOARG) == 0) {
    693 	    if (!int_option(*argv, &iv))
    694 		return 0;
    695 	    if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
    696 		 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
    697 		&& !((opt->flags & OPT_ZEROOK && iv == 0))) {
    698 		char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
    699 		switch (opt->flags & OPT_LIMITS) {
    700 		case OPT_LLIMIT:
    701 		    option_error("%s value must be%s >= %d",
    702 				 opt->name, zok, opt->lower_limit);
    703 		    break;
    704 		case OPT_ULIMIT:
    705 		    option_error("%s value must be%s <= %d",
    706 				 opt->name, zok, opt->upper_limit);
    707 		    break;
    708 		case OPT_LIMITS:
    709 		    option_error("%s value must be%s between %d and %d",
    710 				opt->name, zok, opt->lower_limit, opt->upper_limit);
    711 		    break;
    712 		}
    713 		return 0;
    714 	    }
    715 	}
    716 	a = opt->flags & OPT_VALUE;
    717 	if (a >= 128)
    718 	    a -= 256;		/* sign extend */
    719 	iv += a;
    720 	if (opt->flags & OPT_INC)
    721 	    iv += *(int *)(opt->addr);
    722 	if ((opt->flags & OPT_NOINCR) && !privileged_option) {
    723 	    int oldv = *(int *)(opt->addr);
    724 	    if ((opt->flags & OPT_ZEROINF) ?
    725 		(oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
    726 		option_error("%s value cannot be increased", opt->name);
    727 		return 0;
    728 	    }
    729 	}
    730 	*(int *)(opt->addr) = iv;
    731 	if (opt->addr2 && (opt->flags & OPT_A2COPY))
    732 	    *(int *)(opt->addr2) = iv;
    733 	break;
    734 
    735     case o_uint32:
    736 	if (opt->flags & OPT_NOARG) {
    737 	    v = opt->flags & OPT_VALUE;
    738 	    if (v & 0x80)
    739 		    v |= 0xffffff00U;
    740 	} else if (!number_option(*argv, &v, 16))
    741 	    return 0;
    742 	if (opt->flags & OPT_OR)
    743 	    v |= *(u_int32_t *)(opt->addr);
    744 	*(u_int32_t *)(opt->addr) = v;
    745 	if (opt->addr2 && (opt->flags & OPT_A2COPY))
    746 	    *(u_int32_t *)(opt->addr2) = v;
    747 	break;
    748 
    749     case o_string:
    750 	if (opt->flags & OPT_STATIC) {
    751 	    strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
    752 	} else {
    753 	    sv = strdup(*argv);
    754 	    if (sv == NULL)
    755 		novm("option argument");
    756 	    *(char **)(opt->addr) = sv;
    757 	}
    758 	break;
    759 
    760     case o_special_noarg:
    761     case o_special:
    762 	parser = (int (*) __P((char **))) opt->addr;
    763 	if (!(*parser)(argv))
    764 	    return 0;
    765 	if (opt->flags & OPT_A2LIST) {
    766 	    struct option_value *ovp, **pp;
    767 
    768 	    ovp = malloc(sizeof(*ovp) + strlen(*argv));
    769 	    if (ovp != 0) {
    770 		strcpy(ovp->value, *argv);
    771 		ovp->source = option_source;
    772 		ovp->next = NULL;
    773 		pp = (struct option_value **) &opt->addr2;
    774 		while (*pp != 0)
    775 		    pp = &(*pp)->next;
    776 		*pp = ovp;
    777 	    }
    778 	}
    779 	break;
    780 
    781     case o_wild:
    782 	wildp = (int (*) __P((char *, char **, int))) opt->addr;
    783 	if (!(*wildp)(cmd, argv, 1))
    784 	    return 0;
    785 	break;
    786     }
    787 
    788     if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
    789 		|OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST|OPT_A2OR)) == 0)
    790 	*(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
    791 
    792     mainopt->source = option_source;
    793     mainopt->priority = prio;
    794     mainopt->winner = opt - mainopt;
    795 
    796     return 1;
    797 }
    798 
    799 /*
    800  * override_value - if the option priorities would permit us to
    801  * override the value of option, return 1 and update the priority
    802  * and source of the option value.  Otherwise returns 0.
    803  */
    804 int
    805 override_value(option, priority, source)
    806     const char *option;
    807     int priority;
    808     const char *source;
    809 {
    810 	option_t *opt;
    811 
    812 	opt = find_option(option);
    813 	if (opt == NULL)
    814 		return 0;
    815 	while (opt->flags & OPT_PRIOSUB)
    816 		--opt;
    817 	if ((opt->flags & OPT_PRIO) && priority < opt->priority)
    818 		return 0;
    819 	opt->priority = priority;
    820 	opt->source = source;
    821 	opt->winner = -1;
    822 	return 1;
    823 }
    824 
    825 /*
    826  * n_arguments - tell how many arguments an option takes
    827  */
    828 static int
    829 n_arguments(opt)
    830     option_t *opt;
    831 {
    832 	return (opt->type == o_bool || opt->type == o_special_noarg
    833 		|| (opt->flags & OPT_NOARG))? 0: 1;
    834 }
    835 
    836 /*
    837  * add_options - add a list of options to the set we grok.
    838  */
    839 void
    840 add_options(opt)
    841     option_t *opt;
    842 {
    843     struct option_list *list;
    844 
    845     list = malloc(sizeof(*list));
    846     if (list == 0)
    847 	novm("option list entry");
    848     list->options = opt;
    849     list->next = extra_options;
    850     extra_options = list;
    851 }
    852 
    853 /*
    854  * check_options - check that options are valid and consistent.
    855  */
    856 void
    857 check_options()
    858 {
    859 	if (logfile_fd >= 0 && logfile_fd != log_to_fd)
    860 		close(logfile_fd);
    861 }
    862 
    863 /*
    864  * print_option - print out an option and its value
    865  */
    866 static void
    867 print_option(opt, mainopt, printer, arg)
    868     option_t *opt, *mainopt;
    869     void (*printer) __P((void *, char *, ...));
    870     void *arg;
    871 {
    872 	int i, v;
    873 	char *p;
    874 
    875 	if (opt->flags & OPT_NOPRINT)
    876 		return;
    877 	switch (opt->type) {
    878 	case o_bool:
    879 		v = opt->flags & OPT_VALUE;
    880 		if (*(bool *)opt->addr != v)
    881 			/* this can happen legitimately, e.g. lock
    882 			   option turned off for default device */
    883 			break;
    884 		printer(arg, "%s", opt->name);
    885 		break;
    886 	case o_int:
    887 		v = opt->flags & OPT_VALUE;
    888 		if (v >= 128)
    889 			v -= 256;
    890 		i = *(int *)opt->addr;
    891 		if (opt->flags & OPT_NOARG) {
    892 			printer(arg, "%s", opt->name);
    893 			if (i != v) {
    894 				if (opt->flags & OPT_INC) {
    895 					for (; i > v; i -= v)
    896 						printer(arg, " %s", opt->name);
    897 				} else
    898 					printer(arg, " # oops: %d not %d\n",
    899 						i, v);
    900 			}
    901 		} else {
    902 			printer(arg, "%s %d", opt->name, i);
    903 		}
    904 		break;
    905 	case o_uint32:
    906 		printer(arg, "%s", opt->name);
    907 		if ((opt->flags & OPT_NOARG) == 0)
    908 			printer(arg, " %x", *(u_int32_t *)opt->addr);
    909 		break;
    910 
    911 	case o_string:
    912 		if (opt->flags & OPT_HIDE) {
    913 			p = "??????";
    914 		} else {
    915 			p = (char *) opt->addr;
    916 			if ((opt->flags & OPT_STATIC) == 0)
    917 				p = *(char **)p;
    918 		}
    919 		printer(arg, "%s %q", opt->name, p);
    920 		break;
    921 
    922 	case o_special:
    923 	case o_special_noarg:
    924 	case o_wild:
    925 		if (opt->type != o_wild) {
    926 			printer(arg, "%s", opt->name);
    927 			if (n_arguments(opt) == 0)
    928 				break;
    929 			printer(arg, " ");
    930 		}
    931 		if (opt->flags & OPT_A2PRINTER) {
    932 			void (*oprt) __P((option_t *,
    933 					  void ((*)__P((void *, char *, ...))),
    934 					  void *));
    935 			oprt = (void (*) __P((option_t *,
    936 					 void ((*)__P((void *, char *, ...))),
    937 					 void *)))opt->addr2;
    938 			(*oprt)(opt, printer, arg);
    939 		} else if (opt->flags & OPT_A2STRVAL) {
    940 			p = (char *) opt->addr2;
    941 			if ((opt->flags & OPT_STATIC) == 0)
    942 				p = *(char **)p;
    943 			printer("%q", p);
    944 		} else if (opt->flags & OPT_A2LIST) {
    945 			struct option_value *ovp;
    946 
    947 			ovp = (struct option_value *) opt->addr2;
    948 			for (;;) {
    949 				printer(arg, "%q", ovp->value);
    950 				if ((ovp = ovp->next) == NULL)
    951 					break;
    952 				printer(arg, "\t\t# (from %s)\n%s ",
    953 					ovp->source, opt->name);
    954 			}
    955 		} else {
    956 			printer(arg, "xxx # [don't know how to print value]");
    957 		}
    958 		break;
    959 
    960 	default:
    961 		printer(arg, "# %s value (type %d\?\?)", opt->name, opt->type);
    962 		break;
    963 	}
    964 	printer(arg, "\t\t# (from %s)\n", mainopt->source);
    965 }
    966 
    967 /*
    968  * print_option_list - print out options in effect from an
    969  * array of options.
    970  */
    971 static void
    972 print_option_list(opt, printer, arg)
    973     option_t *opt;
    974     void (*printer) __P((void *, char *, ...));
    975     void *arg;
    976 {
    977 	while (opt->name != NULL) {
    978 		if (opt->priority != OPRIO_DEFAULT
    979 		    && opt->winner != (short int) -1)
    980 			print_option(opt + opt->winner, opt, printer, arg);
    981 		do {
    982 			++opt;
    983 		} while (opt->flags & OPT_PRIOSUB);
    984 	}
    985 }
    986 
    987 /*
    988  * print_options - print out what options are in effect.
    989  */
    990 void
    991 print_options(printer, arg)
    992     void (*printer) __P((void *, char *, ...));
    993     void *arg;
    994 {
    995 	struct option_list *list;
    996 	int i;
    997 
    998 	printer(arg, "pppd options in effect:\n");
    999 	print_option_list(general_options, printer, arg);
   1000 	print_option_list(auth_options, printer, arg);
   1001 	for (list = extra_options; list != NULL; list = list->next)
   1002 		print_option_list(list->options, printer, arg);
   1003 	print_option_list(the_channel->options, printer, arg);
   1004 	for (i = 0; protocols[i] != NULL; ++i)
   1005 		print_option_list(protocols[i]->options, printer, arg);
   1006 }
   1007 
   1008 /*
   1009  * usage - print out a message telling how to use the program.
   1010  */
   1011 static void
   1012 usage()
   1013 {
   1014     if (phase == PHASE_INITIALIZE)
   1015 	fprintf(stderr, usage_string, VERSION, progname);
   1016 }
   1017 
   1018 /*
   1019  * showhelp - print out usage message and exit.
   1020  */
   1021 static int
   1022 showhelp(argv)
   1023     char **argv;
   1024 {
   1025     if (phase == PHASE_INITIALIZE) {
   1026 	usage();
   1027 	exit(0);
   1028     }
   1029     return 0;
   1030 }
   1031 
   1032 /*
   1033  * showversion - print out the version number and exit.
   1034  */
   1035 static int
   1036 showversion(argv)
   1037     char **argv;
   1038 {
   1039     if (phase == PHASE_INITIALIZE) {
   1040 	fprintf(stderr, "pppd version %s\n", VERSION);
   1041 	exit(0);
   1042     }
   1043     return 0;
   1044 }
   1045 
   1046 /*
   1047  * option_error - print a message about an error in an option.
   1048  * The message is logged, and also sent to
   1049  * stderr if phase == PHASE_INITIALIZE.
   1050  */
   1051 void
   1052 option_error __V((char *fmt, ...))
   1053 {
   1054     va_list args;
   1055     char buf[1024];
   1056 
   1057 #if defined(__STDC__)
   1058     va_start(args, fmt);
   1059 #else
   1060     char *fmt;
   1061     va_start(args);
   1062     fmt = va_arg(args, char *);
   1063 #endif
   1064     vslprintf(buf, sizeof(buf), fmt, args);
   1065     va_end(args);
   1066     if (phase == PHASE_INITIALIZE)
   1067 	fprintf(stderr, "%s: %s\n", progname, buf);
   1068 #ifndef ANDROID_CHANGES
   1069     syslog(LOG_ERR, "%s", buf);
   1070 #else
   1071     error("%s", buf);
   1072 #endif
   1073 }
   1074 
   1075 #if 0
   1076 /*
   1077  * readable - check if a file is readable by the real user.
   1078  */
   1079 int
   1080 readable(fd)
   1081     int fd;
   1082 {
   1083     uid_t uid;
   1084     int i;
   1085     struct stat sbuf;
   1086 
   1087     uid = getuid();
   1088     if (uid == 0)
   1089 	return 1;
   1090     if (fstat(fd, &sbuf) != 0)
   1091 	return 0;
   1092     if (sbuf.st_uid == uid)
   1093 	return sbuf.st_mode & S_IRUSR;
   1094     if (sbuf.st_gid == getgid())
   1095 	return sbuf.st_mode & S_IRGRP;
   1096     for (i = 0; i < ngroups; ++i)
   1097 	if (sbuf.st_gid == groups[i])
   1098 	    return sbuf.st_mode & S_IRGRP;
   1099     return sbuf.st_mode & S_IROTH;
   1100 }
   1101 #endif
   1102 
   1103 /*
   1104  * Read a word from a file.
   1105  * Words are delimited by white-space or by quotes (" or ').
   1106  * Quotes, white-space and \ may be escaped with \.
   1107  * \<newline> is ignored.
   1108  */
   1109 int
   1110 getword(f, word, newlinep, filename)
   1111     FILE *f;
   1112     char *word;
   1113     int *newlinep;
   1114     char *filename;
   1115 {
   1116     int c, len, escape;
   1117     int quoted, comment;
   1118     int value, digit, got, n;
   1119 
   1120 #define isoctal(c) ((c) >= '0' && (c) < '8')
   1121 
   1122     *newlinep = 0;
   1123     len = 0;
   1124     escape = 0;
   1125     comment = 0;
   1126 
   1127     /*
   1128      * First skip white-space and comments.
   1129      */
   1130     for (;;) {
   1131 	c = getc(f);
   1132 	if (c == EOF)
   1133 	    break;
   1134 
   1135 	/*
   1136 	 * A newline means the end of a comment; backslash-newline
   1137 	 * is ignored.  Note that we cannot have escape && comment.
   1138 	 */
   1139 	if (c == '\n') {
   1140 	    if (!escape) {
   1141 		*newlinep = 1;
   1142 		comment = 0;
   1143 	    } else
   1144 		escape = 0;
   1145 	    continue;
   1146 	}
   1147 
   1148 	/*
   1149 	 * Ignore characters other than newline in a comment.
   1150 	 */
   1151 	if (comment)
   1152 	    continue;
   1153 
   1154 	/*
   1155 	 * If this character is escaped, we have a word start.
   1156 	 */
   1157 	if (escape)
   1158 	    break;
   1159 
   1160 	/*
   1161 	 * If this is the escape character, look at the next character.
   1162 	 */
   1163 	if (c == '\\') {
   1164 	    escape = 1;
   1165 	    continue;
   1166 	}
   1167 
   1168 	/*
   1169 	 * If this is the start of a comment, ignore the rest of the line.
   1170 	 */
   1171 	if (c == '#') {
   1172 	    comment = 1;
   1173 	    continue;
   1174 	}
   1175 
   1176 	/*
   1177 	 * A non-whitespace character is the start of a word.
   1178 	 */
   1179 	if (!isspace(c))
   1180 	    break;
   1181     }
   1182 
   1183     /*
   1184      * Save the delimiter for quoted strings.
   1185      */
   1186     if (!escape && (c == '"' || c == '\'')) {
   1187         quoted = c;
   1188 	c = getc(f);
   1189     } else
   1190         quoted = 0;
   1191 
   1192     /*
   1193      * Process characters until the end of the word.
   1194      */
   1195     while (c != EOF) {
   1196 	if (escape) {
   1197 	    /*
   1198 	     * This character is escaped: backslash-newline is ignored,
   1199 	     * various other characters indicate particular values
   1200 	     * as for C backslash-escapes.
   1201 	     */
   1202 	    escape = 0;
   1203 	    if (c == '\n') {
   1204 	        c = getc(f);
   1205 		continue;
   1206 	    }
   1207 
   1208 	    got = 0;
   1209 	    switch (c) {
   1210 	    case 'a':
   1211 		value = '\a';
   1212 		break;
   1213 	    case 'b':
   1214 		value = '\b';
   1215 		break;
   1216 	    case 'f':
   1217 		value = '\f';
   1218 		break;
   1219 	    case 'n':
   1220 		value = '\n';
   1221 		break;
   1222 	    case 'r':
   1223 		value = '\r';
   1224 		break;
   1225 	    case 's':
   1226 		value = ' ';
   1227 		break;
   1228 	    case 't':
   1229 		value = '\t';
   1230 		break;
   1231 
   1232 	    default:
   1233 		if (isoctal(c)) {
   1234 		    /*
   1235 		     * \ddd octal sequence
   1236 		     */
   1237 		    value = 0;
   1238 		    for (n = 0; n < 3 && isoctal(c); ++n) {
   1239 			value = (value << 3) + (c & 07);
   1240 			c = getc(f);
   1241 		    }
   1242 		    got = 1;
   1243 		    break;
   1244 		}
   1245 
   1246 		if (c == 'x') {
   1247 		    /*
   1248 		     * \x<hex_string> sequence
   1249 		     */
   1250 		    value = 0;
   1251 		    c = getc(f);
   1252 		    for (n = 0; n < 2 && isxdigit(c); ++n) {
   1253 			digit = toupper(c) - '0';
   1254 			if (digit > 10)
   1255 			    digit += '0' + 10 - 'A';
   1256 			value = (value << 4) + digit;
   1257 			c = getc (f);
   1258 		    }
   1259 		    got = 1;
   1260 		    break;
   1261 		}
   1262 
   1263 		/*
   1264 		 * Otherwise the character stands for itself.
   1265 		 */
   1266 		value = c;
   1267 		break;
   1268 	    }
   1269 
   1270 	    /*
   1271 	     * Store the resulting character for the escape sequence.
   1272 	     */
   1273 	    if (len < MAXWORDLEN-1)
   1274 		word[len] = value;
   1275 	    ++len;
   1276 
   1277 	    if (!got)
   1278 		c = getc(f);
   1279 	    continue;
   1280 
   1281 	}
   1282 
   1283 	/*
   1284 	 * Not escaped: see if we've reached the end of the word.
   1285 	 */
   1286 	if (quoted) {
   1287 	    if (c == quoted)
   1288 		break;
   1289 	} else {
   1290 	    if (isspace(c) || c == '#') {
   1291 		ungetc (c, f);
   1292 		break;
   1293 	    }
   1294 	}
   1295 
   1296 	/*
   1297 	 * Backslash starts an escape sequence.
   1298 	 */
   1299 	if (c == '\\') {
   1300 	    escape = 1;
   1301 	    c = getc(f);
   1302 	    continue;
   1303 	}
   1304 
   1305 	/*
   1306 	 * An ordinary character: store it in the word and get another.
   1307 	 */
   1308 	if (len < MAXWORDLEN-1)
   1309 	    word[len] = c;
   1310 	++len;
   1311 
   1312 	c = getc(f);
   1313     }
   1314 
   1315     /*
   1316      * End of the word: check for errors.
   1317      */
   1318     if (c == EOF) {
   1319 	if (ferror(f)) {
   1320 	    if (errno == 0)
   1321 		errno = EIO;
   1322 	    option_error("Error reading %s: %m", filename);
   1323 	    die(1);
   1324 	}
   1325 	/*
   1326 	 * If len is zero, then we didn't find a word before the
   1327 	 * end of the file.
   1328 	 */
   1329 	if (len == 0)
   1330 	    return 0;
   1331     }
   1332 
   1333     /*
   1334      * Warn if the word was too long, and append a terminating null.
   1335      */
   1336     if (len >= MAXWORDLEN) {
   1337 	option_error("warning: word in file %s too long (%.20s...)",
   1338 		     filename, word);
   1339 	len = MAXWORDLEN - 1;
   1340     }
   1341     word[len] = 0;
   1342 
   1343     return 1;
   1344 
   1345 #undef isoctal
   1346 
   1347 }
   1348 
   1349 /*
   1350  * number_option - parse an unsigned numeric parameter for an option.
   1351  */
   1352 static int
   1353 number_option(str, valp, base)
   1354     char *str;
   1355     u_int32_t *valp;
   1356     int base;
   1357 {
   1358     char *ptr;
   1359 
   1360     *valp = strtoul(str, &ptr, base);
   1361     if (ptr == str) {
   1362 	option_error("invalid numeric parameter '%s' for %s option",
   1363 		     str, current_option);
   1364 	return 0;
   1365     }
   1366     return 1;
   1367 }
   1368 
   1369 
   1370 /*
   1371  * int_option - like number_option, but valp is int *,
   1372  * the base is assumed to be 0, and *valp is not changed
   1373  * if there is an error.
   1374  */
   1375 int
   1376 int_option(str, valp)
   1377     char *str;
   1378     int *valp;
   1379 {
   1380     u_int32_t v;
   1381 
   1382     if (!number_option(str, &v, 0))
   1383 	return 0;
   1384     *valp = (int) v;
   1385     return 1;
   1386 }
   1387 
   1388 
   1389 /*
   1390  * The following procedures parse options.
   1391  */
   1392 
   1393 /*
   1394  * readfile - take commands from a file.
   1395  */
   1396 static int
   1397 readfile(argv)
   1398     char **argv;
   1399 {
   1400     return options_from_file(*argv, 1, 1, privileged_option);
   1401 }
   1402 
   1403 /*
   1404  * callfile - take commands from /etc/ppp/peers/<name>.
   1405  * Name may not contain /../, start with / or ../, or end in /..
   1406  */
   1407 static int
   1408 callfile(argv)
   1409     char **argv;
   1410 {
   1411     char *fname, *arg, *p;
   1412     int l, ok;
   1413 
   1414     arg = *argv;
   1415     ok = 1;
   1416     if (arg[0] == '/' || arg[0] == 0)
   1417 	ok = 0;
   1418     else {
   1419 	for (p = arg; *p != 0; ) {
   1420 	    if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
   1421 		ok = 0;
   1422 		break;
   1423 	    }
   1424 	    while (*p != '/' && *p != 0)
   1425 		++p;
   1426 	    if (*p == '/')
   1427 		++p;
   1428 	}
   1429     }
   1430     if (!ok) {
   1431 	option_error("call option value may not contain .. or start with /");
   1432 	return 0;
   1433     }
   1434 
   1435     l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
   1436     if ((fname = (char *) malloc(l)) == NULL)
   1437 	novm("call file name");
   1438     slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
   1439 
   1440     ok = options_from_file(fname, 1, 1, 1);
   1441 
   1442     free(fname);
   1443     return ok;
   1444 }
   1445 
   1446 #ifdef PPP_FILTER
   1447 /*
   1448  * setpassfilter - Set the pass filter for packets
   1449  */
   1450 static int
   1451 setpassfilter(argv)
   1452     char **argv;
   1453 {
   1454     pcap_t *pc;
   1455     int ret = 0;
   1456 
   1457     pc = pcap_open_dead(DLT_PPP_WITH_DIRECTION, 65535);
   1458     if (pcap_compile(pc, &pass_filter, *argv, 1, netmask) == -1) {
   1459 	option_error("error in pass-filter expression: %s\n",
   1460 		     pcap_geterr(pc));
   1461 	ret = 1;
   1462     }
   1463     pcap_close(pc);
   1464 
   1465     return ret;
   1466 }
   1467 
   1468 /*
   1469  * setactivefilter - Set the active filter for packets
   1470  */
   1471 static int
   1472 setactivefilter(argv)
   1473     char **argv;
   1474 {
   1475     pcap_t *pc;
   1476     int ret = 0;
   1477 
   1478     pc = pcap_open_dead(DLT_PPP_WITH_DIRECTION, 65535);
   1479     if (pcap_compile(pc, &active_filter, *argv, 1, netmask) == -1) {
   1480 	option_error("error in active-filter expression: %s\n",
   1481 		     pcap_geterr(pc));
   1482 	ret = 1;
   1483     }
   1484     pcap_close(pc);
   1485 
   1486     return ret;
   1487 }
   1488 #endif
   1489 
   1490 /*
   1491  * setdomain - Set domain name to append to hostname
   1492  */
   1493 static int
   1494 setdomain(argv)
   1495     char **argv;
   1496 {
   1497     gethostname(hostname, MAXNAMELEN);
   1498     if (**argv != 0) {
   1499 	if (**argv != '.')
   1500 	    strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
   1501 	domain = hostname + strlen(hostname);
   1502 	strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
   1503     }
   1504     hostname[MAXNAMELEN-1] = 0;
   1505     return (1);
   1506 }
   1507 
   1508 static int
   1509 setlogfile(argv)
   1510     char **argv;
   1511 {
   1512     int fd, err;
   1513 
   1514     if (!privileged_option)
   1515 	seteuid(getuid());
   1516     fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
   1517     if (fd < 0 && errno == EEXIST)
   1518 	fd = open(*argv, O_WRONLY | O_APPEND);
   1519     err = errno;
   1520     if (!privileged_option)
   1521 	seteuid(0);
   1522     if (fd < 0) {
   1523 	errno = err;
   1524 	option_error("Can't open log file %s: %m", *argv);
   1525 	return 0;
   1526     }
   1527     strlcpy(logfile_name, *argv, sizeof(logfile_name));
   1528     if (logfile_fd >= 0)
   1529 	close(logfile_fd);
   1530     logfile_fd = fd;
   1531     log_to_fd = fd;
   1532     log_default = 0;
   1533     return 1;
   1534 }
   1535 
   1536 #ifdef MAXOCTETS
   1537 static int
   1538 setmodir(argv)
   1539     char **argv;
   1540 {
   1541     if(*argv == NULL)
   1542 	return 0;
   1543     if(!strcmp(*argv,"in")) {
   1544         maxoctets_dir = PPP_OCTETS_DIRECTION_IN;
   1545     } else if (!strcmp(*argv,"out")) {
   1546         maxoctets_dir = PPP_OCTETS_DIRECTION_OUT;
   1547     } else if (!strcmp(*argv,"max")) {
   1548         maxoctets_dir = PPP_OCTETS_DIRECTION_MAXOVERAL;
   1549     } else {
   1550         maxoctets_dir = PPP_OCTETS_DIRECTION_SUM;
   1551     }
   1552     return 1;
   1553 }
   1554 #endif
   1555 
   1556 #ifdef PLUGIN
   1557 static int
   1558 loadplugin(argv)
   1559     char **argv;
   1560 {
   1561     char *arg = *argv;
   1562     void *handle;
   1563     const char *err;
   1564     void (*init) __P((void));
   1565     char *path = arg;
   1566     const char *vers;
   1567 
   1568     if (strchr(arg, '/') == 0) {
   1569 	const char *base = _PATH_PLUGIN;
   1570 	int l = strlen(base) + strlen(arg) + 2;
   1571 	path = malloc(l);
   1572 	if (path == 0)
   1573 	    novm("plugin file path");
   1574 	strlcpy(path, base, l);
   1575 	strlcat(path, "/", l);
   1576 	strlcat(path, arg, l);
   1577     }
   1578     handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
   1579     if (handle == 0) {
   1580 	err = dlerror();
   1581 	if (err != 0)
   1582 	    option_error("%s", err);
   1583 	option_error("Couldn't load plugin %s", arg);
   1584 	goto err;
   1585     }
   1586     init = (void (*)(void))dlsym(handle, "plugin_init");
   1587     if (init == 0) {
   1588 	option_error("%s has no initialization entry point", arg);
   1589 	goto errclose;
   1590     }
   1591     vers = (const char *) dlsym(handle, "pppd_version");
   1592     if (vers == 0) {
   1593 	warn("Warning: plugin %s has no version information", arg);
   1594     } else if (strcmp(vers, VERSION) != 0) {
   1595 	option_error("Plugin %s is for pppd version %s, this is %s",
   1596 		     arg, vers, VERSION);
   1597 	goto errclose;
   1598     }
   1599     info("Plugin %s loaded.", arg);
   1600     (*init)();
   1601     return 1;
   1602 
   1603  errclose:
   1604     dlclose(handle);
   1605  err:
   1606     if (path != arg)
   1607 	free(path);
   1608     return 0;
   1609 }
   1610 #endif /* PLUGIN */
   1611