X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Foptions.c;h=cea09e39f05a4ef28032fffe1394f8818aa96b96;hb=76016e1b948b7d9675b4e0750d1f943d96d9523b;hp=4870128868f63d10ecf1abc5b1562c06ca0f9416;hpb=36e867a96fbc20777c4d3cb15e7aa4f7180f1452;p=ppp.git diff --git a/pppd/options.c b/pppd/options.c index 4870128..cea09e3 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -40,9 +40,12 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: options.c,v 1.94 2004/11/04 09:46:50 paulus Exp $" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include +#include #include #include #include @@ -51,30 +54,36 @@ #include #include #include -#ifdef PLUGIN +#include +#include +#ifdef PPP_WITH_PLUGINS #include #endif -#ifdef PPP_FILTER +#ifdef PPP_WITH_FILTER #include /* - * DLT_PPP_WITH_DIRECTION is in current libpcap cvs, and should be in - * libpcap-0.8.4. Until that is released, use DLT_PPP - but that means + * There have been 3 or 4 different names for this in libpcap CVS, but + * this seems to be what they have settled on... + * For older versions of libpcap, use DLT_PPP - but that means * we lose the inbound and outbound qualifiers. */ -#ifndef DLT_PPP_WITH_DIRECTION -#define DLT_PPP_WITH_DIRECTION DLT_PPP +#ifndef DLT_PPP_PPPD +#ifdef DLT_PPP_WITHDIRECTION +#define DLT_PPP_PPPD DLT_PPP_WITHDIRECTION +#else +#define DLT_PPP_PPPD DLT_PPP #endif #endif +#endif /* PPP_WITH_FILTER */ #include "pppd.h" #include "pathnames.h" #if defined(ultrix) || defined(NeXT) -char *strdup __P((char *)); +char *strdup(char *); #endif -static const char rcsid[] = RCSID; struct option_value { struct option_value *next; @@ -91,6 +100,10 @@ int default_device = 1; /* Using /dev/tty or equivalent */ char devnam[MAXPATHLEN]; /* Device name */ bool nodetach = 0; /* Don't detach from controlling tty */ bool updetach = 0; /* Detach once link is up */ +bool master_detach; /* Detach when we're (only) multilink master */ +#ifdef SYSTEMD +bool up_sdnotify = 0; /* Notify systemd once link is up */ +#endif int maxconnect = 0; /* Maximum connect time */ char user[MAXNAMELEN]; /* Username for PAP */ char passwd[MAXSECRETLEN]; /* Password for PAP */ @@ -108,28 +121,38 @@ char linkname[MAXPATHLEN]; /* logical name for link */ bool tune_kernel; /* may alter kernel settings */ int connect_delay = 1000; /* wait this many ms after connect script */ int req_unit = -1; /* requested interface unit */ +char path_ipup[MAXPATHLEN]; /* pathname of ip-up script */ +char path_ipdown[MAXPATHLEN];/* pathname of ip-down script */ +char req_ifname[IFNAMSIZ]; /* requested interface name */ bool multilink = 0; /* Enable multilink operation */ char *bundle_name = NULL; /* bundle name for multilink */ bool dump_options; /* print out option values */ +bool show_options; /* print all supported options and exit */ bool dryrun; /* print out option values and exit */ char *domain; /* domain name set by domain option */ int child_wait = 5; /* # seconds to wait for children at exit */ +struct userenv *userenv_list; /* user environment variables */ +int dfl_route_metric = -1; /* metric of the default route to set over the PPP link */ + +#ifdef PPP_WITH_IPV6CP +char path_ipv6up[MAXPATHLEN]; /* pathname of ipv6-up script */ +char path_ipv6down[MAXPATHLEN]; /* pathname of ipv6-down script */ +#endif -#ifdef MAXOCTETS unsigned int maxoctets = 0; /* default - no limit */ int maxoctets_dir = 0; /* default - sum of traffic */ int maxoctets_timeout = 1; /* default 1 second */ -#endif extern option_t auth_options[]; extern struct stat devstat; -#ifdef PPP_FILTER +#ifdef PPP_WITH_FILTER struct bpf_program pass_filter;/* Filter program for packets to pass */ struct bpf_program active_filter; /* Filter program for link-active pkts */ #endif +static option_t *curopt; /* pointer to option being processed */ char *current_option; /* the name of the option being parsed */ int privileged_option; /* set iff the current option came from root */ char *option_source; /* string saying where the option came from */ @@ -139,33 +162,38 @@ bool devnam_fixed; /* can no longer change device name */ static int logfile_fd = -1; /* fd opened for log file */ static char logfile_name[MAXPATHLEN]; /* name of log file */ +static bool noipx_opt; /* dummy for noipx option */ + /* * Prototypes */ -static int setdomain __P((char **)); -static int readfile __P((char **)); -static int callfile __P((char **)); -static int showversion __P((char **)); -static int showhelp __P((char **)); -static void usage __P((void)); -static int setlogfile __P((char **)); -#ifdef PLUGIN -static int loadplugin __P((char **)); +static int setdomain(char **); +static int readfile(char **); +static int callfile(char **); +static int showversion(char **); +static int showhelp(char **); +static void usage(void); +static int setlogfile(char **); +#ifdef PPP_WITH_PLUGINS +static int loadplugin(char **); #endif -#ifdef PPP_FILTER -static int setpassfilter __P((char **)); -static int setactivefilter __P((char **)); +#ifdef PPP_WITH_FILTER +static int setpassfilter(char **); +static int setactivefilter(char **); #endif -#ifdef MAXOCTETS -static int setmodir __P((char **)); -#endif +static int setmodir(char **); + +static int user_setenv(char **); +static void user_setprint(option_t *, printer_func, void *); +static int user_unsetenv(char **); +static void user_unsetprint(option_t *, printer_func, void *); -static option_t *find_option __P((const char *name)); -static int process_option __P((option_t *, char *, char **)); -static int n_arguments __P((option_t *)); -static int number_option __P((char *, u_int32_t *, int)); +static option_t *find_option(char *name); +static int process_option(option_t *, char *, char **); +static int n_arguments(option_t *); +static int number_option(char *, u_int32_t *, int); /* * Structure to store extra lists of options. @@ -194,12 +222,21 @@ option_t general_options[] = { "Don't detach from controlling tty", OPT_PRIO | 1 }, { "-detach", o_bool, &nodetach, "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 }, +#ifdef SYSTEMD + { "up_sdnotify", o_bool, &up_sdnotify, + "Notify systemd once link is up (implies nodetach)", + OPT_PRIOSUB | OPT_A2COPY | 1, &nodetach }, +#endif { "updetach", o_bool, &updetach, "Detach from controlling tty once link is up", OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach }, + { "master_detach", o_bool, &master_detach, + "Detach when we're multilink master but have no link", 1 }, + { "holdoff", o_int, &holdoff, - "Set time in seconds before retrying connection", OPT_PRIO }, + "Set time in seconds before retrying connection", + OPT_PRIO, &holdoff_specified }, { "idle", o_int, &idle_time_limit, "Set time in seconds before disconnecting idle link", OPT_PRIO }, @@ -227,6 +264,10 @@ option_t general_options[] = { { "--version", o_special_noarg, (void *)showversion, "Show version number" }, + { "-v", o_special_noarg, (void *)showversion, + "Show version number" }, + { "show-options", o_bool, &show_options, + "Show all options and exit", 1 }, { "--help", o_special_noarg, (void *)showhelp, "Show brief listing of options" }, { "-h", o_special_noarg, (void *)showhelp, @@ -266,15 +307,47 @@ option_t general_options[] = { "PPP interface unit number to use if possible", OPT_PRIO | OPT_LLIMIT, 0, 0 }, + { "ifname", o_string, req_ifname, + "Set PPP interface name", + OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, IFNAMSIZ }, + { "dump", o_bool, &dump_options, "Print out option values after parsing all options", 1 }, { "dryrun", o_bool, &dryrun, "Stop after parsing, printing, and checking options", 1 }, { "child-timeout", o_int, &child_wait, - "Number of seconds to wait for child processes at exit" }, + "Number of seconds to wait for child processes at exit", + OPT_PRIO }, + + { "set", o_special, (void *)user_setenv, + "Set user environment variable", + OPT_A2PRINTER | OPT_NOPRINT, (void *)user_setprint }, + { "unset", o_special, (void *)user_unsetenv, + "Unset user environment variable", + OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint }, + + { "defaultroute-metric", o_int, &dfl_route_metric, + "Metric to use for the default route (Linux only; -1 for default behavior)", + OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 }, + + { "ip-up-script", o_string, path_ipup, + "Set pathname of ip-up script", + OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, + { "ip-down-script", o_string, path_ipdown, + "Set pathname of ip-down script", + OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, + +#ifdef PPP_WITH_IPV6CP + { "ipv6-up-script", o_string, path_ipv6up, + "Set pathname of ipv6-up script", + OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, + { "ipv6-down-script", o_string, path_ipv6down, + "Set pathname of ipv6-down script", + OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, +#endif -#ifdef HAVE_MULTILINK +#ifdef PPP_WITH_MULTILINK { "multilink", o_bool, &multilink, "Enable multilink operation", OPT_PRIO | 1 }, { "mp", o_bool, &multilink, @@ -286,22 +359,21 @@ option_t general_options[] = { { "bundle", o_string, &bundle_name, "Bundle name for multilink", OPT_PRIO }, -#endif /* HAVE_MULTILINK */ +#endif /* PPP_WITH_MULTILINK */ -#ifdef PLUGIN +#ifdef PPP_WITH_PLUGINS { "plugin", o_special, (void *)loadplugin, "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST }, #endif -#ifdef PPP_FILTER - { "pass-filter", 1, setpassfilter, +#ifdef PPP_WITH_FILTER + { "pass-filter", o_special, setpassfilter, "set filter for packets to pass", OPT_PRIO }, - { "active-filter", 1, setactivefilter, + { "active-filter", o_special, setactivefilter, "set filter for active pkts", OPT_PRIO }, #endif -#ifdef MAXOCTETS { "maxoctets", o_int, &maxoctets, "Set connection traffic limit", OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF }, @@ -312,7 +384,9 @@ option_t general_options[] = { "Set direction for limit traffic (sum,in,out,max)" }, { "mo-timeout", o_int, &maxoctets_timeout, "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 }, -#endif + + /* Dummy option, does nothing */ + { "noipx", o_bool, &noipx_opt, NULL, OPT_NOPRINT | 1 }, { NULL } }; @@ -321,31 +395,12 @@ option_t general_options[] = { #define IMPLEMENTATION "" #endif -static char *usage_string = "\ -pppd version %s\n\ -Usage: %s [ options ], where options are:\n\ - Communicate over the named device\n\ - Set the baud rate to \n\ - : Set the local and/or remote interface IP\n\ - addresses. Either one may be omitted.\n\ - asyncmap Set the desired async map to hex \n\ - auth Require authentication from peer\n\ - connect

