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)
67char *strdup __P((char *));
68#endif
69
70#if !defined(lint) && !defined(_lint)
71static const char rcsid[] = RCSID;
72#endif
73
74/*
75 * Option variables and default values.
76 */
77#ifdef PPP_FILTER
78int	dflag = 0;		/* Tell libpcap we want debugging */
79#endif /* PPP_FILTER */
80int	debug = 0;		/* Debug flag */
81int	kdebugflag = 0;		/* Tell kernel to print debug messages */
82int	default_device = 1;	/* Using /dev/tty or equivalent */
83char	devnam[MAXPATHLEN];	/* Device name */
84int	crtscts = 0;		/* Use hardware flow control */
85bool	modem = 1;		/* Use modem control lines */
86int	inspeed = 0;		/* Input/Output speed requested */
87u_int32_t netmask = 0;		/* IP netmask to set on interface */
88bool	lockflag = 0;		/* Create lock file to lock the serial dev */
89bool	nodetach = 0;		/* Don't detach from controlling tty */
90bool	updetach = 0;		/* Detach once link is up */
91char	*initializer = NULL;	/* Script to initialize physical link */
92char	*connect_script = NULL;	/* Script to establish physical link */
93char	*disconnect_script = NULL; /* Script to disestablish physical link */
94char	*welcomer = NULL;	/* Script to run after phys link estab. */
95char	*ptycommand = NULL;	/* Command to run on other side of pty */
96int	maxconnect = 0;		/* Maximum connect time */
97char	user[MAXNAMELEN];	/* Username for PAP */
98char	passwd[MAXSECRETLEN];	/* Password for PAP */
99bool	persist = 0;		/* Reopen link after it goes down */
100char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
101bool	demand = 0;		/* do dial-on-demand */
102char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
103int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
104int	holdoff = 30;		/* # seconds to pause before reconnecting */
105bool	holdoff_specified;	/* true if a holdoff value has been given */
106bool	notty = 0;		/* Stdin/out is not a tty */
107char	*pty_socket = NULL;	/* Socket to connect to pty */
108char	*record_file = NULL;	/* File to record chars sent/received */
109int	using_pty = 0;
110bool	sync_serial = 0;	/* Device is synchronous serial device */
111int	log_to_fd = 1;		/* send log messages to this fd too */
112int	maxfail = 10;		/* max # of unsuccessful connection attempts */
113char	linkname[MAXPATHLEN];	/* logical name for link */
114bool	tune_kernel;		/* may alter kernel settings */
115int	connect_delay = 1000;	/* wait this many ms after connect script */
116int	max_data_rate;		/* max bytes/sec through charshunt */
117int	req_unit = -1;		/* requested interface unit */
118bool	multilink = 0;		/* Enable multilink operation */
119char	*bundle_name = NULL;	/* bundle name for multilink */
120bool	direct_tty = 0;		/* use standard input directly; not a tty */
121
122/* Maximum depth of include files; prevents looping. */
123#define	MAXFILENESTING	10
124
125struct option_info initializer_info;
126struct option_info connect_script_info;
127struct option_info disconnect_script_info;
128struct option_info welcomer_info;
129struct option_info devnam_info;
130struct option_info ptycommand_info;
131struct option_info ipsrc_info;
132struct option_info ipdst_info;
133struct option_info speed_info;
134
135#ifdef PPP_FILTER
136struct	bpf_program pass_filter;/* Filter program for packets to pass */
137struct	bpf_program active_filter; /* Filter program for link-active pkts */
138pcap_t  pc;			/* Fake struct pcap so we can compile expr */
139#endif /* PPP_FILTER */
140
141char *current_option;		/* the name of the option being parsed */
142bool privileged_option;		/* set iff the current option came from root */
143char *option_source = NULL;	/* string saying where the option came from */
144int option_line = 0;		/* line number in file */
145bool log_to_file;		/* log_to_fd is a file opened by us */
146bool log_to_specific_fd;	/* log_to_fd was specified by user option */
147
148/*
149 * Prototypes.
150 */
151static int setdevname __P((char *));
152static int setipaddr __P((char *));
153static int setspeed __P((char *));
154static int noopt __P((char **, option_t *));
155static int setdomain __P((char **, option_t *));
156static int setnetmask __P((char **, option_t *));
157static int setxonxoff __P((char **, option_t *));
158static int readfile __P((char **, option_t *));
159static int callfile __P((char **, option_t *));
160static int showversion __P((char **, option_t *));
161static int showhelp __P((char **, option_t *));
162static int showalloptions __P((char **, option_t *));
163static void usage __P((void));
164static int setlogfile __P((char **, option_t *));
165#ifdef PLUGIN
166static int loadplugin __P((char **, option_t *));
167#endif
168#ifdef PPP_FILTER
169static int setpassfilter __P((char **, option_t *));
170static int setactivefilter __P((char **, option_t *));
171#endif /* PPP_FILTER */
172static option_t *find_option __P((char *name));
173static int process_option __P((option_t *opt, char **argv, int sline));
174static int n_arguments __P((option_t *opt));
175static int number_option __P((char *str, u_int32_t *valp, int base));
176static u_int32_t opt_hash __P((const void *key));
177static int opt_compare __P((const void *p1, const void *p2));
178
179typedef struct _opt_t {
180    option_t	*p;
181} opt_t;
182
183typedef 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 */
196static hashentry_t *hash_tbl[OPTHASH_TBLSIZE] = { NULL };
197
198/*
199 * Total number of entries in the hash table.
200 */
201int hash_tblcnt = 0;
202
203/*
204 * Valid arguments.
205 */
206option_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 */
352static const char pre_allopt_string[] = "\
353pppd version %s.%d%s\n\
354Usage: %s [ options ], where options are:\n\n\
355";
356
357/* Do not call add_options() on this structure */
358static 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
368static const char post_allopt_string[] = "\
369\n\
370Notes:\
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\
380Please 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 */
388int
389parse_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 */
444int
445options_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
541err:
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 */
564int
565options_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 */
591int
592options_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 */
621int
622options_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
676err:
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 */
685static option_t *
686find_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 */
708static int
709process_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 */
856static int
857n_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 */
868static u_int32_t
869opt_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 */
895void
896add_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 */
945option_t *
946remove_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 */
963static int
964opt_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*/
975static int
976showalloptions(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 */
1048static void
1049usage()
1050{
1051	static const char usage_string[] = "\
1052pppd version %s.%d%s\n\
1053Usage: %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\
1061Use \"%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*/
1074static int
1075showhelp(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*/
1091static int
1092showversion(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 */
1108void
1109option_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 */
1153int
1154getword(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 */
1398static int
1399number_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 */
1419void
1420save_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 */
1432void
1433set_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 */
1445const char *
1446name_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 */
1464int
1465int_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*/
1486static int
1487readfile(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*/
1500static int
1501callfile(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 */
1545static int
1546setpdebug(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*/
1557static int
1558setpassfilter(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*/
1576static int
1577setactivefilter(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*/
1596static int
1597noopt(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*/
1614static int
1615setdomain(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 */
1638static int
1639setspeed(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 */
1661static int
1662setdevname(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 */
1719static int
1720setipaddr(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*/
1793static int
1794setnetmask(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 */
1827int
1828parse_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;
1840again:
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*/
1922static int
1923setxonxoff(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*/
1944static int
1945setlogfile(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*/
1978static int
1979loadplugin(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