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