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