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