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