xref: /netbsd/external/bsd/ppp/dist/pppd/options.c (revision 3dce80e5)
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)
83 char *strdup(char *);
84 #endif
85 
86 
87 struct 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  */
96 int	debug = 0;		/* Debug flag */
97 int	kdebugflag = 0;		/* Tell kernel to print debug messages */
98 int	default_device = 1;	/* Using /dev/tty or equivalent */
99 char	devnam[MAXPATHLEN];	/* Device name */
100 bool	nodetach = 0;		/* Don't detach from controlling tty */
101 bool	updetach = 0;		/* Detach once link is up */
102 bool	master_detach;		/* Detach when we're (only) multilink master */
103 #ifdef SYSTEMD
104 bool	up_sdnotify = 0;	/* Notify systemd once link is up */
105 #endif
106 int	maxconnect = 0;		/* Maximum connect time */
107 char	user[MAXNAMELEN];	/* Username for PAP */
108 char	passwd[MAXSECRETLEN];	/* Password for PAP */
109 bool	persist = 0;		/* Reopen link after it goes down */
110 char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
111 bool	demand = 0;		/* do dial-on-demand */
112 char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
113 int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
114 int	holdoff = 30;		/* # seconds to pause before reconnecting */
115 bool	holdoff_specified;	/* true if a holdoff value has been given */
116 int	log_to_fd = 1;		/* send log messages to this fd too */
117 bool	log_default = 1;	/* log_to_fd is default (stdout) */
118 int	maxfail = 10;		/* max # of unsuccessful connection attempts */
119 char	linkname[MAXPATHLEN];	/* logical name for link */
120 bool	tune_kernel;		/* may alter kernel settings */
121 int	connect_delay = 1000;	/* wait this many ms after connect script */
122 int	req_unit = -1;		/* requested interface unit */
123 char	path_ipup[MAXPATHLEN];	/* pathname of ip-up script */
124 char	path_ipdown[MAXPATHLEN];/* pathname of ip-down script */
125 char	req_ifname[MAXIFNAMELEN];	/* requested interface name */
126 bool	multilink = 0;		/* Enable multilink operation */
127 char	*bundle_name = NULL;	/* bundle name for multilink */
128 bool	dump_options;		/* print out option values */
129 bool	dryrun;			/* print out option values and exit */
130 char	*domain;		/* domain name set by domain option */
131 int	child_wait = 5;		/* # seconds to wait for children at exit */
132 struct userenv *userenv_list;	/* user environment variables */
133 int	dfl_route_metric = -1;	/* metric of the default route to set over the PPP link */
134 
135 #ifdef MAXOCTETS
136 unsigned int  maxoctets = 0;    /* default - no limit */
137 int maxoctets_dir = 0;       /* default - sum of traffic */
138 int maxoctets_timeout = 1;   /* default 1 second */
139 #endif
140 
141 
142 extern option_t auth_options[];
143 extern struct stat devstat;
144 
145 #ifdef PPP_FILTER
146 /* Filter program for packets to pass */
147 struct	bpf_program pass_filter_in;
148 struct	bpf_program pass_filter_out;
149 
150 /* Filter program for link-active packets */
151 struct	bpf_program active_filter_in;
152 struct	bpf_program active_filter_out;
153 #endif
154 
155 static option_t *curopt;	/* pointer to option being processed */
156 char *current_option;		/* the name of the option being parsed */
157 int  privileged_option;		/* set iff the current option came from root */
158 char *option_source;		/* string saying where the option came from */
159 int  option_priority = OPRIO_CFGFILE; /* priority of the current options */
160 bool devnam_fixed;		/* can no longer change device name */
161 
162 static int logfile_fd = -1;	/* fd opened for log file */
163 static char logfile_name[MAXPATHLEN];	/* name of log file */
164 
165 /*
166  * Prototypes
167  */
168 static int setdomain(char **);
169 static int readfile(char **);
170 static int callfile(char **);
171 static int showversion(char **);
172 static int showhelp(char **);
173 static void usage(void);
174 static int setlogfile(char **);
175 #ifdef PLUGIN
176 static int loadplugin(char **);
177 #endif
178 
179 #ifdef PPP_FILTER
180 static int setpassfilter_in(char **);
181 static int setactivefilter_in(char **);
182 static int setpassfilter_out(char **);
183 static int setactivefilter_out(char **);
184 #endif
185 
186 #ifdef MAXOCTETS
187 static int setmodir(char **);
188 #endif
189 
190 static int user_setenv(char **);
191 static void user_setprint(option_t *, printer_func, void *);
192 static int user_unsetenv(char **);
193 static void user_unsetprint(option_t *, printer_func, void *);
194 
195 static option_t *find_option(char *name);
196 static int process_option(option_t *, char *, char **);
197 static int n_arguments(option_t *);
198 static int number_option(char *, u_int32_t *, int);
199 
200 /*
201  * Structure to store extra lists of options.
202  */
203 struct option_list {
204     option_t *options;
205     struct option_list *next;
206 };
207 
208 static struct option_list *extra_options = NULL;
209 
210 /*
211  * Valid arguments.
212  */
213 option_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 
390 static const char *usage_string = "\
391 pppd version %s\n\
392 Usage: %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\
406 See pppd(8) for more options.\n\
407 ";
408 
409 /*
410  * parse_args - parse a string of arguments from the command line.
411  */
412 int
parse_args(int argc,char ** argv)413 parse_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  */
448 int
options_from_file(char * filename,int must_exist,int check_prot,int priv)449 options_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 
510 err:
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  */
521 int
options_from_user(void)522 options_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  */
552 int
options_for_tty(void)553 options_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  */
582 int
options_from_list(struct wordlist * w,int priv)583 options_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 
619 err:
620     return ret;
621 }
622 
623 /*
624  * match_option - see if this option matches an option_t structure.
625  */
626 static int
match_option(char * name,option_t * opt,int dowild)627 match_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  */
644 static option_t *
find_option(char * name)645 find_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  */
677 static int
process_option(option_t * opt,char * cmd,char ** argv)678 process_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  */
873 int
override_value(char * option,int priority,const char * source)874 override_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  */
894 static int
n_arguments(option_t * opt)895 n_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  */
904 void
add_options(option_t * opt)905 add_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  */
920 void
check_options(void)921 check_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  */
930 static void
print_option(option_t * opt,option_t * mainopt,printer_func printer,void * arg)931 print_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  */
1029 static void
print_option_list(option_t * opt,printer_func printer,void * arg)1030 print_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  */
1045 void
print_options(printer_func printer,void * arg)1046 print_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  */
1064 static void
usage(void)1065 usage(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  */
1074 static int
showhelp(char ** argv)1075 showhelp(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  */
1087 static int
showversion(char ** argv)1088 showversion(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  */
1102 void
option_error(char * fmt,...)1103 option_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  */
1120 int
1121 readable(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
getword(FILE * f,char * word,int * newlinep,char * filename)1150 getword(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  */
1391 static int
number_option(char * str,u_int32_t * valp,int base)1392 number_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  */
1411 int
int_option(char * str,int * valp)1412 int_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  */
1430 static int
readfile(char ** argv)1431 readfile(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  */
1440 static int
callfile(char ** argv)1441 callfile(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  */
1483 static int
setpassfilter_in(argv)1484 setpassfilter_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  */
1504 static int
setpassfilter_out(argv)1505 setpassfilter_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  */
1525 static int
setactivefilter_in(char ** argv)1526 setactivefilter_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  */
1545 static int
setactivefilter_out(char ** argv)1546 setactivefilter_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  */
1566 static int
setdomain(char ** argv)1567 setdomain(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 
1580 static int
setlogfile(char ** argv)1581 setlogfile(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
1612 static int
setmodir(char ** argv)1613 setmodir(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
1631 static int
loadplugin(char ** argv)1632 loadplugin(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  */
1688 static int
user_setenv(char ** argv)1689 user_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 
1740 static void
user_setprint(option_t * opt,printer_func printer,void * arg)1741 user_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 
1760 static int
user_unsetenv(char ** argv)1761 user_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 
1808 static void
user_unsetprint(option_t * opt,printer_func printer,void * arg)1809 user_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