xref: /titanic_51/usr/src/cmd/cmd-inet/usr.bin/pppd/options.c (revision 084c18406d32a8fbb6b9a40d864e7c7ddb5b4d9d)
1 /*
2  * options.c - handles option processing for PPP.
3  *
4  * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.
10  *
11  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
15  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17  *
18  * Copyright (c) 1989 Carnegie Mellon University.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that the above copyright notice and this paragraph are
23  * duplicated in all such forms and that any documentation,
24  * advertising materials, and other materials related to such
25  * distribution and use acknowledge that the software was developed
26  * by Carnegie Mellon University.  The name of the
27  * University may not be used to endorse or promote products derived
28  * from this software without specific prior written permission.
29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  */
33 
34 #define RCSID	"$Id: options.c,v 1.74 2000/04/15 01:27:13 masputra Exp $"
35 
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <syslog.h>
43 #include <string.h>
44 #include <netdb.h>
45 #include <pwd.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #ifdef PLUGIN
51 #include <dlfcn.h>
52 #endif /* PLUGIN */
53 #ifdef PPP_FILTER
54 #include <pcap.h>
55 #include <pcap-int.h>	/* XXX: To get struct pcap */
56 #endif /* PPP_FILTER */
57 
58 #include "pppd.h"
59 #include "pathnames.h"
60 #include "patchlevel.h"
61 #include "fsm.h"
62 #include "lcp.h"
63 #include "ipcp.h"
64 
65 #if defined(ultrix) || defined(NeXT)
66 char *strdup __P((char *));
67 #endif
68 
69 #if !defined(lint) && !defined(_lint)
70 static const char rcsid[] = RCSID;
71 #endif
72 
73 /*
74  * Option variables and default values.
75  */
76 #ifdef PPP_FILTER
77 int	dflag = 0;		/* Tell libpcap we want debugging */
78 #endif /* PPP_FILTER */
79 int	debug = 0;		/* Debug flag */
80 int	kdebugflag = 0;		/* Tell kernel to print debug messages */
81 int	default_device = 1;	/* Using /dev/tty or equivalent */
82 char	devnam[MAXPATHLEN];	/* Device name */
83 int	crtscts = 0;		/* Use hardware flow control */
84 bool	modem = 1;		/* Use modem control lines */
85 int	inspeed = 0;		/* Input/Output speed requested */
86 u_int32_t netmask = 0;		/* IP netmask to set on interface */
87 bool	lockflag = 0;		/* Create lock file to lock the serial dev */
88 bool	nodetach = 0;		/* Don't detach from controlling tty */
89 bool	updetach = 0;		/* Detach once link is up */
90 char	*initializer = NULL;	/* Script to initialize physical link */
91 char	*connect_script = NULL;	/* Script to establish physical link */
92 char	*disconnect_script = NULL; /* Script to disestablish physical link */
93 char	*welcomer = NULL;	/* Script to run after phys link estab. */
94 char	*ptycommand = NULL;	/* Command to run on other side of pty */
95 int	maxconnect = 0;		/* Maximum connect time */
96 char	user[MAXNAMELEN];	/* Username for PAP */
97 char	passwd[MAXSECRETLEN];	/* Password for PAP */
98 bool	persist = 0;		/* Reopen link after it goes down */
99 char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
100 bool	demand = 0;		/* do dial-on-demand */
101 char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
102 int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
103 int	holdoff = 30;		/* # seconds to pause before reconnecting */
104 bool	holdoff_specified;	/* true if a holdoff value has been given */
105 bool	notty = 0;		/* Stdin/out is not a tty */
106 char	*pty_socket = NULL;	/* Socket to connect to pty */
107 char	*record_file = NULL;	/* File to record chars sent/received */
108 int	using_pty = 0;
109 bool	sync_serial = 0;	/* Device is synchronous serial device */
110 int	log_to_fd = 1;		/* send log messages to this fd too */
111 int	maxfail = 10;		/* max # of unsuccessful connection attempts */
112 char	linkname[MAXPATHLEN];	/* logical name for link */
113 bool	tune_kernel;		/* may alter kernel settings */
114 int	connect_delay = 1000;	/* wait this many ms after connect script */
115 int	max_data_rate;		/* max bytes/sec through charshunt */
116 int	req_unit = -1;		/* requested interface unit */
117 bool	multilink = 0;		/* Enable multilink operation */
118 char	*bundle_name = NULL;	/* bundle name for multilink */
119 bool	direct_tty = 0;		/* use standard input directly; not a tty */
120 
121 /* Maximum depth of include files; prevents looping. */
122 #define	MAXFILENESTING	10
123 
124 struct option_info initializer_info;
125 struct option_info connect_script_info;
126 struct option_info disconnect_script_info;
127 struct option_info welcomer_info;
128 struct option_info devnam_info;
129 struct option_info ptycommand_info;
130 struct option_info ipsrc_info;
131 struct option_info ipdst_info;
132 struct option_info speed_info;
133 
134 #ifdef PPP_FILTER
135 struct	bpf_program pass_filter;/* Filter program for packets to pass */
136 struct	bpf_program active_filter; /* Filter program for link-active pkts */
137 pcap_t  pc;			/* Fake struct pcap so we can compile expr */
138 #endif /* PPP_FILTER */
139 
140 char *current_option;		/* the name of the option being parsed */
141 bool privileged_option;		/* set iff the current option came from root */
142 char *option_source = NULL;	/* string saying where the option came from */
143 int option_line = 0;		/* line number in file */
144 bool log_to_file;		/* log_to_fd is a file opened by us */
145 bool log_to_specific_fd;	/* log_to_fd was specified by user option */
146 
147 /*
148  * Prototypes.
149  */
150 static int setdevname __P((char *));
151 static int setipaddr __P((char *));
152 static int setspeed __P((char *));
153 static int noopt __P((char **, option_t *));
154 static int setdomain __P((char **, option_t *));
155 static int setnetmask __P((char **, option_t *));
156 static int setxonxoff __P((char **, option_t *));
157 static int readfile __P((char **, option_t *));
158 static int callfile __P((char **, option_t *));
159 static int showversion __P((char **, option_t *));
160 static int showhelp __P((char **, option_t *));
161 static int showalloptions __P((char **, option_t *));
162 static void usage __P((void));
163 static int setlogfile __P((char **, option_t *));
164 #ifdef PLUGIN
165 static int loadplugin __P((char **, option_t *));
166 #endif
167 #ifdef PPP_FILTER
168 static int setpassfilter __P((char **, option_t *));
169 static int setactivefilter __P((char **, option_t *));
170 #endif /* PPP_FILTER */
171 static option_t *find_option __P((char *name));
172 static int process_option __P((option_t *opt, char **argv, int sline));
173 static int n_arguments __P((option_t *opt));
174 static int number_option __P((char *str, u_int32_t *valp, int base));
175 static u_int32_t opt_hash __P((const void *key));
176 static int opt_compare __P((const void *p1, const void *p2));
177 
178 typedef struct _opt_t {
179     option_t	*p;
180 } opt_t;
181 
182 typedef struct _hashentry_t {
183     struct _hashentry_t	*next;
184     opt_t		opt;
185 } hashentry_t;
186 
187 /*
188  * A prime number describing the size of hash table.
189  */
190 #define	OPTHASH_TBLSIZE	101
191 
192 /*
193  * Chained hash table containing pointers to available options.
194  */
195 static hashentry_t *hash_tbl[OPTHASH_TBLSIZE] = { NULL };
196 
197 /*
198  * Total number of entries in the hash table.
199  */
200 int hash_tblcnt = 0;
201 
202 /*
203  * Valid arguments.
204  */
205 option_t general_options[] = {
206     { "debug", o_int, &debug,
207       "Increase debugging level", OPT_INC|OPT_NOARG|1 },
208     { "-d", o_int, &debug,
209       "Increase debugging level", OPT_INC|OPT_NOARG|1 },
210     { "kdebug", o_int, &kdebugflag,
211       "Set kernel driver debug level" },
212     { "nodetach", o_bool, &nodetach,
213       "Don't detach from controlling tty", 1 },
214     { "-detach", o_bool, &nodetach,
215       "Don't detach from controlling tty", 1 },
216     { "updetach", o_bool, &updetach,
217       "Detach from controlling tty once link is up", 1 },
218     { "holdoff", o_int, &holdoff,
219       "Set time in seconds before retrying connection" },
220     { "idle", o_int, &idle_time_limit,
221       "Set time in seconds before disconnecting idle link" },
222     { "lock", o_bool, &lockflag,
223       "Lock serial device with UUCP-style lock file", 1 },
224     { "-all", o_special_noarg, (void *)noopt,
225       "Don't request/allow any LCP or IPCP options (useless)" },
226     { "init", o_string, &initializer,
227       "A program to initialize the device",
228       OPT_A2INFO | OPT_PRIVFIX, &initializer_info },
229     { "connect", o_string, &connect_script,
230       "A program to set up a connection",
231       OPT_A2INFO | OPT_PRIVFIX, &connect_script_info },
232     { "disconnect", o_string, &disconnect_script,
233       "Program to disconnect serial device",
234       OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info },
235     { "welcome", o_string, &welcomer,
236       "Script to welcome client",
237       OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
238     { "pty", o_string, &ptycommand,
239       "Script to run on pseudo-tty master side",
240       OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
241     { "notty", o_bool, &notty,
242       "Input/output is not a tty", OPT_DEVNAM | 1 },
243     { "directtty", o_bool, &direct_tty,
244       "Use standard input as tty without checking", OPT_DEVNAM | 1 },
245     { "socket", o_string, &pty_socket,
246       "Send and receive over socket, arg is host:port", OPT_DEVNAM },
247     { "record", o_string, &record_file,
248       "Record characters sent/received to file" },
249     { "maxconnect", o_int, &maxconnect,
250       "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
251     { "crtscts", o_int, &crtscts,
252       "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) },
253     { "nocrtscts", o_int, &crtscts,
254       "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
255     { "-crtscts", o_int, &crtscts,
256       "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
257     { "cdtrcts", o_int, &crtscts,
258       "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) },
259     { "nocdtrcts", o_int, &crtscts,
260       "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
261     { "xonxoff", o_special_noarg, (void *)setxonxoff,
262       "Set software (XON/XOFF) flow control" },
263     { "domain", o_special, (void *)setdomain,
264       "Add given domain name to hostname" },
265     { "netmask", o_special, (void *)setnetmask,
266       "set netmask" },
267     { "modem", o_bool, &modem,
268       "Use modem control lines", 1 },
269     { "local", o_bool, &modem,
270       "Don't use modem control lines" },
271     { "file", o_special, (void *)readfile,
272       "Take options from a file", OPT_PREPASS },
273     { "call", o_special, (void *)callfile,
274       "Take options from a privileged file", OPT_PREPASS },
275     { "persist", o_bool, &persist,
276       "Keep on reopening connection after close", 1 },
277     { "nopersist", o_bool, &persist,
278       "Turn off persist option" },
279     { "demand", o_bool, &demand,
280       "Dial on demand", OPT_INITONLY | 1, &persist },
281     { "--version", o_special_noarg, (void *)showversion,
282       "Show version number" },
283     { "--help", o_special_noarg, (void *)showhelp,
284       "Show brief listing of options" },
285     { "-h", o_special_noarg, (void *)showhelp,
286       "Show brief listing of options" },
287     { "options", o_special_noarg, (void *)showalloptions,
288       "Show full listing of options" },
289     { "sync", o_bool, &sync_serial,
290       "Use synchronous HDLC serial encoding", 1 },
291     { "logfd", o_int, &log_to_fd,
292       "Send log messages to this file descriptor",
293       0, &log_to_specific_fd },
294     { "logfile", o_special, (void *)setlogfile,
295       "Append log messages to this file" },
296     { "nolog", o_int, &log_to_fd,
297       "Don't send log messages to any file",
298       OPT_NOARG | OPT_VAL(-1) },
299     { "nologfd", o_int, &log_to_fd,
300       "Don't send log messages to any file descriptor",
301       OPT_NOARG | OPT_VAL(-1) },
302     { "linkname", o_string, linkname,
303       "Set logical name for link",
304       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
305     { "maxfail", o_int, &maxfail,
306       "Number of unsuccessful connection attempts to allow" },
307     { "ktune", o_bool, &tune_kernel,
308       "Alter kernel settings as necessary", 1 },
309     { "noktune", o_bool, &tune_kernel,
310       "Don't alter kernel settings", 0 },
311     { "connect-delay", o_int, &connect_delay,
312       "Maximum wait time (msec) after connect script finishes" },
313     { "datarate", o_int, &max_data_rate,
314       "Max data rate in bytes/sec for pty, notty, or record" },
315     { "unit", o_int, &req_unit,
316       "PPP interface unit number to use if possible", OPT_LLIMIT, 0, 0 },
317 #ifdef HAVE_MULTILINK
318     { "multilink", o_bool, &multilink,
319       "Enable multilink operation", 1 },
320     { "nomultilink", o_bool, &multilink,
321       "Disable multilink operation", 0 },
322     { "mp", o_bool, &multilink,
323       "Enable multilink operation", 1 },
324     { "nomp", o_bool, &multilink,
325       "Disable multilink operation", 0 },
326     { "bundle", o_string, &bundle_name,
327       "Bundle name for multilink" },
328 #endif /* HAVE_MULTILINK */
329 #ifdef PLUGIN
330     { "plugin", o_special, (void *)loadplugin,
331       "Load a plug-in module into pppd", OPT_PRIV },
332 #endif /* PLUGIN */
333 #ifdef PPP_FILTER
334     { "pdebug", o_int, &dflag,
335       "libpcap debugging" },
336     { "pass-filter", o_special, setpassfilter,
337       "set filter for packets to pass" },
338     { "active-filter", o_special, setactivefilter,
339       "set filter for active pkts" },
340 #endif /* PPP_FILTER */
341     { NULL }
342 };
343 
344 /*
345  * This string gets printed out when "options" is given on the command
346  * line.  Following this string, all of the available options and
347  * their descriptions are printed out as well.  Certain options which
348  * are not available as part of the option_t structure are placed in
349  * the "dummy" option structure.
350  */
351 static const char pre_allopt_string[] = "\
352 pppd version %s.%d%s\n\
353 Usage: %s [ options ], where options are:\n\n\
354 ";
355 
356 /* Do not call add_options() on this structure */
357 static option_t dummy_options[] = {
358     { "<device>", o_special_noarg, NULL,
359       "Communicate over the named device" },
360     { "<speed>", o_special_noarg, NULL,
361       "Set the baud rate to <speed>" },
362     { "[<loc>]:[<rem>]", o_special_noarg, NULL,
363       "Set the local and/or remote interface IP addresses" },
364     { NULL }
365 };
366 
367 static const char post_allopt_string[] = "\
368 \n\
369 Notes:\
370 \t<n>\tinteger type argument\n\
371 \t<s>\tstring type argument\n\
372 \t<r>\tspecial type argument\n\
373 \t(!)\tprivileged option available only when pppd is executed by root\n\
374 \t\tor when found in the privileged option files (/etc/ppp/options,\n\
375 \t\t/etc/ppp/options.ttyname, /etc/ppp/peers/name, or following\n\
376 \t\t\"--\" in /etc/ppp/pap-secrets or /etc/ppp/chap-secrets).\n\
377 \t(#)\tdisabled option\n\
378 \n\
379 Please see the pppd man page for details.\n";
380 
381 /*
382  * parse_args - parse a string of arguments from the command line.  If prepass
383  * is true, we are scanning for the device name and only processing a few
384  * options, so error messages are suppressed.  Returns 1 upon successful
385  * processing of options, and 0 otherwise.
386  */
387 int
388 parse_args(argc, argv)
389     int argc;
390     char **argv;
391 {
392     char *arg;
393     option_t *opt;
394     int ret;
395 
396     privileged_option = privileged;
397     option_source = "command line";
398     option_line = 0;
399     while (argc > 0) {
400 	arg = *argv++;
401 	--argc;
402 
403 	/*
404 	 * First check to see if it's a known option name.  If so, parse the
405 	 * argument(s) and set the option.
406 	 */
407 	opt = find_option(arg);
408 	if (opt != NULL) {
409 	    int n = n_arguments(opt);
410 	    if (argc < n) {
411 		option_error("too few parameters for option '%s'", arg);
412 		return (0);
413 	    }
414 	    current_option = arg;
415 	    if (!process_option(opt, argv, 0))
416 		return (0);
417 	    argc -= n;
418 	    argv += n;
419 	    continue;
420 	}
421 
422 	/*
423 	 * Maybe a tty name, speed or IP address ?
424 	 */
425 	if (((ret = setdevname(arg)) == 0) &&
426 	    ((ret = setspeed(arg)) == 0) &&
427 	    ((ret = setipaddr(arg)) == 0) && !prepass) {
428 	    option_error("unrecognized option '%s'", arg);
429 	    usage();
430 	    return (0);
431 	}
432 	if (ret < 0)	/* error */
433 	    return (0);
434     }
435     return (1);
436 }
437 
438 /*
439  * options_from_file - read a string of options from a file, and
440  * interpret them.  Returns 1 upon successful processing of options,
441  * and 0 otherwise.
442  */
443 int
444 options_from_file
445 #ifdef __STDC__
446     (char *filename, bool must_exist, bool check_prot, bool priv)
447 #else
448     (filename, must_exist, check_prot, priv)
449     char *filename;
450     bool must_exist;
451     bool check_prot;
452     bool priv;
453 #endif
454 {
455     FILE *f;
456     int i, newline, ret, err;
457     option_t *opt;
458     bool oldpriv;
459     int oldline, sline;
460     char *oldsource;
461     char *argv[MAXARGS];
462     char args[MAXARGS][MAXWORDLEN];
463     char cmd[MAXWORDLEN];
464     static bool firsterr = 1;
465     static int nestlevel = 0;
466 
467     if (nestlevel >= MAXFILENESTING) {
468 	option_error("file nesting too deep");
469 	return (0);
470     }
471     if (check_prot)
472 	(void) seteuid(getuid());
473     errno = 0;
474     f = fopen(filename, "r");
475     err = errno;
476     if (check_prot)
477 	(void) seteuid(0);
478     if (f == NULL) {
479 	if (!must_exist && err == ENOENT)
480 	    return (1);
481 	errno = err;
482 	option_error("Can't open options file %s: %m", filename);
483 	return (0);
484     }
485 
486     nestlevel++;
487     oldpriv = privileged_option;
488     privileged_option = priv;
489     oldsource = option_source;
490     /*
491      * strdup() is used here because the pointer might refer to the
492      * caller's automatic (stack) storage, and the option_info array
493      * records the source file name.
494      */
495     option_source = strdup(filename);
496     oldline = option_line;
497     option_line = 1;
498     if (option_source == NULL)
499 	option_source = "file";
500     ret = 0;
501     while (getword(f, cmd, &newline, filename)) {
502 	sline = option_line;
503 	/*
504 	 * First see if it's a command.
505 	 */
506 	opt = find_option(cmd);
507 	if (opt != NULL) {
508 	    int n = n_arguments(opt);
509 	    for (i = 0; i < n; ++i) {
510 		if (!getword(f, args[i], &newline, filename)) {
511 		    option_error("too few parameters for option '%s'", cmd);
512 		    goto err;
513 		}
514 		argv[i] = args[i];
515 	    }
516 	    current_option = cmd;
517 	    if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
518 		option_error("the '%s' option may not be used here", cmd);
519 		goto err;
520 	    }
521 	    if (!process_option(opt, argv, sline))
522 		goto err;
523 	    continue;
524 	}
525 
526 	/*
527 	 * Maybe a tty name, speed or IP address ?
528 	 */
529 	if (((i = setdevname(cmd)) == 0) &&
530 	    ((i = setspeed(cmd)) == 0) &&
531 	    ((i = setipaddr(cmd)) == 0)) {
532 	    option_error("unrecognized option '%s'", cmd);
533 	    goto err;
534 	}
535 	if (i < 0)		/* error */
536 	    goto err;
537     }
538     ret = 1;
539 
540 err:
541     (void) fclose(f);
542     /* We assume here that we abort all processing on the first error. */
543     if (firsterr)
544 	firsterr = 0;
545     else if (!prepass && !ret)
546 	option_error("error in included file");
547     /*
548      * Cannot free option_source because it might be referenced in one
549      * or more option_info structures now.
550      */
551     privileged_option = oldpriv;
552     option_source = oldsource;
553     option_line = oldline;
554     nestlevel--;
555     return (ret);
556 }
557 
558 /*
559  * options_from_user - see if the user has a ~/.ppprc file, and if so,
560  * interpret options from it.  Returns 1 upon successful processing of
561  * options, and 0 otherwise.
562  */
563 int
564 options_from_user()
565 {
566     char *user, *path, *file;
567     int ret;
568     struct passwd *pw;
569     size_t pl;
570 
571     pw = getpwuid(getuid());
572     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == '\0')
573 	return (1);
574     file = _PATH_USEROPT;
575     pl = strlen(user) + strlen(file) + 2;
576     path = malloc(pl);
577     if (path == NULL)
578 	novm("init file name");
579     (void) slprintf(path, pl, "%s/%s", user, file);
580     ret = options_from_file(path, 0, 1, privileged);
581     free(path);
582     return (ret);
583 }
584 
585 /*
586  * options_for_tty - see if an options file exists for the serial device, and
587  * if so, interpret options from it.  Returns 1 upon successful processing of
588  * options, and 0 otherwise.
589  */
590 int
591 options_for_tty()
592 {
593     char *dev, *path, *p;
594     int ret;
595     size_t pl;
596 
597     dev = devnam;
598     if (strncmp(dev, "/dev/", 5) == 0)
599 	dev += 5;
600     if (dev[0] == '\0' || strcmp(dev, "tty") == 0)
601 	return (1);		/* don't look for /etc/ppp/options.tty */
602     pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
603     path = malloc(pl);
604     if (path == NULL)
605 	novm("tty init file name");
606     (void) slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
607     /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
608     for (p = path + strlen(_PATH_TTYOPT); *p != '\0'; ++p)
609 	if (*p == '/')
610 	    *p = '.';
611     ret = options_from_file(path, 0, 0, 1);
612     free(path);
613     return (ret);
614 }
615 
616 /*
617  * options_from_list - process a string of options in a wordlist.  Returns 1
618  * upon successful processing of options, and 0 otherwise.
619  */
620 int
621 options_from_list
622 #ifdef __STDC__
623     (struct wordlist *w, bool priv)
624 #else
625     (w, priv)
626     struct wordlist *w;
627     bool priv;
628 #endif
629 {
630     char *argv[MAXARGS];
631     option_t *opt;
632     int i, ret = 0;
633 
634     privileged_option = priv;
635 
636     /* Caller is expected to set option_source and option_line. */
637 
638     while (w != NULL) {
639 	/*
640 	 * First see if it's a command.
641 	 */
642 	opt = find_option(w->word);
643 	if (opt != NULL) {
644 	    int n = n_arguments(opt);
645 	    struct wordlist *w0 = w;
646 	    for (i = 0; i < n; ++i) {
647 		w = w->next;
648 		if (w == NULL) {
649 		    option_error("too few parameters for option '%s'",
650 			w0->word);
651 		    goto err;
652 		}
653 		argv[i] = w->word;
654 	    }
655 	    current_option = w0->word;
656 	    if (!process_option(opt, argv, option_line))
657 		goto err;
658 	    continue;
659 	}
660 
661 	/*
662 	 * Options from the {p,ch}ap-secrets files can't change the device
663 	 * name nor the speed.  Therefore, calls to setdevname() and
664 	 * setspeed() were removed.
665 	 */
666 	if ((i = setipaddr(w->word)) == 0) {
667 	    option_error("unrecognized option '%s'", w->word);
668 	    goto err;
669 	}
670 	if (i < 0)		/* error */
671 	    goto err;
672     }
673     ret = 1;
674 
675 err:
676     return (ret);
677 }
678 
679 /*
680  * find_option - scan the option lists for the various protocols looking for an
681  * entry with the given name.  Returns a pointer to the matching option_t
682  * structure upon successful processing of options, and NULL otherwise.
683  */
684 static option_t *
685 find_option(name)
686     char *name;
687 {
688     hashentry_t *bucket;
689 
690     bucket = hash_tbl[opt_hash(name)];
691     for (; bucket != NULL; bucket = bucket->next) {
692 	if (bucket->opt.p->name != NULL) {
693 	    if ((strcmp(bucket->opt.p->name, name) == 0) &&
694 		!(bucket->opt.p->flags & OPT_DISABLE)) {
695 		return (bucket->opt.p);
696 	    }
697 	}
698     }
699     return (NULL);
700 }
701 
702 /*
703  * process_option - process one new-style option (something other than a
704  * port name, bit rate, or IP address).  Returns 1 upon successful
705  * processing of options, and 0 otherwise.
706  */
707 static int
708 process_option(opt, argv, sline)
709     option_t *opt;
710     char **argv;
711     int sline;
712 {
713     u_int32_t v;
714     int iv, a;
715     char *sv;
716     int (*parser) __P((char **, option_t *));
717 
718     if ((opt->flags & OPT_PREPASS) == 0 && prepass)
719 	return (1);
720     if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
721 	option_error("it's too late to use the '%s' option", opt->name);
722 	return (0);
723     }
724     if ((opt->flags & OPT_PRIV) && !privileged_option) {
725 	option_error("using the '%s' option requires root privilege",
726 	    opt->name);
727 	return (0);
728     }
729     if ((opt->flags & OPT_ENABLE) && !privileged_option &&
730 	*(bool *)(opt->addr2) == 0) {
731 	option_error("'%s' option is disabled", opt->name);
732 	return (0);
733     }
734     if ((opt->flags & OPT_PRIVFIX) && !privileged_option) {
735 	struct option_info *ip = (struct option_info *) opt->addr2;
736 	if ((ip != NULL) && ip->priv) {
737 	    option_error("'%s' option cannot be overridden", opt->name);
738 	    return (0);
739 	}
740     }
741 
742     switch (opt->type) {
743     case o_bool:
744 	v = opt->flags & OPT_VALUE;
745 	*(bool *)(opt->addr) = (v != 0);
746 	if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY))
747 	    *(bool *)(opt->addr2) = (v != 0);
748 	break;
749 
750     case o_int:
751 	iv = 0;
752 	if ((opt->flags & OPT_NOARG) == 0) {
753 	    if (!int_option(*argv, &iv))
754 		return (0);
755 	    if ((((opt->flags & OPT_LLIMIT) && (iv < opt->lower_limit)) ||
756 		((opt->flags & OPT_ULIMIT) && (iv > opt->upper_limit))) &&
757 		!((opt->flags & OPT_ZEROOK) && (iv == 0))) {
758 		char *zok = (opt->flags & OPT_ZEROOK) ? " zero or" : "";
759 		switch (opt->flags & OPT_LIMITS) {
760 		case OPT_LLIMIT:
761 		    option_error("%s value must be%s >= %d",
762 				 opt->name, zok, opt->lower_limit);
763 		    break;
764 		case OPT_ULIMIT:
765 		    option_error("%s value must be%s <= %d",
766 				 opt->name, zok, opt->upper_limit);
767 		    break;
768 		case OPT_LIMITS:
769 		    option_error("%s value must be%s between %d and %d",
770 				opt->name, zok, opt->lower_limit, opt->upper_limit);
771 		    break;
772 		}
773 		return (0);
774 	    }
775 	}
776 	a = opt->flags & OPT_VALUE;
777 	if (a >= 128)
778 	    a -= 256;		/* sign extend */
779 	iv += a;
780 	if (opt->flags & OPT_INC)
781 	    iv += *(int *)(opt->addr);
782 	if ((opt->flags & OPT_NOINCR) && !privileged_option) {
783 	    int oldv = *(int *)(opt->addr);
784 
785 	    if ((opt->flags & OPT_ZEROINF) && (iv == 0)) {
786 		if (oldv > 0) {
787 		    option_error("%s value cannot be set to infinity; limited to %d",
788 			opt->name, oldv);
789 		    return (0);
790 		}
791 	    } else if (iv > oldv) {
792 		option_error("%s value cannot be increased beyond %d",
793 		    opt->name, oldv);
794 		return (0);
795 	    }
796 	}
797 	*(int *)(opt->addr) = iv;
798 	if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY))
799 	    *(int *)(opt->addr2) = iv;
800 	break;
801 
802     case o_uint32:
803 	if (opt->flags & OPT_NOARG) {
804 	    v = opt->flags & OPT_VALUE;
805 	} else if (!number_option(*argv, &v, 16))
806 	    return (0);
807 	if (opt->flags & OPT_OR)
808 	    v |= *(u_int32_t *)(opt->addr);
809 	*(u_int32_t *)(opt->addr) = v;
810 	if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY))
811 	    *(u_int32_t *)(opt->addr2) = v;
812 	break;
813 
814     case o_string:
815 	if (opt->flags & OPT_STATIC) {
816 	    (void) strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
817 	    if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY)) {
818 		(void) strlcpy((char *)(opt->addr2), *argv, opt->upper_limit);
819 	    }
820 	} else {
821 	    sv = strdup(*argv);
822 	    if (sv == NULL)
823 		novm("option argument");
824 	    *(char **)(opt->addr) = sv;
825 	    if (opt->addr2 != NULL && (opt->flags & OPT_A2COPY))
826 		*(char **)(opt->addr2) = sv;
827 	}
828 	break;
829 
830     case o_special_noarg:
831     case o_special:
832 	parser = (int (*) __P((char **, option_t *))) opt->addr;
833 	if (!(*parser)(argv, opt))
834 	    return (0);
835 	break;
836     }
837 
838     if (opt->addr2 != NULL) {
839 	if (opt->flags & OPT_A2INFO) {
840 	    struct option_info *ip = (struct option_info *) opt->addr2;
841 	    ip->priv = privileged_option;
842 	    ip->source = option_source;
843 	    ip->line = sline;
844 	} else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
845 	    *(bool *)(opt->addr2) = 1;
846     }
847 
848     return (1);
849 }
850 
851 /*
852  * n_arguments - tell how many arguments an option takes.  Returns 1 upon
853  * successful processing of options, and 0 otherwise.
854  */
855 static int
856 n_arguments(opt)
857     option_t *opt;
858 {
859     return ((opt->type == o_bool || opt->type == o_special_noarg ||
860 	    (opt->flags & OPT_NOARG)) ? 0 : 1);
861 }
862 
863 /*
864  * opt_hash - a hash function that works quite well for strings.  Returns
865  * the hash key of the supplied string.
866  */
867 static u_int32_t
868 opt_hash(key)
869     const void *key;
870 {
871     register const char *ptr;
872     register u_int32_t val;
873 
874     val = 0;
875     ptr = key;
876     while (*ptr != '\0') {
877 	int tmp;
878 	val = (val << 4) + (*ptr);
879 	tmp = val & 0xf0000000;
880 	if (tmp) {
881 	    val ^= (tmp >> 24);
882 	    val ^= tmp;
883 	}
884 	ptr++;
885     }
886     return (val % OPTHASH_TBLSIZE);
887 }
888 
889 /*
890  * add_options - add a list of options to the chained hash table.
891  * Also detect duplicate options, and if found, disable the older
892  * definition and log it as an error.
893  */
894 void
895 add_options(opt)
896     option_t *opt;
897 {
898     register option_t *sopt;
899     register hashentry_t *bucket;
900     register u_int32_t loc;
901     hashentry_t *he;
902 
903     /* fill hash-table */
904     for (sopt = opt; sopt->name != NULL; ++sopt, hash_tblcnt++) {
905 
906 	/* first, allocate a hash entry */
907 	he = (hashentry_t *)malloc(sizeof(*he));
908 	if (he == NULL) {
909 	    novm("option hash table entry");
910 	}
911 	he->opt.p = sopt;
912 	he->next = NULL;
913 
914 	/*
915 	 * fill the chained hash table and take care of any collisions or
916 	 * duplicate items.
917 	 */
918 	loc = opt_hash(sopt->name);
919 	bucket = hash_tbl[loc];
920 	if (bucket != NULL) {
921 	    for (;;) {
922 		if (!(bucket->opt.p->flags & OPT_DISABLE) &&
923 		    strcmp(sopt->name, bucket->opt.p->name) == 0) {
924 		    info("option '%s' redefined; old definition disabled",
925 			sopt->name);
926 		    bucket->opt.p->flags |= OPT_DISABLE;
927 		}
928 		if (bucket->next == NULL)
929 		    break;
930 		bucket = bucket->next;
931 	    }
932 	    bucket->next = he;
933 	} else {
934 	    hash_tbl[loc] = he;
935 	}
936     }
937 }
938 
939 /*
940  * remove_option - disable an option.  Returns the option_t structure
941  * of the disabled option, or NULL if the option name is invalid or if
942  * the option has already been disabled.
943  */
944 option_t *
945 remove_option(name)
946     char *name;
947 {
948     option_t *opt;
949 
950     if ((opt = find_option(name)) != NULL) {
951 	opt->flags |= OPT_DISABLE;
952     }
953     return (opt);
954 }
955 
956 /*
957  * opt_compare - a compare function supplied to the quicksort routine.
958  * Returns an integer less than, equal to, or greater than zero to indicate
959  * if the first argument is considered less than, equal to, or greater
960  * than the second argument.
961  */
962 static int
963 opt_compare(p1, p2)
964     const void *p1;
965     const void *p2;
966 {
967     opt_t *o1 = (opt_t *)p1;
968     opt_t *o2 = (opt_t *)p2;
969 
970     return (strcmp(o1->p->name, o2->p->name));
971 }
972 
973 /*ARGSUSED*/
974 static int
975 showalloptions(argv, topt)
976     char **argv;
977     option_t *topt;
978 {
979 #define	MAXOPTSTRLEN	257
980 #define	PRINTOPTIONS()	{					\
981     (void) slprintf(opt_str, sizeof(opt_str), "%s", opt->name);	\
982     if ((opt->type == o_int || opt->type == o_uint32) &&	\
983 	!(opt->flags & OPT_NOARG)) {				\
984 	(void) strlcat(opt_str, " <n>", sizeof(opt_str));	\
985     } else if (opt->type == o_string) {				\
986 	(void) strlcat(opt_str, " <s>", sizeof(opt_str));	\
987     } else if (opt->type == o_special) {			\
988 	(void) strlcat(opt_str, " <r>", sizeof(opt_str));	\
989     }								\
990     if (opt->flags & OPT_PRIV) {				\
991 	(void) strlcat(opt_str, " (!)", sizeof(opt_str));	\
992     } else if (opt->flags & OPT_DISABLE) {			\
993 	(void) strlcat(opt_str, " (#)", sizeof(opt_str));	\
994     }								\
995     (void) printf("%-26s%s\n", opt_str, opt->description);	\
996 }
997 
998     char opt_str[MAXOPTSTRLEN];
999     option_t *opt;
1000     hashentry_t *bucket;
1001     int i, sofar;
1002     opt_t *sopt;
1003 
1004     if (phase != PHASE_INITIALIZE) {
1005 	return (0);
1006     }
1007     (void) printf(pre_allopt_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
1008 	progname);
1009     for (opt = dummy_options; opt->name != NULL; ++opt) {
1010 	PRINTOPTIONS();
1011     }
1012 
1013     sopt = malloc(sizeof(*sopt) * hash_tblcnt);
1014     if (sopt == NULL) {
1015 	novm("sorted option table");
1016     }
1017 
1018     sofar = 0;
1019     for (i = 0; i < OPTHASH_TBLSIZE; i++) {
1020 	for (bucket = hash_tbl[i]; bucket != NULL; bucket = bucket->next) {
1021 	    if (sofar >= hash_tblcnt) {
1022 		fatal("options hash table corrupted; size mismatch");
1023 	    }
1024 	    sopt[sofar++].p = bucket->opt.p;
1025 	}
1026     }
1027 
1028     qsort((void *)sopt, sofar, sizeof(sopt[0]), opt_compare);
1029     for (i = 0; i < sofar; i++) {
1030 	opt = sopt[i].p;
1031 	PRINTOPTIONS();
1032     }
1033 
1034     (void) printf(post_allopt_string);
1035     (void) free(sopt);
1036 
1037 #undef	MAXOPTSTRLEN
1038 #undef	PRINTOPTIONS
1039     return (0);
1040 }
1041 
1042 /*
1043  * usage - print out a message telling how to use the program.
1044  * This string gets printed out when either "--help" or an invalid option
1045  * is specified.
1046  */
1047 static void
1048 usage()
1049 {
1050 	static const char usage_string[] = "\
1051 pppd version %s.%d%s\n\
1052 Usage: %s [ options ], where options are:\n\
1053 \t<device>\tCommunicate over the named device\n\
1054 \t<speed>\t\tSet the baud rate to <speed>\n\
1055 \t<loc>:<rem>\tSet the local and/or remote interface IP\n\
1056 \t\t\taddresses.  Either one may be omitted.\n\
1057 \tnoauth\t\tDon't require authentication from peer\n\
1058 \tconnect <p>\tInvoke shell command <p> to set up the serial line\n\
1059 \tdefaultroute\tAdd default route through interface\n\
1060 Use \"%s options\" or \"man pppd\" for more options.\n\
1061 ";
1062 
1063     if (phase == PHASE_INITIALIZE)
1064 	(void) fprintf(stderr, usage_string, VERSION, PATCHLEVEL,
1065 	    IMPLEMENTATION, progname, progname);
1066 }
1067 
1068 /*
1069  * showhelp - print out usage message and exit program upon success, or
1070  * return 0 otherwise.
1071  */
1072 /*ARGSUSED*/
1073 static int
1074 showhelp(argv, opt)
1075     char **argv;
1076     option_t *opt;
1077 {
1078     if (phase == PHASE_INITIALIZE) {
1079 	usage();
1080 	exit(0);
1081     }
1082     return (0);
1083 }
1084 
1085 /*
1086  * showversion - print out the version number and exit program  upon success,
1087  * or return 0 otherwise.
1088  */
1089 /*ARGSUSED*/
1090 static int
1091 showversion(argv, opt)
1092     char **argv;
1093     option_t *opt;
1094 {
1095     if (phase == PHASE_INITIALIZE) {
1096 	(void) fprintf(stderr, "pppd version %s.%d%s\n", VERSION, PATCHLEVEL,
1097 	    IMPLEMENTATION);
1098 	exit(0);
1099     }
1100     return (0);
1101 }
1102 
1103 /*
1104  * option_error - print a message about an error in an option.  The message is
1105  * logged, and also sent to stderr if phase == PHASE_INITIALIZE.
1106  */
1107 void
1108 option_error __V((char *fmt, ...))
1109 {
1110     va_list args;
1111     char buf[256];
1112     int i, err;
1113 
1114 #if defined(__STDC__)
1115     va_start(args, fmt);
1116 #else
1117     char *fmt;
1118     va_start(args);
1119     fmt = va_arg(args, char *);
1120 #endif
1121     if (prepass) {
1122 	va_end(args);
1123 	return;
1124     }
1125     err = errno;
1126     if (option_source == NULL) {
1127 	i = 0;
1128     } else if (option_line <= 0) {
1129 	(void) strlcpy(buf, option_source, sizeof (buf));
1130 	i = strlen(buf);
1131     } else {
1132 	i = slprintf(buf, sizeof(buf), "%s:%d", option_source, option_line);
1133     }
1134     if (i != 0) {
1135 	(void) strlcat(buf, ": ", sizeof (buf));
1136 	i += 2;
1137     }
1138     errno = err;
1139     (void) vslprintf(buf + i, sizeof (buf) - i, fmt, args);
1140     va_end(args);
1141     if ((phase == PHASE_INITIALIZE) && !detached)
1142 	(void) fprintf(stderr, "%s: %s\n", progname, buf);
1143     syslog(LOG_ERR, "%s", buf);
1144 }
1145 
1146 /*
1147  * getword - read a word from a file.  Words are delimited by white-space or by
1148  * quotes (" or ').  Quotes, white-space and \ may be escaped with \.
1149  * \<newline> is ignored.  Returns 1 upon successful processing of options,
1150  * and 0 otherwise.
1151  */
1152 int
1153 getword(f, word, newlinep, filename)
1154     FILE *f;
1155     char *word;
1156     int *newlinep;
1157     char *filename;
1158 {
1159     int c, len, escape;
1160     int quoted, comment;
1161     int value, digit, got, n;
1162 
1163 #define isoctal(c) ((c) >= '0' && (c) < '8')
1164 
1165     *newlinep = 0;
1166     len = 0;
1167     escape = 0;
1168     comment = 0;
1169 
1170     /*
1171      * First skip white-space and comments.
1172      */
1173     for (;;) {
1174 	c = getc(f);
1175 	if (c == EOF)
1176 	    break;
1177 
1178 	/*
1179 	 * A newline means the end of a comment; backslash-newline
1180 	 * is ignored.  Note that we cannot have escape && comment.
1181 	 */
1182 	if (c == '\n') {
1183 	    option_line++;
1184 	    if (!escape) {
1185 		*newlinep = 1;
1186 		comment = 0;
1187 	    } else
1188 		escape = 0;
1189 	    continue;
1190 	}
1191 
1192 	/*
1193 	 * Ignore characters other than newline in a comment.
1194 	 */
1195 	if (comment)
1196 	    continue;
1197 
1198 	/*
1199 	 * If this character is escaped, we have a word start.
1200 	 */
1201 	if (escape)
1202 	    break;
1203 
1204 	/*
1205 	 * If this is the escape character, look at the next character.
1206 	 */
1207 	if (c == '\\') {
1208 	    escape = 1;
1209 	    continue;
1210 	}
1211 
1212 	/*
1213 	 * If this is the start of a comment, ignore the rest of the line.
1214 	 */
1215 	if (c == '#') {
1216 	    comment = 1;
1217 	    continue;
1218 	}
1219 
1220 	/*
1221 	 * A non-whitespace character is the start of a word.
1222 	 */
1223 	if (!isspace(c))
1224 	    break;
1225     }
1226 
1227     /*
1228      * Save the delimiter for quoted strings.
1229      */
1230     if (!escape && (c == '"' || c == '\'')) {
1231         quoted = c;
1232 	c = getc(f);
1233     } else
1234         quoted = 0;
1235 
1236     /*
1237      * Process characters until the end of the word.
1238      */
1239     while (c != EOF) {
1240 	if (escape) {
1241 	    /*
1242 	     * This character is escaped: backslash-newline is ignored,
1243 	     * various other characters indicate particular values
1244 	     * as for C backslash-escapes.
1245 	     */
1246 	    escape = 0;
1247 	    if (c == '\n') {
1248 	        c = getc(f);
1249 		continue;
1250 	    }
1251 
1252 	    got = 0;
1253 	    switch (c) {
1254 	    case 'a':
1255 		value = '\a';
1256 		break;
1257 	    case 'b':
1258 		value = '\b';
1259 		break;
1260 	    case 'f':
1261 		value = '\f';
1262 		break;
1263 	    case 'n':
1264 		value = '\n';
1265 		break;
1266 	    case 'r':
1267 		value = '\r';
1268 		break;
1269 	    case 's':
1270 		value = ' ';
1271 		break;
1272 	    case 't':
1273 		value = '\t';
1274 		break;
1275 
1276 	    default:
1277 		if (isoctal(c)) {
1278 		    /*
1279 		     * \ddd octal sequence
1280 		     */
1281 		    value = 0;
1282 		    for (n = 0; n < 3 && isoctal(c); ++n) {
1283 			value = (value << 3) + (c & 07);
1284 			c = getc(f);
1285 		    }
1286 		    got = 1;
1287 		    break;
1288 		}
1289 
1290 		if (c == 'x') {
1291 		    /*
1292 		     * \x<hex_string> sequence
1293 		     */
1294 		    value = 0;
1295 		    c = getc(f);
1296 		    for (n = 0; n < 2 && isxdigit(c); ++n) {
1297 			digit = (islower(c) ? toupper(c) : c) - '0';
1298 			if (digit > 10 || digit < 0)	/* allow non-ASCII */
1299 			    digit += '0' + 10 - 'A';
1300 			value = (value << 4) + digit;
1301 			c = getc (f);
1302 		    }
1303 		    got = 1;
1304 		    break;
1305 		}
1306 
1307 		/*
1308 		 * Otherwise the character stands for itself.
1309 		 */
1310 		value = c;
1311 		break;
1312 	    }
1313 
1314 	    /*
1315 	     * Store the resulting character for the escape sequence.
1316 	     */
1317 	    if (len < MAXWORDLEN) {
1318 		word[len] = value;
1319 		++len;
1320 	    }
1321 
1322 	    if (!got)
1323 		c = getc(f);
1324 	    continue;
1325 
1326 	}
1327 
1328 	/*
1329 	 * Not escaped: see if we've reached the end of the word.
1330 	 */
1331 	if (quoted) {
1332 	    if (c == quoted)
1333 		break;
1334 	} else {
1335 	    if (isspace(c) || c == '#') {
1336 		(void) ungetc (c, f);
1337 		break;
1338 	    }
1339 	}
1340 
1341 	/*
1342 	 * Backslash starts an escape sequence.
1343 	 */
1344 	if (c == '\\') {
1345 	    escape = 1;
1346 	    c = getc(f);
1347 	    continue;
1348 	}
1349 
1350 	/*
1351 	 * An ordinary character: store it in the word and get another.
1352 	 */
1353 	if (len < MAXWORDLEN) {
1354 	    word[len] = c;
1355 	    ++len;
1356 	}
1357 
1358 	c = getc(f);
1359     }
1360 
1361     /*
1362      * End of the word: check for errors.
1363      */
1364     if (c == EOF) {
1365 	if (ferror(f)) {
1366 	    if (errno == 0)
1367 		errno = EIO;
1368 	    option_error("Error reading %s: %m", filename);
1369 	    die(1);
1370 	}
1371 	/*
1372 	 * If len is zero, then we didn't find a word before the
1373 	 * end of the file.
1374 	 */
1375 	if (len == 0)
1376 	    return (0);
1377     }
1378 
1379     /*
1380      * Warn if the word was too long, and append a terminating null.
1381      */
1382     if (len >= MAXWORDLEN) {
1383 	option_error("warning: word in file %s too long (%.20s...)",
1384 		     filename, word);
1385 	len = MAXWORDLEN - 1;
1386     }
1387     word[len] = '\0';
1388 
1389     return (1);
1390 
1391 #undef isoctal
1392 
1393 }
1394 
1395 /*
1396  * number_option - parse an unsigned numeric parameter for an option.
1397  * Returns 1 upon successful processing of options, and 0 otherwise.
1398  */
1399 static int
1400 number_option(str, valp, base)
1401     char *str;
1402     u_int32_t *valp;
1403     int base;
1404 {
1405     char *ptr;
1406 
1407     *valp = strtoul(str, &ptr, base);
1408     if (ptr == str || *ptr != '\0') {
1409 	option_error("invalid numeric parameter '%s' for '%s' option",
1410 		     str, current_option);
1411 	return (0);
1412     }
1413     return (1);
1414 }
1415 
1416 /*
1417  * save_source - store option source, line, and privilege into an
1418  * option_info structure.
1419  */
1420 void
1421 save_source(info)
1422     struct option_info *info;
1423 {
1424     info->priv = privileged_option;
1425     info->source = option_source;
1426     info->line = option_line;
1427 }
1428 
1429 /*
1430  * set_source - set option source, line, and privilege from an
1431  * option_info structure.
1432  */
1433 void
1434 set_source(info)
1435     struct option_info *info;
1436 {
1437     privileged_option = info->priv;
1438     option_source = info->source;
1439     option_line = info->line;
1440 }
1441 
1442 /*
1443  * name_source - return string containing option source and line.  Can
1444  * be used as part of an option_error call.
1445  */
1446 const char *
1447 name_source(info)
1448     struct option_info *info;
1449 {
1450     static char buf[MAXPATHLEN];
1451 
1452     if (info->source == NULL)
1453 	return "none";
1454     if (info->line <= 0)
1455 	return info->source;
1456     (void) slprintf(buf, sizeof (buf), "%s:%d", info->source, info->line);
1457     return (const char *)buf;
1458 }
1459 
1460 /*
1461  * int_option - like number_option, but valp is int *, the base is assumed to
1462  * be 0, and *valp is not changed if there is an error.  Returns 1 upon
1463  * successful processing of options, and 0 otherwise.
1464  */
1465 int
1466 int_option(str, valp)
1467     char *str;
1468     int *valp;
1469 {
1470     u_int32_t v;
1471 
1472     if (!number_option(str, &v, 0))
1473 	return (0);
1474     *valp = (int) v;
1475     return (1);
1476 }
1477 
1478 
1479 /*
1480  * The following procedures parse options.
1481  */
1482 
1483 /*
1484  * readfile - take commands from a file.
1485  */
1486 /*ARGSUSED*/
1487 static int
1488 readfile(argv, opt)
1489     char **argv;
1490     option_t *opt;
1491 {
1492     return (options_from_file(*argv, 1, 1, privileged_option));
1493 }
1494 
1495 /*
1496  * callfile - take commands from /etc/ppp/peers/<name>.  Name may not contain
1497  * /../, start with / or ../, or end in /.  Returns 1 upon successful
1498  * processing of options, and 0 otherwise.
1499  */
1500 /*ARGSUSED*/
1501 static int
1502 callfile(argv, opt)
1503     char **argv;
1504     option_t *opt;
1505 {
1506     char *fname, *arg, *p;
1507     int l, ok;
1508 
1509     arg = *argv;
1510     ok = 1;
1511     if (arg[0] == '/' || arg[0] == '\0')
1512 	ok = 0;
1513     else {
1514 	for (p = arg; *p != '\0'; ) {
1515 	    if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
1516 		ok = 0;
1517 		break;
1518 	    }
1519 	    while (*p != '/' && *p != '\0')
1520 		++p;
1521 	    if (*p == '/')
1522 		++p;
1523 	}
1524     }
1525     if (!ok) {
1526 	option_error("call option value may not contain .. or start with /");
1527 	return (0);
1528     }
1529 
1530     l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1531     if ((fname = (char *) malloc(l)) == NULL)
1532 	novm("call file name");
1533     (void) slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
1534 
1535     ok = options_from_file(fname, 1, 1, 1);
1536 
1537     free(fname);
1538     return (ok);
1539 }
1540 
1541 #ifdef PPP_FILTER
1542 /*
1543  * setpdebug - set libpcap debugging level.  Returns 1 upon successful
1544  * processing of options, and 0 otherwise.
1545  */
1546 static int
1547 setpdebug(argv)
1548     char **argv;
1549 {
1550     return (int_option(*argv, &dflag));
1551 }
1552 
1553 /*
1554  * setpassfilter - set the pass filter for packets.  Returns 1 upon successful
1555  * processing of options, and 0 otherwise.
1556  */
1557 /*ARGSUSED*/
1558 static int
1559 setpassfilter(argv, opt)
1560     char **argv;
1561     option_t *opt;
1562 {
1563     pc.linktype = DLT_PPP;
1564     pc.snapshot = PPP_HDRLEN;
1565 
1566     if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
1567 	return (1);
1568     option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
1569     return (0);
1570 }
1571 
1572 /*
1573  * setactivefilter - set the active filter for packets.  Returns 1 upon
1574  * successful processing of options, and 0 otherwise.
1575  */
1576 /*ARGSUSED*/
1577 static int
1578 setactivefilter(argv, opt)
1579     char **argv;
1580     option_t *opt;
1581 {
1582     pc.linktype = DLT_PPP;
1583     pc.snapshot = PPP_HDRLEN;
1584 
1585     if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
1586 	return (1);
1587     option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
1588     return (0);
1589 }
1590 #endif /* PPP_FILTER */
1591 
1592 /*
1593  * noopt - disable all options.  Returns 1 upon successful processing of
1594  * options, and 0 otherwise.
1595  */
1596 /*ARGSUSED*/
1597 static int
1598 noopt(argv, opt)
1599     char **argv;
1600     option_t *opt;
1601 {
1602     BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
1603     BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
1604     BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
1605     BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
1606 
1607     return (1);
1608 }
1609 
1610 /*
1611  * setdomain - set domain name to append to hostname.  Returns 1 upon
1612  * successful processing of options, and 0 otherwise.
1613  */
1614 /*ARGSUSED*/
1615 static int
1616 setdomain(argv, opt)
1617     char **argv;
1618     option_t *opt;
1619 {
1620     if (!privileged_option) {
1621 	option_error("using the domain option requires root privilege");
1622 	return (0);
1623     }
1624     (void) gethostname(hostname, MAXHOSTNAMELEN+1);
1625     if (**argv != '\0') {
1626 	if (**argv != '.')
1627 	    (void) strncat(hostname, ".", MAXHOSTNAMELEN - strlen(hostname));
1628 	(void) strncat(hostname, *argv, MAXHOSTNAMELEN - strlen(hostname));
1629     }
1630     hostname[MAXHOSTNAMELEN] = '\0';
1631     return (1);
1632 }
1633 
1634 
1635 /*
1636  * setspeed - set the speed.  Returns 1 upon successful processing of options,
1637  * and 0 otherwise.
1638  */
1639 static int
1640 setspeed(arg)
1641     char *arg;
1642 {
1643     char *ptr;
1644     int spd;
1645 
1646     if (prepass)
1647 	return (1);
1648     spd = strtol(arg, &ptr, 0);
1649     if (ptr == arg || *ptr != '\0' || spd <= 0)
1650 	return (0);
1651     inspeed = spd;
1652     save_source(&speed_info);
1653     return (1);
1654 }
1655 
1656 
1657 /*
1658  * setdevname - set the device name.  Returns 1 upon successful processing of
1659  * options, 0 when the device does not exist, and -1 when an error is
1660  * encountered.
1661  */
1662 static int
1663 setdevname(cp)
1664     char *cp;
1665 {
1666     struct stat statbuf;
1667     char dev[MAXPATHLEN];
1668 
1669     if (*cp == '\0')
1670 	return (0);
1671 
1672     if (strncmp("/dev/", cp, 5) != 0) {
1673 	(void) strlcpy(dev, "/dev/", sizeof(dev));
1674 	(void) strlcat(dev, cp, sizeof(dev));
1675 	cp = dev;
1676     }
1677 
1678     /*
1679      * Check if there is a character device by this name.
1680      */
1681     if (stat(cp, &statbuf) < 0) {
1682 	if (errno == ENOENT) {
1683 	    return (0);
1684 	}
1685 	option_error("Couldn't stat '%s': %m", cp);
1686 	return (-1);
1687     }
1688     if (!S_ISCHR(statbuf.st_mode)) {
1689 	option_error("'%s' is not a character device", cp);
1690 	return (-1);
1691     }
1692 
1693     if (phase != PHASE_INITIALIZE) {
1694 	option_error("device name cannot be changed after initialization");
1695 	return (-1);
1696     } else if (devnam_fixed) {
1697 	option_error("per-tty options file may not specify device name");
1698 	return (-1);
1699     }
1700 
1701     if (devnam_info.priv && !privileged_option) {
1702 	option_error("device name %s from %s cannot be overridden",
1703 	    devnam, name_source(&devnam_info));
1704 	return (-1);
1705     }
1706 
1707     (void) strlcpy(devnam, cp, sizeof(devnam));
1708     devstat = statbuf;
1709     default_device = 0;
1710     save_source(&devnam_info);
1711 
1712     return (1);
1713 }
1714 
1715 
1716 /*
1717  * setipaddr - set the IP address.  Returns 1 upon successful processing of
1718  * options, 0 when the argument does not contain a `:', and -1 for error.
1719  */
1720 static int
1721 setipaddr(arg)
1722     char *arg;
1723 {
1724     struct hostent *hp;
1725     char *colon;
1726     u_int32_t local, remote;
1727     ipcp_options *wo = &ipcp_wantoptions[0];
1728 
1729     /*
1730      * IP address pair separated by ":".
1731      */
1732     if ((colon = strchr(arg, ':')) == NULL)
1733 	return (0);
1734     if (prepass)
1735 	return (1);
1736 
1737     /*
1738      * If colon first character, then no local addr.
1739      */
1740     if (colon != arg) {
1741 	*colon = '\0';
1742 	if ((local = inet_addr(arg)) == (u_int32_t) -1) {
1743 	    if ((hp = gethostbyname(arg)) == NULL) {
1744 		option_error("unknown host: %s", arg);
1745 		return (-1);
1746 	    } else {
1747 		BCOPY(hp->h_addr, &local, sizeof(local));
1748 	    }
1749 	}
1750 	if (bad_ip_adrs(local)) {
1751 	    option_error("bad local IP address %I", local);
1752 	    return (-1);
1753 	}
1754 	if (local != 0) {
1755 	    save_source(&ipsrc_info);
1756 	    wo->ouraddr = local;
1757 	}
1758 	*colon = ':';
1759     }
1760 
1761     /*
1762      * If colon last character, then no remote addr.
1763      */
1764     if (*++colon != '\0') {
1765 	if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
1766 	    if ((hp = gethostbyname(colon)) == NULL) {
1767 		option_error("unknown host: %s", colon);
1768 		return (-1);
1769 	    } else {
1770 		BCOPY(hp->h_addr, &remote, sizeof(remote));
1771 		if (remote_name[0] == '\0')
1772 		    (void) strlcpy(remote_name, colon, sizeof(remote_name));
1773 	    }
1774 	}
1775 	if (bad_ip_adrs(remote)) {
1776 	    option_error("bad remote IP address %I", remote);
1777 	    return (-1);
1778 	}
1779 	if (remote != 0) {
1780 	    save_source(&ipdst_info);
1781 	    wo->hisaddr = remote;
1782 	}
1783     }
1784 
1785     return (1);
1786 }
1787 
1788 
1789 /*
1790  * setnetmask - set the netmask to be used on the interface.  Returns 1 upon
1791  * successful processing of options, and 0 otherwise.
1792  */
1793 /*ARGSUSED*/
1794 static int
1795 setnetmask(argv, opt)
1796     char **argv;
1797     option_t *opt;
1798 {
1799     u_int32_t mask;
1800     int n;
1801     char *p;
1802 
1803     /*
1804      * Unfortunately, if we use inet_addr, we can't tell whether
1805      * a result of all 1s is an error or a valid 255.255.255.255.
1806      */
1807     p = *argv;
1808     n = parse_dotted_ip(p, &mask);
1809 
1810     mask = htonl(mask);
1811 
1812     if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
1813 	option_error("invalid netmask value '%s'", *argv);
1814 	return (0);
1815     }
1816 
1817     netmask = mask;
1818     return (1);
1819 }
1820 
1821 /*
1822  * parse_dotted_ip - parse and convert the IP address string to make
1823  * sure it conforms to the dotted notation.  Returns the length of
1824  * processed characters upon success, and 0 otherwise.  If successful,
1825  * the converted IP address number is stored in vp, in the host byte
1826  * order.
1827  */
1828 int
1829 parse_dotted_ip(cp, vp)
1830     register char *cp;
1831     u_int32_t *vp;
1832 {
1833     register u_int32_t val, base, n;
1834     register char c;
1835     char *cp0 = cp;
1836     u_char parts[3], *pp = parts;
1837 
1838     if ((*cp == '\0') || (vp == NULL))
1839 	return (0);			/* disallow null string in cp */
1840     *vp = 0;
1841 again:
1842     /*
1843      * Collect number up to ``.''.  Values are specified as for C:
1844      *	    0x=hex, 0=octal, other=decimal.
1845      */
1846     val = 0; base = 10;
1847     if (*cp == '0') {
1848 	if (*++cp == 'x' || *cp == 'X')
1849 	    base = 16, cp++;
1850 	else
1851 	    base = 8;
1852     }
1853     while ((c = *cp) != '\0') {
1854 	if (isdigit(c)) {
1855 	    if ((c - '0') >= base)
1856 		break;
1857 	    val = (val * base) + (c - '0');
1858 	    cp++;
1859 	    continue;
1860 	}
1861 	if (base == 16 && isxdigit(c)) {
1862 	    val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
1863 	    cp++;
1864 	    continue;
1865 	}
1866 	break;
1867     }
1868     if (*cp == '.') {
1869 	/*
1870 	 * Internet format:
1871 	 *	a.b.c.d
1872 	 *	a.b.c	(with c treated as 16-bits)
1873 	 *	a.b	(with b treated as 24 bits)
1874 	 */
1875 	if ((pp >= parts + 3) || (val > 0xff)) {
1876 	    return (0);
1877 	}
1878 	*pp++ = (u_char)val;
1879 	cp++;
1880 	goto again;
1881     }
1882     /*
1883      * Check for trailing characters.
1884      */
1885     if (*cp != '\0' && !isspace(*cp)) {
1886 	return (0);
1887     }
1888     /*
1889      * Concoct the address according to the number of parts specified.
1890      */
1891     n = pp - parts;
1892     switch (n) {
1893     case 0:				/* a -- 32 bits */
1894 	break;
1895     case 1:				/* a.b -- 8.24 bits */
1896 	if (val > 0xffffff)
1897 	    return (0);
1898 	val |= parts[0] << 24;
1899 	break;
1900     case 2:				/* a.b.c -- 8.8.16 bits */
1901 	if (val > 0xffff)
1902 	    return (0);
1903 	val |= (parts[0] << 24) | (parts[1] << 16);
1904 	break;
1905     case 3:				/* a.b.c.d -- 8.8.8.8 bits */
1906 	if (val > 0xff)
1907 	    return (0);
1908 	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
1909 	break;
1910     default:
1911 	return (0);
1912     }
1913     *vp = val;
1914     return (cp - cp0);
1915 }
1916 
1917 /*
1918  * setxonxoff - modify the asyncmap to include escaping XON and XOFF
1919  * characters used for software flow control.  Returns 1 upon successful
1920  * processing of options, and 0 otherwise.
1921  */
1922 /*ARGSUSED*/
1923 static int
1924 setxonxoff(argv, opt)
1925     char **argv;
1926     option_t *opt;
1927 {
1928     int xonxoff = 0x000A0000;
1929 
1930     lcp_wantoptions[0].neg_asyncmap = 1;
1931     lcp_wantoptions[0].asyncmap |= xonxoff;	/* escape ^S and ^Q */
1932     lcp_allowoptions[0].asyncmap |= xonxoff;
1933     xmit_accm[0][0] |= xonxoff;
1934     xmit_accm[0][4] |= xonxoff;		/* escape 0x91 and 0x93 as well */
1935 
1936     crtscts = -2;
1937     return (1);
1938 }
1939 
1940 /*
1941  * setlogfile - open (or create) a file used for logging purposes.  Returns 1
1942  * upon success, and 0 otherwise.
1943  */
1944 /*ARGSUSED*/
1945 static int
1946 setlogfile(argv, opt)
1947     char **argv;
1948     option_t *opt;
1949 {
1950     int fd, err;
1951 
1952     if (!privileged_option)
1953 	(void) seteuid(getuid());
1954     fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
1955     if (fd < 0 && errno == EEXIST)
1956 	fd = open(*argv, O_WRONLY | O_APPEND);
1957     err = errno;
1958     if (!privileged_option)
1959 	(void) seteuid(0);
1960     if (fd < 0) {
1961 	errno = err;
1962 	option_error("Can't open log file %s: %m", *argv);
1963 	return (0);
1964     }
1965     if (log_to_file && log_to_fd >= 0)
1966 	(void) close(log_to_fd);
1967     log_to_fd = fd;
1968     log_to_file = 1;
1969     early_log = 0;
1970     return (1);
1971 }
1972 
1973 #ifdef PLUGIN
1974 /*
1975  * loadplugin - load and initialize the plugin.  Returns 1 upon successful
1976  * processing of the plugin, and 0 otherwise.
1977  */
1978 /*ARGSUSED*/
1979 static int
1980 loadplugin(argv, opt)
1981     char **argv;
1982     option_t *opt;
1983 {
1984     char *arg = *argv;
1985     void *handle;
1986     const char *err;
1987     void (*init) __P((void));
1988 
1989     handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW);
1990     if (handle == NULL) {
1991 	err = dlerror();
1992 	if (err != NULL)
1993 	    option_error("%s", err);
1994 	option_error("Couldn't load plugin %s", arg);
1995 	return (0);
1996     }
1997     init = (void (*)(void))dlsym(handle, "plugin_init");
1998     if (init == NULL) {
1999 	option_error("%s has no initialization entry point", arg);
2000 	(void) dlclose(handle);
2001 	return (0);
2002     }
2003     info("Plugin %s loaded.", arg);
2004     (*init)();
2005     return (1);
2006 }
2007 #endif /* PLUGIN */
2008