source: rtems/cpukit/pppd/options.c @ 0286b9f

4.104.114.84.95
Last change on this file since 0286b9f was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:11

2001-01-31 Mike Siers <mikes@…>

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