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

4.104.114.84.95
Last change on this file since c55df85 was 2f1b930, checked in by Joel Sherrill <joel.sherrill@…>, on 08/16/01 at 20:42:09

2001-08-16 Mike Siers <mikes@…>

  • Update of PPPD to 2.3.11 from 2.3.5 and addition of an example application. Mike's notes on the modifications:
    • renamed error() function because of namespace problems
    • removed calls to the exit() funciton
    • removed extra files from the pppd source directory
    • defined pppd task constant values in rtemspppd.h
    • modifyied example code to get actual tick per second value
    • placed the pppd 2.3.11 man page file (pppd.8) into the pppd directory
  • pppd/cbcp.c, pppd/cbcp.h, pppd/main.c, pppd/ppp_tty.c, pppd/pppmain.c, pppd/rtems-ppp.c, pppd/rtems-ppp.c: Deleted.
  • pppd/pppd.8, pppd/rtemsmain.c, pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/utils.c, pppd/example/Makefile, pppd/example/README, pppd/example/init.c, pppd/example/netconfig.h, pppd/example/ppp.conf, pppd/example/pppdapp.c, pppd/example/system.h: New files.
  • modem/ppp_tty.c, net/if_ppp.h, pppd/Makefile.am, pppd/README, pppd/STATUS, pppd/auth.c, pppd/ccp.c, pppd/ccp.h, pppd/chap.c, pppd/chap.h, pppd/chap_ms.c, pppd/chap_ms.h, pppd/chat.c, pppd/demand.c, pppd/fsm.c, pppd/fsm.h, pppd/ipcp.c, pppd/ipcp.h, pppd/ipxcp.c, pppd/ipxcp.h, pppd/lcp.c, pppd/lcp.h, pppd/magic.c, pppd/magic.h, pppd/options.c, pppd/patchlevel.h, pppd/pathnames.h, pppd/pppd.h, pppd/upap.c, pppd/upap.h: Modified.
  • 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
