1/*
2 * options.c - handles option processing for PPP.
3 *
4 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *
18 * 3. The name "Carnegie Mellon University" must not be used to
19 *    endorse or promote products derived from this software without
20 *    prior written permission. For permission or any legal
21 *    details, please contact
22 *      Office of Technology Transfer
23 *      Carnegie Mellon University
24 *      5000 Forbes Avenue
25 *      Pittsburgh, PA  15213-3890
26 *      (412) 268-4387, fax: (412) 268-7395
27 *      tech-transfer@andrew.cmu.edu
28 *
29 * 4. Redistributions of any form whatsoever must retain the following
30 *    acknowledgment:
31 *    "This product includes software developed by Computing Services
32 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 *
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 */
42
43#define RCSID	"$Id: options.c,v 1.102 2008/06/15 06:53:06 paulus Exp $"
44
45#include <ctype.h>
46#include <stdio.h>
47#include <errno.h>
48#include <unistd.h>
49#include <fcntl.h>
50#include <stdlib.h>
51#include <syslog.h>
52#include <string.h>
53#include <pwd.h>
54#ifdef PLUGIN
55#include <dlfcn.h>
56#endif
57
58#ifdef PPP_FILTER
59#include <pcap.h>
60/*
61 * There have been 3 or 4 different names for this in libpcap CVS, but
62 * this seems to be what they have settled on...
63 * For older versions of libpcap, use DLT_PPP - but that means
64 * we lose the inbound and outbound qualifiers.
65 */
66#ifndef DLT_PPP_PPPD
67#ifdef DLT_PPP_WITHDIRECTION
68#define DLT_PPP_PPPD	DLT_PPP_WITHDIRECTION
69#else
70#define DLT_PPP_PPPD	DLT_PPP
71#endif
72#endif
73#endif /* PPP_FILTER */
74
75#include "pppd.h"
76#include "pathnames.h"
77
78#if defined(ultrix) || defined(NeXT)
79char *strdup __P((char *));
80#endif
81bool tx_only;			/* JYWeng 20031216: idle time counting on tx traffic */
82
83static const char rcsid[] = RCSID;
84
85struct option_value {
86    struct option_value *next;
87    const char *source;
88    char value[1];
89};
90
91/*
92 * Option variables and default values.
93 */
94bool	nochecktime = 0;	/* Don't check time */
95int	debug = 0;		/* Debug flag */
96int	kdebugflag = 0;		/* Tell kernel to print debug messages */
97int	default_device = 1;	/* Using /dev/tty or equivalent */
98char	devnam[MAXPATHLEN];	/* Device name */
99bool	nodetach = 0;		/* Don't detach from controlling tty */
100bool	updetach = 0;		/* Detach once link is up */
101bool	master_detach;		/* Detach when we're (only) multilink master */
102int	maxconnect = 0;		/* Maximum connect time */
103char	user[MAXNAMELEN];	/* Username for PAP */
104char	passwd[MAXSECRETLEN];	/* Password for PAP */
105bool	persist = 0;		/* Reopen link after it goes down */
106char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
107bool	demand = 0;		/* do dial-on-demand */
108char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
109
110int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
111int	holdoff = 30;		/* # seconds to pause before reconnecting */
112bool	holdoff_specified;	/* true if a holdoff value has been given */
113int	log_to_fd = 1;		/* send log messages to this fd too */
114bool	log_default = 1;	/* log_to_fd is default (stdout) */
115int	maxfail = 10;		/* max # of unsuccessful connection attempts */
116char	linkname[MAXPATHLEN];	/* logical name for link */
117bool	tune_kernel;		/* may alter kernel settings */
118int	connect_delay = 1000;	/* wait this many ms after connect script */
119int	req_unit = -1;		/* requested interface unit */
120int	req_minunit = -1;	/* requested minimal interface unit */
121char	req_ifname[32];		/* requested interface name */
122bool	multilink = 0;		/* Enable multilink operation */
123char	*bundle_name = NULL;	/* bundle name for multilink */
124bool	dump_options;		/* print out option values */
125bool	dryrun;			/* print out option values and exit */
126char	*domain;		/* domain name set by domain option */
127int	child_wait = 5;		/* # seconds to wait for children at exit */
128struct userenv *userenv_list;	/* user environment variables */
129
130#ifdef MAXOCTETS
131unsigned int  maxoctets = 0;    /* default - no limit */
132int maxoctets_dir = 0;       /* default - sum of traffic */
133int maxoctets_timeout = 1;   /* default 1 second */
134#endif
135
136
137extern option_t auth_options[];
138extern struct stat devstat;
139
140#ifdef PPP_FILTER
141struct	bpf_program pass_filter;/* Filter program for packets to pass */
142struct	bpf_program active_filter; /* Filter program for link-active pkts */
143#endif
144
145static option_t *curopt;	/* pointer to option being processed */
146char *current_option;		/* the name of the option being parsed */
147int  privileged_option;		/* set iff the current option came from root */
148char *option_source;		/* string saying where the option came from */
149int  option_priority = OPRIO_CFGFILE; /* priority of the current options */
150bool devnam_fixed;		/* can no longer change device name */
151
152static int logfile_fd = -1;	/* fd opened for log file */
153static char logfile_name[MAXPATHLEN];	/* name of log file */
154
155/*
156 * Prototypes
157 */
158static int setdomain __P((char **));
159static int readfile __P((char **));
160static int callfile __P((char **));
161static int showversion __P((char **));
162static int showhelp __P((char **));
163static void usage __P((void));
164static int setlogfile __P((char **));
165#ifdef PLUGIN
166static int loadplugin __P((char **));
167#endif
168
169#ifdef PPP_FILTER
170static int setpassfilter __P((char **));
171static int setactivefilter __P((char **));
172#endif
173
174#ifdef MAXOCTETS
175static int setmodir __P((char **));
176#endif
177
178static int user_setenv __P((char **));
179static void user_setprint __P((option_t *, printer_func, void *));
180static int user_unsetenv __P((char **));
181static void user_unsetprint __P((option_t *, printer_func, void *));
182
183static option_t *find_option __P((const char *name));
184static int process_option __P((option_t *, char *, char **));
185static int n_arguments __P((option_t *));
186static int number_option __P((char *, u_int32_t *, int));
187
188/*
189 * Structure to store extra lists of options.
190 */
191struct option_list {
192    option_t *options;
193    struct option_list *next;
194};
195
196static struct option_list *extra_options = NULL;
197
198/*
199 * Valid arguments.
200 */
201option_t general_options[] = {
202    { "nochecktime", o_bool, &nochecktime,
203      "Don't check time", OPT_PRIO | 1 },
204    { "debug", o_int, &debug,
205      "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
206    { "-d", o_int, &debug,
207      "Increase debugging level",
208      OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
209
210    { "kdebug", o_int, &kdebugflag,
211      "Set kernel driver debug level", OPT_PRIO },
212
213    { "nodetach", o_bool, &nodetach,
214      "Don't detach from controlling tty", OPT_PRIO | 1 },
215    { "-detach", o_bool, &nodetach,
216      "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
217    { "updetach", o_bool, &updetach,
218      "Detach from controlling tty once link is up",
219      OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
220
221    { "master_detach", o_bool, &master_detach,
222      "Detach when we're multilink master but have no link", 1 },
223
224    { "holdoff", o_int, &holdoff,
225      "Set time in seconds before retrying connection",
226      OPT_PRIO, &holdoff_specified },
227
228    { "idle", o_int, &idle_time_limit,
229      "Set time in seconds before disconnecting idle link", OPT_PRIO },
230
231    { "maxconnect", o_int, &maxconnect,
232      "Set connection time limit",
233      OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
234
235    { "domain", o_special, (void *)setdomain,
236      "Add given domain name to hostname",
237      OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
238
239    { "file", o_special, (void *)readfile,
240      "Take options from a file", OPT_NOPRINT },
241    { "call", o_special, (void *)callfile,
242      "Take options from a privileged file", OPT_NOPRINT },
243
244    { "persist", o_bool, &persist,
245      "Keep on reopening connection after close", OPT_PRIO | 1 },
246    { "nopersist", o_bool, &persist,
247      "Turn off persist option", OPT_PRIOSUB },
248
249    { "demand", o_bool, &demand,
250      "Dial on demand", OPT_INITONLY | 1, &persist },
251
252    { "--version", o_special_noarg, (void *)showversion,
253      "Show version number" },
254    { "--help", o_special_noarg, (void *)showhelp,
255      "Show brief listing of options" },
256    { "-h", o_special_noarg, (void *)showhelp,
257      "Show brief listing of options", OPT_ALIAS },
258
259    { "logfile", o_special, (void *)setlogfile,
260      "Append log messages to this file",
261      OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
262    { "logfd", o_int, &log_to_fd,
263      "Send log messages to this file descriptor",
264      OPT_PRIOSUB | OPT_A2CLR, &log_default },
265    { "nolog", o_int, &log_to_fd,
266      "Don't send log messages to any file",
267      OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
268    { "nologfd", o_int, &log_to_fd,
269      "Don't send log messages to any file descriptor",
270      OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
271
272    { "linkname", o_string, linkname,
273      "Set logical name for link",
274      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
275
276    { "maxfail", o_int, &maxfail,
277      "Maximum number of unsuccessful connection attempts to allow",
278      OPT_PRIO },
279
280    { "ktune", o_bool, &tune_kernel,
281      "Alter kernel settings as necessary", OPT_PRIO | 1 },
282    { "noktune", o_bool, &tune_kernel,
283      "Don't alter kernel settings", OPT_PRIOSUB },
284
285    { "connect-delay", o_int, &connect_delay,
286      "Maximum time (in ms) to wait after connect script finishes",
287      OPT_PRIO },
288
289    { "unit", o_int, &req_unit,
290      "PPP interface unit number to use if possible",
291      OPT_PRIO | OPT_LLIMIT, 0, 0 },
292    { "minunit", o_int, &req_minunit,
293      "PPP interface minimal unit number",
294      OPT_PRIO | OPT_LLIMIT, 0, 0 },
295
296    { "ifname", o_string, req_ifname,
297      "PPP interface name to use if possible",
298      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, sizeof(req_ifname) },
299
300    { "dump", o_bool, &dump_options,
301      "Print out option values after parsing all options", 1 },
302    { "dryrun", o_bool, &dryrun,
303      "Stop after parsing, printing, and checking options", 1 },
304
305    { "child-timeout", o_int, &child_wait,
306      "Number of seconds to wait for child processes at exit",
307      OPT_PRIO },
308
309    { "set", o_special, (void *)user_setenv,
310      "Set user environment variable",
311      OPT_A2PRINTER | OPT_NOPRINT, (void *)user_setprint },
312    { "unset", o_special, (void *)user_unsetenv,
313      "Unset user environment variable",
314      OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint },
315
316#ifdef HAVE_MULTILINK
317    { "multilink", o_bool, &multilink,
318      "Enable multilink operation", OPT_PRIO | 1 },
319    { "mp", o_bool, &multilink,
320      "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
321    { "nomultilink", o_bool, &multilink,
322      "Disable multilink operation", OPT_PRIOSUB | 0 },
323    { "nomp", o_bool, &multilink,
324      "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
325
326    { "bundle", o_string, &bundle_name,
327      "Bundle name for multilink", OPT_PRIO },
328#endif /* HAVE_MULTILINK */
329
330#ifdef PLUGIN
331    { "plugin", o_special, (void *)loadplugin,
332      "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
333#endif
334
335#ifdef PPP_FILTER
336    { "pass-filter", o_special, setpassfilter,
337      "set filter for packets to pass", OPT_PRIO },
338
339    { "active-filter", o_special, setactivefilter,
340      "set filter for active pkts", OPT_PRIO },
341#endif
342
343#ifdef MAXOCTETS
344    { "maxoctets", o_int, &maxoctets,
345      "Set connection traffic limit",
346      OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
347    { "mo", o_int, &maxoctets,
348      "Set connection traffic limit",
349      OPT_ALIAS | OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
350    { "mo-direction", o_special, setmodir,
351      "Set direction for limit traffic (sum,in,out,max)" },
352    { "mo-timeout", o_int, &maxoctets_timeout,
353      "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
354#endif
355
356/* JYWeng 20031216: add for tx_only option*/
357    { "tx_only", o_bool, &tx_only,
358      "set idle time counting on tx_only or not", 1 },
359
360    { NULL }
361};
362
363#ifndef IMPLEMENTATION
364#define IMPLEMENTATION ""
365#endif
366
367static char *usage_string = "\
368pppd version %s\n\
369Usage: %s [ options ], where options are:\n\
370	<device>	Communicate over the named device\n\
371	<speed>		Set the baud rate to <speed>\n\
372	<loc>:<rem>	Set the local and/or remote interface IP\n\
373			addresses.  Either one may be omitted.\n\
374	asyncmap <n>	Set the desired async map to hex <n>\n\
375	auth		Require authentication from peer\n\
376        connect <p>     Invoke shell command <p> to set up the serial line\n\
377	crtscts		Use hardware RTS/CTS flow control\n\
378	defaultroute	Add default route through interface\n\
379	file <f>	Take options from file <f>\n\
380	modem		Use modem control lines\n\
381	mru <n>		Set MRU value to <n> for negotiation\n\
382See pppd(8) for more options.\n\
383";
384
385/*
386 * parse_args - parse a string of arguments from the command line.
387 */
388int
389parse_args(argc, argv)
390    int argc;
391    char **argv;
392{
393    char *arg;
394    option_t *opt;
395    int n;
396
397    privileged_option = privileged;
398    option_source = "command line";
399    option_priority = OPRIO_CMDLINE;
400    while (argc > 0) {
401	arg = *argv++;
402	--argc;
403	opt = find_option(arg);
404	if (opt == NULL) {
405	    option_error("unrecognized option '%s'", arg);
406	    usage();
407	    return 0;
408	}
409
410	n = n_arguments(opt);
411	if (argc < n) {
412	    option_error("too few parameters for option %s", arg);
413	    return 0;
414	}
415	if (!process_option(opt, arg, argv))
416	    return 0;
417	argc -= n;
418	argv += n;
419    }
420    return 1;
421}
422
423/*
424 * options_from_file - Read a string of options from a file,
425 * and interpret them.
426 */
427int
428options_from_file(filename, must_exist, check_prot, priv)
429    char *filename;
430    int must_exist;
431    int check_prot;
432    int priv;
433{
434    FILE *f;
435    int i, newline, ret, err;
436    option_t *opt;
437    int oldpriv, n;
438    char *oldsource;
439    uid_t euid;
440    char *argv[MAXARGS];
441    char args[MAXARGS][MAXWORDLEN];
442    char cmd[MAXWORDLEN];
443
444    euid = geteuid();
445    if (check_prot && seteuid(getuid()) == -1) {
446	option_error("unable to drop privileges to open %s: %m", filename);
447	return 0;
448    }
449    f = fopen(filename, "r");
450    err = errno;
451    if (check_prot && seteuid(euid) == -1)
452	fatal("unable to regain privileges");
453    if (f == NULL) {
454	errno = err;
455	if (!must_exist) {
456	    if (err != ENOENT && err != ENOTDIR)
457		warn("Warning: can't open options file %s: %m", filename);
458	    return 1;
459	}
460	option_error("Can't open options file %s: %m", filename);
461	return 0;
462    }
463
464    oldpriv = privileged_option;
465    privileged_option = priv;
466    oldsource = option_source;
467    option_source = strdup(filename);
468    if (option_source == NULL)
469	option_source = "file";
470    ret = 0;
471    while (getword(f, cmd, &newline, filename)) {
472	opt = find_option(cmd);
473	if (opt == NULL) {
474	    option_error("In file %s: unrecognized option '%s'",
475			 filename, cmd);
476	    goto err;
477	}
478	n = n_arguments(opt);
479	for (i = 0; i < n; ++i) {
480	    if (!getword(f, args[i], &newline, filename)) {
481		option_error(
482			"In file %s: too few parameters for option '%s'",
483			filename, cmd);
484		goto err;
485	    }
486	    argv[i] = args[i];
487	}
488	if (!process_option(opt, cmd, argv))
489	    goto err;
490    }
491    ret = 1;
492
493err:
494    fclose(f);
495    privileged_option = oldpriv;
496    option_source = oldsource;
497    return ret;
498}
499
500/*
501 * options_from_user - See if the use has a ~/.ppprc file,
502 * and if so, interpret options from it.
503 */
504int
505options_from_user()
506{
507    char *user, *path, *file;
508    int ret;
509    struct passwd *pw;
510    size_t pl;
511
512    pw = getpwuid(getuid());
513    if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
514	return 1;
515    file = _PATH_USEROPT;
516    pl = strlen(user) + strlen(file) + 2;
517    path = malloc(pl);
518    if (path == NULL)
519	novm("init file name");
520    slprintf(path, pl, "%s/%s", user, file);
521    option_priority = OPRIO_CFGFILE;
522    ret = options_from_file(path, 0, 1, privileged);
523    free(path);
524    return ret;
525}
526
527/*
528 * options_for_tty - See if an options file exists for the serial
529 * device, and if so, interpret options from it.
530 * We only allow the per-tty options file to override anything from
531 * the command line if it is something that the user can't override
532 * once it has been set by root; this is done by giving configuration
533 * files a lower priority than the command line.
534 */
535int
536options_for_tty()
537{
538    char *dev, *path, *p;
539    int ret;
540    size_t pl;
541
542    dev = devnam;
543    if ((p = strstr(dev, "/dev/")) != NULL)
544	dev = p + 5;
545    if (dev[0] == 0 || strcmp(dev, "tty") == 0)
546	return 1;		/* don't look for /etc/ppp/options.tty */
547    pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
548    path = malloc(pl);
549    if (path == NULL)
550	novm("tty init file name");
551    slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
552    /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
553    for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
554	if (*p == '/')
555	    *p = '.';
556    option_priority = OPRIO_CFGFILE;
557    ret = options_from_file(path, 0, 0, 1);
558    free(path);
559    return ret;
560}
561
562/*
563 * options_from_list - process a string of options in a wordlist.
564 */
565int
566options_from_list(w, priv)
567    struct wordlist *w;
568    int priv;
569{
570    char *argv[MAXARGS];
571    option_t *opt;
572    int i, n, ret = 0;
573    struct wordlist *w0;
574
575    privileged_option = priv;
576    option_source = "secrets file";
577    option_priority = OPRIO_SECFILE;
578
579    while (w != NULL) {
580	opt = find_option(w->word);
581	if (opt == NULL) {
582	    option_error("In secrets file: unrecognized option '%s'",
583			 w->word);
584	    goto err;
585	}
586	n = n_arguments(opt);
587	w0 = w;
588	for (i = 0; i < n; ++i) {
589	    w = w->next;
590	    if (w == NULL) {
591		option_error(
592			"In secrets file: too few parameters for option '%s'",
593			w0->word);
594		goto err;
595	    }
596	    argv[i] = w->word;
597	}
598	if (!process_option(opt, w0->word, argv))
599	    goto err;
600	w = w->next;
601    }
602    ret = 1;
603
604err:
605    return ret;
606}
607
608/*
609 * match_option - see if this option matches an option_t structure.
610 */
611static int
612match_option(name, opt, dowild)
613    char *name;
614    option_t *opt;
615    int dowild;
616{
617	int (*match) __P((char *, char **, int));
618
619	if (dowild != (opt->type == o_wild))
620		return 0;
621	if (!dowild)
622		return strcmp(name, opt->name) == 0;
623	match = (int (*) __P((char *, char **, int))) opt->addr;
624	return (*match)(name, NULL, 0);
625}
626
627/*
628 * find_option - scan the option lists for the various protocols
629 * looking for an entry with the given name.
630 * This could be optimized by using a hash table.
631 */
632static option_t *
633find_option(name)
634    const char *name;
635{
636	option_t *opt;
637	struct option_list *list;
638	int i, dowild;
639
640	for (dowild = 0; dowild <= 1; ++dowild) {
641		for (opt = general_options; opt->name != NULL; ++opt)
642			if (match_option(name, opt, dowild))
643				return opt;
644		for (opt = auth_options; opt->name != NULL; ++opt)
645			if (match_option(name, opt, dowild))
646				return opt;
647		for (list = extra_options; list != NULL; list = list->next)
648			for (opt = list->options; opt->name != NULL; ++opt)
649				if (match_option(name, opt, dowild))
650					return opt;
651		for (opt = the_channel->options; opt->name != NULL; ++opt)
652			if (match_option(name, opt, dowild))
653				return opt;
654		for (i = 0; protocols[i] != NULL; ++i)
655			if ((opt = protocols[i]->options) != NULL)
656				for (; opt->name != NULL; ++opt)
657					if (match_option(name, opt, dowild))
658						return opt;
659	}
660	return NULL;
661}
662
663/*
664 * process_option - process one new-style option.
665 */
666static int
667process_option(opt, cmd, argv)
668    option_t *opt;
669    char *cmd;
670    char **argv;
671{
672    u_int32_t v;
673    int iv, a;
674    char *sv;
675    int (*parser) __P((char **));
676    int (*wildp) __P((char *, char **, int));
677    char *optopt = (opt->type == o_wild)? "": " option";
678    int prio = option_priority;
679    option_t *mainopt = opt;
680
681    current_option = opt->name;
682    if ((opt->flags & OPT_PRIVFIX) && privileged_option)
683	prio += OPRIO_ROOT;
684    while (mainopt->flags & OPT_PRIOSUB)
685	--mainopt;
686    if (mainopt->flags & OPT_PRIO) {
687	if (prio < mainopt->priority) {
688	    /* new value doesn't override old */
689	    if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
690		option_error("%s%s set in %s cannot be overridden\n",
691			     opt->name, optopt, mainopt->source);
692		return 0;
693	    }
694	    return 1;
695	}
696	if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
697	    warn("%s%s from %s overrides command line",
698		 opt->name, optopt, option_source);
699    }
700
701    if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
702	option_error("%s%s cannot be changed after initialization",
703		     opt->name, optopt);
704	return 0;
705    }
706    if ((opt->flags & OPT_PRIV) && !privileged_option) {
707	option_error("using the %s%s requires root privilege",
708		     opt->name, optopt);
709	return 0;
710    }
711    if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
712	option_error("%s%s is disabled", opt->name, optopt);
713	return 0;
714    }
715    if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
716	option_error("the %s%s may not be changed in %s",
717		     opt->name, optopt, option_source);
718	return 0;
719    }
720
721    switch (opt->type) {
722    case o_bool:
723	v = opt->flags & OPT_VALUE;
724	*(bool *)(opt->addr) = v;
725	if (opt->addr2 && (opt->flags & OPT_A2COPY))
726	    *(bool *)(opt->addr2) = v;
727	else if (opt->addr2 && (opt->flags & OPT_A2CLR))
728	    *(bool *)(opt->addr2) = 0;
729	else if (opt->addr2 && (opt->flags & OPT_A2CLRB))
730	    *(u_char *)(opt->addr2) &= ~v;
731	else if (opt->addr2 && (opt->flags & OPT_A2OR))
732	    *(u_char *)(opt->addr2) |= v;
733	break;
734
735    case o_int:
736	iv = 0;
737	if ((opt->flags & OPT_NOARG) == 0) {
738	    if (!int_option(*argv, &iv))
739		return 0;
740	    if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
741		 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
742		&& !((opt->flags & OPT_ZEROOK && iv == 0))) {
743		char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
744		switch (opt->flags & OPT_LIMITS) {
745		case OPT_LLIMIT:
746		    option_error("%s value must be%s >= %d",
747				 opt->name, zok, opt->lower_limit);
748		    break;
749		case OPT_ULIMIT:
750		    option_error("%s value must be%s <= %d",
751				 opt->name, zok, opt->upper_limit);
752		    break;
753		case OPT_LIMITS:
754		    option_error("%s value must be%s between %d and %d",
755				opt->name, zok, opt->lower_limit, opt->upper_limit);
756		    break;
757		}
758		return 0;
759	    }
760	}
761	a = opt->flags & OPT_VALUE;
762	if (a >= 128)
763	    a -= 256;		/* sign extend */
764	iv += a;
765	if (opt->flags & OPT_INC)
766	    iv += *(int *)(opt->addr);
767	if ((opt->flags & OPT_NOINCR) && !privileged_option) {
768	    int oldv = *(int *)(opt->addr);
769	    if ((opt->flags & OPT_ZEROINF) ?
770		(oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
771		option_error("%s value cannot be increased", opt->name);
772		return 0;
773	    }
774	}
775	*(int *)(opt->addr) = iv;
776	if (opt->addr2 && (opt->flags & OPT_A2COPY))
777	    *(int *)(opt->addr2) = iv;
778	break;
779
780    case o_uint32:
781	if (opt->flags & OPT_NOARG) {
782	    v = opt->flags & OPT_VALUE;
783	    if (v & 0x80)
784		    v |= 0xffffff00U;
785	} else if (!number_option(*argv, &v, 16))
786	    return 0;
787	if (opt->flags & OPT_OR)
788	    v |= *(u_int32_t *)(opt->addr);
789	*(u_int32_t *)(opt->addr) = v;
790	if (opt->addr2 && (opt->flags & OPT_A2COPY))
791	    *(u_int32_t *)(opt->addr2) = v;
792	break;
793
794    case o_string:
795	if (opt->flags & OPT_STATIC) {
796	    strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
797	} else {
798	    char **optptr = (char **)(opt->addr);
799	    sv = strdup(*argv);
800	    if (sv == NULL)
801		novm("option argument");
802	    if (*optptr && opt->source)
803		free(*optptr);
804	    *optptr = sv;
805	}
806	break;
807
808    case o_special_noarg:
809    case o_special:
810	parser = (int (*) __P((char **))) opt->addr;
811	curopt = opt;
812	if (!(*parser)(argv))
813	    return 0;
814	if (opt->flags & OPT_A2LIST) {
815	    struct option_value *ovp, *pp;
816
817	    ovp = malloc(sizeof(*ovp) + strlen(*argv));
818	    if (ovp != 0) {
819		strcpy(ovp->value, *argv);
820		ovp->source = option_source;
821		ovp->next = NULL;
822		if (opt->addr2 == NULL) {
823		    opt->addr2 = ovp;
824		} else {
825		    for (pp = opt->addr2; pp->next != NULL; pp = pp->next)
826			;
827		    pp->next = ovp;
828		}
829	    }
830	}
831	break;
832
833    case o_wild:
834	wildp = (int (*) __P((char *, char **, int))) opt->addr;
835	if (!(*wildp)(cmd, argv, 1))
836	    return 0;
837	break;
838    }
839
840    /*
841     * If addr2 wasn't used by any flag (OPT_A2COPY, etc.) but is set,
842     * treat it as a bool and set/clear it based on the OPT_A2CLR bit.
843     */
844    if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
845		|OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST|OPT_A2OR)) == 0)
846	*(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
847
848    mainopt->source = option_source;
849    mainopt->priority = prio;
850    mainopt->winner = opt - mainopt;
851
852    return 1;
853}
854
855/*
856 * override_value - if the option priorities would permit us to
857 * override the value of option, return 1 and update the priority
858 * and source of the option value.  Otherwise returns 0.
859 */
860int
861override_value(option, priority, source)
862    const char *option;
863    int priority;
864    const char *source;
865{
866	option_t *opt;
867
868	opt = find_option(option);
869	if (opt == NULL)
870		return 0;
871	while (opt->flags & OPT_PRIOSUB)
872		--opt;
873	if ((opt->flags & OPT_PRIO) && priority < opt->priority)
874		return 0;
875	opt->priority = priority;
876	opt->source = source;
877	opt->winner = -1;
878	return 1;
879}
880
881/*
882 * n_arguments - tell how many arguments an option takes
883 */
884static int
885n_arguments(opt)
886    option_t *opt;
887{
888	return (opt->type == o_bool || opt->type == o_special_noarg
889		|| (opt->flags & OPT_NOARG))? 0: 1;
890}
891
892/*
893 * add_options - add a list of options to the set we grok.
894 */
895void
896add_options(opt)
897    option_t *opt;
898{
899    struct option_list *list;
900
901    list = malloc(sizeof(*list));
902    if (list == 0)
903	novm("option list entry");
904    list->options = opt;
905    list->next = extra_options;
906    extra_options = list;
907}
908
909/*
910 * check_options - check that options are valid and consistent.
911 */
912void
913check_options()
914{
915	if (logfile_fd >= 0 && logfile_fd != log_to_fd)
916		close(logfile_fd);
917}
918
919/*
920 * print_option - print out an option and its value
921 */
922static void
923print_option(opt, mainopt, printer, arg)
924    option_t *opt, *mainopt;
925    printer_func printer;
926    void *arg;
927{
928	int i, v;
929	char *p;
930
931	if (opt->flags & OPT_NOPRINT)
932		return;
933	switch (opt->type) {
934	case o_bool:
935		v = opt->flags & OPT_VALUE;
936		if (*(bool *)opt->addr != v)
937			/* this can happen legitimately, e.g. lock
938			   option turned off for default device */
939			break;
940		printer(arg, "%s", opt->name);
941		break;
942	case o_int:
943		v = opt->flags & OPT_VALUE;
944		if (v >= 128)
945			v -= 256;
946		i = *(int *)opt->addr;
947		if (opt->flags & OPT_NOARG) {
948			printer(arg, "%s", opt->name);
949			if (i != v) {
950				if (opt->flags & OPT_INC) {
951					for (; i > v; i -= v)
952						printer(arg, " %s", opt->name);
953				} else
954					printer(arg, " # oops: %d not %d\n",
955						i, v);
956			}
957		} else {
958			printer(arg, "%s %d", opt->name, i);
959		}
960		break;
961	case o_uint32:
962		printer(arg, "%s", opt->name);
963		if ((opt->flags & OPT_NOARG) == 0)
964			printer(arg, " %x", *(u_int32_t *)opt->addr);
965		break;
966
967	case o_string:
968		if (opt->flags & OPT_HIDE) {
969			p = "??????";
970		} else {
971			p = (char *) opt->addr;
972			if ((opt->flags & OPT_STATIC) == 0)
973				p = *(char **)p;
974		}
975		printer(arg, "%s %q", opt->name, p);
976		break;
977
978	case o_special:
979	case o_special_noarg:
980	case o_wild:
981		if (opt->type != o_wild) {
982			printer(arg, "%s", opt->name);
983			if (n_arguments(opt) == 0)
984				break;
985			printer(arg, " ");
986		}
987		if (opt->flags & OPT_A2PRINTER) {
988			void (*oprt) __P((option_t *, printer_func, void *));
989			oprt = (void (*) __P((option_t *, printer_func,
990					 void *)))opt->addr2;
991			(*oprt)(opt, printer, arg);
992		} else if (opt->flags & OPT_A2STRVAL) {
993			p = (char *) opt->addr2;
994			if ((opt->flags & OPT_STATIC) == 0)
995				p = *(char **)p;
996			printer("%q", p);
997		} else if (opt->flags & OPT_A2LIST) {
998			struct option_value *ovp;
999
1000			ovp = (struct option_value *) opt->addr2;
1001			for (;;) {
1002				printer(arg, "%q", ovp->value);
1003				if ((ovp = ovp->next) == NULL)
1004					break;
1005				printer(arg, "\t\t# (from %s)\n%s ",
1006					ovp->source, opt->name);
1007			}
1008		} else {
1009			printer(arg, "xxx # [don't know how to print value]");
1010		}
1011		break;
1012
1013	default:
1014		printer(arg, "# %s value (type %d\?\?)", opt->name, opt->type);
1015		break;
1016	}
1017	printer(arg, "\t\t# (from %s)\n", mainopt->source);
1018}
1019
1020/*
1021 * print_option_list - print out options in effect from an
1022 * array of options.
1023 */
1024static void
1025print_option_list(opt, printer, arg)
1026    option_t *opt;
1027    printer_func printer;
1028    void *arg;
1029{
1030	while (opt->name != NULL) {
1031		if (opt->priority != OPRIO_DEFAULT
1032		    && opt->winner != (short int) -1)
1033			print_option(opt + opt->winner, opt, printer, arg);
1034		do {
1035			++opt;
1036		} while (opt->flags & OPT_PRIOSUB);
1037	}
1038}
1039
1040/*
1041 * print_options - print out what options are in effect.
1042 */
1043void
1044print_options(printer, arg)
1045    printer_func printer;
1046    void *arg;
1047{
1048	struct option_list *list;
1049	int i;
1050
1051	printer(arg, "pppd options in effect:\n");
1052	print_option_list(general_options, printer, arg);
1053	print_option_list(auth_options, printer, arg);
1054	for (list = extra_options; list != NULL; list = list->next)
1055		print_option_list(list->options, printer, arg);
1056	print_option_list(the_channel->options, printer, arg);
1057	for (i = 0; protocols[i] != NULL; ++i)
1058		print_option_list(protocols[i]->options, printer, arg);
1059}
1060
1061/*
1062 * usage - print out a message telling how to use the program.
1063 */
1064static void
1065usage()
1066{
1067    if (phase == PHASE_INITIALIZE)
1068	fprintf(stderr, usage_string, VERSION, progname);
1069}
1070
1071/*
1072 * showhelp - print out usage message and exit.
1073 */
1074static int
1075showhelp(argv)
1076    char **argv;
1077{
1078    if (phase == PHASE_INITIALIZE) {
1079	usage();
1080	exit(0);
1081    }
1082    return 0;
1083}
1084
1085/*
1086 * showversion - print out the version number and exit.
1087 */
1088static int
1089showversion(argv)
1090    char **argv;
1091{
1092    if (phase == PHASE_INITIALIZE) {
1093	fprintf(stderr, "pppd version %s\n", VERSION);
1094	exit(0);
1095    }
1096    return 0;
1097}
1098
1099/*
1100 * option_error - print a message about an error in an option.
1101 * The message is logged, and also sent to
1102 * stderr if phase == PHASE_INITIALIZE.
1103 */
1104void
1105option_error __V((char *fmt, ...))
1106{
1107    va_list args;
1108    char buf[1024];
1109
1110#if defined(__STDC__)
1111    va_start(args, fmt);
1112#else
1113    char *fmt;
1114    va_start(args);
1115    fmt = va_arg(args, char *);
1116#endif
1117    vslprintf(buf, sizeof(buf), fmt, args);
1118    va_end(args);
1119    if (phase == PHASE_INITIALIZE)
1120	fprintf(stderr, "%s: %s\n", progname, buf);
1121    syslog(LOG_ERR, "%s", buf);
1122}
1123
1124#if 0
1125/*
1126 * readable - check if a file is readable by the real user.
1127 */
1128int
1129readable(fd)
1130    int fd;
1131{
1132    uid_t uid;
1133    int i;
1134    struct stat sbuf;
1135
1136    uid = getuid();
1137    if (uid == 0)
1138	return 1;
1139    if (fstat(fd, &sbuf) != 0)
1140	return 0;
1141    if (sbuf.st_uid == uid)
1142	return sbuf.st_mode & S_IRUSR;
1143    if (sbuf.st_gid == getgid())
1144	return sbuf.st_mode & S_IRGRP;
1145    for (i = 0; i < ngroups; ++i)
1146	if (sbuf.st_gid == groups[i])
1147	    return sbuf.st_mode & S_IRGRP;
1148    return sbuf.st_mode & S_IROTH;
1149}
1150#endif
1151
1152/*
1153 * Read a word from a file.
1154 * Words are delimited by white-space or by quotes (" or ').
1155 * Quotes, white-space and \ may be escaped with \.
1156 * \<newline> is ignored.
1157 */
1158int
1159getword(f, word, newlinep, filename)
1160    FILE *f;
1161    char *word;
1162    int *newlinep;
1163    char *filename;
1164{
1165    int c, len, escape;
1166    int quoted, comment;
1167    int value, digit, got, n;
1168
1169#define isoctal(c) ((c) >= '0' && (c) < '8')
1170
1171    *newlinep = 0;
1172    len = 0;
1173    escape = 0;
1174    comment = 0;
1175    quoted = 0;
1176
1177    /*
1178     * First skip white-space and comments.
1179     */
1180    for (;;) {
1181	c = getc(f);
1182	if (c == EOF)
1183	    break;
1184
1185	/*
1186	 * A newline means the end of a comment; backslash-newline
1187	 * is ignored.  Note that we cannot have escape && comment.
1188	 */
1189	if (c == '\n') {
1190	    if (!escape) {
1191		*newlinep = 1;
1192		comment = 0;
1193	    } else
1194		escape = 0;
1195	    continue;
1196	}
1197
1198	/*
1199	 * Ignore characters other than newline in a comment.
1200	 */
1201	if (comment)
1202	    continue;
1203
1204	/*
1205	 * If this character is escaped, we have a word start.
1206	 */
1207	if (escape)
1208	    break;
1209
1210	/*
1211	 * If this is the escape character, look at the next character.
1212	 */
1213	if (c == '\\') {
1214	    escape = 1;
1215	    continue;
1216	}
1217
1218	/*
1219	 * If this is the start of a comment, ignore the rest of the line.
1220	 */
1221	if (c == '#') {
1222	    comment = 1;
1223	    continue;
1224	}
1225
1226	/*
1227	 * A non-whitespace character is the start of a word.
1228	 */
1229	if (!isspace(c))
1230	    break;
1231    }
1232
1233    /*
1234     * Process characters until the end of the word.
1235     */
1236    while (c != EOF) {
1237	if (escape) {
1238	    /*
1239	     * This character is escaped: backslash-newline is ignored,
1240	     * various other characters indicate particular values
1241	     * as for C backslash-escapes.
1242	     */
1243	    escape = 0;
1244	    if (c == '\n') {
1245	        c = getc(f);
1246		continue;
1247	    }
1248
1249	    got = 0;
1250	    switch (c) {
1251	    case 'a':
1252		value = '\a';
1253		break;
1254	    case 'b':
1255		value = '\b';
1256		break;
1257	    case 'f':
1258		value = '\f';
1259		break;
1260	    case 'n':
1261		value = '\n';
1262		break;
1263	    case 'r':
1264		value = '\r';
1265		break;
1266	    case 's':
1267		value = ' ';
1268		break;
1269	    case 't':
1270		value = '\t';
1271		break;
1272
1273	    default:
1274		if (isoctal(c)) {
1275		    /*
1276		     * \ddd octal sequence
1277		     */
1278		    value = 0;
1279		    for (n = 0; n < 3 && isoctal(c); ++n) {
1280			value = (value << 3) + (c & 07);
1281			c = getc(f);
1282		    }
1283		    got = 1;
1284		    break;
1285		}
1286
1287		if (c == 'x') {
1288		    /*
1289		     * \x<hex_string> sequence
1290		     */
1291		    value = 0;
1292		    c = getc(f);
1293		    for (n = 0; n < 2 && isxdigit(c); ++n) {
1294			digit = toupper(c) - '0';
1295			if (digit > 10)
1296			    digit += '0' + 10 - 'A';
1297			value = (value << 4) + digit;
1298			c = getc (f);
1299		    }
1300		    got = 1;
1301		    break;
1302		}
1303
1304		/*
1305		 * Otherwise the character stands for itself.
1306		 */
1307		value = c;
1308		break;
1309	    }
1310
1311	    /*
1312	     * Store the resulting character for the escape sequence.
1313	     */
1314	    if (len < MAXWORDLEN) {
1315		word[len] = value;
1316		++len;
1317	    }
1318
1319	    if (!got)
1320		c = getc(f);
1321	    continue;
1322	}
1323
1324	/*
1325	 * Backslash starts a new escape sequence.
1326	 */
1327	if (c == '\\') {
1328	    escape = 1;
1329	    c = getc(f);
1330	    continue;
1331	}
1332
1333	/*
1334	 * Not escaped: check for the start or end of a quoted
1335	 * section and see if we've reached the end of the word.
1336	 */
1337	if (quoted) {
1338	    if (c == quoted) {
1339		quoted = 0;
1340		c = getc(f);
1341		continue;
1342	    }
1343	} else if (c == '"' || c == '\'') {
1344	    quoted = c;
1345	    c = getc(f);
1346	    continue;
1347	} else if (isspace(c) || c == '#') {
1348	    ungetc (c, f);
1349	    break;
1350	}
1351
1352	/*
1353	 * An ordinary character: store it in the word and get another.
1354	 */
1355	if (len < MAXWORDLEN) {
1356	    word[len] = c;
1357	    ++len;
1358	}
1359
1360	c = getc(f);
1361    }
1362
1363    /*
1364     * End of the word: check for errors.
1365     */
1366    if (c == EOF) {
1367	if (ferror(f)) {
1368	    if (errno == 0)
1369		errno = EIO;
1370	    option_error("Error reading %s: %m", filename);
1371	    die(1);
1372	}
1373	/*
1374	 * If len is zero, then we didn't find a word before the
1375	 * end of the file.
1376	 */
1377	if (len == 0)
1378	    return 0;
1379	if (quoted)
1380	    option_error("warning: quoted word runs to end of file (%.20s...)",
1381			 filename, word);
1382    }
1383
1384    /*
1385     * Warn if the word was too long, and append a terminating null.
1386     */
1387    if (len >= MAXWORDLEN) {
1388	option_error("warning: word in file %s too long (%.20s...)",
1389		     filename, word);
1390	len = MAXWORDLEN - 1;
1391    }
1392    word[len] = 0;
1393
1394    return 1;
1395
1396#undef isoctal
1397
1398}
1399
1400/*
1401 * number_option - parse an unsigned numeric parameter for an option.
1402 */
1403static int
1404number_option(str, valp, base)
1405    char *str;
1406    u_int32_t *valp;
1407    int base;
1408{
1409    char *ptr;
1410
1411    *valp = strtoul(str, &ptr, base);
1412    if (ptr == str) {
1413	option_error("invalid numeric parameter '%s' for %s option",
1414		     str, current_option);
1415	return 0;
1416    }
1417    return 1;
1418}
1419
1420
1421/*
1422 * int_option - like number_option, but valp is int *,
1423 * the base is assumed to be 0, and *valp is not changed
1424 * if there is an error.
1425 */
1426int
1427int_option(str, valp)
1428    char *str;
1429    int *valp;
1430{
1431    u_int32_t v;
1432
1433    if (!number_option(str, &v, 0))
1434	return 0;
1435    *valp = (int) v;
1436    return 1;
1437}
1438
1439
1440/*
1441 * The following procedures parse options.
1442 */
1443
1444/*
1445 * readfile - take commands from a file.
1446 */
1447static int
1448readfile(argv)
1449    char **argv;
1450{
1451    return options_from_file(*argv, 1, 1, privileged_option);
1452}
1453
1454/*
1455 * callfile - take commands from /etc/ppp/peers/<name>.
1456 * Name may not contain /../, start with / or ../, or end in /..
1457 */
1458static int
1459callfile(argv)
1460    char **argv;
1461{
1462    char *fname, *arg, *p;
1463    int l, ok;
1464
1465    arg = *argv;
1466    ok = 1;
1467    if (arg[0] == '/' || arg[0] == 0)
1468	ok = 0;
1469    else {
1470	for (p = arg; *p != 0; ) {
1471	    if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
1472		ok = 0;
1473		break;
1474	    }
1475	    while (*p != '/' && *p != 0)
1476		++p;
1477	    if (*p == '/')
1478		++p;
1479	}
1480    }
1481    if (!ok) {
1482	option_error("call option value may not contain .. or start with /");
1483	return 0;
1484    }
1485
1486    l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1487    if ((fname = (char *) malloc(l)) == NULL)
1488	novm("call file name");
1489    slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
1490
1491    ok = options_from_file(fname, 1, 1, 1);
1492
1493    free(fname);
1494    return ok;
1495}
1496
1497#ifdef PPP_FILTER
1498/*
1499 * setpassfilter - Set the pass filter for packets
1500 */
1501static int
1502setpassfilter(argv)
1503    char **argv;
1504{
1505    pcap_t *pc;
1506    int ret = 1;
1507
1508    pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
1509    if (pcap_compile(pc, &pass_filter, *argv, 1, netmask) == -1) {
1510	option_error("error in pass-filter expression: %s\n",
1511		     pcap_geterr(pc));
1512	ret = 0;
1513    }
1514    pcap_close(pc);
1515
1516    return ret;
1517}
1518
1519/*
1520 * setactivefilter - Set the active filter for packets
1521 */
1522static int
1523setactivefilter(argv)
1524    char **argv;
1525{
1526    pcap_t *pc;
1527    int ret = 1;
1528
1529    pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
1530    if (pcap_compile(pc, &active_filter, *argv, 1, netmask) == -1) {
1531	option_error("error in active-filter expression: %s\n",
1532		     pcap_geterr(pc));
1533	ret = 0;
1534    }
1535    pcap_close(pc);
1536
1537    return ret;
1538}
1539#endif
1540
1541/*
1542 * setdomain - Set domain name to append to hostname
1543 */
1544static int
1545setdomain(argv)
1546    char **argv;
1547{
1548    gethostname(hostname, MAXNAMELEN);
1549    if (**argv != 0) {
1550	if (**argv != '.')
1551	    strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
1552	domain = hostname + strlen(hostname);
1553	strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
1554    }
1555    hostname[MAXNAMELEN-1] = 0;
1556    return (1);
1557}
1558
1559static int
1560setlogfile(argv)
1561    char **argv;
1562{
1563    int fd, err;
1564    uid_t euid;
1565
1566    euid = geteuid();
1567    if (!privileged_option && seteuid(getuid()) == -1) {
1568	option_error("unable to drop permissions to open %s: %m", *argv);
1569	return 0;
1570    }
1571    fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
1572    if (fd < 0 && errno == EEXIST)
1573	fd = open(*argv, O_WRONLY | O_APPEND);
1574    err = errno;
1575    if (!privileged_option && seteuid(euid) == -1)
1576	fatal("unable to regain privileges: %m");
1577    if (fd < 0) {
1578	errno = err;
1579	option_error("Can't open log file %s: %m", *argv);
1580	return 0;
1581    }
1582    strlcpy(logfile_name, *argv, sizeof(logfile_name));
1583    if (logfile_fd >= 0)
1584	close(logfile_fd);
1585    logfile_fd = fd;
1586    log_to_fd = fd;
1587    log_default = 0;
1588    return 1;
1589}
1590
1591#ifdef MAXOCTETS
1592static int
1593setmodir(argv)
1594    char **argv;
1595{
1596    if(*argv == NULL)
1597	return 0;
1598    if(!strcmp(*argv,"in")) {
1599        maxoctets_dir = PPP_OCTETS_DIRECTION_IN;
1600    } else if (!strcmp(*argv,"out")) {
1601        maxoctets_dir = PPP_OCTETS_DIRECTION_OUT;
1602    } else if (!strcmp(*argv,"max")) {
1603        maxoctets_dir = PPP_OCTETS_DIRECTION_MAXOVERAL;
1604    } else {
1605        maxoctets_dir = PPP_OCTETS_DIRECTION_SUM;
1606    }
1607    return 1;
1608}
1609#endif
1610
1611#ifdef PLUGIN
1612static int
1613loadplugin(argv)
1614    char **argv;
1615{
1616    char *arg = *argv;
1617    void *handle;
1618    const char *err;
1619    void (*init) __P((void));
1620    char *path = arg;
1621    const char *vers;
1622
1623    if (strchr(arg, '/') == 0) {
1624	const char *base = _PATH_PLUGIN;
1625	int l = strlen(base) + strlen(arg) + 2;
1626	path = malloc(l);
1627	if (path == 0)
1628	    novm("plugin file path");
1629	strlcpy(path, base, l);
1630	strlcat(path, "/", l);
1631	strlcat(path, arg, l);
1632    }
1633    handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
1634    if (handle == 0) {
1635	err = dlerror();
1636	if (err != 0)
1637	    option_error("%s", err);
1638	option_error("Couldn't load plugin %s", arg);
1639	goto err;
1640    }
1641    init = (void (*)(void))dlsym(handle, "plugin_init");
1642    if (init == 0) {
1643	option_error("%s has no initialization entry point", arg);
1644	goto errclose;
1645    }
1646    vers = (const char *) dlsym(handle, "pppd_version");
1647    if (vers == 0) {
1648	warn("Warning: plugin %s has no version information", arg);
1649    } else if (strcmp(vers, VERSION) != 0) {
1650	option_error("Plugin %s is for pppd version %s, this is %s",
1651		     arg, vers, VERSION);
1652	goto errclose;
1653    }
1654    info("Plugin %s loaded.", arg);
1655    (*init)();
1656    return 1;
1657
1658 errclose:
1659    dlclose(handle);
1660 err:
1661    if (path != arg)
1662	free(path);
1663    return 0;
1664}
1665#endif /* PLUGIN */
1666
1667/*
1668 * Set an environment variable specified by the user.
1669 */
1670static int
1671user_setenv(argv)
1672    char **argv;
1673{
1674    char *arg = argv[0];
1675    char *eqp;
1676    struct userenv *uep, **insp;
1677
1678    if ((eqp = strchr(arg, '=')) == NULL) {
1679	option_error("missing = in name=value: %s", arg);
1680	return 0;
1681    }
1682    if (eqp == arg) {
1683	option_error("missing variable name: %s", arg);
1684	return 0;
1685    }
1686    for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
1687	int nlen = strlen(uep->ue_name);
1688	if (nlen == (eqp - arg) &&
1689	    strncmp(arg, uep->ue_name, nlen) == 0)
1690	    break;
1691    }
1692    /* Ignore attempts by unprivileged users to override privileged sources */
1693    if (uep != NULL && !privileged_option && uep->ue_priv)
1694	return 1;
1695    /* The name never changes, so allocate it with the structure */
1696    if (uep == NULL) {
1697	uep = malloc(sizeof (*uep) + (eqp-arg));
1698	strncpy(uep->ue_name, arg, eqp-arg);
1699	uep->ue_name[eqp-arg] = '\0';
1700	uep->ue_next = NULL;
1701	insp = &userenv_list;
1702	while (*insp != NULL)
1703	    insp = &(*insp)->ue_next;
1704	*insp = uep;
1705    } else {
1706	struct userenv *uep2;
1707	for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
1708	    if (uep2 != uep && !uep2->ue_isset)
1709		break;
1710	}
1711	if (uep2 == NULL && !uep->ue_isset)
1712	    find_option("unset")->flags |= OPT_NOPRINT;
1713	free(uep->ue_value);
1714    }
1715    uep->ue_isset = 1;
1716    uep->ue_priv = privileged_option;
1717    uep->ue_source = option_source;
1718    uep->ue_value = strdup(eqp + 1);
1719    curopt->flags &= ~OPT_NOPRINT;
1720    return 1;
1721}
1722
1723static void
1724user_setprint(opt, printer, arg)
1725    option_t *opt;
1726    printer_func printer;
1727    void *arg;
1728{
1729    struct userenv *uep, *uepnext;
1730
1731    uepnext = userenv_list;
1732    while (uepnext != NULL && !uepnext->ue_isset)
1733	uepnext = uepnext->ue_next;
1734    while ((uep = uepnext) != NULL) {
1735	uepnext = uep->ue_next;
1736	while (uepnext != NULL && !uepnext->ue_isset)
1737	    uepnext = uepnext->ue_next;
1738	(*printer)(arg, "%s=%s", uep->ue_name, uep->ue_value);
1739	if (uepnext != NULL)
1740	    (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
1741	else
1742	    opt->source = uep->ue_source;
1743    }
1744}
1745
1746static int
1747user_unsetenv(argv)
1748    char **argv;
1749{
1750    struct userenv *uep, **insp;
1751    char *arg = argv[0];
1752
1753    if (strchr(arg, '=') != NULL) {
1754	option_error("unexpected = in name: %s", arg);
1755	return 0;
1756    }
1757    if (arg == '\0') {
1758	option_error("missing variable name for unset");
1759	return 0;
1760    }
1761    for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
1762	if (strcmp(arg, uep->ue_name) == 0)
1763	    break;
1764    }
1765    /* Ignore attempts by unprivileged users to override privileged sources */
1766    if (uep != NULL && !privileged_option && uep->ue_priv)
1767	return 1;
1768    /* The name never changes, so allocate it with the structure */
1769    if (uep == NULL) {
1770	uep = malloc(sizeof (*uep) + strlen(arg));
1771	strcpy(uep->ue_name, arg);
1772	uep->ue_next = NULL;
1773	insp = &userenv_list;
1774	while (*insp != NULL)
1775	    insp = &(*insp)->ue_next;
1776	*insp = uep;
1777    } else {
1778	struct userenv *uep2;
1779	for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
1780	    if (uep2 != uep && uep2->ue_isset)
1781		break;
1782	}
1783	if (uep2 == NULL && uep->ue_isset)
1784	    find_option("set")->flags |= OPT_NOPRINT;
1785	free(uep->ue_value);
1786    }
1787    uep->ue_isset = 0;
1788    uep->ue_priv = privileged_option;
1789    uep->ue_source = option_source;
1790    uep->ue_value = NULL;
1791    curopt->flags &= ~OPT_NOPRINT;
1792    return 1;
1793}
1794
1795static void
1796user_unsetprint(opt, printer, arg)
1797    option_t *opt;
1798    printer_func printer;
1799    void *arg;
1800{
1801    struct userenv *uep, *uepnext;
1802
1803    uepnext = userenv_list;
1804    while (uepnext != NULL && uepnext->ue_isset)
1805	uepnext = uepnext->ue_next;
1806    while ((uep = uepnext) != NULL) {
1807	uepnext = uep->ue_next;
1808	while (uepnext != NULL && uepnext->ue_isset)
1809	    uepnext = uepnext->ue_next;
1810	(*printer)(arg, "%s", uep->ue_name);
1811	if (uepnext != NULL)
1812	    (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
1813	else
1814	    opt->source = uep->ue_source;
1815    }
1816}
1817