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