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