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