Invoke shell command

to set up the serial line\n\ - crtscts Use hardware RTS/CTS flow control\n\ - defaultroute Add default route through interface\n\ - file Take options from file \n\ - modem Use modem control lines\n\ - mru Set MRU value to for negotiation\n\ -See pppd(8) for more options.\n\ -"; /* * parse_args - parse a string of arguments from the command line. */ int -parse_args(argc, argv) - int argc; - char **argv; +parse_args(int argc, char **argv) { char *arg; option_t *opt; @@ -381,27 +436,27 @@ parse_args(argc, argv) * and interpret them. */ int -options_from_file(filename, must_exist, check_prot, priv) - char *filename; - int must_exist; - int check_prot; - int priv; +options_from_file(char *filename, int must_exist, int check_prot, int priv) { FILE *f; int i, newline, ret, err; option_t *opt; int oldpriv, n; char *oldsource; + uid_t euid; char *argv[MAXARGS]; char args[MAXARGS][MAXWORDLEN]; char cmd[MAXWORDLEN]; - if (check_prot) - seteuid(getuid()); + euid = geteuid(); + if (check_prot && seteuid(getuid()) == -1) { + option_error("unable to drop privileges to open %s: %m", filename); + return 0; + } f = fopen(filename, "r"); err = errno; - if (check_prot) - seteuid(0); + if (check_prot && seteuid(euid) == -1) + fatal("unable to regain privileges"); if (f == NULL) { errno = err; if (!must_exist) { @@ -454,7 +509,7 @@ err: * and if so, interpret options from it. */ int -options_from_user() +options_from_user(void) { char *user, *path, *file; int ret; @@ -464,7 +519,7 @@ options_from_user() pw = getpwuid(getuid()); if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) return 1; - file = _PATH_USEROPT; + file = PPP_PATH_USEROPT; pl = strlen(user) + strlen(file) + 2; path = malloc(pl); if (path == NULL) @@ -485,7 +540,7 @@ options_from_user() * files a lower priority than the command line. */ int -options_for_tty() +options_for_tty(void) { char *dev, *path, *p; int ret; @@ -496,13 +551,13 @@ options_for_tty() dev = p + 5; if (dev[0] == 0 || strcmp(dev, "tty") == 0) return 1; /* don't look for /etc/ppp/options.tty */ - pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1; + pl = strlen(PPP_PATH_TTYOPT) + strlen(dev) + 1; path = malloc(pl); if (path == NULL) novm("tty init file name"); - slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev); + slprintf(path, pl, "%s%s", PPP_PATH_TTYOPT, dev); /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */ - for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p) + for (p = path + strlen(PPP_PATH_TTYOPT); *p != 0; ++p) if (*p == '/') *p = '.'; option_priority = OPRIO_CFGFILE; @@ -515,9 +570,7 @@ options_for_tty() * options_from_list - process a string of options in a wordlist. */ int -options_from_list(w, priv) - struct wordlist *w; - int priv; +options_from_list(struct wordlist *w, int priv) { char *argv[MAXARGS]; option_t *opt; @@ -561,18 +614,15 @@ err: * match_option - see if this option matches an option_t structure. */ static int -match_option(name, opt, dowild) - char *name; - option_t *opt; - int dowild; +match_option(char *name, option_t *opt, int dowild) { - int (*match) __P((char *, char **, int)); + int (*match)(char *, char **, int); if (dowild != (opt->type == o_wild)) return 0; if (!dowild) return strcmp(name, opt->name) == 0; - match = (int (*) __P((char *, char **, int))) opt->addr; + match = (int (*)(char *, char **, int)) opt->addr; return (*match)(name, NULL, 0); } @@ -582,8 +632,7 @@ match_option(name, opt, dowild) * This could be optimized by using a hash table. */ static option_t * -find_option(name) - const char *name; +find_option(char *name) { option_t *opt; struct option_list *list; @@ -616,16 +665,13 @@ find_option(name) * process_option - process one new-style option. */ static int -process_option(opt, cmd, argv) - option_t *opt; - char *cmd; - char **argv; +process_option(option_t *opt, char *cmd, char **argv) { u_int32_t v; int iv, a; char *sv; - int (*parser) __P((char **)); - int (*wildp) __P((char *, char **, int)); + int (*parser)(char **); + int (*wildp)(char *, char **, int); char *optopt = (opt->type == o_wild)? "": " option"; int prio = option_priority; option_t *mainopt = opt; @@ -747,41 +793,57 @@ process_option(opt, cmd, argv) if (opt->flags & OPT_STATIC) { strlcpy((char *)(opt->addr), *argv, opt->upper_limit); } else { + char **optptr = (char **)(opt->addr); sv = strdup(*argv); if (sv == NULL) novm("option argument"); - *(char **)(opt->addr) = sv; + if (*optptr) + free(*optptr); + *optptr = sv; + } + /* obfuscate original argument for things like password */ + if (opt->flags & OPT_HIDE) { + memset(*argv, '?', strlen(*argv)); + *argv = "********"; } break; case o_special_noarg: case o_special: - parser = (int (*) __P((char **))) opt->addr; + parser = (int (*)(char **)) opt->addr; + curopt = opt; if (!(*parser)(argv)) return 0; if (opt->flags & OPT_A2LIST) { - struct option_value *ovp, **pp; + struct option_value *ovp, *pp; ovp = malloc(sizeof(*ovp) + strlen(*argv)); if (ovp != 0) { strcpy(ovp->value, *argv); ovp->source = option_source; ovp->next = NULL; - pp = (struct option_value **) &opt->addr2; - while (*pp != 0) - pp = &(*pp)->next; - *pp = ovp; + if (opt->addr2 == NULL) { + opt->addr2 = ovp; + } else { + for (pp = opt->addr2; pp->next != NULL; pp = pp->next) + ; + pp->next = ovp; + } } } break; case o_wild: - wildp = (int (*) __P((char *, char **, int))) opt->addr; + wildp = (int (*)(char *, char **, int)) opt->addr; if (!(*wildp)(cmd, argv, 1)) return 0; break; } + /* + * If addr2 wasn't used by any flag (OPT_A2COPY, etc.) but is set, + * treat it as a bool and set/clear it based on the OPT_A2CLR bit. + */ if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE |OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST|OPT_A2OR)) == 0) *(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR); @@ -799,10 +861,7 @@ process_option(opt, cmd, argv) * and source of the option value. Otherwise returns 0. */ int -override_value(option, priority, source) - const char *option; - int priority; - const char *source; +override_value(char *option, int priority, const char *source) { option_t *opt; @@ -823,8 +882,7 @@ override_value(option, priority, source) * n_arguments - tell how many arguments an option takes */ static int -n_arguments(opt) - option_t *opt; +n_arguments(option_t *opt) { return (opt->type == o_bool || opt->type == o_special_noarg || (opt->flags & OPT_NOARG))? 0: 1; @@ -834,8 +892,7 @@ n_arguments(opt) * add_options - add a list of options to the set we grok. */ void -add_options(opt) - option_t *opt; +add_options(option_t *opt) { struct option_list *list; @@ -851,7 +908,7 @@ add_options(opt) * check_options - check that options are valid and consistent. */ void -check_options() +check_options(void) { if (logfile_fd >= 0 && logfile_fd != log_to_fd) close(logfile_fd); @@ -861,10 +918,7 @@ check_options() * print_option - print out an option and its value */ static void -print_option(opt, mainopt, printer, arg) - option_t *opt, *mainopt; - void (*printer) __P((void *, char *, ...)); - void *arg; +print_option(option_t *opt, option_t *mainopt, printer_func printer, void *arg) { int i, v; char *p; @@ -926,18 +980,15 @@ print_option(opt, mainopt, printer, arg) printer(arg, " "); } if (opt->flags & OPT_A2PRINTER) { - void (*oprt) __P((option_t *, - void ((*)__P((void *, char *, ...))), - void *)); - oprt = (void (*) __P((option_t *, - void ((*)__P((void *, char *, ...))), - void *)))opt->addr2; + void (*oprt)(option_t *, printer_func, void *); + oprt = (void (*)(option_t *, printer_func, void *)) + opt->addr2; (*oprt)(opt, printer, arg); } else if (opt->flags & OPT_A2STRVAL) { p = (char *) opt->addr2; if ((opt->flags & OPT_STATIC) == 0) p = *(char **)p; - printer("%q", p); + printer(arg, "%q", p); } else if (opt->flags & OPT_A2LIST) { struct option_value *ovp; @@ -966,10 +1017,7 @@ print_option(opt, mainopt, printer, arg) * array of options. */ static void -print_option_list(opt, printer, arg) - option_t *opt; - void (*printer) __P((void *, char *, ...)); - void *arg; +print_option_list(option_t *opt, printer_func printer, void *arg) { while (opt->name != NULL) { if (opt->priority != OPRIO_DEFAULT @@ -985,9 +1033,7 @@ print_option_list(opt, printer, arg) * print_options - print out what options are in effect. */ void -print_options(printer, arg) - void (*printer) __P((void *, char *, ...)); - void *arg; +print_options(printer_func printer, void *arg) { struct option_list *list; int i; @@ -1006,18 +1052,42 @@ print_options(printer, arg) * usage - print out a message telling how to use the program. */ static void -usage() +usage(void) { - if (phase == PHASE_INITIALIZE) - fprintf(stderr, usage_string, VERSION, progname); + FILE *fp = stderr; + if (phase == PHASE_INITIALIZE) { + fprintf(fp, "%s v%s\n", PACKAGE_NAME, PACKAGE_VERSION); + fprintf(fp, "Copyright (C) 1999-2022 Paul Mackerras, and others. All rights reserved.\n\n"); + + + fprintf(fp, "License BSD: The 3 clause BSD license \n"); + fprintf(fp, "This is free software: you are free to change and redistribute it.\n"); + fprintf(fp, "There is NO WARRANTY, to the extent permitted by law.\n\n"); + + fprintf(fp, "Report Bugs:\n %s\n\n", PACKAGE_BUGREPORT); + fprintf(fp, "Usage: %s [ options ], where options are:\n", progname); + fprintf(fp, " Communicate over the named device\n"); + fprintf(fp, " Set the baud rate to \n"); + fprintf(fp, " : Set the local and/or remote interface IP\n"); + fprintf(fp, " addresses. Either one may be omitted.\n"); + fprintf(fp, " asyncmap Set the desired async map to hex \n"); + fprintf(fp, " auth Require authentication from peer\n"); + fprintf(fp, " connect

