]> git.ozlabs.org Git - ppp.git/blob - pppd/options.c
update: hide-password, behaviour of auth/noauth
[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.46 1999/02/26 11:03:34 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 ((f = fopen(filename, "r")) == NULL) {
346         if (!must_exist && errno == ENOENT)
347             return 1;
348         option_error("Can't open options file %s: %m", filename);
349         return 0;
350     }
351     if (check_prot && !readable(fileno(f))) {
352         option_error("Can't open options file %s: access denied", filename);
353         fclose(f);
354         return 0;
355     }
356
357     oldpriv = privileged_option;
358     privileged_option = priv;
359     oldsource = option_source;
360     option_source = strdup(filename);
361     if (option_source == NULL)
362         option_source = "file";
363     ret = 0;
364     while (getword(f, cmd, &newline, filename)) {
365         /*
366          * First see if it's a command.
367          */
368         opt = find_option(cmd);
369         if (opt != NULL) {
370             int n = n_arguments(opt);
371             for (i = 0; i < n; ++i) {
372                 if (!getword(f, args[i], &newline, filename)) {
373                     option_error(
374                         "In file %s: too few parameters for option '%s'",
375                         filename, cmd);
376                     goto err;
377                 }
378                 argv[i] = args[i];
379             }
380             current_option = cmd;
381             if (!process_option(opt, argv))
382                 goto err;
383             continue;
384         }
385
386         /*
387          * Maybe a tty name, speed or IP address?
388          */
389         if ((i = setdevname(cmd, 0)) == 0
390             && (i = setspeed(cmd)) == 0
391             && (i = setipaddr(cmd)) == 0) {
392             option_error("In file %s: unrecognized option '%s'",
393                          filename, cmd);
394             goto err;
395         }
396         if (i < 0)              /* error */
397             goto err;
398     }
399     ret = 1;
400
401 err:
402     fclose(f);
403     privileged_option = oldpriv;
404     option_source = oldsource;
405     return ret;
406 }
407
408 /*
409  * options_from_user - See if the use has a ~/.ppprc file,
410  * and if so, interpret options from it.
411  */
412 int
413 options_from_user()
414 {
415     char *user, *path, *file;
416     int ret;
417     struct passwd *pw;
418
419     pw = getpwuid(getuid());
420     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
421         return 1;
422     file = _PATH_USEROPT;
423     path = malloc(strlen(user) + strlen(file) + 2);
424     if (path == NULL)
425         novm("init file name");
426     strcpy(path, user);
427     strcat(path, "/");
428     strcat(path, file);
429     ret = options_from_file(path, 0, 1, privileged);
430     free(path);
431     return ret;
432 }
433
434 /*
435  * options_for_tty - See if an options file exists for the serial
436  * device, and if so, interpret options from it.
437  */
438 int
439 options_for_tty()
440 {
441     char *dev, *path, *p;
442     int ret;
443
444     dev = devnam;
445     if (strncmp(dev, "/dev/", 5) == 0)
446         dev += 5;
447     if (strcmp(dev, "tty") == 0)
448         return 1;               /* don't look for /etc/ppp/options.tty */
449     path = malloc(strlen(_PATH_TTYOPT) + strlen(dev) + 1);
450     if (path == NULL)
451         novm("tty init file name");
452     strcpy(path, _PATH_TTYOPT);
453     /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
454     for (p = path + strlen(path); *dev != 0; ++dev)
455         *p++ = (*dev == '/'? '.': *dev);
456     *p = 0;
457     ret = options_from_file(path, 0, 0, 1);
458     free(path);
459     return ret;
460 }
461
462 /*
463  * find_option - scan the option lists for the various protocols
464  * looking for an entry with the given name.
465  * This could be optimized by using a hash table.
466  */
467 static option_t *
468 find_option(char *name)
469 {
470     option_t *opt;
471     int i;
472
473     for (opt = general_options; opt->name != NULL; ++opt)
474         if (strcmp(name, opt->name) == 0)
475             return opt;
476     for (opt = auth_options; opt->name != NULL; ++opt)
477         if (strcmp(name, opt->name) == 0)
478             return opt;
479     for (i = 0; protocols[i] != NULL; ++i)
480         if ((opt = protocols[i]->options) != NULL)
481             for (; opt->name != NULL; ++opt)
482                 if (strcmp(name, opt->name) == 0)
483                     return opt;
484     return NULL;
485 }
486
487 /*
488  * process_option - process one new-style option.
489  */
490 static int
491 process_option(opt, argv)
492     option_t *opt;
493     char **argv;
494 {
495     u_int32_t v;
496     int iv, a;
497     char *sv;
498     int (*parser) __P((char **));
499
500     if ((opt->flags & OPT_PRIV) && !privileged_option) {
501         option_error("using the %s option requires root privilege", opt->name);
502         return 0;
503     }
504     if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
505         option_error("%s option is disabled", opt->name);
506         return 0;
507     }
508
509     switch (opt->type) {
510     case o_bool:
511         v = opt->flags & OPT_VALUE;
512         *(bool *)(opt->addr) = v;
513         if (opt->addr2 && (opt->flags & OPT_A2COPY))
514             *(bool *)(opt->addr2) = v;
515         break;
516
517     case o_int:
518         iv = 0;
519         if ((opt->flags & OPT_NOARG) == 0) {
520             if (!int_option(*argv, &iv))
521                 return 0;
522             if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
523                  || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
524                 && !((opt->flags & OPT_ZEROOK && iv == 0))) {
525                 char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
526                 switch (opt->flags & OPT_LIMITS) {
527                 case OPT_LLIMIT:
528                     option_error("%s value must be%s >= %d",
529                                  opt->name, zok, opt->lower_limit);
530                     break;
531                 case OPT_ULIMIT:
532                     option_error("%s value must be%s <= %d",
533                                  opt->name, zok, opt->upper_limit);
534                     break;
535                 case OPT_LIMITS:
536                     option_error("%s value must be%s between %d and %d",
537                                 opt->name, opt->lower_limit, opt->upper_limit);
538                     break;
539                 }
540                 return 0;
541             }
542         }
543         a = opt->flags & OPT_VALUE;
544         if (a >= 128)
545             a -= 256;           /* sign extend */
546         iv += a;
547         if (opt->flags & OPT_INC)
548             iv += *(int *)(opt->addr);
549         if ((opt->flags & OPT_NOINCR) && !privileged_option) {
550             int oldv = *(int *)(opt->addr);
551             if ((opt->flags & OPT_ZEROINF) ?
552                 (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
553                 option_error("%s value cannot be increased", opt->name);
554                 return 0;
555             }
556         }
557         *(int *)(opt->addr) = iv;
558         if (opt->addr2 && (opt->flags & OPT_A2COPY))
559             *(int *)(opt->addr2) = iv;
560         break;
561
562     case o_uint32:
563         if (opt->flags & OPT_NOARG) {
564             v = opt->flags & OPT_VALUE;
565         } else if (!number_option(*argv, &v, 16))
566             return 0;
567         if (opt->flags & OPT_OR)
568             v |= *(u_int32_t *)(opt->addr);
569         *(u_int32_t *)(opt->addr) = v;
570         if (opt->addr2 && (opt->flags & OPT_A2COPY))
571             *(u_int32_t *)(opt->addr2) = v;
572         break;
573
574     case o_string:
575         if (opt->flags & OPT_STATIC) {
576             if (opt->upper_limit) {
577                 strncpy((char *)(opt->addr), *argv, opt->upper_limit);
578                 ((char *)(opt->addr))[opt->upper_limit-1] = 0;
579             } else
580                 strcpy((char *)(opt->addr), *argv);
581         } else {
582             sv = strdup(*argv);
583             if (sv == NULL)
584                 novm("option argument");
585             *(char **)(opt->addr) = sv;
586         }
587         break;
588
589     case o_special_noarg:
590     case o_special:
591         parser = (int (*) __P((char **))) opt->addr;
592         if (!(*parser)(argv))
593             return 0;
594         break;
595     }
596
597     if (opt->addr2) {
598         if (opt->flags & OPT_A2INFO) {
599             struct option_info *ip = (struct option_info *) opt->addr2;
600             ip->priv = privileged_option;
601             ip->source = option_source;
602         } else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
603             *(bool *)(opt->addr2) = 1;
604     }
605
606     return 1;
607 }
608
609 /*
610  * n_arguments - tell how many arguments an option takes
611  */
612 static int
613 n_arguments(option_t *opt)
614 {
615     return (opt->type == o_bool || opt->type == o_special_noarg
616             || (opt->flags & OPT_NOARG))? 0: 1;
617 }
618
619 /*
620  * usage - print out a message telling how to use the program.
621  */
622 void
623 usage()
624 {
625     if (phase == PHASE_INITIALIZE)
626         fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
627                 progname);
628 }
629
630 /*
631  * showhelp - print out usage message and exit.
632  */
633 static int
634 showhelp(argv)
635     char **argv;
636 {
637     if (phase == PHASE_INITIALIZE) {
638         usage();
639         exit(0);
640     }
641     return 0;
642 }
643
644 /*
645  * showversion - print out the version number and exit.
646  */
647 static int
648 showversion(argv)
649     char **argv;
650 {
651     if (phase == PHASE_INITIALIZE) {
652         fprintf(stderr, "pppd version %s patch level %d%s\n",
653                 VERSION, PATCHLEVEL, IMPLEMENTATION);
654         exit(0);
655     }
656     return 0;
657 }
658
659 /*
660  * option_error - print a message about an error in an option.
661  * The message is logged, and also sent to
662  * stderr if phase == PHASE_INITIALIZE.
663  */
664 void
665 option_error __V((char *fmt, ...))
666 {
667     va_list args;
668     char buf[256];
669
670 #if __STDC__
671     va_start(args, fmt);
672 #else
673     char *fmt;
674     va_start(args);
675     fmt = va_arg(args, char *);
676 #endif
677     vfmtmsg(buf, sizeof(buf), fmt, args);
678     va_end(args);
679     if (phase == PHASE_INITIALIZE)
680         fprintf(stderr, "%s: %s\n", progname, buf);
681     syslog(LOG_ERR, "%s", buf);
682 }
683
684 /*
685  * readable - check if a file is readable by the real user.
686  */
687 int
688 readable(fd)
689     int fd;
690 {
691     uid_t uid;
692     int ngroups, i;
693     struct stat sbuf;
694     GIDSET_TYPE groups[NGROUPS_MAX];
695
696     uid = getuid();
697     if (uid == 0)
698         return 1;
699     if (fstat(fd, &sbuf) != 0)
700         return 0;
701     if (sbuf.st_uid == uid)
702         return sbuf.st_mode & S_IRUSR;
703     if (sbuf.st_gid == getgid())
704         return sbuf.st_mode & S_IRGRP;
705     ngroups = getgroups(NGROUPS_MAX, groups);
706     for (i = 0; i < ngroups; ++i)
707         if (sbuf.st_gid == groups[i])
708             return sbuf.st_mode & S_IRGRP;
709     return sbuf.st_mode & S_IROTH;
710 }
711
712 /*
713  * Read a word from a file.
714  * Words are delimited by white-space or by quotes (" or ').
715  * Quotes, white-space and \ may be escaped with \.
716  * \<newline> is ignored.
717  */
718 int
719 getword(f, word, newlinep, filename)
720     FILE *f;
721     char *word;
722     int *newlinep;
723     char *filename;
724 {
725     int c, len, escape;
726     int quoted, comment;
727     int value, digit, got, n;
728
729 #define isoctal(c) ((c) >= '0' && (c) < '8')
730
731     *newlinep = 0;
732     len = 0;
733     escape = 0;
734     comment = 0;
735
736     /*
737      * First skip white-space and comments.
738      */
739     for (;;) {
740         c = getc(f);
741         if (c == EOF)
742             break;
743
744         /*
745          * A newline means the end of a comment; backslash-newline
746          * is ignored.  Note that we cannot have escape && comment.
747          */
748         if (c == '\n') {
749             if (!escape) {
750                 *newlinep = 1;
751                 comment = 0;
752             } else
753                 escape = 0;
754             continue;
755         }
756
757         /*
758          * Ignore characters other than newline in a comment.
759          */
760         if (comment)
761             continue;
762
763         /*
764          * If this character is escaped, we have a word start.
765          */
766         if (escape)
767             break;
768
769         /*
770          * If this is the escape character, look at the next character.
771          */
772         if (c == '\\') {
773             escape = 1;
774             continue;
775         }
776
777         /*
778          * If this is the start of a comment, ignore the rest of the line.
779          */
780         if (c == '#') {
781             comment = 1;
782             continue;
783         }
784
785         /*
786          * A non-whitespace character is the start of a word.
787          */
788         if (!isspace(c))
789             break;
790     }
791
792     /*
793      * Save the delimiter for quoted strings.
794      */
795     if (!escape && (c == '"' || c == '\'')) {
796         quoted = c;
797         c = getc(f);
798     } else
799         quoted = 0;
800
801     /*
802      * Process characters until the end of the word.
803      */
804     while (c != EOF) {
805         if (escape) {
806             /*
807              * This character is escaped: backslash-newline is ignored,
808              * various other characters indicate particular values
809              * as for C backslash-escapes.
810              */
811             escape = 0;
812             if (c == '\n') {
813                 c = getc(f);
814                 continue;
815             }
816
817             got = 0;
818             switch (c) {
819             case 'a':
820                 value = '\a';
821                 break;
822             case 'b':
823                 value = '\b';
824                 break;
825             case 'f':
826                 value = '\f';
827                 break;
828             case 'n':
829                 value = '\n';
830                 break;
831             case 'r':
832                 value = '\r';
833                 break;
834             case 's':
835                 value = ' ';
836                 break;
837             case 't':
838                 value = '\t';
839                 break;
840
841             default:
842                 if (isoctal(c)) {
843                     /*
844                      * \ddd octal sequence
845                      */
846                     value = 0;
847                     for (n = 0; n < 3 && isoctal(c); ++n) {
848                         value = (value << 3) + (c & 07);
849                         c = getc(f);
850                     }
851                     got = 1;
852                     break;
853                 }
854
855                 if (c == 'x') {
856                     /*
857                      * \x<hex_string> sequence
858                      */
859                     value = 0;
860                     c = getc(f);
861                     for (n = 0; n < 2 && isxdigit(c); ++n) {
862                         digit = toupper(c) - '0';
863                         if (digit > 10)
864                             digit += '0' + 10 - 'A';
865                         value = (value << 4) + digit;
866                         c = getc (f);
867                     }
868                     got = 1;
869                     break;
870                 }
871
872                 /*
873                  * Otherwise the character stands for itself.
874                  */
875                 value = c;
876                 break;
877             }
878
879             /*
880              * Store the resulting character for the escape sequence.
881              */
882             if (len < MAXWORDLEN-1)
883                 word[len] = value;
884             ++len;
885
886             if (!got)
887                 c = getc(f);
888             continue;
889
890         }
891
892         /*
893          * Not escaped: see if we've reached the end of the word.
894          */
895         if (quoted) {
896             if (c == quoted)
897                 break;
898         } else {
899             if (isspace(c) || c == '#') {
900                 ungetc (c, f);
901                 break;
902             }
903         }
904
905         /*
906          * Backslash starts an escape sequence.
907          */
908         if (c == '\\') {
909             escape = 1;
910             c = getc(f);
911             continue;
912         }
913
914         /*
915          * An ordinary character: store it in the word and get another.
916          */
917         if (len < MAXWORDLEN-1)
918             word[len] = c;
919         ++len;
920
921         c = getc(f);
922     }
923
924     /*
925      * End of the word: check for errors.
926      */
927     if (c == EOF) {
928         if (ferror(f)) {
929             if (errno == 0)
930                 errno = EIO;
931             option_error("Error reading %s: %m", filename);
932             die(1);
933         }
934         /*
935          * If len is zero, then we didn't find a word before the
936          * end of the file.
937          */
938         if (len == 0)
939             return 0;
940     }
941
942     /*
943      * Warn if the word was too long, and append a terminating null.
944      */
945     if (len >= MAXWORDLEN) {
946         option_error("warning: word in file %s too long (%.20s...)",
947                      filename, word);
948         len = MAXWORDLEN - 1;
949     }
950     word[len] = 0;
951
952     return 1;
953
954 #undef isoctal
955
956 }
957
958 /*
959  * number_option - parse an unsigned numeric parameter for an option.
960  */
961 int
962 number_option(str, valp, base)
963     char *str;
964     u_int32_t *valp;
965     int base;
966 {
967     char *ptr;
968
969     *valp = strtoul(str, &ptr, base);
970     if (ptr == str) {
971         option_error("invalid numeric parameter '%s' for %s option",
972                      str, current_option);
973         return 0;
974     }
975     return 1;
976 }
977
978
979 /*
980  * int_option - like number_option, but valp is int *,
981  * the base is assumed to be 0, and *valp is not changed
982  * if there is an error.
983  */
984 int
985 int_option(str, valp)
986     char *str;
987     int *valp;
988 {
989     u_int32_t v;
990
991     if (!number_option(str, &v, 0))
992         return 0;
993     *valp = (int) v;
994     return 1;
995 }
996
997
998 /*
999  * The following procedures parse options.
1000  */
1001
1002 /*
1003  * readfile - take commands from a file.
1004  */
1005 static int
1006 readfile(argv)
1007     char **argv;
1008 {
1009     return options_from_file(*argv, 1, 1, privileged_option);
1010 }
1011
1012 /*
1013  * callfile - take commands from /etc/ppp/peers/<name>.
1014  * Name may not contain /../, start with / or ../, or end in /..
1015  */
1016 static int
1017 callfile(argv)
1018     char **argv;
1019 {
1020     char *fname, *arg, *p;
1021     int l, ok;
1022
1023     arg = *argv;
1024     ok = 1;
1025     if (arg[0] == '/' || arg[0] == 0)
1026         ok = 0;
1027     else {
1028         for (p = arg; *p != 0; ) {
1029             if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
1030                 ok = 0;
1031                 break;
1032             }
1033             while (*p != '/' && *p != 0)
1034                 ++p;
1035             if (*p == '/')
1036                 ++p;
1037         }
1038     }
1039     if (!ok) {
1040         option_error("call option value may not contain .. or start with /");
1041         return 0;
1042     }
1043
1044     l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1045     if ((fname = (char *) malloc(l)) == NULL)
1046         novm("call file name");
1047     strcpy(fname, _PATH_PEERFILES);
1048     strcat(fname, arg);
1049
1050     ok = options_from_file(fname, 1, 1, 1);
1051
1052     free(fname);
1053     return ok;
1054 }
1055
1056 #ifdef PPP_FILTER
1057 /*
1058  * setpdebug - Set libpcap debugging level.
1059  */
1060 static int
1061 setpdebug(argv)
1062     char **argv;
1063 {
1064     return int_option(*argv, &dflag);
1065 }
1066
1067 /*
1068  * setpassfilter - Set the pass filter for packets
1069  */
1070 static int
1071 setpassfilter(argv)
1072     char **argv;
1073 {
1074     pc.linktype = DLT_PPP;
1075     pc.snapshot = PPP_HDRLEN;
1076  
1077     if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
1078         return 1;
1079     option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
1080     return 0;
1081 }
1082
1083 /*
1084  * setactivefilter - Set the active filter for packets
1085  */
1086 static int
1087 setactivefilter(argv)
1088     char **argv;
1089 {
1090     pc.linktype = DLT_PPP;
1091     pc.snapshot = PPP_HDRLEN;
1092  
1093     if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
1094         return 1;
1095     option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
1096     return 0;
1097 }
1098 #endif
1099
1100 /*
1101  * noopt - Disable all options.
1102  */
1103 static int
1104 noopt(argv)
1105     char **argv;
1106 {
1107     BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
1108     BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
1109     BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
1110     BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
1111
1112     return (1);
1113 }
1114
1115 /*
1116  * setdomain - Set domain name to append to hostname 
1117  */
1118 static int
1119 setdomain(argv)
1120     char **argv;
1121 {
1122     if (!privileged_option) {
1123         option_error("using the domain option requires root privilege");
1124         return 0;
1125     }
1126     gethostname(hostname, MAXNAMELEN);
1127     if (**argv != 0) {
1128         if (**argv != '.')
1129             strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
1130         strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
1131     }
1132     hostname[MAXNAMELEN-1] = 0;
1133     return (1);
1134 }
1135
1136
1137 /*
1138  * setspeed - Set the speed.
1139  */
1140 static int
1141 setspeed(arg)
1142     char *arg;
1143 {
1144     char *ptr;
1145     int spd;
1146
1147     spd = strtol(arg, &ptr, 0);
1148     if (ptr == arg || *ptr != 0 || spd == 0)
1149         return 0;
1150     inspeed = spd;
1151     return 1;
1152 }
1153
1154
1155 /*
1156  * setdevname - Set the device name.
1157  */
1158 static int
1159 setdevname(cp, quiet)
1160     char *cp;
1161     int quiet;
1162 {
1163     struct stat statbuf;
1164     char dev[MAXPATHLEN];
1165
1166     if (*cp == 0)
1167         return 0;
1168
1169     if (strncmp("/dev/", cp, 5) != 0) {
1170         strcpy(dev, "/dev/");
1171         strncat(dev, cp, MAXPATHLEN - 5);
1172         dev[MAXPATHLEN-1] = 0;
1173         cp = dev;
1174     }
1175
1176     /*
1177      * Check if there is a device by this name.
1178      */
1179     if (stat(cp, &statbuf) < 0) {
1180         if (errno == ENOENT || quiet)
1181             return 0;
1182         option_error("Couldn't stat %s: %m", cp);
1183         return -1;
1184     }
1185
1186     if (!privileged_option) {
1187         if (!quiet)
1188             option_error("setting the device name requires root privilege");
1189         return -1;
1190     }
1191
1192     (void) strncpy(devnam, cp, MAXPATHLEN);
1193     devnam[MAXPATHLEN-1] = 0;
1194     default_device = FALSE;
1195   
1196     return 1;
1197 }
1198
1199
1200 /*
1201  * setipaddr - Set the IP address
1202  */
1203 static int
1204 setipaddr(arg)
1205     char *arg;
1206 {
1207     struct hostent *hp;
1208     char *colon;
1209     u_int32_t local, remote;
1210     ipcp_options *wo = &ipcp_wantoptions[0];
1211   
1212     /*
1213      * IP address pair separated by ":".
1214      */
1215     if ((colon = strchr(arg, ':')) == NULL)
1216         return 0;
1217   
1218     /*
1219      * If colon first character, then no local addr.
1220      */
1221     if (colon != arg) {
1222         *colon = '\0';
1223         if ((local = inet_addr(arg)) == -1) {
1224             if ((hp = gethostbyname(arg)) == NULL) {
1225                 option_error("unknown host: %s", arg);
1226                 return -1;
1227             } else {
1228                 local = *(u_int32_t *)hp->h_addr;
1229             }
1230         }
1231         if (bad_ip_adrs(local)) {
1232             option_error("bad local IP address %s", ip_ntoa(local));
1233             return -1;
1234         }
1235         if (local != 0)
1236             wo->ouraddr = local;
1237         *colon = ':';
1238     }
1239   
1240     /*
1241      * If colon last character, then no remote addr.
1242      */
1243     if (*++colon != '\0') {
1244         if ((remote = inet_addr(colon)) == -1) {
1245             if ((hp = gethostbyname(colon)) == NULL) {
1246                 option_error("unknown host: %s", colon);
1247                 return -1;
1248             } else {
1249                 remote = *(u_int32_t *)hp->h_addr;
1250                 if (remote_name[0] == 0) {
1251                     strncpy(remote_name, colon, MAXNAMELEN);
1252                     remote_name[MAXNAMELEN-1] = 0;
1253                 }
1254             }
1255         }
1256         if (bad_ip_adrs(remote)) {
1257             option_error("bad remote IP address %s", ip_ntoa(remote));
1258             return -1;
1259         }
1260         if (remote != 0)
1261             wo->hisaddr = remote;
1262     }
1263
1264     return 1;
1265 }
1266
1267
1268 /*
1269  * setnetmask - set the netmask to be used on the interface.
1270  */
1271 static int
1272 setnetmask(argv)
1273     char **argv;
1274 {
1275     u_int32_t mask, b;
1276     int n, ok;
1277     char *p, *endp;
1278
1279     /*
1280      * Unfortunately, if we use inet_addr, we can't tell whether
1281      * a result of all 1s is an error or a valid 255.255.255.255.
1282      */
1283     p = *argv;
1284     ok = 0;
1285     mask = 0;
1286     for (n = 3;; --n) {
1287         b = strtoul(p, &endp, 0);
1288         if (endp == p)
1289             break;
1290         if (b < 0 || b > 255) {
1291             if (n == 3) {
1292                 /* accept e.g. 0xffffff00 */
1293                 p = endp;
1294                 mask = b;
1295             }
1296             break;
1297         }
1298         mask |= b << (n * 8);
1299         p = endp;
1300         if (*p != '.' || n == 0)
1301             break;
1302         ++p;
1303     }
1304
1305     mask = htonl(mask);
1306
1307     if (*p != 0 || (netmask & ~mask) != 0) {
1308         option_error("invalid netmask value '%s'", *argv);
1309         return 0;
1310     }
1311
1312     netmask = mask;
1313     return (1);
1314 }
1315
1316 static int
1317 setxonxoff(argv)
1318     char **argv;
1319 {
1320     lcp_wantoptions[0].asyncmap |= 0x000A0000;  /* escape ^S and ^Q */
1321     lcp_wantoptions[0].neg_asyncmap = 1;
1322
1323     crtscts = -2;
1324     return (1);
1325 }