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