Invoke shell command

to set up the serial line\n"); + fprintf(fp, " crtscts Use hardware RTS/CTS flow control\n"); + fprintf(fp, " defaultroute Add default route through interface\n"); + fprintf(fp, " file Take options from file \n"); + fprintf(fp, " modem Use modem control lines\n"); + fprintf(fp, " mru Set MRU value to for negotiation\n"); + fprintf(fp, " show-options Display an extended list of options\n"); + fprintf(fp, "See pppd(8) for more options.\n"); + } } /* * showhelp - print out usage message and exit. */ static int -showhelp(argv) - char **argv; +showhelp(char **argv) { if (phase == PHASE_INITIALIZE) { usage(); @@ -1030,34 +1100,82 @@ showhelp(argv) * showversion - print out the version number and exit. */ static int -showversion(argv) - char **argv; +showversion(char **argv) { if (phase == PHASE_INITIALIZE) { - fprintf(stderr, "pppd version %s\n", VERSION); + fprintf(stdout, "pppd version %s\n", VERSION); exit(0); } return 0; } +/* + * Print a set of options including the name of the group of options + */ +static void +showopts_list(FILE *fp, const char *title, option_t *list, ...) +{ + option_t *opt = list; + va_list varg; + + if (opt && opt->name) { + va_start(varg, list); + vfprintf(fp, title, varg); + fprintf(fp, ":\n"); + va_end(varg); + + do { + fprintf(fp, " %-22s %s\n", opt->name, opt->description?:""); + opt++; + } while (opt && opt->name); + + fprintf(fp, "\n"); + } +} + +/* + * Dumps the list of available options + */ +void +showopts(void) +{ + struct option_list *list; + FILE *fp = stderr; + int i = 0; + + showopts_list(fp, "General Options", + general_options); + + showopts_list(fp, "Authentication Options", + auth_options); + + for (list = extra_options; list != NULL; list = list->next) + showopts_list(fp, "Extra Options", list->options); + + showopts_list(fp, "Channel Options", + the_channel->options); + + for (i = 0; protocols[i] != NULL; ++i) { + if (protocols[i]->options != NULL) { + showopts_list(fp, "%s Options", + protocols[i]->options, + protocols[i]->name); + } + } +} + /* * option_error - print a message about an error in an option. * The message is logged, and also sent to * stderr if phase == PHASE_INITIALIZE. */ void -option_error __V((char *fmt, ...)) +option_error(char *fmt, ...) { va_list args; char buf[1024]; -#if defined(__STDC__) va_start(args, fmt); -#else - char *fmt; - va_start(args); - fmt = va_arg(args, char *); -#endif vslprintf(buf, sizeof(buf), fmt, args); va_end(args); if (phase == PHASE_INITIALIZE) @@ -1070,8 +1188,7 @@ option_error __V((char *fmt, ...)) * readable - check if a file is readable by the real user. */ int -readable(fd) - int fd; +readable(int fd) { uid_t uid; int i; @@ -1100,11 +1217,7 @@ readable(fd) * \ is ignored. */ int -getword(f, word, newlinep, filename) - FILE *f; - char *word; - int *newlinep; - char *filename; +getword(FILE *f, char *word, int *newlinep, char *filename) { int c, len, escape; int quoted, comment; @@ -1116,6 +1229,7 @@ getword(f, word, newlinep, filename) len = 0; escape = 0; comment = 0; + quoted = 0; /* * First skip white-space and comments. @@ -1173,15 +1287,6 @@ getword(f, word, newlinep, filename) break; } - /* - * Save the delimiter for quoted strings. - */ - if (!escape && (c == '"' || c == '\'')) { - quoted = c; - c = getc(f); - } else - quoted = 0; - /* * Process characters until the end of the word. */ @@ -1263,47 +1368,55 @@ getword(f, word, newlinep, filename) /* * Store the resulting character for the escape sequence. */ - if (len < MAXWORDLEN-1) + if (len < MAXWORDLEN) { word[len] = value; - ++len; + ++len; + } if (!got) c = getc(f); continue; - } /* - * Not escaped: see if we've reached the end of the word. + * Backslash starts a new escape sequence. */ - if (quoted) { - if (c == quoted) - break; - } else { - if (isspace(c) || c == '#') { - ungetc (c, f); - break; - } + if (c == '\\') { + escape = 1; + c = getc(f); + continue; } /* - * Backslash starts an escape sequence. + * Not escaped: check for the start or end of a quoted + * section and see if we've reached the end of the word. */ - if (c == '\\') { - escape = 1; + if (quoted) { + if (c == quoted) { + quoted = 0; + c = getc(f); + continue; + } + } else if (c == '"' || c == '\'') { + quoted = c; c = getc(f); continue; + } else if (isspace(c) || c == '#') { + ungetc (c, f); + break; } /* * An ordinary character: store it in the word and get another. */ - if (len < MAXWORDLEN-1) + if (len < MAXWORDLEN) { word[len] = c; - ++len; + ++len; + } c = getc(f); } + word[MAXWORDLEN-1] = 0; /* make sure word is null-terminated */ /* * End of the word: check for errors. @@ -1321,6 +1434,9 @@ getword(f, word, newlinep, filename) */ if (len == 0) return 0; + if (quoted) + option_error("warning: quoted word runs to end of file (%.20s...)", + filename, word); } /* @@ -1343,10 +1459,7 @@ getword(f, word, newlinep, filename) * number_option - parse an unsigned numeric parameter for an option. */ static int -number_option(str, valp, base) - char *str; - u_int32_t *valp; - int base; +number_option(char *str, u_int32_t *valp, int base) { char *ptr; @@ -1366,9 +1479,7 @@ number_option(str, valp, base) * if there is an error. */ int -int_option(str, valp) - char *str; - int *valp; +int_option(char *str, int *valp) { u_int32_t v; @@ -1387,8 +1498,7 @@ int_option(str, valp) * readfile - take commands from a file. */ static int -readfile(argv) - char **argv; +readfile(char **argv) { return options_from_file(*argv, 1, 1, privileged_option); } @@ -1398,8 +1508,7 @@ readfile(argv) * Name may not contain /../, start with / or ../, or end in /.. */ static int -callfile(argv) - char **argv; +callfile(char **argv) { char *fname, *arg, *p; int l, ok; @@ -1425,10 +1534,11 @@ callfile(argv) return 0; } - l = strlen(arg) + strlen(_PATH_PEERFILES) + 1; + l = strlen(arg) + strlen(PPP_PATH_PEERFILES) + 1; if ((fname = (char *) malloc(l)) == NULL) novm("call file name"); - slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg); + slprintf(fname, l, "%s%s", PPP_PATH_PEERFILES, arg); + script_setenv("CALL_FILE", arg, 0); ok = options_from_file(fname, 1, 1, 1); @@ -1436,22 +1546,21 @@ callfile(argv) return ok; } -#ifdef PPP_FILTER +#ifdef PPP_WITH_FILTER /* * setpassfilter - Set the pass filter for packets */ static int -setpassfilter(argv) - char **argv; +setpassfilter(char **argv) { pcap_t *pc; - int ret = 0; + int ret = 1; - pc = pcap_open_dead(DLT_PPP_WITH_DIRECTION, 65535); + pc = pcap_open_dead(DLT_PPP_PPPD, 65535); if (pcap_compile(pc, &pass_filter, *argv, 1, netmask) == -1) { option_error("error in pass-filter expression: %s\n", pcap_geterr(pc)); - ret = 1; + ret = 0; } pcap_close(pc); @@ -1462,17 +1571,16 @@ setpassfilter(argv) * setactivefilter - Set the active filter for packets */ static int -setactivefilter(argv) - char **argv; +setactivefilter(char **argv) { pcap_t *pc; - int ret = 0; + int ret = 1; - pc = pcap_open_dead(DLT_PPP_WITH_DIRECTION, 65535); + pc = pcap_open_dead(DLT_PPP_PPPD, 65535); if (pcap_compile(pc, &active_filter, *argv, 1, netmask) == -1) { option_error("error in active-filter expression: %s\n", pcap_geterr(pc)); - ret = 1; + ret = 0; } pcap_close(pc); @@ -1484,8 +1592,7 @@ setactivefilter(argv) * setdomain - Set domain name to append to hostname */ static int -setdomain(argv) - char **argv; +setdomain(char **argv) { gethostname(hostname, MAXNAMELEN); if (**argv != 0) { @@ -1499,19 +1606,22 @@ setdomain(argv) } static int -setlogfile(argv) - char **argv; +setlogfile(char **argv) { int fd, err; + uid_t euid; - if (!privileged_option) - seteuid(getuid()); + euid = geteuid(); + if (!privileged_option && seteuid(getuid()) == -1) { + option_error("unable to drop permissions to open %s: %m", *argv); + return 0; + } fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644); if (fd < 0 && errno == EEXIST) fd = open(*argv, O_WRONLY | O_APPEND); err = errno; - if (!privileged_option) - seteuid(0); + if (!privileged_option && seteuid(euid) == -1) + fatal("unable to regain privileges: %m"); if (fd < 0) { errno = err; option_error("Can't open log file %s: %m", *argv); @@ -1526,10 +1636,8 @@ setlogfile(argv) return 1; } -#ifdef MAXOCTETS static int -setmodir(argv) - char **argv; +setmodir(char **argv) { if(*argv == NULL) return 0; @@ -1544,22 +1652,20 @@ setmodir(argv) } return 1; } -#endif -#ifdef PLUGIN +#ifdef PPP_WITH_PLUGINS static int -loadplugin(argv) - char **argv; +loadplugin(char **argv) { char *arg = *argv; void *handle; const char *err; - void (*init) __P((void)); + void (*init)(void); char *path = arg; const char *vers; if (strchr(arg, '/') == 0) { - const char *base = _PATH_PLUGIN; + const char *base = PPP_PATH_PLUGIN; int l = strlen(base) + strlen(arg) + 2; path = malloc(l); if (path == 0) @@ -1600,4 +1706,147 @@ loadplugin(argv) free(path); return 0; } -#endif /* PLUGIN */ +#endif /* PPP_WITH_PLUGINS */ + +/* + * Set an environment variable specified by the user. + */ +static int +user_setenv(char **argv) +{ + char *arg = argv[0]; + char *eqp; + struct userenv *uep, **insp; + + if ((eqp = strchr(arg, '=')) == NULL) { + option_error("missing = in name=value: %s", arg); + return 0; + } + if (eqp == arg) { + option_error("missing variable name: %s", arg); + return 0; + } + for (uep = userenv_list; uep != NULL; uep = uep->ue_next) { + int nlen = strlen(uep->ue_name); + if (nlen == (eqp - arg) && + strncmp(arg, uep->ue_name, nlen) == 0) + break; + } + /* Ignore attempts by unprivileged users to override privileged sources */ + if (uep != NULL && !privileged_option && uep->ue_priv) + return 1; + /* The name never changes, so allocate it with the structure */ + if (uep == NULL) { + uep = malloc(sizeof (*uep) + (eqp-arg)); + strncpy(uep->ue_name, arg, eqp-arg); + uep->ue_name[eqp-arg] = '\0'; + uep->ue_next = NULL; + insp = &userenv_list; + while (*insp != NULL) + insp = &(*insp)->ue_next; + *insp = uep; + } else { + struct userenv *uep2; + for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) { + if (uep2 != uep && !uep2->ue_isset) + break; + } + if (uep2 == NULL && !uep->ue_isset) + find_option("unset")->flags |= OPT_NOPRINT; + free(uep->ue_value); + } + uep->ue_isset = 1; + uep->ue_priv = privileged_option; + uep->ue_source = option_source; + uep->ue_value = strdup(eqp + 1); + curopt->flags &= ~OPT_NOPRINT; + return 1; +} + +static void +user_setprint(option_t *opt, printer_func printer, void *arg) +{ + struct userenv *uep, *uepnext; + + uepnext = userenv_list; + while (uepnext != NULL && !uepnext->ue_isset) + uepnext = uepnext->ue_next; + while ((uep = uepnext) != NULL) { + uepnext = uep->ue_next; + while (uepnext != NULL && !uepnext->ue_isset) + uepnext = uepnext->ue_next; + (*printer)(arg, "%s=%s", uep->ue_name, uep->ue_value); + if (uepnext != NULL) + (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name); + else + opt->source = uep->ue_source; + } +} + +static int +user_unsetenv(char **argv) +{ + struct userenv *uep, **insp; + char *arg = argv[0]; + + if (strchr(arg, '=') != NULL) { + option_error("unexpected = in name: %s", arg); + return 0; + } + if (*arg == '\0') { + option_error("missing variable name for unset"); + return 0; + } + for (uep = userenv_list; uep != NULL; uep = uep->ue_next) { + if (strcmp(arg, uep->ue_name) == 0) + break; + } + /* Ignore attempts by unprivileged users to override privileged sources */ + if (uep != NULL && !privileged_option && uep->ue_priv) + return 1; + /* The name never changes, so allocate it with the structure */ + if (uep == NULL) { + uep = malloc(sizeof (*uep) + strlen(arg)); + strcpy(uep->ue_name, arg); + uep->ue_next = NULL; + insp = &userenv_list; + while (*insp != NULL) + insp = &(*insp)->ue_next; + *insp = uep; + } else { + struct userenv *uep2; + for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) { + if (uep2 != uep && uep2->ue_isset) + break; + } + if (uep2 == NULL && uep->ue_isset) + find_option("set")->flags |= OPT_NOPRINT; + free(uep->ue_value); + } + uep->ue_isset = 0; + uep->ue_priv = privileged_option; + uep->ue_source = option_source; + uep->ue_value = NULL; + curopt->flags &= ~OPT_NOPRINT; + return 1; +} + +static void +user_unsetprint(option_t *opt, printer_func printer, void *arg) +{ + struct userenv *uep, *uepnext; + + uepnext = userenv_list; + while (uepnext != NULL && uepnext->ue_isset) + uepnext = uepnext->ue_next; + while ((uep = uepnext) != NULL) { + uepnext = uep->ue_next; + while (uepnext != NULL && uepnext->ue_isset) + uepnext = uepnext->ue_next; + (*printer)(arg, "%s", uep->ue_name); + if (uepnext != NULL) + (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name); + else + opt->source = uep->ue_source; + } +}