56#if defined(ultrix) || defined(NeXT)
57char *strdup __P((char *));
58#endif
59
60static const char rcsid[] = RCSID;
61
62/*
63 * Option variables and default values.
64 */
65#ifdef PPP_FILTER
66int     dflag = 0;              /* Tell libpcap we want debugging */
67#endif
68int     debug = 0;              /* Debug flag */
69int     kdebugflag = 0;         /* Tell kernel to print debug messages */
70int     default_device = 1;     /* Using /dev/tty or equivalent */
71char    devnam[MAXPATHLEN];     /* Device name */
72int     crtscts = 0;            /* Use hardware flow control */
73bool    modem = 1;              /* Use modem control lines */
74int     inspeed = 0;            /* Input/Output speed requested */
75u_int32_t netmask = 0;          /* IP netmask to set on interface */
76bool    lockflag = 0;           /* Create lock file to lock the serial dev */
77bool    nodetach = 0;           /* Don't detach from controlling tty */
78bool    updetach = 0;           /* Detach once link is up */
79char    *initializer = NULL;    /* Script to initialize physical link */
80char    *connect_script = NULL; /* Script to establish physical link */
81char    *disconnect_script = NULL; /* Script to disestablish physical link */
82char    *welcomer = NULL;       /* Script to run after phys link estab. */
83char    *ptycommand = NULL;     /* Command to run on other side of pty */
84int     maxconnect = 0;         /* Maximum connect time */
85char    user[MAXNAMELEN];       /* Username for PAP */
86char    passwd[MAXSECRETLEN];   /* Password for PAP */
87bool    persist = 0;            /* Reopen link after it goes down */
88char    our_name[MAXNAMELEN];   /* Our name for authentication purposes */
89bool    demand = 0;             /* do dial-on-demand */
90char    *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
91int     idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
92int     holdoff = 30;           /* # seconds to pause before reconnecting */
93bool    holdoff_specified;      /* true if a holdoff value has been given */
94bool    notty = 0;              /* Stdin/out is not a tty */
95char    *record_file = NULL;    /* File to record chars sent/received */
96int     using_pty = 0;
97bool    sync_serial = 0;        /* Device is synchronous serial device */
98int     log_to_fd = 1;          /* send log messages to this fd too */
99int     maxfail = 10;           /* max # of unsuccessful connection attempts */
100char    linkname[MAXPATHLEN];   /* logical name for link */
101bool    tune_kernel;            /* may alter kernel settings */
102int     connect_delay = 1000;   /* wait this many ms after connect script */
103
104extern option_t auth_options[];
105extern struct stat devstat;
106extern int prepass;             /* Doing pre-pass to find device name */
107
108struct option_info initializer_info;
109struct option_info connect_script_info;
110struct option_info disconnect_script_info;
111struct option_info welcomer_info;
112struct option_info devnam_info;
113struct option_info ptycommand_info;
114
115#ifdef PPP_FILTER
116struct  bpf_program pass_filter;/* Filter program for packets to pass */
117struct  bpf_program active_filter; /* Filter program for link-active pkts */
118pcap_t  pc;                     /* Fake struct pcap so we can compile expr */
119#endif
120
121char *current_option;           /* the name of the option being parsed */
122int  privileged_option;         /* set iff the current option came from root */
123char *option_source;            /* string saying where the option came from */
124bool log_to_file;               /* log_to_fd is a file opened by us */
125
126/*
127 * Prototypes
128 */
129static int setdevname __P((char *));
130static int setipaddr __P((char *));
131static int setspeed __P((char *));
132static int noopt __P((char **));
133static int setdomain __P((char **));
134static int setnetmask __P((char **));
135static int setxonxoff __P((char **));
136static int readfile __P((char **));
137static int callfile __P((char **));
138static void usage __P((void));
139static int setlogfile __P((char **));
140#ifdef PLUGIN
141static int loadplugin __P((char **));
142#endif
143
144#ifdef PPP_FILTER
145static int setpassfilter __P((char **));
146static int setactivefilter __P((char **));
147#endif
148
149static option_t *find_option __P((char *name));
150static int process_option __P((option_t *, char **));
151static int n_arguments __P((option_t *));
152static int number_option __P((char *, u_int32_t *, int));
153
154/*
155 * Structure to store extra lists of options.
156 */
157struct option_list {
158    option_t *options;
159    struct option_list *next;
160};
161
162static struct option_list *extra_options = NULL;
163
164/*
165 * Valid arguments.
166 */
167option_t general_options[] = {
168    { "debug", o_int, &debug,
169      "Increase debugging level", OPT_INC|OPT_NOARG|1 },
170    { "-d", o_int, &debug,
171      "Increase debugging level", OPT_INC|OPT_NOARG|1 },
172    { "kdebug", o_int, &kdebugflag,
173      "Set kernel driver debug level" },
174    { "nodetach", o_bool, &nodetach,
175      "Don't detach from controlling tty", 1 },
176    { "-detach", o_bool, &nodetach,
177      "Don't detach from controlling tty", 1 },
178    { "updetach", o_bool, &updetach,
179      "Detach from controlling tty once link is up", 1 },
180    { "holdoff", o_int, &holdoff,
181      "Set time in seconds before retrying connection" },
182    { "idle", o_int, &idle_time_limit,
183      "Set time in seconds before disconnecting idle link" },
184    { "lock", o_bool, &lockflag,
185      "Lock serial device with UUCP-style lock file", 1 },
186    { "-all", o_special_noarg, noopt,
187      "Don't request/allow any LCP or IPCP options (useless)" },
188    { "init", o_string, &initializer,
189      "A program to initialize the device",
190      OPT_A2INFO | OPT_PRIVFIX, &initializer_info },
191    { "connect", o_string, &connect_script,
192      "A program to set up a connection",
193      OPT_A2INFO | OPT_PRIVFIX, &connect_script_info },
194    { "disconnect", o_string, &disconnect_script,
195      "Program to disconnect serial device",
196      OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info },
197    { "welcome", o_string, &welcomer,
198      "Script to welcome client",
199      OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
200    { "pty", o_string, &ptycommand,
201      "Script to run on pseudo-tty master side",
202      OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
203    { "notty", o_bool, &notty,
204      "Input/output is not a tty", OPT_DEVNAM | 1 },
205    { "record", o_string, &record_file,
206      "Record characters sent/received to file" },
207    { "maxconnect", o_int, &maxconnect,
208      "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
209    { "crtscts", o_int, &crtscts,
210      "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) },
211    { "nocrtscts", o_int, &crtscts,
212      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
213    { "-crtscts", o_int, &crtscts,
214      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
215    { "cdtrcts", o_int, &crtscts,
216      "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) },
217    { "nocdtrcts", o_int, &crtscts,
218      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
219    { "xonxoff", o_special_noarg, setxonxoff,
220      "Set software (XON/XOFF) flow control" },
221    { "domain", o_special, setdomain,
222      "Add given domain name to hostname" },
223    { "mtu", o_int, &lcp_allowoptions[0].mru,
224      "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
225    { "netmask", o_special, setnetmask,
226      "set netmask" },
227    { "modem", o_bool, &modem,
228      "Use modem control lines", 1 },
229    { "local", o_bool, &modem,
230      "Don't use modem control lines" },
231    { "file", o_special, readfile,
232      "Take options from a file", OPT_PREPASS },
233    { "call", o_special, callfile,
234      "Take options from a privileged file", OPT_PREPASS },
235    { "persist", o_bool, &persist,
236      "Keep on reopening connection after close", 1 },
237    { "nopersist", o_bool, &persist,
238      "Turn off persist option" },
239    { "demand", o_bool, &demand,
240      "Dial on demand", OPT_INITONLY | 1, &persist },
241    { "sync", o_bool, &sync_serial,
242      "Use synchronous HDLC serial encoding", 1 },
243    { "logfd", o_int, &log_to_fd,
244      "Send log messages to this file descriptor" },
245    { "logfile", o_special, setlogfile,
246      "Append log messages to this file" },
247    { "nolog", o_int, &log_to_fd,
248      "Don't send log messages to any file",
249      OPT_NOARG | OPT_VAL(-1) },
250    { "nologfd", o_int, &log_to_fd,
251      "Don't send log messages to any file descriptor",
252      OPT_NOARG | OPT_VAL(-1) },
253    { "linkname", o_string, linkname,
254      "Set logical name for link",
255      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
256    { "maxfail", o_int, &maxfail,
257      "Maximum number of unsuccessful connection attempts to allow" },
258    { "ktune", o_bool, &tune_kernel,
259      "Alter kernel settings as necessary", 1 },
260    { "noktune", o_bool, &tune_kernel,
261      "Don't alter kernel settings", 0 },
262    { "connect-delay", o_int, &connect_delay,
263      "Maximum time (in ms) to wait after connect script finishes" },
264#ifdef PLUGIN
265    { "plugin", o_special, loadplugin,
266      "Load a plug-in module into pppd", OPT_PRIV },
267#endif
268
269#ifdef PPP_FILTER
270    { "pdebug", o_int, &dflag,
271      "libpcap debugging" },
272    { "pass-filter", 1, setpassfilter,
273      "set filter for packets to pass" },
274    { "active-filter", 1, setactivefilter,
275      "set filter for active pkts" },
276#endif
277
278    { NULL }
279};
280
281#ifndef IMPLEMENTATION
282#define IMPLEMENTATION ""
283#endif
284
285static char *usage_string = "\
286pppd version %s.%d%s\n\
287Usage: %s [ options ], where options are:\n\
288        <device>        Communicate over the named device\n\
289        <speed>         Set the baud rate to <speed>\n\
290        <loc>:<rem>     Set the local and/or remote interface IP\n\
291                        addresses.  Either one may be omitted.\n\
292        asyncmap <n>    Set the desired async map to hex <n>\n\
293        auth            Require authentication from peer\n\
294        connect <p>     Invoke shell command <p> to set up the serial line\n\
295        crtscts         Use hardware RTS/CTS flow control\n\
296        defaultroute    Add default route through interface\n\
297        file <f>        Take options from file <f>\n\
298        modem           Use modem control lines\n\
299        mru <n>         Set MRU value to <n> for negotiation\n\
300See pppd(8) for more options.\n\
301";
302
303/*
304 * parse_args - parse a string of arguments from the command line.
305 * If prepass is true, we are scanning for the device name and only
306 * processing a few options, so error messages are suppressed.
307 */
308int
309parse_args(argc, argv)
310    int argc;
311    char **argv;
312{
313    char *arg;
314    option_t *opt;
315    int ret;
316
317    privileged_option = privileged;
318    option_source = "command line";
319    while (argc > 0) {
320        arg = *argv++;
321        --argc;
322
323        /*
324         * First see if it's an option in the new option list.
325         */
326        opt = find_option(arg);
327        if (opt != NULL) {
328            int n = n_arguments(opt);
329            if (argc < n) {
330                option_error("too few parameters for option %s", arg);
331                return 0;
332            }
333            current_option = arg;
334            if (!process_option(opt, argv))
335                return 0;
336            argc -= n;
337            argv += n;
338            continue;
339        }
340
341        /*
342         * Maybe a tty name, speed or IP address?
343         */
344        if ((ret = setdevname(arg)) == 0
345            && (ret = setspeed(arg)) == 0
346            && (ret = setipaddr(arg)) == 0
347            && !prepass) {
348            option_error("unrecognized option '%s'", arg);
349            usage();
350            return 0;
351        }
352        if (ret < 0)    /* error */
353            return 0;
354    }
355    return 1;
356}
357
358#if 0
359/*
360 * scan_args - scan the command line arguments to get the tty name,
361 * if specified.  Also checks whether the notty or pty option was given.
362 */
363void
364scan_args(argc, argv)
365    int argc;
366    char **argv;
367{
368    char *arg;
369    option_t *opt;
370
371    privileged_option = privileged;
372    while (argc > 0) {
373        arg = *argv++;
374        --argc;
375
376        if (strcmp(arg, "notty") == 0 || strcmp(arg, "pty") == 0)
377            using_pty = 1;
378
379        /* Skip options and their arguments */
380        opt = find_option(arg);
381        if (opt != NULL) {
382            int n = n_arguments(opt);
383            argc -= n;
384            argv += n;
385            continue;
386        }
387
388        /* Check if it's a tty name and copy it if so */
389        (void) setdevname(arg, 1);
390    }
391}
392#endif
393
394/*
395 * options_from_file - Read a string of options from a file,
396 * and interpret them.
397 */
398int
399options_from_file(filename, must_exist, check_prot, priv)
400    char *filename;
401    int must_exist;
402    int check_prot;
403    int priv;
404{
405    FILE *f;
406    int i, newline, ret, err;
407    option_t *opt;
408    int oldpriv;
409    char *oldsource;
410    char *argv[MAXARGS];
411    char args[MAXARGS][MAXWORDLEN];
412    char cmd[MAXWORDLEN];
413
414    f = fopen(filename, "r");
415    err = errno;
416    if (f == NULL) {
417        if (!must_exist && err == ENOENT)
418            return 1;
419        errno = err;
420        option_error("Can't open options file %s: %m", filename);
421        return 0;
422    }
423
424    oldpriv = privileged_option;
425    privileged_option = priv;
426    oldsource = option_source;
427    option_source = strdup(filename);
428    if (option_source == NULL)
429        option_source = "file";
430    ret = 0;
431    while (getword(f, cmd, &newline, filename)) {
432        /*
433         * First see if it's a command.
434         */
435        opt = find_option(cmd);
436        if (opt != NULL) {
437            int n = n_arguments(opt);
438            for (i = 0; i < n; ++i) {
439                if (!getword(f, args[i], &newline, filename)) {
440                    option_error(
441                        "In file %s: too few parameters for option '%s'",
442                        filename, cmd);
443                    goto err;
444                }
445                argv[i] = args[i];
446            }
447            current_option = cmd;
448            if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
449                option_error("the %s option may not be used in the %s file",
450                             cmd, filename);
451                goto err;
452            }
453            if (!process_option(opt, argv))
454                goto err;
455            continue;
456        }
457
458        /*
459         * Maybe a tty name, speed or IP address?
460         */
461        if ((i = setdevname(cmd)) == 0
462            && (i = setspeed(cmd)) == 0
463            && (i = setipaddr(cmd)) == 0) {
464            option_error("In file %s: unrecognized option '%s'",
465                         filename, cmd);
466            goto err;
467        }
468        if (i < 0)              /* error */
469            goto err;
470    }
471    ret = 1;
472
473err:
474    fclose(f);
475    privileged_option = oldpriv;
476    option_source = oldsource;
477    return ret;
478}
479
480/*
481 * options_from_user - See if the use has a ~/.ppprc file,
482 * and if so, interpret options from it.
483 */
484int
485options_from_user()
486{
487    return 0;
488}
489
490/*
491 * options_for_tty - See if an options file exists for the serial
492 * device, and if so, interpret options from it.
493 */
494int
495options_for_tty()
496{
497    char *dev, *path, *p;
498    int ret;
499    size_t pl;
500
501    dev = devnam;
502    if (strncmp(dev, "/dev/", 5) == 0)
503        dev += 5;
504    if (dev[0] == 0 || strcmp(dev, "tty") == 0)
505        return 1;               /* don't look for /etc/ppp/options.tty */
506    pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
507    path = malloc(pl);
508    if (path == NULL)
509        novm("tty init file name");
510    slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
511    /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
512    for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
513        if (*p == '/')
514            *p = '.';
515    ret = options_from_file(path, 0, 0, 1);
516    free(path);
517    return ret;
518}
519
520/*
521 * options_from_list - process a string of options in a wordlist.
522 */
523int
524options_from_list(w, priv)
525    struct wordlist *w;
526    int priv;
527{
528    char *argv[MAXARGS];
529    option_t *opt;
530    int i, ret = 0;
531
532    privileged_option = priv;
533    option_source = "secrets file";
534
535    while (w != NULL) {
536        /*
537         * First see if it's a command.
538         */
539        opt = find_option(w->word);
540        if (opt != NULL) {
541            int n = n_arguments(opt);
542            struct wordlist *w0 = w;
543            for (i = 0; i < n; ++i) {
544                w = w->next;
545                if (w == NULL) {
546                    option_error(
547                        "In secrets file: too few parameters for option '%s'",
548                        w0->word);
549                    goto err;
550                }
551                argv[i] = w->word;
552            }
553            current_option = w0->word;
554            if (!process_option(opt, argv))
555                goto err;
556            w = w->next;
557            continue;
558        }
559
560        /*
561         * Maybe a tty name, speed or IP address?
562         */
563        if ((i = setdevname(w->word)) == 0
564            && (i = setspeed(w->word)) == 0
565            && (i = setipaddr(w->word)) == 0) {
566            option_error("In secrets file: unrecognized option '%s'",
567                         w->word);
568            goto err;
569        }
570        if (i < 0)              /* error */
571            goto err;
572        w = w->next;
573    }
574    ret = 1;
575
576err:
577    return ret;
578}
579
580/*
581 * find_option - scan the option lists for the various protocols
582 * looking for an entry with the given name.
583 * This could be optimized by using a hash table.
584 */
585static option_t *
586find_option(name)
587    char *name;
588{
589    option_t *opt;
590    struct option_list *list;
591    int i;
592
593    for (list = extra_options; list != NULL; list = list->next)
594        for (opt = list->options; opt->name != NULL; ++opt)
595            if (strcmp(name, opt->name) == 0)
596                return opt;
597    for (opt = general_options; opt->name != NULL; ++opt)
598        if (strcmp(name, opt->name) == 0)
599            return opt;
600    for (opt = auth_options; opt->name != NULL; ++opt)
601        if (strcmp(name, opt->name) == 0)
602            return opt;
603    for (i = 0; protocols[i] != NULL; ++i)
604        if ((opt = protocols[i]->options) != NULL)
605            for (; opt->name != NULL; ++opt)
606                if (strcmp(name, opt->name) == 0)
607                    return opt;
608    return NULL;
609}
610
611/*
612 * process_option - process one new-style option.
613 */
614static int
615process_option(opt, argv)
616    option_t *opt;
617    char **argv;
618{
619    u_int32_t v;
620    int iv, a;
621    char *sv;
622    int (*parser) __P((char **));
623
624    if ((opt->flags & OPT_PREPASS) == 0 && prepass)
625        return 1;
626    if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
627        option_error("it's too late to use the %s option", opt->name);
628        return 0;
629    }
630    if ((opt->flags & OPT_PRIV) && !privileged_option) {
631        option_error("using the %s option requires root privilege", opt->name);
632        return 0;
633    }
634    if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
635        option_error("%s option is disabled", opt->name);
636        return 0;
637    }
638    if ((opt->flags & OPT_PRIVFIX) && !privileged_option) {
639        struct option_info *ip = (struct option_info *) opt->addr2;
640        if (ip && ip->priv) {
641            option_error("%s option cannot be overridden", opt->name);
642            return 0;
643        }
644    }
645
646    switch (opt->type) {
647    case o_bool:
648        v = opt->flags & OPT_VALUE;
649        *(bool *)(opt->addr) = v;
650        if (opt->addr2 && (opt->flags & OPT_A2COPY))
651            *(bool *)(opt->addr2) = v;
652        break;
653
654    case o_int:
655        iv = 0;
656        if ((opt->flags & OPT_NOARG) == 0) {
657            if (!int_option(*argv, &iv))
658                return 0;
659            if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
660                 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
661                && !((opt->flags & OPT_ZEROOK && iv == 0))) {
662                char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
663                switch (opt->flags & OPT_LIMITS) {
664                case OPT_LLIMIT:
665                    option_error("%s value must be%s >= %d",
666                                 opt->name, zok, opt->lower_limit);
667                    break;
668                case OPT_ULIMIT:
669                    option_error("%s value must be%s <= %d",
670                                 opt->name, zok, opt->upper_limit);
671                    break;
672                case OPT_LIMITS:
673                    option_error("%s value must be%s between %d and %d",
674                                opt->name, opt->lower_limit, opt->upper_limit);
675                    break;
676                }
677                return 0;
678            }
679        }
680        a = opt->flags & OPT_VALUE;
681        if (a >= 128)
682            a -= 256;           /* sign extend */
683        iv += a;
684        if (opt->flags & OPT_INC)
685            iv += *(int *)(opt->addr);
686        if ((opt->flags & OPT_NOINCR) && !privileged_option) {
687            int oldv = *(int *)(opt->addr);
688            if ((opt->flags & OPT_ZEROINF) ?
689                (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
690                option_error("%s value cannot be increased", opt->name);
691                return 0;
692            }
693        }
694        *(int *)(opt->addr) = iv;
695        if (opt->addr2 && (opt->flags & OPT_A2COPY))
696            *(int *)(opt->addr2) = iv;
697        break;
698
699    case o_uint32:
700        if (opt->flags & OPT_NOARG) {
701            v = opt->flags & OPT_VALUE;
702        } else if (!number_option(*argv, &v, 16))
703            return 0;
704        if (opt->flags & OPT_OR)
705            v |= *(u_int32_t *)(opt->addr);
706        *(u_int32_t *)(opt->addr) = v;
707        if (opt->addr2 && (opt->flags & OPT_A2COPY))
708            *(u_int32_t *)(opt->addr2) = v;
709        break;
710
711    case o_string:
712        if (opt->flags & OPT_STATIC) {
713            strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
714        } else {
715            sv = strdup(*argv);
716            if (sv == NULL)
717                novm("option argument");
718            *(char **)(opt->addr) = sv;
719        }
720        break;
721
722    case o_special_noarg:
723    case o_special:
724        parser = (int (*) __P((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 (phase == PHASE_INITIALIZE)
777        fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
778                progname);
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 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  int      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 2400:
1253          spdValue = B2400;
1254          break;
1255        case 4800:
1256          spdValue = B4800;
1257          break;
1258        case 9600:
1259          spdValue = B9600;
1260          break;
1261        case 19200:
1262          spdValue = B19200;
1263          break;
1264        case 38400:
1265          spdValue = B38400;
1266          break;
1267        case 57600:
1268          spdValue = B57600;
1269          break;
1270        case 115200:
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 (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) __P((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.