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