source: rtems/c/src/libnetworking/pppd/options.c @ 48cdb95a

4.104.114.84.95
Last change on this file since 48cdb95a was 48cdb95a, checked in by Joel Sherrill <joel.sherrill@…>, on 04/10/03 at 16:20:38

2003-04-10 Joel Sherrill <joel@…>

PR 371/pppd

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