]> git.ozlabs.org Git - ppp.git/blob - pppd/options.c
ec52cbbf71b0d0ae6db352f53dc9ff00c3292fdb
[ppp.git] / pppd / options.c
1 /*
2  * options.c - handles option processing for PPP.
3  *
4  * Copyright (c) 1989 Carnegie Mellon University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are permitted
8  * provided that the above copyright notice and this paragraph are
9  * duplicated in all such forms and that any documentation,
10  * advertising materials, and other materials related to such
11  * distribution and use acknowledge that the software was developed
12  * by Carnegie Mellon University.  The name of the
13  * University may not be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19
20 #define RCSID   "$Id: options.c,v 1.78 2001/02/22 03:15:20 paulus Exp $"
21
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <syslog.h>
29 #include <string.h>
30 #include <pwd.h>
31 #ifdef PLUGIN
32 #include <dlfcn.h>
33 #endif
34 #ifdef PPP_FILTER
35 #include <pcap.h>
36 #include <pcap-int.h>   /* XXX: To get struct pcap */
37 #endif
38
39 #include "pppd.h"
40 #include "pathnames.h"
41 #include "patchlevel.h"
42
43 #if defined(ultrix) || defined(NeXT)
44 char *strdup __P((char *));
45 #endif
46
47 static const char rcsid[] = RCSID;
48
49 /*
50  * Option variables and default values.
51  */
52 #ifdef PPP_FILTER
53 int     dflag = 0;              /* Tell libpcap we want debugging */
54 #endif
55 int     debug = 0;              /* Debug flag */
56 int     kdebugflag = 0;         /* Tell kernel to print debug messages */
57 int     default_device = 1;     /* Using /dev/tty or equivalent */
58 char    devnam[MAXPATHLEN];     /* Device name */
59 bool    nodetach = 0;           /* Don't detach from controlling tty */
60 bool    updetach = 0;           /* Detach once link is up */
61 int     maxconnect = 0;         /* Maximum connect time */
62 char    user[MAXNAMELEN];       /* Username for PAP */
63 char    passwd[MAXSECRETLEN];   /* Password for PAP */
64 bool    persist = 0;            /* Reopen link after it goes down */
65 char    our_name[MAXNAMELEN];   /* Our name for authentication purposes */
66 bool    demand = 0;             /* do dial-on-demand */
67 char    *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
68 int     idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
69 int     holdoff = 30;           /* # seconds to pause before reconnecting */
70 bool    holdoff_specified;      /* true if a holdoff value has been given */
71 int     log_to_fd = 1;          /* send log messages to this fd too */
72 int     maxfail = 10;           /* max # of unsuccessful connection attempts */
73 char    linkname[MAXPATHLEN];   /* logical name for link */
74 bool    tune_kernel;            /* may alter kernel settings */
75 int     connect_delay = 1000;   /* wait this many ms after connect script */
76 int     req_unit = -1;          /* requested interface unit */
77 bool    multilink = 0;          /* Enable multilink operation */
78 char    *bundle_name = NULL;    /* bundle name for multilink */
79
80 extern option_t auth_options[];
81 extern struct stat devstat;
82
83 #ifdef PPP_FILTER
84 struct  bpf_program pass_filter;/* Filter program for packets to pass */
85 struct  bpf_program active_filter; /* Filter program for link-active pkts */
86 pcap_t  pc;                     /* Fake struct pcap so we can compile expr */
87 #endif
88
89 char *current_option;           /* the name of the option being parsed */
90 int  privileged_option;         /* set iff the current option came from root */
91 char *option_source;            /* string saying where the option came from */
92 int  option_priority = OPRIO_CFGFILE; /* priority of the current options */
93 bool devnam_fixed;              /* can no longer change device name */
94
95 bool log_to_file;               /* log_to_fd is a file opened by us */
96 bool log_to_specific_fd;        /* log_to_fd was specified by user option */
97
98 /*
99  * Prototypes
100  */
101 static int setdomain __P((char **));
102 static int readfile __P((char **));
103 static int callfile __P((char **));
104 static int showversion __P((char **));
105 static int showhelp __P((char **));
106 static void usage __P((void));
107 static int setlogfile __P((char **));
108 #ifdef PLUGIN
109 static int loadplugin __P((char **));
110 #endif
111
112 #ifdef PPP_FILTER
113 static int setpassfilter __P((char **));
114 static int setactivefilter __P((char **));
115 #endif
116
117 static option_t *find_option __P((char *name));
118 static int process_option __P((option_t *, char *, char **));
119 static int n_arguments __P((option_t *));
120 static int number_option __P((char *, u_int32_t *, int));
121
122 /*
123  * Structure to store extra lists of options.
124  */
125 struct option_list {
126     option_t *options;
127     struct option_list *next;
128 };
129
130 static struct option_list *extra_options = NULL;
131
132 /*
133  * Valid arguments.
134  */
135 option_t general_options[] = {
136     { "debug", o_int, &debug,
137       "Increase debugging level", OPT_INC|OPT_NOARG|1 },
138     { "-d", o_int, &debug,
139       "Increase debugging level", OPT_INC|OPT_NOARG|1 },
140     { "kdebug", o_int, &kdebugflag,
141       "Set kernel driver debug level" },
142     { "nodetach", o_bool, &nodetach,
143       "Don't detach from controlling tty", 1 },
144     { "-detach", o_bool, &nodetach,
145       "Don't detach from controlling tty", 1 },
146     { "updetach", o_bool, &updetach,
147       "Detach from controlling tty once link is up", 1 },
148     { "holdoff", o_int, &holdoff,
149       "Set time in seconds before retrying connection" },
150     { "idle", o_int, &idle_time_limit,
151       "Set time in seconds before disconnecting idle link" },
152     { "maxconnect", o_int, &maxconnect,
153       "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
154     { "domain", o_special, (void *)setdomain,
155       "Add given domain name to hostname", OPT_PRIV },
156     { "file", o_special, (void *)readfile,
157       "Take options from a file" },
158     { "call", o_special, (void *)callfile,
159       "Take options from a privileged file" },
160     { "persist", o_bool, &persist,
161       "Keep on reopening connection after close", 1 },
162     { "nopersist", o_bool, &persist,
163       "Turn off persist option" },
164     { "demand", o_bool, &demand,
165       "Dial on demand", OPT_INITONLY | 1, &persist },
166     { "--version", o_special_noarg, (void *)showversion,
167       "Show version number" },
168     { "--help", o_special_noarg, (void *)showhelp,
169       "Show brief listing of options" },
170     { "-h", o_special_noarg, (void *)showhelp,
171       "Show brief listing of options" },
172     { "logfd", o_int, &log_to_fd,
173       "Send log messages to this file descriptor",
174       0, &log_to_specific_fd },
175     { "logfile", o_special, (void *)setlogfile,
176       "Append log messages to this file" },
177     { "nolog", o_int, &log_to_fd,
178       "Don't send log messages to any file",
179       OPT_NOARG | OPT_VAL(-1) },
180     { "nologfd", o_int, &log_to_fd,
181       "Don't send log messages to any file descriptor",
182       OPT_NOARG | OPT_VAL(-1) },
183     { "linkname", o_string, linkname,
184       "Set logical name for link",
185       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
186     { "maxfail", o_int, &maxfail,
187       "Maximum number of unsuccessful connection attempts to allow" },
188     { "ktune", o_bool, &tune_kernel,
189       "Alter kernel settings as necessary", 1 },
190     { "noktune", o_bool, &tune_kernel,
191       "Don't alter kernel settings", 0 },
192     { "connect-delay", o_int, &connect_delay,
193       "Maximum time (in ms) to wait after connect script finishes" },
194     { "unit", o_int, &req_unit,
195       "PPP interface unit number to use if possible", OPT_LLIMIT, 0, 0 },
196 #ifdef HAVE_MULTILINK
197     { "multilink", o_bool, &multilink,
198       "Enable multilink operation", 1 },
199     { "nomultilink", o_bool, &multilink,
200       "Disable multilink operation", 0 },
201     { "mp", o_bool, &multilink,
202       "Enable multilink operation", 1 },
203     { "nomp", o_bool, &multilink,
204       "Disable multilink operation", 0 },
205     { "bundle", o_string, &bundle_name,
206       "Bundle name for multilink" },
207 #endif /* HAVE_MULTILINK */
208 #ifdef PLUGIN
209     { "plugin", o_special, (void *)loadplugin,
210       "Load a plug-in module into pppd", OPT_PRIV },
211 #endif
212
213 #ifdef PPP_FILTER
214     { "pdebug", o_int, &dflag,
215       "libpcap debugging" },
216     { "pass-filter", 1, setpassfilter,
217       "set filter for packets to pass" },
218     { "active-filter", 1, setactivefilter,
219       "set filter for active pkts" },
220 #endif
221
222     { NULL }
223 };
224
225 #ifndef IMPLEMENTATION
226 #define IMPLEMENTATION ""
227 #endif
228
229 static char *usage_string = "\
230 pppd version %s.%d%s\n\
231 Usage: %s [ options ], where options are:\n\
232         <device>        Communicate over the named device\n\
233         <speed>         Set the baud rate to <speed>\n\
234         <loc>:<rem>     Set the local and/or remote interface IP\n\
235                         addresses.  Either one may be omitted.\n\
236         asyncmap <n>    Set the desired async map to hex <n>\n\
237         auth            Require authentication from peer\n\
238         connect <p>     Invoke shell command <p> to set up the serial line\n\
239         crtscts         Use hardware RTS/CTS flow control\n\
240         defaultroute    Add default route through interface\n\
241         file <f>        Take options from file <f>\n\
242         modem           Use modem control lines\n\
243         mru <n>         Set MRU value to <n> for negotiation\n\
244 See pppd(8) for more options.\n\
245 ";
246
247 /*
248  * parse_args - parse a string of arguments from the command line.
249  */
250 int
251 parse_args(argc, argv)
252     int argc;
253     char **argv;
254 {
255     char *arg;
256     option_t *opt;
257     int n;
258
259     privileged_option = privileged;
260     option_source = "command line";
261     option_priority = OPRIO_CMDLINE;
262     while (argc > 0) {
263         arg = *argv++;
264         --argc;
265         opt = find_option(arg);
266         if (opt == NULL) {
267             option_error("unrecognized option '%s'", arg);
268             usage();
269             return 0;
270         }
271         n = n_arguments(opt);
272         if (argc < n) {
273             option_error("too few parameters for option %s", arg);
274             return 0;
275         }
276         if (!process_option(opt, arg, argv))
277             return 0;
278         argc -= n;
279         argv += n;
280     }
281     return 1;
282 }
283
284 /*
285  * options_from_file - Read a string of options from a file,
286  * and interpret them.
287  */
288 int
289 options_from_file(filename, must_exist, check_prot, priv)
290     char *filename;
291     int must_exist;
292     int check_prot;
293     int priv;
294 {
295     FILE *f;
296     int i, newline, ret, err;
297     option_t *opt;
298     int oldpriv, n;
299     char *oldsource;
300     char *argv[MAXARGS];
301     char args[MAXARGS][MAXWORDLEN];
302     char cmd[MAXWORDLEN];
303
304     if (check_prot)
305         seteuid(getuid());
306     f = fopen(filename, "r");
307     err = errno;
308     if (check_prot)
309         seteuid(0);
310     if (f == NULL) {
311         errno = err;
312         if (!must_exist) {
313             if (err != ENOENT && err != ENOTDIR)
314                 warn("Warning: can't open options file %s: %m", filename);
315             return 1;
316         }
317         option_error("Can't open options file %s: %m", filename);
318         return 0;
319     }
320
321     oldpriv = privileged_option;
322     privileged_option = priv;
323     oldsource = option_source;
324     option_source = strdup(filename);
325     if (option_source == NULL)
326         option_source = "file";
327     ret = 0;
328     while (getword(f, cmd, &newline, filename)) {
329         opt = find_option(cmd);
330         if (opt == NULL) {
331             option_error("In file %s: unrecognized option '%s'",
332                          filename, cmd);
333             goto err;
334         }
335         n = n_arguments(opt);
336         for (i = 0; i < n; ++i) {
337             if (!getword(f, args[i], &newline, filename)) {
338                 option_error(
339                         "In file %s: too few parameters for option '%s'",
340                         filename, cmd);
341                 goto err;
342             }
343             argv[i] = args[i];
344         }
345         if (!process_option(opt, cmd, argv))
346             goto err;
347     }
348     ret = 1;
349
350 err:
351     fclose(f);
352     privileged_option = oldpriv;
353     option_source = oldsource;
354     return ret;
355 }
356
357 /*
358  * options_from_user - See if the use has a ~/.ppprc file,
359  * and if so, interpret options from it.
360  */
361 int
362 options_from_user()
363 {
364     char *user, *path, *file;
365     int ret;
366     struct passwd *pw;
367     size_t pl;
368
369     pw = getpwuid(getuid());
370     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
371         return 1;
372     file = _PATH_USEROPT;
373     pl = strlen(user) + strlen(file) + 2;
374     path = malloc(pl);
375     if (path == NULL)
376         novm("init file name");
377     slprintf(path, pl, "%s/%s", user, file);
378     option_priority = OPRIO_CFGFILE;
379     ret = options_from_file(path, 0, 1, privileged);
380     free(path);
381     return ret;
382 }
383
384 /*
385  * options_for_tty - See if an options file exists for the serial
386  * device, and if so, interpret options from it.
387  * We only allow the per-tty options file to override anything from
388  * the command line if it is something that the user can't override
389  * once it has been set by root; this is done by giving configuration
390  * files a lower priority than the command line.
391  */
392 int
393 options_for_tty()
394 {
395     char *dev, *path, *p;
396     int ret;
397     size_t pl;
398
399     dev = devnam;
400     if (strncmp(dev, "/dev/", 5) == 0)
401         dev += 5;
402     if (dev[0] == 0 || strcmp(dev, "tty") == 0)
403         return 1;               /* don't look for /etc/ppp/options.tty */
404     pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
405     path = malloc(pl);
406     if (path == NULL)
407         novm("tty init file name");
408     slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
409     /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
410     for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
411         if (*p == '/')
412             *p = '.';
413     option_priority = OPRIO_CFGFILE;
414     ret = options_from_file(path, 0, 0, 1);
415     free(path);
416     return ret;
417 }
418
419 /*
420  * options_from_list - process a string of options in a wordlist.
421  */
422 int
423 options_from_list(w, priv)
424     struct wordlist *w;
425     int priv;
426 {
427     char *argv[MAXARGS];
428     option_t *opt;
429     int i, n, ret = 0;
430     struct wordlist *w0;
431
432     privileged_option = priv;
433     option_source = "secrets file";
434     option_priority = OPRIO_SECFILE;
435
436     while (w != NULL) {
437         opt = find_option(w->word);
438         if (opt == NULL) {
439             option_error("In secrets file: unrecognized option '%s'",
440                          w->word);
441             goto err;
442         }
443         n = n_arguments(opt);
444         w0 = w;
445         for (i = 0; i < n; ++i) {
446             w = w->next;
447             if (w == NULL) {
448                 option_error(
449                         "In secrets file: too few parameters for option '%s'",
450                         w0->word);
451                 goto err;
452             }
453             argv[i] = w->word;
454         }
455         if (!process_option(opt, w0->word, argv))
456             goto err;
457     }
458     ret = 1;
459
460 err:
461     return ret;
462 }
463
464 /*
465  * match_option - see if this option matches an option_t structure.
466  */
467 static int
468 match_option(name, opt, dowild)
469     char *name;
470     option_t *opt;
471     int dowild;
472 {
473         int (*match) __P((char *, char **, int));
474
475         if (dowild != (opt->type == o_wild))
476                 return 0;
477         if (!dowild)
478                 return strcmp(name, opt->name) == 0;
479         match = (int (*) __P((char *, char **, int))) opt->addr;
480         return (*match)(name, NULL, 0);
481 }
482
483 /*
484  * find_option - scan the option lists for the various protocols
485  * looking for an entry with the given name.
486  * This could be optimized by using a hash table.
487  */
488 static option_t *
489 find_option(name)
490     char *name;
491 {
492         option_t *opt;
493         struct option_list *list;
494         int i, dowild;
495
496         for (dowild = 0; dowild <= 1; ++dowild) {
497                 for (opt = general_options; opt->name != NULL; ++opt)
498                         if (match_option(name, opt, dowild))
499                                 return opt;
500                 for (opt = auth_options; opt->name != NULL; ++opt)
501                         if (match_option(name, opt, dowild))
502                                 return opt;
503                 for (list = extra_options; list != NULL; list = list->next)
504                         for (opt = list->options; opt->name != NULL; ++opt)
505                                 if (match_option(name, opt, dowild))
506                                         return opt;
507                 for (i = 0; protocols[i] != NULL; ++i)
508                         if ((opt = protocols[i]->options) != NULL)
509                                 for (; opt->name != NULL; ++opt)
510                                         if (match_option(name, opt, dowild))
511                                                 return opt;
512         }
513         return NULL;
514 }
515
516 /*
517  * process_option - process one new-style option.
518  */
519 static int
520 process_option(opt, cmd, argv)
521     option_t *opt;
522     char *cmd;
523     char **argv;
524 {
525     u_int32_t v;
526     int iv, a;
527     char *sv;
528     int (*parser) __P((char **));
529     int (*wildp) __P((char *, char **, int));
530     char *optopt = (opt->type == o_wild)? "": " option";
531     int prio = option_priority;
532
533     if ((opt->flags & OPT_PRIVFIX) && privileged_option)
534         prio += OPRIO_ROOT;
535     /* Multipart options (like the local:remote IP address option)
536        need to keep a separate priority value for each part,
537        so we let the parser function handle that. */
538     if ((opt->flags & OPT_MULTIPART) == 0) {
539         if (prio < opt->priority) {
540             /* new value doesn't override old */
541             if (prio == OPRIO_CMDLINE && opt->priority > OPRIO_ROOT) {
542                 option_error("%s%s set in %s cannot be overridden\n",
543                                  opt->name, optopt, opt->source);
544                 return 0;
545             }
546             return 1;
547         }
548         if (prio > OPRIO_ROOT && opt->priority == OPRIO_CMDLINE)
549             warn("%s%s from %s overrides command line",
550                  opt->name, optopt, option_source);
551     }
552
553     if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
554         option_error("%s%s cannot be changed after initialization",
555                      opt->name, optopt);
556         return 0;
557     }
558     if ((opt->flags & OPT_PRIV) && !privileged_option) {
559         option_error("using the %s%s requires root privilege",
560                      opt->name, optopt);
561         return 0;
562     }
563     if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
564         option_error("%s%s is disabled", opt->name, optopt);
565         return 0;
566     }
567     if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
568         option_error("the %s%s may not be changed in %s",
569                      opt->name, optopt, option_source);
570         return 0;
571     }
572
573     switch (opt->type) {
574     case o_bool:
575         v = opt->flags & OPT_VALUE;
576         *(bool *)(opt->addr) = v;
577         if (opt->addr2 && (opt->flags & OPT_A2COPY))
578             *(bool *)(opt->addr2) = v;
579         break;
580
581     case o_int:
582         iv = 0;
583         if ((opt->flags & OPT_NOARG) == 0) {
584             if (!int_option(*argv, &iv))
585                 return 0;
586             if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
587                  || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
588                 && !((opt->flags & OPT_ZEROOK && iv == 0))) {
589                 char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
590                 switch (opt->flags & OPT_LIMITS) {
591                 case OPT_LLIMIT:
592                     option_error("%s value must be%s >= %d",
593                                  opt->name, zok, opt->lower_limit);
594                     break;
595                 case OPT_ULIMIT:
596                     option_error("%s value must be%s <= %d",
597                                  opt->name, zok, opt->upper_limit);
598                     break;
599                 case OPT_LIMITS:
600                     option_error("%s value must be%s between %d and %d",
601                                 opt->name, opt->lower_limit, opt->upper_limit);
602                     break;
603                 }
604                 return 0;
605             }
606         }
607         a = opt->flags & OPT_VALUE;
608         if (a >= 128)
609             a -= 256;           /* sign extend */
610         iv += a;
611         if (opt->flags & OPT_INC)
612             iv += *(int *)(opt->addr);
613         if ((opt->flags & OPT_NOINCR) && !privileged_option) {
614             int oldv = *(int *)(opt->addr);
615             if ((opt->flags & OPT_ZEROINF) ?
616                 (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
617                 option_error("%s value cannot be increased", opt->name);
618                 return 0;
619             }
620         }
621         *(int *)(opt->addr) = iv;
622         if (opt->addr2 && (opt->flags & OPT_A2COPY))
623             *(int *)(opt->addr2) = iv;
624         break;
625
626     case o_uint32:
627         if (opt->flags & OPT_NOARG) {
628             v = opt->flags & OPT_VALUE;
629         } else if (!number_option(*argv, &v, 16))
630             return 0;
631         if (opt->flags & OPT_OR)
632             v |= *(u_int32_t *)(opt->addr);
633         *(u_int32_t *)(opt->addr) = v;
634         if (opt->addr2 && (opt->flags & OPT_A2COPY))
635             *(u_int32_t *)(opt->addr2) = v;
636         break;
637
638     case o_string:
639         if (opt->flags & OPT_STATIC) {
640             strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
641         } else {
642             sv = strdup(*argv);
643             if (sv == NULL)
644                 novm("option argument");
645             *(char **)(opt->addr) = sv;
646         }
647         break;
648
649     case o_special_noarg:
650     case o_special:
651         parser = (int (*) __P((char **))) opt->addr;
652         if (!(*parser)(argv))
653             return 0;
654         break;
655
656     case o_wild:
657         wildp = (int (*) __P((char *, char **, int))) opt->addr;
658         if (!(*wildp)(cmd, argv, 1))
659             return 0;
660         break;
661     }
662
663     if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
664         *(bool *)(opt->addr2) = 1;
665
666     opt->source = option_source;
667     opt->priority = prio;
668
669     return 1;
670 }
671
672 /*
673  * n_arguments - tell how many arguments an option takes
674  */
675 static int
676 n_arguments(opt)
677     option_t *opt;
678 {
679         return (opt->type == o_bool || opt->type == o_special_noarg
680                 || (opt->flags & OPT_NOARG))? 0: 1;
681 }
682
683 /*
684  * add_options - add a list of options to the set we grok.
685  */
686 void
687 add_options(opt)
688     option_t *opt;
689 {
690     struct option_list *list;
691
692     list = malloc(sizeof(*list));
693     if (list == 0)
694         novm("option list entry");
695     list->options = opt;
696     list->next = extra_options;
697     extra_options = list;
698 }
699
700 /*
701  * usage - print out a message telling how to use the program.
702  */
703 static void
704 usage()
705 {
706     if (phase == PHASE_INITIALIZE)
707         fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
708                 progname);
709 }
710
711 /*
712  * showhelp - print out usage message and exit.
713  */
714 static int
715 showhelp(argv)
716     char **argv;
717 {
718     if (phase == PHASE_INITIALIZE) {
719         usage();
720         exit(0);
721     }
722     return 0;
723 }
724
725 /*
726  * showversion - print out the version number and exit.
727  */
728 static int
729 showversion(argv)
730     char **argv;
731 {
732     if (phase == PHASE_INITIALIZE) {
733         fprintf(stderr, "pppd version %s.%d%s\n",
734                 VERSION, PATCHLEVEL, IMPLEMENTATION);
735         exit(0);
736     }
737     return 0;
738 }
739
740 /*
741  * option_error - print a message about an error in an option.
742  * The message is logged, and also sent to
743  * stderr if phase == PHASE_INITIALIZE.
744  */
745 void
746 option_error __V((char *fmt, ...))
747 {
748     va_list args;
749     char buf[1024];
750
751 #if defined(__STDC__)
752     va_start(args, fmt);
753 #else
754     char *fmt;
755     va_start(args);
756     fmt = va_arg(args, char *);
757 #endif
758     vslprintf(buf, sizeof(buf), fmt, args);
759     va_end(args);
760     if (phase == PHASE_INITIALIZE)
761         fprintf(stderr, "%s: %s\n", progname, buf);
762     syslog(LOG_ERR, "%s", buf);
763 }
764
765 #if 0
766 /*
767  * readable - check if a file is readable by the real user.
768  */
769 int
770 readable(fd)
771     int fd;
772 {
773     uid_t uid;
774     int i;
775     struct stat sbuf;
776
777     uid = getuid();
778     if (uid == 0)
779         return 1;
780     if (fstat(fd, &sbuf) != 0)
781         return 0;
782     if (sbuf.st_uid == uid)
783         return sbuf.st_mode & S_IRUSR;
784     if (sbuf.st_gid == getgid())
785         return sbuf.st_mode & S_IRGRP;
786     for (i = 0; i < ngroups; ++i)
787         if (sbuf.st_gid == groups[i])
788             return sbuf.st_mode & S_IRGRP;
789     return sbuf.st_mode & S_IROTH;
790 }
791 #endif
792
793 /*
794  * Read a word from a file.
795  * Words are delimited by white-space or by quotes (" or ').
796  * Quotes, white-space and \ may be escaped with \.
797  * \<newline> is ignored.
798  */
799 int
800 getword(f, word, newlinep, filename)
801     FILE *f;
802     char *word;
803     int *newlinep;
804     char *filename;
805 {
806     int c, len, escape;
807     int quoted, comment;
808     int value, digit, got, n;
809
810 #define isoctal(c) ((c) >= '0' && (c) < '8')
811
812     *newlinep = 0;
813     len = 0;
814     escape = 0;
815     comment = 0;
816
817     /*
818      * First skip white-space and comments.
819      */
820     for (;;) {
821         c = getc(f);
822         if (c == EOF)
823             break;
824
825         /*
826          * A newline means the end of a comment; backslash-newline
827          * is ignored.  Note that we cannot have escape && comment.
828          */
829         if (c == '\n') {
830             if (!escape) {
831                 *newlinep = 1;
832                 comment = 0;
833             } else
834                 escape = 0;
835             continue;
836         }
837
838         /*
839          * Ignore characters other than newline in a comment.
840          */
841         if (comment)
842             continue;
843
844         /*
845          * If this character is escaped, we have a word start.
846          */
847         if (escape)
848             break;
849
850         /*
851          * If this is the escape character, look at the next character.
852          */
853         if (c == '\\') {
854             escape = 1;
855             continue;
856         }
857
858         /*
859          * If this is the start of a comment, ignore the rest of the line.
860          */
861         if (c == '#') {
862             comment = 1;
863             continue;
864         }
865
866         /*
867          * A non-whitespace character is the start of a word.
868          */
869         if (!isspace(c))
870             break;
871     }
872
873     /*
874      * Save the delimiter for quoted strings.
875      */
876     if (!escape && (c == '"' || c == '\'')) {
877         quoted = c;
878         c = getc(f);
879     } else
880         quoted = 0;
881
882     /*
883      * Process characters until the end of the word.
884      */
885     while (c != EOF) {
886         if (escape) {
887             /*
888              * This character is escaped: backslash-newline is ignored,
889              * various other characters indicate particular values
890              * as for C backslash-escapes.
891              */
892             escape = 0;
893             if (c == '\n') {
894                 c = getc(f);
895                 continue;
896             }
897
898             got = 0;
899             switch (c) {
900             case 'a':
901                 value = '\a';
902                 break;
903             case 'b':
904                 value = '\b';
905                 break;
906             case 'f':
907                 value = '\f';
908                 break;
909             case 'n':
910                 value = '\n';
911                 break;
912             case 'r':
913                 value = '\r';
914                 break;
915             case 's':
916                 value = ' ';
917                 break;
918             case 't':
919                 value = '\t';
920                 break;
921
922             default:
923                 if (isoctal(c)) {
924                     /*
925                      * \ddd octal sequence
926                      */
927                     value = 0;
928                     for (n = 0; n < 3 && isoctal(c); ++n) {
929                         value = (value << 3) + (c & 07);
930                         c = getc(f);
931                     }
932                     got = 1;
933                     break;
934                 }
935
936                 if (c == 'x') {
937                     /*
938                      * \x<hex_string> sequence
939                      */
940                     value = 0;
941                     c = getc(f);
942                     for (n = 0; n < 2 && isxdigit(c); ++n) {
943                         digit = toupper(c) - '0';
944                         if (digit > 10)
945                             digit += '0' + 10 - 'A';
946                         value = (value << 4) + digit;
947                         c = getc (f);
948                     }
949                     got = 1;
950                     break;
951                 }
952
953                 /*
954                  * Otherwise the character stands for itself.
955                  */
956                 value = c;
957                 break;
958             }
959
960             /*
961              * Store the resulting character for the escape sequence.
962              */
963             if (len < MAXWORDLEN-1)
964                 word[len] = value;
965             ++len;
966
967             if (!got)
968                 c = getc(f);
969             continue;
970
971         }
972
973         /*
974          * Not escaped: see if we've reached the end of the word.
975          */
976         if (quoted) {
977             if (c == quoted)
978                 break;
979         } else {
980             if (isspace(c) || c == '#') {
981                 ungetc (c, f);
982                 break;
983             }
984         }
985
986         /*
987          * Backslash starts an escape sequence.
988          */
989         if (c == '\\') {
990             escape = 1;
991             c = getc(f);
992             continue;
993         }
994
995         /*
996          * An ordinary character: store it in the word and get another.
997          */
998         if (len < MAXWORDLEN-1)
999             word[len] = c;
1000         ++len;
1001
1002         c = getc(f);
1003     }
1004
1005     /*
1006      * End of the word: check for errors.
1007      */
1008     if (c == EOF) {
1009         if (ferror(f)) {
1010             if (errno == 0)
1011                 errno = EIO;
1012             option_error("Error reading %s: %m", filename);
1013             die(1);
1014         }
1015         /*
1016          * If len is zero, then we didn't find a word before the
1017          * end of the file.
1018          */
1019         if (len == 0)
1020             return 0;
1021     }
1022
1023     /*
1024      * Warn if the word was too long, and append a terminating null.
1025      */
1026     if (len >= MAXWORDLEN) {
1027         option_error("warning: word in file %s too long (%.20s...)",
1028                      filename, word);
1029         len = MAXWORDLEN - 1;
1030     }
1031     word[len] = 0;
1032
1033     return 1;
1034
1035 #undef isoctal
1036
1037 }
1038
1039 /*
1040  * number_option - parse an unsigned numeric parameter for an option.
1041  */
1042 static int
1043 number_option(str, valp, base)
1044     char *str;
1045     u_int32_t *valp;
1046     int base;
1047 {
1048     char *ptr;
1049
1050     *valp = strtoul(str, &ptr, base);
1051     if (ptr == str) {
1052         option_error("invalid numeric parameter '%s' for %s option",
1053                      str, current_option);
1054         return 0;
1055     }
1056     return 1;
1057 }
1058
1059
1060 /*
1061  * int_option - like number_option, but valp is int *,
1062  * the base is assumed to be 0, and *valp is not changed
1063  * if there is an error.
1064  */
1065 int
1066 int_option(str, valp)
1067     char *str;
1068     int *valp;
1069 {
1070     u_int32_t v;
1071
1072     if (!number_option(str, &v, 0))
1073         return 0;
1074     *valp = (int) v;
1075     return 1;
1076 }
1077
1078
1079 /*
1080  * The following procedures parse options.
1081  */
1082
1083 /*
1084  * readfile - take commands from a file.
1085  */
1086 static int
1087 readfile(argv)
1088     char **argv;
1089 {
1090     return options_from_file(*argv, 1, 1, privileged_option);
1091 }
1092
1093 /*
1094  * callfile - take commands from /etc/ppp/peers/<name>.
1095  * Name may not contain /../, start with / or ../, or end in /..
1096  */
1097 static int
1098 callfile(argv)
1099     char **argv;
1100 {
1101     char *fname, *arg, *p;
1102     int l, ok;
1103
1104     arg = *argv;
1105     ok = 1;
1106     if (arg[0] == '/' || arg[0] == 0)
1107         ok = 0;
1108     else {
1109         for (p = arg; *p != 0; ) {
1110             if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
1111                 ok = 0;
1112                 break;
1113             }
1114             while (*p != '/' && *p != 0)
1115                 ++p;
1116             if (*p == '/')
1117                 ++p;
1118         }
1119     }
1120     if (!ok) {
1121         option_error("call option value may not contain .. or start with /");
1122         return 0;
1123     }
1124
1125     l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1126     if ((fname = (char *) malloc(l)) == NULL)
1127         novm("call file name");
1128     slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
1129
1130     ok = options_from_file(fname, 1, 1, 1);
1131
1132     free(fname);
1133     return ok;
1134 }
1135
1136 #ifdef PPP_FILTER
1137 /*
1138  * setpassfilter - Set the pass filter for packets
1139  */
1140 static int
1141 setpassfilter(argv)
1142     char **argv;
1143 {
1144     pc.linktype = DLT_PPP;
1145     pc.snapshot = PPP_HDRLEN;
1146  
1147     if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
1148         return 1;
1149     option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
1150     return 0;
1151 }
1152
1153 /*
1154  * setactivefilter - Set the active filter for packets
1155  */
1156 static int
1157 setactivefilter(argv)
1158     char **argv;
1159 {
1160     pc.linktype = DLT_PPP;
1161     pc.snapshot = PPP_HDRLEN;
1162  
1163     if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
1164         return 1;
1165     option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
1166     return 0;
1167 }
1168 #endif
1169
1170 /*
1171  * setdomain - Set domain name to append to hostname 
1172  */
1173 static int
1174 setdomain(argv)
1175     char **argv;
1176 {
1177     gethostname(hostname, MAXNAMELEN);
1178     if (**argv != 0) {
1179         if (**argv != '.')
1180             strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
1181         strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
1182     }
1183     hostname[MAXNAMELEN-1] = 0;
1184     return (1);
1185 }
1186
1187
1188 static int
1189 setlogfile(argv)
1190     char **argv;
1191 {
1192     int fd, err;
1193
1194     if (!privileged_option)
1195         seteuid(getuid());
1196     fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
1197     if (fd < 0 && errno == EEXIST)
1198         fd = open(*argv, O_WRONLY | O_APPEND);
1199     err = errno;
1200     if (!privileged_option)
1201         seteuid(0);
1202     if (fd < 0) {
1203         errno = err;
1204         option_error("Can't open log file %s: %m", *argv);
1205         return 0;
1206     }
1207     if (log_to_file && log_to_fd >= 0)
1208         close(log_to_fd);
1209     log_to_fd = fd;
1210     log_to_file = 1;
1211     return 1;
1212 }
1213
1214 #ifdef PLUGIN
1215 static int
1216 loadplugin(argv)
1217     char **argv;
1218 {
1219     char *arg = *argv;
1220     void *handle;
1221     const char *err;
1222     void (*init) __P((void));
1223
1224     handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW);
1225     if (handle == 0) {
1226         err = dlerror();
1227         if (err != 0)
1228             option_error("%s", err);
1229         option_error("Couldn't load plugin %s", arg);
1230         return 0;
1231     }
1232     init = (void (*)(void))dlsym(handle, "plugin_init");
1233     if (init == 0) {
1234         option_error("%s has no initialization entry point", arg);
1235         dlclose(handle);
1236         return 0;
1237     }
1238     info("Plugin %s loaded.", arg);
1239     (*init)();
1240     return 1;
1241 }
1242 #endif /* PLUGIN */