source: rtems/cpukit/pppd/options.c @ 5bd75823

5
Last change on this file since 5bd75823 was 33a1a4db, checked in by Peng Fan <van.freenix@…>, on 04/05/16 at 12:45:55

cpukit: pppd: fix compile warning

rcsid is defined, but not used. So discard it.

Signed-off-by: Peng Fan <van.freenix@…>

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