source: rtems-libbsd/rtemsbsd/pppd/options.c @ 70fa95a

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 70fa95a was 70fa95a, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 30, 2014 at 12:46:12 PM

ppp: Import from RTEMS sources

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