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