source: rtems/cpukit/pppd/options.c @ ed92e28

4.104.114.84.95
Last change on this file since ed92e28 was ed92e28, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/27/07 at 17:02:30

Include <net/ppp_comp.h> instead of <net/ppp-comp.h>.

  • Property mode set to 100644
File size: 34.8 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 */
71u_int32_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 *, u_int32_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 },
166    { "-d", o_int, &debug,
167      "Increase debugging level", OPT_INC|OPT_NOARG|1 },
168    { "kdebug", o_int, &kdebugflag,
169      "Set kernel driver debug level" },
170    { "nodetach", o_bool, &nodetach,
171      "Don't detach from controlling tty", 1 },
172    { "-detach", o_bool, &nodetach,
173      "Don't detach from controlling tty", 1 },
174    { "updetach", o_bool, &updetach,
175      "Detach from controlling tty once link is up", 1 },
176    { "holdoff", o_int, &holdoff,
177      "Set time in seconds before retrying connection" },
178    { "idle", o_int, &idle_time_limit,
179      "Set time in seconds before disconnecting idle link" },
180    { "lock", o_bool, &lockflag,
181      "Lock serial device with UUCP-style lock file", 1 },
182    { "-all", o_special_noarg, noopt,
183      "Don't request/allow any LCP or IPCP options (useless)" },
184    { "init", o_string, &initializer,
185      "A program to initialize the device",
186      OPT_A2INFO | OPT_PRIVFIX, &initializer_info },
187    { "connect", o_string, &connect_script,
188      "A program to set up a connection",
189      OPT_A2INFO | OPT_PRIVFIX, &connect_script_info },
190    { "disconnect", o_string, &disconnect_script,
191      "Program to disconnect serial device",
192      OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info },
193    { "welcome", o_string, &welcomer,
194      "Script to welcome client",
195      OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
196    { "pty", o_string, &ptycommand,
197      "Script to run on pseudo-tty master side",
198      OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
199    { "notty", o_bool, &notty,
200      "Input/output is not a tty", OPT_DEVNAM | 1 },
201    { "record", o_string, &record_file,
202      "Record characters sent/received to file" },
203    { "maxconnect", o_int, &maxconnect,
204      "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
205    { "crtscts", o_int, &crtscts,
206      "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) },
207    { "nocrtscts", o_int, &crtscts,
208      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
209    { "-crtscts", o_int, &crtscts,
210      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
211    { "cdtrcts", o_int, &crtscts,
212      "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) },
213    { "nocdtrcts", o_int, &crtscts,
214      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
215    { "xonxoff", o_special_noarg, setxonxoff,
216      "Set software (XON/XOFF) flow control" },
217    { "domain", o_special, setdomain,
218      "Add given domain name to hostname" },
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" },
223    { "modem", o_bool, &modem,
224      "Use modem control lines", 1 },
225    { "local", o_bool, &modem,
226      "Don't use modem control lines" },
227    { "file", o_special, readfile,
228      "Take options from a file", OPT_PREPASS },
229    { "call", o_special, callfile,
230      "Take options from a privileged file", OPT_PREPASS },
231    { "persist", o_bool, &persist,
232      "Keep on reopening connection after close", 1 },
233    { "nopersist", o_bool, &persist,
234      "Turn off persist option" },
235    { "demand", o_bool, &demand,
236      "Dial on demand", OPT_INITONLY | 1, &persist },
237    { "sync", o_bool, &sync_serial,
238      "Use synchronous HDLC serial encoding", 1 },
239    { "logfd", o_int, &log_to_fd,
240      "Send log messages to this file descriptor" },
241    { "logfile", o_special, setlogfile,
242      "Append log messages to this file" },
243    { "nolog", o_int, &log_to_fd,
244      "Don't send log messages to any file",
245      OPT_NOARG | OPT_VAL(-1) },
246    { "nologfd", o_int, &log_to_fd,
247      "Don't send log messages to any file descriptor",
248      OPT_NOARG | OPT_VAL(-1) },
249    { "linkname", o_string, linkname,
250      "Set logical name for link",
251      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
252    { "maxfail", o_int, &maxfail,
253      "Maximum number of unsuccessful connection attempts to allow" },
254    { "ktune", o_bool, &tune_kernel,
255      "Alter kernel settings as necessary", 1 },
256    { "noktune", o_bool, &tune_kernel,
257      "Don't alter kernel settings", 0 },
258    { "connect-delay", o_int, &connect_delay,
259      "Maximum time (in ms) to wait after connect script finishes" },
260#ifdef PLUGIN
261    { "plugin", o_special, loadplugin,
262      "Load a plug-in module into pppd", OPT_PRIV },
263#endif
264
265#ifdef PPP_FILTER
266    { "pdebug", o_int, &dflag,
267      "libpcap debugging" },
268    { "pass-filter", 1, setpassfilter,
269      "set filter for packets to pass" },
270    { "active-filter", 1, setactivefilter,
271      "set filter for active pkts" },
272#endif
273
274    { NULL }
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(argc, argv)
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(filename, must_exist, check_prot, priv)
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()
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()
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(w, priv)
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(name)
583    char *name;
584{
585    option_t *opt;
586    struct option_list *list;
587    int i;
588
589    for (list = extra_options; list != NULL; list = list->next)
590        for (opt = list->options; opt->name != NULL; ++opt)
591            if (strcmp(name, opt->name) == 0)
592                return opt;
593    for (opt = general_options; opt->name != NULL; ++opt)
594        if (strcmp(name, opt->name) == 0)
595            return opt;
596    for (opt = auth_options; opt->name != NULL; ++opt)
597        if (strcmp(name, opt->name) == 0)
598            return opt;
599    for (i = 0; protocols[i] != NULL; ++i)
600        if ((opt = protocols[i]->options) != NULL)
601            for (; opt->name != NULL; ++opt)
602                if (strcmp(name, opt->name) == 0)
603                    return opt;
604    return NULL;
605}
606
607/*
608 * process_option - process one new-style option.
609 */
610static int
611process_option(opt, argv)
612    option_t *opt;
613    char **argv;
614{
615    u_int32_t v;
616    int iv, a;
617    char *sv;
618    int (*parser)(char **);
619
620    if ((opt->flags & OPT_PREPASS) == 0 && prepass)
621        return 1;
622    if ((opt->flags & OPT_INITONLY) && pppd_phase != PHASE_INITIALIZE) {
623        option_error("it's too late to use the %s option", opt->name);
624        return 0;
625    }
626    if ((opt->flags & OPT_PRIV) && !privileged_option) {
627        option_error("using the %s option requires root privilege", opt->name);
628        return 0;
629    }
630    if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
631        option_error("%s option is disabled", opt->name);
632        return 0;
633    }
634    if ((opt->flags & OPT_PRIVFIX) && !privileged_option) {
635        struct option_info *ip = (struct option_info *) opt->addr2;
636        if (ip && ip->priv) {
637            option_error("%s option cannot be overridden", opt->name);
638            return 0;
639        }
640    }
641
642    switch (opt->type) {
643    case o_bool:
644        v = opt->flags & OPT_VALUE;
645        *(bool *)(opt->addr) = v;
646        if (opt->addr2 && (opt->flags & OPT_A2COPY))
647            *(bool *)(opt->addr2) = v;
648        break;
649
650    case o_int:
651        iv = 0;
652        if ((opt->flags & OPT_NOARG) == 0) {
653            if (!int_option(*argv, &iv))
654                return 0;
655            if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
656                 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
657                && !((opt->flags & OPT_ZEROOK && iv == 0))) {
658                char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
659                switch (opt->flags & OPT_LIMITS) {
660                case OPT_LLIMIT:
661                    option_error("%s value must be%s >= %d",
662                                 opt->name, zok, opt->lower_limit);
663                    break;
664                case OPT_ULIMIT:
665                    option_error("%s value must be%s <= %d",
666                                 opt->name, zok, opt->upper_limit);
667                    break;
668                case OPT_LIMITS:
669                    option_error("%s value must be%s between %d and %d",
670                                opt->name, opt->lower_limit, opt->upper_limit);
671                    break;
672                }
673                return 0;
674            }
675        }
676        a = opt->flags & OPT_VALUE;
677        if (a >= 128)
678            a -= 256;           /* sign extend */
679        iv += a;
680        if (opt->flags & OPT_INC)
681            iv += *(int *)(opt->addr);
682        if ((opt->flags & OPT_NOINCR) && !privileged_option) {
683            int oldv = *(int *)(opt->addr);
684            if ((opt->flags & OPT_ZEROINF) ?
685                (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
686                option_error("%s value cannot be increased", opt->name);
687                return 0;
688            }
689        }
690        *(int *)(opt->addr) = iv;
691        if (opt->addr2 && (opt->flags & OPT_A2COPY))
692            *(int *)(opt->addr2) = iv;
693        break;
694
695    case o_uint32:
696        if (opt->flags & OPT_NOARG) {
697            v = opt->flags & OPT_VALUE;
698        } else if (!number_option(*argv, &v, 16))
699            return 0;
700        if (opt->flags & OPT_OR)
701            v |= *(u_int32_t *)(opt->addr);
702        *(u_int32_t *)(opt->addr) = v;
703        if (opt->addr2 && (opt->flags & OPT_A2COPY))
704            *(u_int32_t *)(opt->addr2) = v;
705        break;
706
707    case o_string:
708        if (opt->flags & OPT_STATIC) {
709            strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
710        } else {
711            sv = strdup(*argv);
712            if (sv == NULL)
713                novm("option argument");
714            if ( *(char **)(opt->addr) != NULL ) {
715                free((void *)*(char **)(opt->addr));
716                *(char **)(opt->addr) = NULL;
717            }
718            *(char **)(opt->addr) = sv;
719        }
720        break;
721
722    case o_special_noarg:
723    case o_special:
724        parser = (int (*)(char **)) opt->addr;
725        if (!(*parser)(argv))
726            return 0;
727        break;
728    }
729
730    if (opt->addr2) {
731        if (opt->flags & OPT_A2INFO) {
732            struct option_info *ip = (struct option_info *) opt->addr2;
733            ip->priv = privileged_option;
734            ip->source = option_source;
735        } else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
736            *(bool *)(opt->addr2) = 1;
737    }
738
739    return 1;
740}
741
742/*
743 * n_arguments - tell how many arguments an option takes
744 */
745static int
746n_arguments(opt)
747    option_t *opt;
748{
749    return (opt->type == o_bool || opt->type == o_special_noarg
750            || (opt->flags & OPT_NOARG))? 0: 1;
751}
752
753/*
754 * add_options - add a list of options to the set we grok.
755 */
756void
757add_options(opt)
758    option_t *opt;
759{
760    struct option_list *list;
761
762    list = malloc(sizeof(*list));
763    if (list == 0)
764        novm("option list entry");
765    list->options = opt;
766    list->next = extra_options;
767    extra_options = list;
768}
769
770/*
771 * usage - print out a message telling how to use the program.
772 */
773static void
774usage()
775{
776    if (pppd_phase == PHASE_INITIALIZE)
777        fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
778                "rtems_pppd");
779}
780
781/*
782 * option_error - print a message about an error in an option.
783 * The message is logged, and also sent to
784 * stderr if pppd_phase == PHASE_INITIALIZE.
785 */
786void
787option_error __V((char *fmt, ...))
788{
789    va_list args;
790    char buf[256];
791
792#if defined(__STDC__)
793    va_start(args, fmt);
794#else
795    char *fmt;
796    va_start(args);
797    fmt = va_arg(args, char *);
798#endif
799    if (prepass) {
800        va_end(args);
801        return;
802    }
803    vslprintf(buf, sizeof(buf), fmt, args);
804    va_end(args);
805
806    fprintf(stderr, "pppd: %s\n", buf);
807}
808
809/*
810 * Read a word from a file.
811 * Words are delimited by white-space or by quotes (" or ').
812 * Quotes, white-space and \ may be escaped with \.
813 * \<newline> is ignored.
814 */
815int
816getword(f, word, newlinep, filename)
817    FILE *f;
818    char *word;
819    int *newlinep;
820    char *filename;
821{
822    int c, len, escape;
823    int quoted, comment;
824    int value, digit, got, n;
825
826#define isoctal(c) ((c) >= '0' && (c) < '8')
827
828    *newlinep = 0;
829    len = 0;
830    escape = 0;
831    comment = 0;
832
833    /*
834     * First skip white-space and comments.
835     */
836    for (;;) {
837        c = getc(f);
838        if (c == EOF)
839            break;
840
841        /*
842         * A newline means the end of a comment; backslash-newline
843         * is ignored.  Note that we cannot have escape && comment.
844         */
845        if (c == '\n') {
846            if (!escape) {
847                *newlinep = 1;
848                comment = 0;
849            } else
850                escape = 0;
851            continue;
852        }
853
854        /*
855         * Ignore characters other than newline in a comment.
856         */
857        if (comment)
858            continue;
859
860        /*
861         * If this character is escaped, we have a word start.
862         */
863        if (escape)
864            break;
865
866        /*
867         * If this is the escape character, look at the next character.
868         */
869        if (c == '\\') {
870            escape = 1;
871            continue;
872        }
873
874        /*
875         * If this is the start of a comment, ignore the rest of the line.
876         */
877        if (c == '#') {
878            comment = 1;
879            continue;
880        }
881
882        /*
883         * A non-whitespace character is the start of a word.
884         */
885        if (!isspace(c))
886            break;
887    }
888
889    /*
890     * Save the delimiter for quoted strings.
891     */
892    if (!escape && (c == '"' || c == '\'')) {
893        quoted = c;
894        c = getc(f);
895    } else
896        quoted = 0;
897
898    /*
899     * Process characters until the end of the word.
900     */
901    while (c != EOF) {
902        if (escape) {
903            /*
904             * This character is escaped: backslash-newline is ignored,
905             * various other characters indicate particular values
906             * as for C backslash-escapes.
907             */
908            escape = 0;
909            if (c == '\n') {
910                c = getc(f);
911                continue;
912            }
913
914            got = 0;
915            switch (c) {
916            case 'a':
917                value = '\a';
918                break;
919            case 'b':
920                value = '\b';
921                break;
922            case 'f':
923                value = '\f';
924                break;
925            case 'n':
926                value = '\n';
927                break;
928            case 'r':
929                value = '\r';
930                break;
931            case 's':
932                value = ' ';
933                break;
934            case 't':
935                value = '\t';
936                break;
937
938            default:
939                if (isoctal(c)) {
940                    /*
941                     * \ddd octal sequence
942                     */
943                    value = 0;
944                    for (n = 0; n < 3 && isoctal(c); ++n) {
945                        value = (value << 3) + (c & 07);
946                        c = getc(f);
947                    }
948                    got = 1;
949                    break;
950                }
951
952                if (c == 'x') {
953                    /*
954                     * \x<hex_string> sequence
955                     */
956                    value = 0;
957                    c = getc(f);
958                    for (n = 0; n < 2 && isxdigit(c); ++n) {
959                        digit = toupper(c) - '0';
960                        if (digit > 10)
961                            digit += '0' + 10 - 'A';
962                        value = (value << 4) + digit;
963                        c = getc (f);
964                    }
965                    got = 1;
966                    break;
967                }
968
969                /*
970                 * Otherwise the character stands for itself.
971                 */
972                value = c;
973                break;
974            }
975
976            /*
977             * Store the resulting character for the escape sequence.
978             */
979            if (len < MAXWORDLEN-1)
980                word[len] = value;
981            ++len;
982
983            if (!got)
984                c = getc(f);
985            continue;
986
987        }
988
989        /*
990         * Not escaped: see if we've reached the end of the word.
991         */
992        if (quoted) {
993            if (c == quoted)
994                break;
995        } else {
996            if (isspace(c) || c == '#') {
997                ungetc (c, f);
998                break;
999            }
1000        }
1001
1002        /*
1003         * Backslash starts an escape sequence.
1004         */
1005        if (c == '\\') {
1006            escape = 1;
1007            c = getc(f);
1008            continue;
1009        }
1010
1011        /*
1012         * An ordinary character: store it in the word and get another.
1013         */
1014        if (len < MAXWORDLEN-1)
1015            word[len] = c;
1016        ++len;
1017
1018        c = getc(f);
1019    }
1020
1021    /*
1022     * End of the word: check for errors.
1023     */
1024    if (c == EOF) {
1025        if (ferror(f)) {
1026            if (errno == 0)
1027                errno = EIO;
1028            option_error("Error reading %s: %m", filename);
1029            die(1);
1030        }
1031        /*
1032         * If len is zero, then we didn't find a word before the
1033         * end of the file.
1034         */
1035        if (len == 0)
1036            return 0;
1037    }
1038
1039    /*
1040     * Warn if the word was too long, and append a terminating null.
1041     */
1042    if (len >= MAXWORDLEN) {
1043        option_error("warning: word in file %s too long (%.20s...)",
1044                     filename, word);
1045        len = MAXWORDLEN - 1;
1046    }
1047    word[len] = 0;
1048
1049    return 1;
1050
1051#undef isoctal
1052
1053}
1054
1055/*
1056 * number_option - parse an unsigned numeric parameter for an option.
1057 */
1058static int
1059number_option(str, valp, base)
1060    char *str;
1061    u_int32_t *valp;
1062    int base;
1063{
1064    char *ptr;
1065
1066    *valp = strtoul(str, &ptr, base);
1067    if (ptr == str) {
1068        option_error("invalid numeric parameter '%s' for %s option",
1069                     str, current_option);
1070        return 0;
1071    }
1072    return 1;
1073}
1074
1075
1076/*
1077 * int_option - like number_option, but valp is int *,
1078 * the base is assumed to be 0, and *valp is not changed
1079 * if there is an error.
1080 */
1081int
1082int_option(str, valp)
1083    char *str;
1084    int *valp;
1085{
1086    u_int32_t v;
1087
1088    if (!number_option(str, &v, 0))
1089        return 0;
1090    *valp = (int) v;
1091    return 1;
1092}
1093
1094
1095/*
1096 * The following procedures parse options.
1097 */
1098
1099/*
1100 * readfile - take commands from a file.
1101 */
1102static int
1103readfile(argv)
1104    char **argv;
1105{
1106    return options_from_file(*argv, 1, 1, privileged_option);
1107}
1108
1109/*
1110 * callfile - take commands from /etc/ppp/peers/<name>.
1111 * Name may not contain /../, start with / or ../, or end in /..
1112 */
1113static int
1114callfile(argv)
1115    char **argv;
1116{
1117    char *fname, *arg, *p;
1118    int l, ok;
1119
1120    arg = *argv;
1121    ok = 1;
1122    if (arg[0] == '/' || arg[0] == 0)
1123        ok = 0;
1124    else {
1125        for (p = arg; *p != 0; ) {
1126            if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
1127                ok = 0;
1128                break;
1129            }
1130            while (*p != '/' && *p != 0)
1131                ++p;
1132            if (*p == '/')
1133                ++p;
1134        }
1135    }
1136    if (!ok) {
1137        option_error("call option value may not contain .. or start with /");
1138        return 0;
1139    }
1140
1141    l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1142    if ((fname = (char *) malloc(l)) == NULL)
1143        novm("call file name");
1144    slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
1145
1146    ok = options_from_file(fname, 1, 1, 1);
1147
1148    free(fname);
1149    return ok;
1150}
1151
1152#ifdef PPP_FILTER
1153/*
1154 * setpdebug - Set libpcap debugging level.
1155 */
1156static int
1157setpdebug(argv)
1158    char **argv;
1159{
1160    return int_option(*argv, &dflag);
1161}
1162
1163/*
1164 * setpassfilter - Set the pass filter for packets
1165 */
1166static int
1167setpassfilter(argv)
1168    char **argv;
1169{
1170    pc.linktype = DLT_PPP;
1171    pc.snapshot = PPP_HDRLEN;
1172 
1173    if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
1174        return 1;
1175    option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
1176    return 0;
1177}
1178
1179/*
1180 * setactivefilter - Set the active filter for packets
1181 */
1182static int
1183setactivefilter(argv)
1184    char **argv;
1185{
1186    pc.linktype = DLT_PPP;
1187    pc.snapshot = PPP_HDRLEN;
1188 
1189    if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
1190        return 1;
1191    option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
1192    return 0;
1193}
1194#endif
1195
1196/*
1197 * noopt - Disable all options.
1198 */
1199static int
1200noopt(argv)
1201    char **argv;
1202{
1203    BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
1204    BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
1205    BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
1206    BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
1207
1208    return (1);
1209}
1210
1211/*
1212 * setdomain - Set domain name to append to hostname
1213 */
1214static int
1215setdomain(argv)
1216    char **argv;
1217{
1218    if (!privileged_option) {
1219        option_error("using the domain option requires root privilege");
1220        return 0;
1221    }
1222    gethostname(hostname, MAXNAMELEN);
1223    if (**argv != 0) {
1224        if (**argv != '.')
1225            strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
1226        strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
1227    }
1228    hostname[MAXNAMELEN-1] = 0;
1229    return (1);
1230}
1231
1232
1233/*
1234 * setspeed - Set the speed.
1235 */
1236static int
1237setspeed(arg)
1238    char *arg;
1239{
1240  int      spd;
1241  uint32_t ret      = (int)1;
1242  speed_t  spdValue = (speed_t)0;
1243  char    *ptr;
1244
1245  if ( !prepass ) {
1246    spd = strtol(arg, &ptr, 0);
1247    if (ptr == arg || *ptr != 0 || spd == 0) {
1248      ret = (int)0;
1249    }
1250    else {
1251      switch ( spd ) {
1252        case 2400L:
1253          spdValue = B2400;
1254          break;
1255        case 4800L:
1256          spdValue = B4800;
1257          break;
1258        case 9600L:
1259          spdValue = B9600;
1260          break;
1261        case 19200L:
1262          spdValue = B19200;
1263          break;
1264        case 38400L:
1265          spdValue = B38400;
1266          break;
1267        case 57600L:
1268          spdValue = B57600;
1269          break;
1270        case 115200L:
1271          spdValue = B115200;
1272          break;
1273        default:
1274          ret = (int)0;
1275          break;
1276      }
1277
1278      if ( spdValue ) {
1279        inspeed = spdValue;
1280      }
1281    }
1282  }
1283
1284  return ( ret );
1285}
1286
1287
1288/*
1289 * setdevname - Set the device name.
1290 */
1291static int
1292setdevname(cp)
1293    char *cp;
1294{
1295    struct stat statbuf;
1296    char dev[MAXPATHLEN];
1297
1298    if (*cp == 0)
1299        return 0;
1300
1301    if (strncmp("/dev/", cp, 5) != 0) {
1302        strlcpy(dev, "/dev/", sizeof(dev));
1303        strlcat(dev, cp, sizeof(dev));
1304        cp = dev;
1305    }
1306
1307    /*
1308     * Check if there is a character device by this name.
1309     */
1310    if (stat(cp, &statbuf) < 0) {
1311        if (errno == ENOENT)
1312            return 0;
1313        option_error("Couldn't stat %s: %m", cp);
1314        return -1;
1315    }
1316    if (!S_ISCHR(statbuf.st_mode)) {
1317        option_error("%s is not a character device", cp);
1318        return -1;
1319    }
1320
1321    if (pppd_phase != PHASE_INITIALIZE) {
1322        option_error("device name cannot be changed after initialization");
1323        return -1;
1324    } else if (devnam_fixed) {
1325        option_error("per-tty options file may not specify device name");
1326        return -1;
1327    }
1328
1329    if (devnam_info.priv && !privileged_option) {
1330        option_error("device name cannot be overridden");
1331        return -1;
1332    }
1333
1334    strlcpy(devnam, cp, sizeof(devnam));
1335    devstat = statbuf;
1336    default_device = 0;
1337    devnam_info.priv = privileged_option;
1338    devnam_info.source = option_source;
1339 
1340    return 1;
1341}
1342
1343
1344/*
1345 * setipaddr - Set the IP address
1346 */
1347static int
1348setipaddr(arg)
1349    char *arg;
1350{
1351    struct hostent *hp;
1352    char *colon;
1353    u_int32_t local, remote;
1354    ipcp_options *wo = &ipcp_wantoptions[0];
1355 
1356    /*
1357     * IP address pair separated by ":".
1358     */
1359    if ((colon = strchr(arg, ':')) == NULL)
1360        return 0;
1361    if (prepass)
1362        return 1;
1363 
1364    /*
1365     * If colon first character, then no local addr.
1366     */
1367    if (colon != arg) {
1368        *colon = '\0';
1369        if ((local = inet_addr(arg)) == (u_int32_t) -1) {
1370            if ((hp = gethostbyname(arg)) == NULL) {
1371                option_error("unknown host: %s", arg);
1372                return -1;
1373            } else {
1374                local = *(u_int32_t *)hp->h_addr;
1375            }
1376        }
1377        if (bad_ip_adrs(local)) {
1378            option_error("bad local IP address %s", ip_ntoa(local));
1379            return -1;
1380        }
1381        if (local != 0)
1382            wo->ouraddr = local;
1383        *colon = ':';
1384    }
1385 
1386    /*
1387     * If colon last character, then no remote addr.
1388     */
1389    if (*++colon != '\0') {
1390        if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
1391            if ((hp = gethostbyname(colon)) == NULL) {
1392                option_error("unknown host: %s", colon);
1393                return -1;
1394            } else {
1395                remote = *(u_int32_t *)hp->h_addr;
1396                if (remote_name[0] == 0)
1397                    strlcpy(remote_name, colon, sizeof(remote_name));
1398            }
1399        }
1400        if (bad_ip_adrs(remote)) {
1401            option_error("bad remote IP address %s", ip_ntoa(remote));
1402            return -1;
1403        }
1404        if (remote != 0)
1405            wo->hisaddr = remote;
1406    }
1407
1408    return 1;
1409}
1410
1411
1412/*
1413 * setnetmask - set the netmask to be used on the interface.
1414 */
1415static int
1416setnetmask(argv)
1417    char **argv;
1418{
1419    u_int32_t mask, b;
1420    int n, ok;
1421    char *p, *endp;
1422
1423    /*
1424     * Unfortunately, if we use inet_addr, we can't tell whether
1425     * a result of all 1s is an error or a valid 255.255.255.255.
1426     */
1427    p = *argv;
1428    ok = 0;
1429    mask = 0;
1430    for (n = 3;; --n) {
1431        b = strtoul(p, &endp, 0);
1432        if (endp == p)
1433            break;
1434        if (b > 255) {
1435            if (n == 3) {
1436                /* accept e.g. 0xffffff00 */
1437                p = endp;
1438                mask = b;
1439            }
1440            break;
1441        }
1442        mask |= b << (n * 8);
1443        p = endp;
1444        if (*p != '.' || n == 0)
1445            break;
1446        ++p;
1447    }
1448
1449    mask = htonl(mask);
1450
1451    if (*p != 0 || (netmask & ~mask) != 0) {
1452        option_error("invalid netmask value '%s'", *argv);
1453        return 0;
1454    }
1455
1456    netmask = mask;
1457    return (1);
1458}
1459
1460static int
1461setxonxoff(argv)
1462    char **argv;
1463{
1464    lcp_wantoptions[0].asyncmap |= 0x000A0000;  /* escape ^S and ^Q */
1465    lcp_wantoptions[0].neg_asyncmap = 1;
1466
1467    crtscts = -2;
1468    return (1);
1469}
1470
1471static int
1472setlogfile(argv)
1473    char **argv;
1474{
1475    int fd, err;
1476
1477    fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
1478    if (fd < 0 && errno == EEXIST)
1479        fd = open(*argv, O_WRONLY | O_APPEND);
1480    err = errno;
1481    if (fd < 0) {
1482        errno = err;
1483        option_error("Can't open log file %s: %m", *argv);
1484        return 0;
1485    }
1486    if (log_to_file && log_to_fd >= 0)
1487        close(log_to_fd);
1488    log_to_fd = fd;
1489    log_to_file = 1;
1490    return 1;
1491}
1492
1493#ifdef PLUGIN
1494static int
1495loadplugin(argv)
1496    char **argv;
1497{
1498    char *arg = *argv;
1499    void *handle;
1500    const char *err;
1501    void (*init)(void);
1502
1503    handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW);
1504    if (handle == 0) {
1505        err = dlerror();
1506        if (err != 0)
1507            option_error("%s", err);
1508        option_error("Couldn't load plugin %s", arg);
1509        return 0;
1510    }
1511    init = dlsym(handle, "plugin_init");
1512    if (init == 0) {
1513        option_error("%s has no initialization entry point", arg);
1514        dlclose(handle);
1515        return 0;
1516    }
1517    info("Plugin %s loaded.", arg);
1518    (*init)();
1519    return 1;
1520}
1521#endif /* PLUGIN */
Note: See TracBrowser for help on using the repository browser.