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