Home | History | Annotate | Line # | Download | only in pppd
      1 /*	$NetBSD: options.c,v 1.7 2025/01/08 19:59:39 christos Exp $	*/
      2 
      3 /*
      4  * options.c - handles option processing for PPP.
      5  *
      6  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in
     17  *    the documentation and/or other materials provided with the
     18  *    distribution.
     19  *
     20  * 3. The name "Carnegie Mellon University" must not be used to
     21  *    endorse or promote products derived from this software without
     22  *    prior written permission. For permission or any legal
     23  *    details, please contact
     24  *      Office of Technology Transfer
     25  *      Carnegie Mellon University
     26  *      5000 Forbes Avenue
     27  *      Pittsburgh, PA  15213-3890
     28  *      (412) 268-4387, fax: (412) 268-7395
     29  *      tech-transfer (at) andrew.cmu.edu
     30  *
     31  * 4. Redistributions of any form whatsoever must retain the following
     32  *    acknowledgment:
     33  *    "This product includes software developed by Computing Services
     34  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     35  *
     36  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     37  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     38  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     39  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     40  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     41  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     42  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     43  */
     44 
     45 #include <sys/cdefs.h>
     46 __RCSID("$NetBSD: options.c,v 1.7 2025/01/08 19:59:39 christos Exp $");
     47 
     48 #ifdef HAVE_CONFIG_H
     49 #include "config.h"
     50 #endif
     51 
     52 #include <ctype.h>
     53 #include <stdarg.h>
     54 #include <stdio.h>
     55 #include <errno.h>
     56 #include <unistd.h>
     57 #include <fcntl.h>
     58 #include <stdlib.h>
     59 #include <syslog.h>
     60 #include <string.h>
     61 #include <pwd.h>
     62 #include <sys/param.h>
     63 #include <net/if.h>
     64 #ifdef PPP_WITH_PLUGINS
     65 #include <dlfcn.h>
     66 #endif
     67 
     68 #ifdef PPP_WITH_FILTER
     69 #include <pcap.h>
     70 /*
     71  * There have been 3 or 4 different names for this in libpcap CVS, but
     72  * this seems to be what they have settled on...
     73  * For older versions of libpcap, use DLT_PPP - but that means
     74  * we lose the inbound and outbound qualifiers.
     75  */
     76 #ifndef DLT_PPP_PPPD
     77 #ifdef DLT_PPP_WITHDIRECTION
     78 #define DLT_PPP_PPPD	DLT_PPP_WITHDIRECTION
     79 #else
     80 #define DLT_PPP_PPPD	DLT_PPP
     81 #endif
     82 #endif
     83 #endif /* PPP_WITH_FILTER */
     84 
     85 #include "pppd-private.h"
     86 #include "options.h"
     87 #include "upap.h"
     88 #include "pathnames.h"
     89 
     90 #if defined(ultrix) || defined(NeXT)
     91 char *strdup(char *);
     92 #endif
     93 
     94 
     95 struct option_value {
     96     struct option_value *next;
     97     const char *source;
     98     char value[1];
     99 };
    100 
    101 /*
    102  * Option variables and default values.
    103  */
    104 int	debug = 0;		/* Debug flag */
    105 int	kdebugflag = 0;		/* Tell kernel to print debug messages */
    106 int	default_device = 1;	/* Using /dev/tty or equivalent */
    107 bool	nodetach = 0;		/* Don't detach from controlling tty */
    108 bool	updetach = 0;		/* Detach once link is up */
    109 bool	master_detach;		/* Detach when we're (only) multilink master */
    110 #ifdef SYSTEMD
    111 bool	up_sdnotify = 0;	/* Notify systemd once link is up */
    112 #endif
    113 int	maxconnect = 0;		/* Maximum connect time */
    114 char	user[MAXNAMELEN];	/* Username for PAP */
    115 char	passwd[MAXSECRETLEN];	/* Password for PAP */
    116 bool	persist = 0;		/* Reopen link after it goes down */
    117 char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
    118 bool	demand = 0;		/* do dial-on-demand */
    119 int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
    120 int	holdoff = 30;		/* # seconds to pause before reconnecting */
    121 bool	holdoff_specified;	/* true if a holdoff value has been given */
    122 int	log_to_fd = 1;		/* send log messages to this fd too */
    123 bool	log_default = 1;	/* log_to_fd is default (stdout) */
    124 int	maxfail = 10;		/* max # of unsuccessful connection attempts */
    125 char	linkname[MAXPATHLEN];	/* logical name for link */
    126 bool	tune_kernel;		/* may alter kernel settings */
    127 int	connect_delay = 1000;	/* wait this many ms after connect script */
    128 int	req_unit = -1;		/* requested interface unit */
    129 char	path_net_init[MAXPATHLEN]; /* pathname of net-init script */
    130 char	path_net_preup[MAXPATHLEN];/* pathname of net-pre-up script */
    131 char	path_net_down[MAXPATHLEN]; /* pathname of net-down script */
    132 char	path_ipup[MAXPATHLEN];	/* pathname of ip-up script */
    133 char	path_ipdown[MAXPATHLEN];/* pathname of ip-down script */
    134 char	path_ippreup[MAXPATHLEN]; /* pathname of ip-pre-up script */
    135 char	req_ifname[IFNAMSIZ];	/* requested interface name */
    136 bool	multilink = 0;		/* Enable multilink operation */
    137 char	*bundle_name = NULL;	/* bundle name for multilink */
    138 bool	dump_options;		/* print out option values */
    139 bool	show_options;		/* print all supported options and exit */
    140 bool	dryrun;			/* print out option values and exit */
    141 char	*domain;		/* domain name set by domain option */
    142 int	child_wait = 5;		/* # seconds to wait for children at exit */
    143 struct userenv *userenv_list;	/* user environment variables */
    144 int	dfl_route_metric = -1;	/* metric of the default route to set over the PPP link */
    145 
    146 #ifdef PPP_WITH_IPV6CP
    147 char	path_ipv6up[MAXPATHLEN];   /* pathname of ipv6-up script */
    148 char	path_ipv6down[MAXPATHLEN]; /* pathname of ipv6-down script */
    149 #endif
    150 
    151 unsigned int  maxoctets = 0;    /* default - no limit */
    152 session_limit_dir_t maxoctets_dir = PPP_OCTETS_DIRECTION_SUM; /* default - sum of traffic */
    153 int maxoctets_timeout = 1;   /* default 1 second */
    154 
    155 
    156 extern struct option auth_options[];
    157 extern struct stat devstat;
    158 
    159 #ifdef PPP_WITH_FILTER
    160 /* Filter program for packets to pass */
    161 struct	bpf_program pass_filter_in;
    162 struct	bpf_program pass_filter_out;
    163 
    164 /* Filter program for link-active packets */
    165 struct	bpf_program active_filter_in;
    166 struct	bpf_program active_filter_out;
    167 #endif
    168 
    169 static struct option *curopt;	/* pointer to option being processed */
    170 char *current_option;		/* the name of the option being parsed */
    171 int  privileged_option;		/* set iff the current option came from root */
    172 char *option_source;		/* string saying where the option came from */
    173 int  option_priority = OPRIO_CFGFILE; /* priority of the current options */
    174 bool devnam_fixed;		/* can no longer change device name */
    175 
    176 static int logfile_fd = -1;	/* fd opened for log file */
    177 static char logfile_name[MAXPATHLEN];	/* name of log file */
    178 
    179 static bool noipx_opt;		/* dummy for noipx option */
    180 
    181 /*
    182  * Prototypes
    183  */
    184 static int setdomain(char **);
    185 static int readfile(char **);
    186 static int callfile(char **);
    187 static int showversion(char **);
    188 static int showhelp(char **);
    189 static void usage(void);
    190 static int setlogfile(char **);
    191 #ifdef PPP_WITH_PLUGINS
    192 static int loadplugin(char **);
    193 #endif
    194 
    195 #ifdef PPP_WITH_FILTER
    196 static int setpassfilter_in(char **);
    197 static int setactivefilter_in(char **);
    198 static int setpassfilter_out(char **);
    199 static int setactivefilter_out(char **);
    200 #endif
    201 
    202 static int setmodir(char **);
    203 
    204 static int user_setenv(char **);
    205 static void user_setprint(struct option *, printer_func, void *);
    206 static int user_unsetenv(char **);
    207 static void user_unsetprint(struct option *, printer_func, void *);
    208 
    209 static struct option *find_option(char *name);
    210 static int process_option(struct option *, char *, char **);
    211 static int n_arguments(struct option *);
    212 static int number_option(char *, u_int32_t *, int);
    213 
    214 /*
    215  * Structure to store extra lists of options.
    216  */
    217 struct option_list {
    218     struct option *options;
    219     struct option_list *next;
    220 };
    221 
    222 static struct option_list *extra_options = NULL;
    223 
    224 /*
    225  * Valid arguments.
    226  */
    227 struct option general_options[] = {
    228     { "debug", o_int, &debug,
    229       "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
    230     { "-d", o_int, &debug,
    231       "Increase debugging level",
    232       OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
    233 
    234     { "kdebug", o_int, &kdebugflag,
    235       "Set kernel driver debug level", OPT_PRIO },
    236 
    237     { "nodetach", o_bool, &nodetach,
    238       "Don't detach from controlling tty", OPT_PRIO | 1 },
    239     { "-detach", o_bool, &nodetach,
    240       "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
    241 #ifdef SYSTEMD
    242     { "up_sdnotify", o_bool, &up_sdnotify,
    243       "Notify systemd once link is up (implies nodetach)",
    244       OPT_PRIOSUB | OPT_A2COPY | 1, &nodetach },
    245 #endif
    246     { "updetach", o_bool, &updetach,
    247       "Detach from controlling tty once link is up",
    248       OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
    249 
    250     { "master_detach", o_bool, &master_detach,
    251       "Detach when we're multilink master but have no link", 1 },
    252 
    253     { "holdoff", o_int, &holdoff,
    254       "Set time in seconds before retrying connection",
    255       OPT_PRIO, &holdoff_specified },
    256 
    257     { "idle", o_int, &idle_time_limit,
    258       "Set time in seconds before disconnecting idle link", OPT_PRIO },
    259 
    260     { "maxconnect", o_int, &maxconnect,
    261       "Set connection time limit",
    262       OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
    263 
    264     { "domain", o_special, (void *)setdomain,
    265       "Add given domain name to hostname",
    266       OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
    267 
    268     { "file", o_special, (void *)readfile,
    269       "Take options from a file", OPT_NOPRINT },
    270     { "call", o_special, (void *)callfile,
    271       "Take options from a privileged file", OPT_NOPRINT },
    272 
    273     { "persist", o_bool, &persist,
    274       "Keep on reopening connection after close", OPT_PRIO | 1 },
    275     { "nopersist", o_bool, &persist,
    276       "Turn off persist option", OPT_PRIOSUB },
    277 
    278     { "demand", o_bool, &demand,
    279       "Dial on demand", OPT_INITONLY | 1, &persist },
    280 
    281     { "--version", o_special_noarg, (void *)showversion,
    282       "Show version number" },
    283     { "-v", o_special_noarg, (void *)showversion,
    284       "Show version number" },
    285     { "show-options", o_bool, &show_options,
    286       "Show all options and exit", 1 },
    287     { "--help", o_special_noarg, (void *)showhelp,
    288       "Show brief listing of options" },
    289     { "-h", o_special_noarg, (void *)showhelp,
    290       "Show brief listing of options", OPT_ALIAS },
    291 
    292     { "logfile", o_special, (void *)setlogfile,
    293       "Append log messages to this file",
    294       OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
    295     { "logfd", o_int, &log_to_fd,
    296       "Send log messages to this file descriptor",
    297       OPT_PRIOSUB | OPT_A2CLR, &log_default },
    298     { "nolog", o_int, &log_to_fd,
    299       "Don't send log messages to any file",
    300       OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
    301     { "nologfd", o_int, &log_to_fd,
    302       "Don't send log messages to any file descriptor",
    303       OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
    304 
    305     { "linkname", o_string, linkname,
    306       "Set logical name for link",
    307       OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
    308 
    309     { "maxfail", o_int, &maxfail,
    310       "Maximum number of unsuccessful connection attempts to allow",
    311       OPT_PRIO },
    312 
    313     { "ktune", o_bool, &tune_kernel,
    314       "Alter kernel settings as necessary", OPT_PRIO | 1 },
    315     { "noktune", o_bool, &tune_kernel,
    316       "Don't alter kernel settings", OPT_PRIOSUB },
    317 
    318     { "connect-delay", o_int, &connect_delay,
    319       "Maximum time (in ms) to wait after connect script finishes",
    320       OPT_PRIO },
    321 
    322     { "unit", o_int, &req_unit,
    323       "PPP interface unit number to use if possible",
    324       OPT_PRIO | OPT_LLIMIT, 0, 0 },
    325 
    326     { "ifname", o_string, req_ifname,
    327       "Set PPP interface name",
    328       OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, IFNAMSIZ },
    329 
    330     { "dump", o_bool, &dump_options,
    331       "Print out option values after parsing all options", 1 },
    332     { "dryrun", o_bool, &dryrun,
    333       "Stop after parsing, printing, and checking options", 1 },
    334 
    335     { "child-timeout", o_int, &child_wait,
    336       "Number of seconds to wait for child processes at exit",
    337       OPT_PRIO },
    338 
    339     { "set", o_special, (void *)user_setenv,
    340       "Set user environment variable",
    341       OPT_A2PRINTER | OPT_NOPRINT, (void *)user_setprint },
    342     { "unset", o_special, (void *)user_unsetenv,
    343       "Unset user environment variable",
    344       OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint },
    345 
    346     { "defaultroute-metric", o_int, &dfl_route_metric,
    347       "Metric to use for the default route (Linux only; -1 for default behavior)",
    348       OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 },
    349 
    350     { "net-init-script", o_string, path_net_init,
    351       "Set pathname of net-init script",
    352       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    353     { "net-pre-up-script", o_string, path_net_preup,
    354       "Set pathname of net-preup script",
    355       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    356     { "net-down-script", o_string, path_net_down,
    357       "Set pathname of net-down script",
    358       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    359 
    360     { "ip-up-script", o_string, path_ipup,
    361       "Set pathname of ip-up script",
    362       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    363     { "ip-down-script", o_string, path_ipdown,
    364       "Set pathname of ip-down script",
    365       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    366     { "ip-pre-up-script", o_string, path_ippreup,
    367       "Set pathname of ip-pre-up script",
    368       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    369 
    370 #ifdef PPP_WITH_IPV6CP
    371     { "ipv6-up-script", o_string, path_ipv6up,
    372       "Set pathname of ipv6-up script",
    373       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    374     { "ipv6-down-script", o_string, path_ipv6down,
    375       "Set pathname of ipv6-down script",
    376       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
    377 #endif
    378 
    379 #ifdef PPP_WITH_MULTILINK
    380     { "multilink", o_bool, &multilink,
    381       "Enable multilink operation", OPT_PRIO | 1 },
    382     { "mp", o_bool, &multilink,
    383       "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
    384     { "nomultilink", o_bool, &multilink,
    385       "Disable multilink operation", OPT_PRIOSUB | 0 },
    386     { "nomp", o_bool, &multilink,
    387       "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
    388 
    389     { "bundle", o_string, &bundle_name,
    390       "Bundle name for multilink", OPT_PRIO },
    391 #endif /* PPP_WITH_MULTILINK */
    392 
    393 #ifdef PPP_WITH_PLUGINS
    394     { "plugin", o_special, (void *)loadplugin,
    395       "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
    396 #endif
    397 
    398 #ifdef PPP_WITH_FILTER
    399     { "pass-filter-in", o_special, setpassfilter_in,
    400       "set filter for packets to pass inwards", OPT_PRIO },
    401     { "pass-filter-out", o_special, setpassfilter_out,
    402       "set filter for packets to pass outwards", OPT_PRIO },
    403 
    404     { "active-filter-in", o_special, setactivefilter_in,
    405       "set filter for active pkts inwards", OPT_PRIO },
    406     { "active-filter-out", o_special, setactivefilter_out,
    407       "set filter for active pkts outwards", OPT_PRIO },
    408 #endif
    409 
    410     { "maxoctets", o_int, &maxoctets,
    411       "Set connection traffic limit",
    412       OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
    413     { "mo", o_int, &maxoctets,
    414       "Set connection traffic limit",
    415       OPT_ALIAS | OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
    416     { "mo-direction", o_special, setmodir,
    417       "Set direction for limit traffic (sum,in,out,max)" },
    418     { "mo-timeout", o_int, &maxoctets_timeout,
    419       "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
    420 
    421     /* Dummy option, does nothing */
    422     { "noipx", o_bool, &noipx_opt, NULL, OPT_NOPRINT | 1 },
    423 
    424     { NULL }
    425 };
    426 
    427 #ifndef IMPLEMENTATION
    428 #define IMPLEMENTATION ""
    429 #endif
    430 
    431 int
    432 ppp_get_max_idle_time()
    433 {
    434     return idle_time_limit;
    435 }
    436 
    437 void
    438 ppp_set_max_idle_time(unsigned int max)
    439 {
    440     idle_time_limit = max;
    441 }
    442 
    443 int
    444 ppp_get_max_connect_time()
    445 {
    446     return maxconnect;
    447 }
    448 
    449 void
    450 ppp_set_max_connect_time(unsigned int max)
    451 {
    452     maxconnect = max;
    453 }
    454 
    455 void
    456 ppp_set_session_limit(unsigned int octets)
    457 {
    458     maxoctets = octets;
    459 }
    460 
    461 void
    462 ppp_set_session_limit_dir(unsigned int dir)
    463 {
    464     if (dir > 4)
    465         dir = PPP_OCTETS_DIRECTION_SUM;
    466     maxoctets_dir = (session_limit_dir_t) dir;
    467 }
    468 
    469 bool
    470 debug_on()
    471 {
    472     return !!debug;
    473 }
    474 
    475 int
    476 ppp_get_path(ppp_path_t type, char *buf, size_t bufsz)
    477 {
    478     const char *path;
    479 
    480     if (buf && bufsz > 0) {
    481         switch (type) {
    482         case PPP_DIR_LOG:
    483             path = PPP_PATH_VARLOG;
    484             break;
    485         case PPP_DIR_RUNTIME:
    486             path = PPP_PATH_VARRUN;
    487             break;
    488 #ifdef PPP_WITH_PLUGINS
    489         case PPP_DIR_PLUGIN:
    490             path = PPP_PATH_PLUGIN;
    491             break;
    492 #endif
    493         case PPP_DIR_CONF:
    494             path = PPP_PATH_CONFDIR;
    495             break;
    496 	default:
    497 	    return -1;
    498         }
    499         return strlcpy(buf, path, bufsz);
    500     }
    501     return -1;
    502 }
    503 
    504 int
    505 ppp_get_filepath(ppp_path_t type, const char *name, char *buf, size_t bufsz)
    506 {
    507     const char *path;
    508 
    509     if (buf && bufsz > 0) {
    510         switch (type) {
    511         case PPP_DIR_LOG:
    512             path = PPP_PATH_VARLOG;
    513             break;
    514         case PPP_DIR_RUNTIME:
    515             path = PPP_PATH_VARRUN;
    516             break;
    517 #ifdef PPP_WITH_PLUGINS
    518         case PPP_DIR_PLUGIN:
    519             path = PPP_PATH_PLUGIN;
    520             break;
    521 #endif
    522 	case PPP_DIR_CONF:
    523             path = PPP_PATH_CONFDIR;
    524             break;
    525 	default:
    526 	    return -1;
    527         }
    528         return slprintf(buf, bufsz, "%s/%s", path, name);
    529     }
    530     return -1;
    531 }
    532 
    533 bool ppp_persist(void)
    534 {
    535     return !!persist;
    536 }
    537 
    538 /*
    539  * parse_args - parse a string of arguments from the command line.
    540  */
    541 int
    542 parse_args(int argc, char **argv)
    543 {
    544     char *arg;
    545     struct option *opt;
    546     int n;
    547 
    548     privileged_option = privileged;
    549     option_source = "command line";
    550     option_priority = OPRIO_CMDLINE;
    551     while (argc > 0) {
    552 	arg = *argv++;
    553 	--argc;
    554 	opt = find_option(arg);
    555 	if (opt == NULL) {
    556 	    ppp_option_error("unrecognized option '%s'", arg);
    557 	    usage();
    558 	    return 0;
    559 	}
    560 	n = n_arguments(opt);
    561 	if (argc < n) {
    562 	    ppp_option_error("too few parameters for option %s", arg);
    563 	    return 0;
    564 	}
    565 	if (!process_option(opt, arg, argv))
    566 	    return 0;
    567 	argc -= n;
    568 	argv += n;
    569     }
    570     return 1;
    571 }
    572 
    573 /*
    574  * options_from_file - Read a string of options from a file,
    575  * and interpret them.
    576  */
    577 int
    578 ppp_options_from_file(char *filename, int must_exist, int check_prot, int priv)
    579 {
    580     FILE *f;
    581     int i, newline, ret, err;
    582     struct option *opt;
    583     int oldpriv, n;
    584     char *oldsource;
    585     uid_t euid;
    586     char *argv[MAXARGS];
    587     char args[MAXARGS][MAXWORDLEN];
    588     char cmd[MAXWORDLEN];
    589 
    590     euid = geteuid();
    591     if (check_prot && seteuid(getuid()) == -1) {
    592 	ppp_option_error("unable to drop privileges to open %s: %m", filename);
    593 	return 0;
    594     }
    595     f = fopen(filename, "r");
    596     err = errno;
    597     if (check_prot && seteuid(euid) == -1)
    598 	fatal("unable to regain privileges");
    599     if (f == NULL) {
    600 	errno = err;
    601 	if (!must_exist) {
    602 	    if (err != ENOENT && err != ENOTDIR)
    603 		warn("Warning: can't open options file %s: %m", filename);
    604 	    return 1;
    605 	}
    606 	ppp_option_error("Can't open options file %s: %m", filename);
    607 	return 0;
    608     }
    609 
    610     oldpriv = privileged_option;
    611     privileged_option = priv;
    612     oldsource = option_source;
    613     option_source = strdup(filename);
    614     if (option_source == NULL)
    615 	option_source = "file";
    616     ret = 0;
    617     while (getword(f, cmd, &newline, filename)) {
    618 	opt = find_option(cmd);
    619 	if (opt == NULL) {
    620 	    ppp_option_error("In file %s: unrecognized option '%s'",
    621 			 filename, cmd);
    622 	    goto err;
    623 	}
    624 	n = n_arguments(opt);
    625 	for (i = 0; i < n; ++i) {
    626 	    if (!getword(f, args[i], &newline, filename)) {
    627 		ppp_option_error(
    628 			"In file %s: too few parameters for option '%s'",
    629 			filename, cmd);
    630 		goto err;
    631 	    }
    632 	    argv[i] = args[i];
    633 	}
    634 	if (!process_option(opt, cmd, argv))
    635 	    goto err;
    636     }
    637     ret = 1;
    638 
    639 err:
    640     fclose(f);
    641     free(option_source);
    642     privileged_option = oldpriv;
    643     option_source = oldsource;
    644     return ret;
    645 }
    646 
    647 /*
    648  * options_from_user - See if the use has a ~/.ppprc file,
    649  * and if so, interpret options from it.
    650  */
    651 int
    652 options_from_user(void)
    653 {
    654     char *user, *path, *file;
    655     int ret;
    656     struct passwd *pw;
    657     size_t pl;
    658 
    659     pw = getpwuid(getuid());
    660     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
    661 	return 1;
    662     file = PPP_PATH_USEROPT;
    663     pl = strlen(user) + strlen(file) + 2;
    664     path = malloc(pl);
    665     if (path == NULL)
    666 	novm("init file name");
    667     slprintf(path, pl, "%s/%s", user, file);
    668     option_priority = OPRIO_CFGFILE;
    669     ret = ppp_options_from_file(path, 0, 1, privileged);
    670     free(path);
    671     return ret;
    672 }
    673 
    674 /*
    675  * options_for_tty - See if an options file exists for the serial
    676  * device, and if so, interpret options from it.
    677  * We only allow the per-tty options file to override anything from
    678  * the command line if it is something that the user can't override
    679  * once it has been set by root; this is done by giving configuration
    680  * files a lower priority than the command line.
    681  */
    682 int
    683 options_for_tty(void)
    684 {
    685     char *dev, *path, *p;
    686     int ret;
    687     size_t pl;
    688 
    689     dev = devnam;
    690     if ((p = strstr(dev, "/dev/")) != NULL)
    691 	dev = p + 5;
    692     if (dev[0] == 0 || strcmp(dev, "tty") == 0)
    693 	return 1;		/* don't look for /etc/ppp/options.tty */
    694     pl = strlen(PPP_PATH_TTYOPT) + strlen(dev) + 1;
    695     path = malloc(pl);
    696     if (path == NULL)
    697 	novm("tty init file name");
    698     slprintf(path, pl, "%s%s", PPP_PATH_TTYOPT, dev);
    699     /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
    700     for (p = path + strlen(PPP_PATH_TTYOPT); *p != 0; ++p)
    701 	if (*p == '/')
    702 	    *p = '.';
    703     option_priority = OPRIO_CFGFILE;
    704     ret = ppp_options_from_file(path, 0, 0, 1);
    705     free(path);
    706     return ret;
    707 }
    708 
    709 /*
    710  * options_from_list - process a string of options in a wordlist.
    711  */
    712 int
    713 options_from_list(struct wordlist *w, int priv)
    714 {
    715     char *argv[MAXARGS];
    716     struct option *opt;
    717     int i, n, ret = 0;
    718     struct wordlist *w0;
    719 
    720     privileged_option = priv;
    721     option_source = "secrets file";
    722     option_priority = OPRIO_SECFILE;
    723 
    724     while (w != NULL) {
    725 	opt = find_option(w->word);
    726 	if (opt == NULL) {
    727 	    ppp_option_error("In secrets file: unrecognized option '%s'",
    728 			 w->word);
    729 	    goto err;
    730 	}
    731 	n = n_arguments(opt);
    732 	w0 = w;
    733 	for (i = 0; i < n; ++i) {
    734 	    w = w->next;
    735 	    if (w == NULL) {
    736 		ppp_option_error(
    737 			"In secrets file: too few parameters for option '%s'",
    738 			w0->word);
    739 		goto err;
    740 	    }
    741 	    argv[i] = w->word;
    742 	}
    743 	if (!process_option(opt, w0->word, argv))
    744 	    goto err;
    745 	w = w->next;
    746     }
    747     ret = 1;
    748 
    749 err:
    750     return ret;
    751 }
    752 
    753 /*
    754  * match_option - see if this option matches an option structure.
    755  */
    756 static int
    757 match_option(char *name, struct option *opt, int dowild)
    758 {
    759 	int (*match)(char *, char **, int);
    760 
    761 	if (dowild != (opt->type == o_wild))
    762 		return 0;
    763 	if (!dowild)
    764 		return strcmp(name, opt->name) == 0;
    765 	match = (int (*)(char *, char **, int)) opt->addr;
    766 	return (*match)(name, NULL, 0);
    767 }
    768 
    769 /*
    770  * find_option - scan the option lists for the various protocols
    771  * looking for an entry with the given name.
    772  * This could be optimized by using a hash table.
    773  */
    774 static struct option *
    775 find_option(char *name)
    776 {
    777 	struct option *opt;
    778 	struct option_list *list;
    779 	int i, dowild;
    780 
    781 	for (dowild = 0; dowild <= 1; ++dowild) {
    782 		for (opt = general_options; opt->name != NULL; ++opt)
    783 			if (match_option(name, opt, dowild))
    784 				return opt;
    785 		for (opt = auth_options; opt->name != NULL; ++opt)
    786 			if (match_option(name, opt, dowild))
    787 				return opt;
    788 		for (list = extra_options; list != NULL; list = list->next)
    789 			for (opt = list->options; opt->name != NULL; ++opt)
    790 				if (match_option(name, opt, dowild))
    791 					return opt;
    792 		for (opt = the_channel->options; opt->name != NULL; ++opt)
    793 			if (match_option(name, opt, dowild))
    794 				return opt;
    795 		for (i = 0; protocols[i] != NULL; ++i)
    796 			if ((opt = protocols[i]->options) != NULL)
    797 				for (; opt->name != NULL; ++opt)
    798 					if (match_option(name, opt, dowild))
    799 						return opt;
    800 	}
    801 	return NULL;
    802 }
    803 
    804 /*
    805  * process_option - process one new-style option.
    806  */
    807 static int
    808 process_option(struct option *opt, char *cmd, char **argv)
    809 {
    810     u_int32_t v;
    811     int iv, a;
    812     char *sv;
    813     int (*parser)(char **);
    814     int (*wildp)(char *, char **, int);
    815     char *optopt = (opt->type == o_wild)? "": " option";
    816     int prio = option_priority;
    817     struct option *mainopt = opt;
    818 
    819     current_option = opt->name;
    820     if ((opt->flags & OPT_PRIVFIX) && privileged_option)
    821 	prio += OPRIO_ROOT;
    822     while (mainopt->flags & OPT_PRIOSUB)
    823 	--mainopt;
    824     if (mainopt->flags & OPT_PRIO) {
    825 	if (prio < mainopt->priority) {
    826 	    /* new value doesn't override old */
    827 	    if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
    828 		ppp_option_error("%s%s set in %s cannot be overridden\n",
    829 			     opt->name, optopt, mainopt->source);
    830 		return 0;
    831 	    }
    832 	    return 1;
    833 	}
    834 	if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
    835 	    warn("%s%s from %s overrides command line",
    836 		 opt->name, optopt, option_source);
    837     }
    838 
    839     if ((opt->flags & OPT_INITONLY) && !in_phase(PHASE_INITIALIZE)) {
    840 	ppp_option_error("%s%s cannot be changed after initialization",
    841 		     opt->name, optopt);
    842 	return 0;
    843     }
    844     if ((opt->flags & OPT_PRIV) && !privileged_option) {
    845 	ppp_option_error("using the %s%s requires root privilege",
    846 		     opt->name, optopt);
    847 	return 0;
    848     }
    849     if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
    850 	ppp_option_error("%s%s is disabled", opt->name, optopt);
    851 	return 0;
    852     }
    853     if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
    854 	ppp_option_error("the %s%s may not be changed in %s",
    855 		     opt->name, optopt, option_source);
    856 	return 0;
    857     }
    858 
    859     switch (opt->type) {
    860     case o_bool:
    861 	v = opt->flags & OPT_VALUE;
    862 	*(bool *)(opt->addr) = v;
    863 	if (opt->addr2 && (opt->flags & OPT_A2COPY))
    864 	    *(bool *)(opt->addr2) = v;
    865 	else if (opt->addr2 && (opt->flags & OPT_A2CLR))
    866 	    *(bool *)(opt->addr2) = 0;
    867 	else if (opt->addr2 && (opt->flags & OPT_A2CLRB))
    868 	    *(u_char *)(opt->addr2) &= ~v;
    869 	else if (opt->addr2 && (opt->flags & OPT_A2OR))
    870 	    *(u_char *)(opt->addr2) |= v;
    871 	break;
    872 
    873     case o_int:
    874 	iv = 0;
    875 	if ((opt->flags & OPT_NOARG) == 0) {
    876 	    if (!ppp_int_option(*argv, &iv))
    877 		return 0;
    878 	    if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
    879 		 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
    880 		&& !((opt->flags & OPT_ZEROOK && iv == 0))) {
    881 		char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
    882 		switch (opt->flags & OPT_LIMITS) {
    883 		case OPT_LLIMIT:
    884 		    ppp_option_error("%s value must be%s >= %d",
    885 				 opt->name, zok, opt->lower_limit);
    886 		    break;
    887 		case OPT_ULIMIT:
    888 		    ppp_option_error("%s value must be%s <= %d",
    889 				 opt->name, zok, opt->upper_limit);
    890 		    break;
    891 		case OPT_LIMITS:
    892 		    ppp_option_error("%s value must be%s between %d and %d",
    893 				opt->name, zok, opt->lower_limit, opt->upper_limit);
    894 		    break;
    895 		}
    896 		return 0;
    897 	    }
    898 	}
    899 	a = opt->flags & OPT_VALUE;
    900 	if (a >= 128)
    901 	    a -= 256;		/* sign extend */
    902 	iv += a;
    903 	if (opt->flags & OPT_INC)
    904 	    iv += *(int *)(opt->addr);
    905 	if ((opt->flags & OPT_NOINCR) && !privileged_option) {
    906 	    int oldv = *(int *)(opt->addr);
    907 	    if ((opt->flags & OPT_ZEROINF) ?
    908 		(oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
    909 		ppp_option_error("%s value cannot be increased", opt->name);
    910 		return 0;
    911 	    }
    912 	}
    913 	*(int *)(opt->addr) = iv;
    914 	if (opt->addr2 && (opt->flags & OPT_A2COPY))
    915 	    *(int *)(opt->addr2) = iv;
    916 	break;
    917 
    918     case o_uint32:
    919 	if (opt->flags & OPT_NOARG) {
    920 	    v = opt->flags & OPT_VALUE;
    921 	    if (v & 0x80)
    922 		    v |= 0xffffff00U;
    923 	} else if (!number_option(*argv, &v, 16))
    924 	    return 0;
    925 	if (opt->flags & OPT_OR)
    926 	    v |= *(u_int32_t *)(opt->addr);
    927 	*(u_int32_t *)(opt->addr) = v;
    928 	if (opt->addr2 && (opt->flags & OPT_A2COPY))
    929 	    *(u_int32_t *)(opt->addr2) = v;
    930 	break;
    931 
    932     case o_string:
    933 	if (opt->flags & OPT_STATIC) {
    934 	    strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
    935 	} else {
    936 	    char **optptr = (char **)(opt->addr);
    937 	    sv = strdup(*argv);
    938 	    if (sv == NULL)
    939 		novm("option argument");
    940 	    if (*optptr)
    941 		free(*optptr);
    942 	    *optptr = sv;
    943 	}
    944 	/* obfuscate original argument for things like password */
    945 	if (opt->flags & OPT_HIDE) {
    946 	    memset(*argv, '?', strlen(*argv));
    947 	    *argv = "********";
    948 	}
    949 	break;
    950 
    951     case o_special_noarg:
    952     case o_special:
    953 	parser = (int (*)(char **)) opt->addr;
    954 	curopt = opt;
    955 	if (!(*parser)(argv))
    956 	    return 0;
    957 	if (opt->flags & OPT_A2LIST) {
    958 	    struct option_value *ovp, *pp;
    959 
    960 	    ovp = malloc(sizeof(*ovp) + strlen(*argv));
    961 	    if (ovp != 0) {
    962 		strcpy(ovp->value, *argv);
    963 		ovp->source = option_source;
    964 		ovp->next = NULL;
    965 		if (opt->addr2 == NULL) {
    966 		    opt->addr2 = ovp;
    967 		} else {
    968 		    for (pp = opt->addr2; pp->next != NULL; pp = pp->next)
    969 			;
    970 		    pp->next = ovp;
    971 		}
    972 	    }
    973 	}
    974 	break;
    975 
    976     case o_wild:
    977 	wildp = (int (*)(char *, char **, int)) opt->addr;
    978 	if (!(*wildp)(cmd, argv, 1))
    979 	    return 0;
    980 	break;
    981     }
    982 
    983     /*
    984      * If addr2 wasn't used by any flag (OPT_A2COPY, etc.) but is set,
    985      * treat it as a bool and set/clear it based on the OPT_A2CLR bit.
    986      */
    987     if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
    988 		|OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST|OPT_A2OR)) == 0)
    989 	*(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
    990 
    991     mainopt->source = option_source;
    992     mainopt->priority = prio;
    993     mainopt->winner = opt - mainopt;
    994 
    995     return 1;
    996 }
    997 
    998 /*
    999  * override_value - if the option priorities would permit us to
   1000  * override the value of option, return 1 and update the priority
   1001  * and source of the option value.  Otherwise returns 0.
   1002  */
   1003 int
   1004 override_value(char *option, int priority, const char *source)
   1005 {
   1006 	struct option *opt;
   1007 
   1008 	opt = find_option(option);
   1009 	if (opt == NULL)
   1010 		return 0;
   1011 	while (opt->flags & OPT_PRIOSUB)
   1012 		--opt;
   1013 	if ((opt->flags & OPT_PRIO) && priority < opt->priority)
   1014 		return 0;
   1015 	opt->priority = priority;
   1016 	opt->source = source;
   1017 	opt->winner = -1;
   1018 	return 1;
   1019 }
   1020 
   1021 /*
   1022  * n_arguments - tell how many arguments an option takes
   1023  */
   1024 static int
   1025 n_arguments(struct option *opt)
   1026 {
   1027 	return (opt->type == o_bool || opt->type == o_special_noarg
   1028 		|| (opt->flags & OPT_NOARG))? 0: 1;
   1029 }
   1030 
   1031 /*
   1032  * add_options - add a list of options to the set we grok.
   1033  */
   1034 void
   1035 ppp_add_options(struct option *opt)
   1036 {
   1037     struct option_list *list;
   1038 
   1039     list = malloc(sizeof(*list));
   1040     if (list == 0)
   1041 	novm("option list entry");
   1042     list->options = opt;
   1043     list->next = extra_options;
   1044     extra_options = list;
   1045 }
   1046 
   1047 /*
   1048  * check_options - check that options are valid and consistent.
   1049  */
   1050 void
   1051 check_options(void)
   1052 {
   1053 	if (logfile_fd >= 0 && logfile_fd != log_to_fd)
   1054 		close(logfile_fd);
   1055 }
   1056 
   1057 /*
   1058  * print_option - print out an option and its value
   1059  */
   1060 static void
   1061 print_option(struct option *opt, struct option *mainopt, printer_func printer, void *arg)
   1062 {
   1063 	int i, v;
   1064 	char *p;
   1065 
   1066 	if (opt->flags & OPT_NOPRINT)
   1067 		return;
   1068 	switch (opt->type) {
   1069 	case o_bool:
   1070 		v = opt->flags & OPT_VALUE;
   1071 		if (*(bool *)opt->addr != v)
   1072 			/* this can happen legitimately, e.g. lock
   1073 			   option turned off for default device */
   1074 			break;
   1075 		printer(arg, "%s", opt->name);
   1076 		break;
   1077 	case o_int:
   1078 		v = opt->flags & OPT_VALUE;
   1079 		if (v >= 128)
   1080 			v -= 256;
   1081 		i = *(int *)opt->addr;
   1082 		if (opt->flags & OPT_NOARG) {
   1083 			printer(arg, "%s", opt->name);
   1084 			if (i != v) {
   1085 				if (opt->flags & OPT_INC) {
   1086 					for (; i > v; i -= v)
   1087 						printer(arg, " %s", opt->name);
   1088 				} else
   1089 					printer(arg, " # oops: %d not %d\n",
   1090 						i, v);
   1091 			}
   1092 		} else {
   1093 			printer(arg, "%s %d", opt->name, i);
   1094 		}
   1095 		break;
   1096 	case o_uint32:
   1097 		printer(arg, "%s", opt->name);
   1098 		if ((opt->flags & OPT_NOARG) == 0)
   1099 			printer(arg, " %x", *(u_int32_t *)opt->addr);
   1100 		break;
   1101 
   1102 	case o_string:
   1103 		if (opt->flags & OPT_HIDE) {
   1104 			p = "??????";
   1105 		} else {
   1106 			p = (char *) opt->addr;
   1107 			if ((opt->flags & OPT_STATIC) == 0)
   1108 				p = *(char **)p;
   1109 		}
   1110 		printer(arg, "%s %q", opt->name, p);
   1111 		break;
   1112 
   1113 	case o_special:
   1114 	case o_special_noarg:
   1115 	case o_wild:
   1116 		if (opt->type != o_wild) {
   1117 			printer(arg, "%s", opt->name);
   1118 			if (n_arguments(opt) == 0)
   1119 				break;
   1120 			printer(arg, " ");
   1121 		}
   1122 		if (opt->flags & OPT_A2PRINTER) {
   1123 			void (*oprt)(struct option *, printer_func, void *);
   1124 			oprt = (void (*)(struct option *, printer_func, void *))
   1125 				opt->addr2;
   1126 			(*oprt)(opt, printer, arg);
   1127 		} else if (opt->flags & OPT_A2STRVAL) {
   1128 			p = (char *) opt->addr2;
   1129 			if ((opt->flags & OPT_STATIC) == 0)
   1130 				p = *(char **)p;
   1131 			printer(arg, "%q", p);
   1132 		} else if (opt->flags & OPT_A2LIST) {
   1133 			struct option_value *ovp;
   1134 
   1135 			ovp = (struct option_value *) opt->addr2;
   1136 			for (;;) {
   1137 				printer(arg, "%q", ovp->value);
   1138 				if ((ovp = ovp->next) == NULL)
   1139 					break;
   1140 				printer(arg, "\t\t# (from %s)\n%s ",
   1141 					ovp->source, opt->name);
   1142 			}
   1143 		} else {
   1144 			printer(arg, "xxx # [don't know how to print value]");
   1145 		}
   1146 		break;
   1147 
   1148 	default:
   1149 		printer(arg, "# %s value (type %d\?\?)", opt->name, opt->type);
   1150 		break;
   1151 	}
   1152 	printer(arg, "\t\t# (from %s)\n", mainopt->source);
   1153 }
   1154 
   1155 /*
   1156  * print_option_list - print out options in effect from an
   1157  * array of options.
   1158  */
   1159 static void
   1160 print_option_list(struct option *opt, printer_func printer, void *arg)
   1161 {
   1162 	while (opt->name != NULL) {
   1163 		if (opt->priority != OPRIO_DEFAULT
   1164 		    && opt->winner != (short int) -1)
   1165 			print_option(opt + opt->winner, opt, printer, arg);
   1166 		do {
   1167 			++opt;
   1168 		} while (opt->flags & OPT_PRIOSUB);
   1169 	}
   1170 }
   1171 
   1172 /*
   1173  * print_options - print out what options are in effect.
   1174  */
   1175 void
   1176 print_options(printer_func printer, void *arg)
   1177 {
   1178 	struct option_list *list;
   1179 	int i;
   1180 
   1181 	printer(arg, "pppd options in effect:\n");
   1182 	print_option_list(general_options, printer, arg);
   1183 	print_option_list(auth_options, printer, arg);
   1184 	for (list = extra_options; list != NULL; list = list->next)
   1185 		print_option_list(list->options, printer, arg);
   1186 	print_option_list(the_channel->options, printer, arg);
   1187 	for (i = 0; protocols[i] != NULL; ++i)
   1188 		print_option_list(protocols[i]->options, printer, arg);
   1189 }
   1190 
   1191 /*
   1192  * usage - print out a message telling how to use the program.
   1193  */
   1194 static void
   1195 usage(void)
   1196 {
   1197     FILE *fp = stderr;
   1198     if (in_phase(PHASE_INITIALIZE)) {
   1199         fprintf(fp, "%s v%s\n", PACKAGE_NAME, PACKAGE_VERSION);
   1200         fprintf(fp, "Copyright (C) 1999-2024 Paul Mackerras, and others. All rights reserved.\n\n");
   1201 
   1202 
   1203         fprintf(fp, "License BSD: The 3 clause BSD license <https://opensource.org/licenses/BSD-3-Clause>\n");
   1204         fprintf(fp, "This is free software: you are free to change and redistribute it.\n");
   1205         fprintf(fp, "There is NO WARRANTY, to the extent permitted by law.\n\n");
   1206 
   1207         fprintf(fp, "Report Bugs:\n   %s\n\n", PACKAGE_BUGREPORT);
   1208         fprintf(fp, "Usage: %s [ options ], where options are:\n", progname);
   1209         fprintf(fp, "   <device>        Communicate over the named device\n");
   1210         fprintf(fp, "   <speed>         Set the baud rate to <speed>\n");
   1211         fprintf(fp, "   <loc>:<rem>     Set the local and/or remote interface IP\n");
   1212         fprintf(fp, "                   addresses.  Either one may be omitted.\n");
   1213         fprintf(fp, "   asyncmap <n>    Set the desired async map to hex <n>\n");
   1214         fprintf(fp, "   auth            Require authentication from peer\n");
   1215         fprintf(fp, "   connect <p>     Invoke shell command <p> to set up the serial line\n");
   1216         fprintf(fp, "   crtscts         Use hardware RTS/CTS flow control\n");
   1217         fprintf(fp, "   defaultroute    Add default route through interface\n");
   1218         fprintf(fp, "   file <f>        Take options from file <f>\n");
   1219         fprintf(fp, "   modem           Use modem control lines\n");
   1220         fprintf(fp, "   mru <n>         Set MRU value to <n> for negotiation\n");
   1221         fprintf(fp, "   show-options    Display an extended list of options\n");
   1222         fprintf(fp, "See pppd(8) for more options.\n");
   1223     }
   1224 }
   1225 
   1226 /*
   1227  * showhelp - print out usage message and exit.
   1228  */
   1229 static int
   1230 showhelp(char **argv)
   1231 {
   1232     if (in_phase(PHASE_INITIALIZE)) {
   1233 	usage();
   1234 	exit(0);
   1235     }
   1236     return 0;
   1237 }
   1238 
   1239 /*
   1240  * showversion - print out the version number and exit.
   1241  */
   1242 static int
   1243 showversion(char **argv)
   1244 {
   1245     if (in_phase(PHASE_INITIALIZE)) {
   1246 	fprintf(stdout, "pppd version %s\n", VERSION);
   1247 	exit(0);
   1248     }
   1249     return 0;
   1250 }
   1251 
   1252 /*
   1253  * Print a set of options including the name of the group of options
   1254  */
   1255 static void
   1256 showopts_list(FILE *fp, const char *title, struct option *list, ...)
   1257 {
   1258 	struct option *opt = list;
   1259     va_list varg;
   1260 
   1261     if (opt && opt->name) {
   1262         va_start(varg, list);
   1263         vfprintf(fp, title, varg);
   1264         fprintf(fp, ":\n");
   1265         va_end(varg);
   1266 
   1267         do {
   1268             fprintf(fp, "    %-22s %s\n", opt->name, opt->description?:"");
   1269             opt++;
   1270         } while (opt && opt->name);
   1271 
   1272         fprintf(fp, "\n");
   1273     }
   1274 }
   1275 
   1276 /*
   1277  * Dumps the list of available options
   1278  */
   1279 void
   1280 showopts(void)
   1281 {
   1282     struct option_list *list;
   1283     FILE *fp = stderr;
   1284     int i = 0;
   1285 
   1286     showopts_list(fp, "General Options",
   1287             general_options);
   1288 
   1289     showopts_list(fp, "Authentication Options",
   1290             auth_options);
   1291 
   1292     for (list = extra_options; list != NULL; list = list->next)
   1293 		showopts_list(fp, "Extra Options", list->options);
   1294 
   1295     showopts_list(fp, "Channel Options",
   1296             the_channel->options);
   1297 
   1298     for (i = 0; protocols[i] != NULL; ++i) {
   1299         if (protocols[i]->options != NULL) {
   1300             showopts_list(fp, "%s Options",
   1301                     protocols[i]->options,
   1302                     protocols[i]->name);
   1303         }
   1304     }
   1305 }
   1306 
   1307 /*
   1308  * ppp_option_error - print a message about an error in an option.
   1309  * The message is logged, and also sent to
   1310  * stderr if in_phase(PHASE_INITIALIZE).
   1311  */
   1312 void
   1313 ppp_option_error(char *fmt, ...)
   1314 {
   1315     va_list args;
   1316     char buf[1024];
   1317 
   1318     va_start(args, fmt);
   1319     vslprintf(buf, sizeof(buf), fmt, args);
   1320     va_end(args);
   1321     if (in_phase(PHASE_INITIALIZE))
   1322 	fprintf(stderr, "%s: %s\n", progname, buf);
   1323     syslog(LOG_ERR, "%s", buf);
   1324 }
   1325 
   1326 #if 0
   1327 /*
   1328  * readable - check if a file is readable by the real user.
   1329  */
   1330 int
   1331 readable(int fd)
   1332 {
   1333     uid_t uid;
   1334     int i;
   1335     struct stat sbuf;
   1336 
   1337     uid = getuid();
   1338     if (uid == 0)
   1339 	return 1;
   1340     if (fstat(fd, &sbuf) != 0)
   1341 	return 0;
   1342     if (sbuf.st_uid == uid)
   1343 	return sbuf.st_mode & S_IRUSR;
   1344     if (sbuf.st_gid == getgid())
   1345 	return sbuf.st_mode & S_IRGRP;
   1346     for (i = 0; i < ngroups; ++i)
   1347 	if (sbuf.st_gid == groups[i])
   1348 	    return sbuf.st_mode & S_IRGRP;
   1349     return sbuf.st_mode & S_IROTH;
   1350 }
   1351 #endif
   1352 
   1353 /*
   1354  * Read a word from a file.
   1355  * Words are delimited by white-space or by quotes (" or ').
   1356  * Quotes, white-space and \ may be escaped with \.
   1357  * \<newline> is ignored.
   1358  */
   1359 int
   1360 getword(FILE *f, char *word, int *newlinep, char *filename)
   1361 {
   1362     int c, len, escape;
   1363     int quoted, comment;
   1364     int value, digit, got, n;
   1365 
   1366 #define isoctal(c) ((c) >= '0' && (c) < '8')
   1367 
   1368     *newlinep = 0;
   1369     len = 0;
   1370     escape = 0;
   1371     comment = 0;
   1372     quoted = 0;
   1373 
   1374     /*
   1375      * First skip white-space and comments.
   1376      */
   1377     for (;;) {
   1378 	c = getc(f);
   1379 	if (c == EOF)
   1380 	    break;
   1381 
   1382 	/*
   1383 	 * A newline means the end of a comment; backslash-newline
   1384 	 * is ignored.  Note that we cannot have escape && comment.
   1385 	 */
   1386 	if (c == '\n') {
   1387 	    if (!escape) {
   1388 		*newlinep = 1;
   1389 		comment = 0;
   1390 	    } else
   1391 		escape = 0;
   1392 	    continue;
   1393 	}
   1394 
   1395 	/*
   1396 	 * Ignore characters other than newline in a comment.
   1397 	 */
   1398 	if (comment)
   1399 	    continue;
   1400 
   1401 	/*
   1402 	 * If this character is escaped, we have a word start.
   1403 	 */
   1404 	if (escape)
   1405 	    break;
   1406 
   1407 	/*
   1408 	 * If this is the escape character, look at the next character.
   1409 	 */
   1410 	if (c == '\\') {
   1411 	    escape = 1;
   1412 	    continue;
   1413 	}
   1414 
   1415 	/*
   1416 	 * If this is the start of a comment, ignore the rest of the line.
   1417 	 */
   1418 	if (c == '#') {
   1419 	    comment = 1;
   1420 	    continue;
   1421 	}
   1422 
   1423 	/*
   1424 	 * A non-whitespace character is the start of a word.
   1425 	 */
   1426 	if (!isspace(c))
   1427 	    break;
   1428     }
   1429 
   1430     /*
   1431      * Process characters until the end of the word.
   1432      */
   1433     while (c != EOF) {
   1434 	if (escape) {
   1435 	    /*
   1436 	     * This character is escaped: backslash-newline is ignored,
   1437 	     * various other characters indicate particular values
   1438 	     * as for C backslash-escapes.
   1439 	     */
   1440 	    escape = 0;
   1441 	    if (c == '\n') {
   1442 	        c = getc(f);
   1443 		continue;
   1444 	    }
   1445 
   1446 	    got = 0;
   1447 	    switch (c) {
   1448 	    case 'a':
   1449 		value = '\a';
   1450 		break;
   1451 	    case 'b':
   1452 		value = '\b';
   1453 		break;
   1454 	    case 'f':
   1455 		value = '\f';
   1456 		break;
   1457 	    case 'n':
   1458 		value = '\n';
   1459 		break;
   1460 	    case 'r':
   1461 		value = '\r';
   1462 		break;
   1463 	    case 's':
   1464 		value = ' ';
   1465 		break;
   1466 	    case 't':
   1467 		value = '\t';
   1468 		break;
   1469 
   1470 	    default:
   1471 		if (isoctal((unsigned char)c)) {
   1472 		    /*
   1473 		     * \ddd octal sequence
   1474 		     */
   1475 		    value = 0;
   1476 		    for (n = 0; n < 3 && isoctal((unsigned char)c); ++n) {
   1477 			value = (value << 3) + (c & 07);
   1478 			c = getc(f);
   1479 		    }
   1480 		    got = 1;
   1481 		    break;
   1482 		}
   1483 
   1484 		if (c == 'x') {
   1485 		    /*
   1486 		     * \x<hex_string> sequence
   1487 		     */
   1488 		    value = 0;
   1489 		    c = getc(f);
   1490 		    for (n = 0; n < 2 && isxdigit((unsigned char)c); ++n) {
   1491 			digit = toupper((unsigned char)c) - '0';
   1492 			if (digit > 10)
   1493 			    digit += '0' + 10 - 'A';
   1494 			value = (value << 4) + digit;
   1495 			c = getc (f);
   1496 		    }
   1497 		    got = 1;
   1498 		    break;
   1499 		}
   1500 
   1501 		/*
   1502 		 * Otherwise the character stands for itself.
   1503 		 */
   1504 		value = c;
   1505 		break;
   1506 	    }
   1507 
   1508 	    /*
   1509 	     * Store the resulting character for the escape sequence.
   1510 	     */
   1511 	    if (len < MAXWORDLEN) {
   1512 		word[len] = value;
   1513 		++len;
   1514 	    }
   1515 
   1516 	    if (!got)
   1517 		c = getc(f);
   1518 	    continue;
   1519 	}
   1520 
   1521 	/*
   1522 	 * Backslash starts a new escape sequence.
   1523 	 */
   1524 	if (c == '\\') {
   1525 	    escape = 1;
   1526 	    c = getc(f);
   1527 	    continue;
   1528 	}
   1529 
   1530 	/*
   1531 	 * Not escaped: check for the start or end of a quoted
   1532 	 * section and see if we've reached the end of the word.
   1533 	 */
   1534 	if (quoted) {
   1535 	    if (c == quoted) {
   1536 		quoted = 0;
   1537 		c = getc(f);
   1538 		continue;
   1539 	    }
   1540 	} else if (c == '"' || c == '\'') {
   1541 	    quoted = c;
   1542 	    c = getc(f);
   1543 	    continue;
   1544 	} else if (isspace(c) || c == '#') {
   1545 	    ungetc (c, f);
   1546 	    break;
   1547 	}
   1548 
   1549 	/*
   1550 	 * An ordinary character: store it in the word and get another.
   1551 	 */
   1552 	if (len < MAXWORDLEN) {
   1553 	    word[len] = c;
   1554 	    ++len;
   1555 	}
   1556 
   1557 	c = getc(f);
   1558     }
   1559     word[MAXWORDLEN-1] = 0;	/* make sure word is null-terminated */
   1560 
   1561     /*
   1562      * End of the word: check for errors.
   1563      */
   1564     if (c == EOF) {
   1565 	if (ferror(f)) {
   1566 	    if (errno == 0)
   1567 		errno = EIO;
   1568 	    ppp_option_error("Error reading %s: %m", filename);
   1569 	    die(1);
   1570 	}
   1571 	/*
   1572 	 * If len is zero, then we didn't find a word before the
   1573 	 * end of the file.
   1574 	 */
   1575 	if (len == 0)
   1576 	    return 0;
   1577 	if (quoted)
   1578 	    ppp_option_error("warning: quoted word runs to end of file (%.20s...)",
   1579 			 filename, word);
   1580     }
   1581 
   1582     /*
   1583      * Warn if the word was too long, and append a terminating null.
   1584      */
   1585     if (len >= MAXWORDLEN) {
   1586 	ppp_option_error("warning: word in file %s too long (%.20s...)",
   1587 		     filename, word);
   1588 	len = MAXWORDLEN - 1;
   1589     }
   1590     word[len] = 0;
   1591 
   1592     return 1;
   1593 
   1594 #undef isoctal
   1595 
   1596 }
   1597 
   1598 /*
   1599  * number_option - parse an unsigned numeric parameter for an option.
   1600  */
   1601 static int
   1602 number_option(char *str, u_int32_t *valp, int base)
   1603 {
   1604     char *ptr;
   1605 
   1606     *valp = strtoul(str, &ptr, base);
   1607     if (ptr == str) {
   1608 	ppp_option_error("invalid numeric parameter '%s' for %s option",
   1609 		     str, current_option);
   1610 	return 0;
   1611     }
   1612     return 1;
   1613 }
   1614 
   1615 
   1616 /*
   1617  * int_option - like number_option, but valp is int *,
   1618  * the base is assumed to be 0, and *valp is not changed
   1619  * if there is an error.
   1620  */
   1621 int
   1622 ppp_int_option(char *str, int *valp)
   1623 {
   1624     u_int32_t v;
   1625 
   1626     if (!number_option(str, &v, 0))
   1627 	return 0;
   1628     *valp = (int) v;
   1629     return 1;
   1630 }
   1631 
   1632 
   1633 /*
   1634  * The following procedures parse options.
   1635  */
   1636 
   1637 /*
   1638  * readfile - take commands from a file.
   1639  */
   1640 static int
   1641 readfile(char **argv)
   1642 {
   1643     return ppp_options_from_file(*argv, 1, 1, privileged_option);
   1644 }
   1645 
   1646 /*
   1647  * callfile - take commands from /etc/ppp/peers/<name>.
   1648  * Name may not contain /../, start with / or ../, or end in /..
   1649  */
   1650 static int
   1651 callfile(char **argv)
   1652 {
   1653     char *fname, *arg, *p;
   1654     int l, ok;
   1655 
   1656     arg = *argv;
   1657     ok = 1;
   1658     if (arg[0] == '/' || arg[0] == 0)
   1659 	ok = 0;
   1660     else {
   1661 	for (p = arg; *p != 0; ) {
   1662 	    if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
   1663 		ok = 0;
   1664 		break;
   1665 	    }
   1666 	    while (*p != '/' && *p != 0)
   1667 		++p;
   1668 	    if (*p == '/')
   1669 		++p;
   1670 	}
   1671     }
   1672     if (!ok) {
   1673 	ppp_option_error("call option value may not contain .. or start with /");
   1674 	return 0;
   1675     }
   1676 
   1677     l = strlen(arg) + strlen(PPP_PATH_PEERFILES) + 1;
   1678     if ((fname = (char *) malloc(l)) == NULL)
   1679 	novm("call file name");
   1680     slprintf(fname, l, "%s%s", PPP_PATH_PEERFILES, arg);
   1681     ppp_script_setenv("CALL_FILE", arg, 0);
   1682 
   1683     ok = ppp_options_from_file(fname, 1, 1, 1);
   1684 
   1685     free(fname);
   1686     return ok;
   1687 }
   1688 
   1689 #ifdef PPP_WITH_FILTER
   1690 /*
   1691  * setpassfilter_in - Set the pass filter for incoming packets
   1692  */
   1693 static int
   1694 setpassfilter_in(argv)
   1695     char **argv;
   1696 {
   1697     pcap_t *pc;
   1698     int ret = 1;
   1699 
   1700     pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
   1701     if (pcap_compile(pc, &pass_filter_in, *argv, 1, netmask) == -1) {
   1702 	ppp_option_error("error in pass-filter-in expression: %s\n",
   1703 			 pcap_geterr(pc));
   1704 	ret = 0;
   1705     }
   1706     pcap_close(pc);
   1707 
   1708     return ret;
   1709 }
   1710 
   1711 /*
   1712  * setpassfilter_out - Set the pass filter for outgoing packets
   1713  */
   1714 static int
   1715 setpassfilter_out(argv)
   1716     char **argv;
   1717 {
   1718     pcap_t *pc;
   1719     int ret = 1;
   1720 
   1721     pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
   1722     if (pcap_compile(pc, &pass_filter_out, *argv, 1, netmask) == -1) {
   1723 	ppp_option_error("error in pass-filter-out expression: %s\n",
   1724 			 pcap_geterr(pc));
   1725 	ret = 0;
   1726     }
   1727     pcap_close(pc);
   1728 
   1729     return ret;
   1730 }
   1731 
   1732 /*
   1733  * setactivefilter_in - Set the active filter for incoming packets
   1734  */
   1735 static int
   1736 setactivefilter_in(char **argv)
   1737 {
   1738     pcap_t *pc;
   1739     int ret = 1;
   1740 
   1741     pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
   1742     if (pcap_compile(pc, &active_filter_in, *argv, 1, netmask) == -1) {
   1743 	ppp_option_error("error in active-filter-in expression: %s\n",
   1744 			 pcap_geterr(pc));
   1745 	ret = 0;
   1746     }
   1747     pcap_close(pc);
   1748 
   1749     return ret;
   1750 }
   1751 
   1752 /*
   1753  * setactivefilter_out - Set the active filter for outgoing packets
   1754  */
   1755 static int
   1756 setactivefilter_out(char **argv)
   1757 {
   1758     pcap_t *pc;
   1759     int ret = 1;
   1760 
   1761     pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
   1762     if (pcap_compile(pc, &active_filter_out, *argv, 1, netmask) == -1) {
   1763 	ppp_option_error("error in active-filter-out expression: %s\n",
   1764 			 pcap_geterr(pc));
   1765 	ret = 0;
   1766     }
   1767     pcap_close(pc);
   1768 
   1769     return ret;
   1770 }
   1771 #endif
   1772 
   1773 /*
   1774  * setdomain - Set domain name to append to hostname
   1775  */
   1776 static int
   1777 setdomain(char **argv)
   1778 {
   1779     gethostname(hostname, MAXNAMELEN);
   1780     if (**argv != 0) {
   1781 	if (**argv != '.')
   1782 	    strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
   1783 	domain = hostname + strlen(hostname);
   1784 	strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
   1785     }
   1786     hostname[MAXNAMELEN-1] = 0;
   1787     return (1);
   1788 }
   1789 
   1790 static int
   1791 setlogfile(char **argv)
   1792 {
   1793     int fd, err;
   1794     uid_t euid;
   1795 
   1796     euid = geteuid();
   1797     if (!privileged_option && seteuid(getuid()) == -1) {
   1798 	ppp_option_error("unable to drop permissions to open %s: %m", *argv);
   1799 	return 0;
   1800     }
   1801     fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
   1802     if (fd < 0 && errno == EEXIST)
   1803 	fd = open(*argv, O_WRONLY | O_APPEND);
   1804     err = errno;
   1805     if (!privileged_option && seteuid(euid) == -1)
   1806 	fatal("unable to regain privileges: %m");
   1807     if (fd < 0) {
   1808 	errno = err;
   1809 	ppp_option_error("Can't open log file %s: %m", *argv);
   1810 	return 0;
   1811     }
   1812     strlcpy(logfile_name, *argv, sizeof(logfile_name));
   1813     if (logfile_fd >= 0)
   1814 	close(logfile_fd);
   1815     logfile_fd = fd;
   1816     log_to_fd = fd;
   1817     log_default = 0;
   1818     return 1;
   1819 }
   1820 
   1821 static int
   1822 setmodir(char **argv)
   1823 {
   1824     if(*argv == NULL)
   1825 	return 0;
   1826     if(!strcmp(*argv,"in")) {
   1827         maxoctets_dir = PPP_OCTETS_DIRECTION_IN;
   1828     } else if (!strcmp(*argv,"out")) {
   1829         maxoctets_dir = PPP_OCTETS_DIRECTION_OUT;
   1830     } else if (!strcmp(*argv,"max")) {
   1831         maxoctets_dir = PPP_OCTETS_DIRECTION_MAXOVERAL;
   1832     } else {
   1833         maxoctets_dir = PPP_OCTETS_DIRECTION_SUM;
   1834     }
   1835     return 1;
   1836 }
   1837 
   1838 #ifdef PPP_WITH_PLUGINS
   1839 static int
   1840 loadplugin(char **argv)
   1841 {
   1842     char *arg = *argv;
   1843     void *handle;
   1844     const char *err;
   1845     void (*init)(void);
   1846     char *path = arg;
   1847     const char *vers;
   1848 
   1849     if (strchr(arg, '/') == 0) {
   1850 	const char *base = PPP_PATH_PLUGIN;
   1851 	int l = strlen(base) + strlen(arg) + 2;
   1852 	path = malloc(l);
   1853 	if (path == 0)
   1854 	    novm("plugin file path");
   1855 	strlcpy(path, base, l);
   1856 	strlcat(path, "/", l);
   1857 	strlcat(path, arg, l);
   1858     }
   1859     handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
   1860     if (handle == 0) {
   1861 	err = dlerror();
   1862 	if (err != 0)
   1863 	    ppp_option_error("%s", err);
   1864 	ppp_option_error("Couldn't load plugin %s", arg);
   1865 	goto err;
   1866     }
   1867     init = (void (*)(void))dlsym(handle, "plugin_init");
   1868     if (init == 0) {
   1869 	ppp_option_error("%s has no initialization entry point", arg);
   1870 	goto errclose;
   1871     }
   1872     vers = (const char *) dlsym(handle, "pppd_version");
   1873     if (vers == 0) {
   1874 	warn("Warning: plugin %s has no version information", arg);
   1875     } else if (strcmp(vers, VERSION) != 0) {
   1876 	ppp_option_error("Plugin %s is for pppd version %s, this is %s",
   1877 		     arg, vers, VERSION);
   1878 	goto errclose;
   1879     }
   1880     info("Plugin %s loaded.", arg);
   1881     (*init)();
   1882     if (path != arg)
   1883 	free(path);
   1884     return 1;
   1885 
   1886  errclose:
   1887     dlclose(handle);
   1888  err:
   1889     if (path != arg)
   1890 	free(path);
   1891     return 0;
   1892 }
   1893 #endif /* PPP_WITH_PLUGINS */
   1894 
   1895 /*
   1896  * Set an environment variable specified by the user.
   1897  */
   1898 static int
   1899 user_setenv(char **argv)
   1900 {
   1901     char *arg = argv[0];
   1902     char *eqp;
   1903     struct userenv *uep, **insp;
   1904 
   1905     if ((eqp = strchr(arg, '=')) == NULL) {
   1906 	ppp_option_error("missing = in name=value: %s", arg);
   1907 	return 0;
   1908     }
   1909     if (eqp == arg) {
   1910 	ppp_option_error("missing variable name: %s", arg);
   1911 	return 0;
   1912     }
   1913     for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
   1914 	int nlen = strlen(uep->ue_name);
   1915 	if (nlen == (eqp - arg) &&
   1916 	    strncmp(arg, uep->ue_name, nlen) == 0)
   1917 	    break;
   1918     }
   1919     /* Ignore attempts by unprivileged users to override privileged sources */
   1920     if (uep != NULL && !privileged_option && uep->ue_priv)
   1921 	return 1;
   1922     /* The name never changes, so allocate it with the structure */
   1923     if (uep == NULL) {
   1924 	uep = malloc(sizeof (*uep) + (eqp-arg));
   1925 	if (uep == NULL) {
   1926 		novm("environment variable");
   1927 		return 1;
   1928 	}
   1929 	strncpy(uep->ue_name, arg, eqp-arg);
   1930 	uep->ue_name[eqp-arg] = '\0';
   1931 	uep->ue_next = NULL;
   1932 	insp = &userenv_list;
   1933 	while (*insp != NULL)
   1934 	    insp = &(*insp)->ue_next;
   1935 	*insp = uep;
   1936     } else {
   1937 	struct userenv *uep2;
   1938 	for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
   1939 	    if (uep2 != uep && !uep2->ue_isset)
   1940 		break;
   1941 	}
   1942 	if (uep2 == NULL && !uep->ue_isset)
   1943 	    find_option("unset")->flags |= OPT_NOPRINT;
   1944 	free(uep->ue_value);
   1945     }
   1946     uep->ue_isset = 1;
   1947     uep->ue_priv = privileged_option;
   1948     uep->ue_source = option_source;
   1949     uep->ue_value = strdup(eqp + 1);
   1950     curopt->flags &= ~OPT_NOPRINT;
   1951     return 1;
   1952 }
   1953 
   1954 static void
   1955 user_setprint(struct option *opt, printer_func printer, void *arg)
   1956 {
   1957     struct userenv *uep, *uepnext;
   1958 
   1959     uepnext = userenv_list;
   1960     while (uepnext != NULL && !uepnext->ue_isset)
   1961 	uepnext = uepnext->ue_next;
   1962     while ((uep = uepnext) != NULL) {
   1963 	uepnext = uep->ue_next;
   1964 	while (uepnext != NULL && !uepnext->ue_isset)
   1965 	    uepnext = uepnext->ue_next;
   1966 	(*printer)(arg, "%s=%s", uep->ue_name, uep->ue_value);
   1967 	if (uepnext != NULL)
   1968 	    (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
   1969 	else
   1970 	    opt->source = uep->ue_source;
   1971     }
   1972 }
   1973 
   1974 static int
   1975 user_unsetenv(char **argv)
   1976 {
   1977     struct userenv *uep, **insp;
   1978     char *arg = argv[0];
   1979 
   1980     if (strchr(arg, '=') != NULL) {
   1981 	ppp_option_error("unexpected = in name: %s", arg);
   1982 	return 0;
   1983     }
   1984     if (*arg == '\0') {
   1985 	ppp_option_error("missing variable name for unset");
   1986 	return 0;
   1987     }
   1988     for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
   1989 	if (strcmp(arg, uep->ue_name) == 0)
   1990 	    break;
   1991     }
   1992     /* Ignore attempts by unprivileged users to override privileged sources */
   1993     if (uep != NULL && !privileged_option && uep->ue_priv)
   1994 	return 1;
   1995     /* The name never changes, so allocate it with the structure */
   1996     if (uep == NULL) {
   1997 	uep = malloc(sizeof (*uep) + strlen(arg));
   1998 	if (uep == NULL) {
   1999 		novm("environment variable");
   2000 		return 1;
   2001 	}
   2002 	strcpy(uep->ue_name, arg);
   2003 	uep->ue_next = NULL;
   2004 	insp = &userenv_list;
   2005 	while (*insp != NULL)
   2006 	    insp = &(*insp)->ue_next;
   2007 	*insp = uep;
   2008     } else {
   2009 	struct userenv *uep2;
   2010 	for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
   2011 	    if (uep2 != uep && uep2->ue_isset)
   2012 		break;
   2013 	}
   2014 	if (uep2 == NULL && uep->ue_isset)
   2015 	    find_option("set")->flags |= OPT_NOPRINT;
   2016 	free(uep->ue_value);
   2017     }
   2018     uep->ue_isset = 0;
   2019     uep->ue_priv = privileged_option;
   2020     uep->ue_source = option_source;
   2021     uep->ue_value = NULL;
   2022     curopt->flags &= ~OPT_NOPRINT;
   2023     return 1;
   2024 }
   2025 
   2026 static void
   2027 user_unsetprint(struct option *opt, printer_func printer, void *arg)
   2028 {
   2029     struct userenv *uep, *uepnext;
   2030 
   2031     uepnext = userenv_list;
   2032     while (uepnext != NULL && uepnext->ue_isset)
   2033 	uepnext = uepnext->ue_next;
   2034     while ((uep = uepnext) != NULL) {
   2035 	uepnext = uep->ue_next;
   2036 	while (uepnext != NULL && uepnext->ue_isset)
   2037 	    uepnext = uepnext->ue_next;
   2038 	(*printer)(arg, "%s", uep->ue_name);
   2039 	if (uepnext != NULL)
   2040 	    (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
   2041 	else
   2042 	    opt->source = uep->ue_source;
   2043     }
   2044 }
   2045