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