]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/options.c
pppd.8: Document netmask option
[ppp.git] / pppd / options.c
index 177488ca681392c3971e432642c7e97a0638a894..227e615c956154b9e14676a0e0f5f1fa58ac41fc 100644 (file)
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: options.c,v 1.102 2008/06/15 06:53:06 paulus Exp $"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
 #include <ctype.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <string.h>
 #include <pwd.h>
-#ifdef PLUGIN
+#include <sys/param.h>
+#include <net/if.h>
+#ifdef PPP_WITH_PLUGINS
 #include <dlfcn.h>
 #endif
 
-#ifdef PPP_FILTER
+#ifdef PPP_WITH_FILTER
 #include <pcap.h>
 /*
  * There have been 3 or 4 different names for this in libpcap CVS, but
 #define DLT_PPP_PPPD   DLT_PPP
 #endif
 #endif
-#endif /* PPP_FILTER */
+#endif /* PPP_WITH_FILTER */
 
-#include "pppd.h"
+#include "pppd-private.h"
+#include "options.h"
+#include "upap.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;
@@ -93,17 +99,18 @@ struct option_value {
 int    debug = 0;              /* Debug flag */
 int    kdebugflag = 0;         /* Tell kernel to print debug messages */
 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 */
 bool   persist = 0;            /* Reopen link after it goes down */
 char   our_name[MAXNAMELEN];   /* Our name for authentication purposes */
 bool   demand = 0;             /* do dial-on-demand */
-char   *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
 int    idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
 int    holdoff = 30;           /* # seconds to pause before reconnecting */
 bool   holdoff_specified;      /* true if a holdoff value has been given */
@@ -114,32 +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   req_ifname[MAXIFNAMELEN];       /* requested interface name */
+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 MAXOCTETS
+#ifdef PPP_WITH_IPV6CP
+char   path_ipv6up[MAXPATHLEN];   /* pathname of ipv6-up script */
+char   path_ipv6down[MAXPATHLEN]; /* pathname of ipv6-down script */
+#endif
+
 unsigned int  maxoctets = 0;    /* default - no limit */
-int maxoctets_dir = 0;       /* default - sum of traffic */
+session_limit_dir_t maxoctets_dir = PPP_OCTETS_DIRECTION_SUM; /* default - sum of traffic */
 int maxoctets_timeout = 1;   /* default 1 second */ 
-#endif
 
 
-extern option_t auth_options[];
+extern struct option 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 */
+static struct option *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 */
@@ -149,44 +162,44 @@ 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 __P((char **));
-static void user_setprint __P((option_t *, printer_func, void *));
-static int user_unsetenv __P((char **));
-static void user_unsetprint __P((option_t *, printer_func, void *));
+static int user_setenv(char **);
+static void user_setprint(struct option *, printer_func, void *);
+static int user_unsetenv(char **);
+static void user_unsetprint(struct option *, 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 struct option *find_option(char *name);
+static int process_option(struct option *, char *, char **);
+static int n_arguments(struct option *);
+static int number_option(char *, u_int32_t *, int);
 
 /*
  * Structure to store extra lists of options.
  */
 struct option_list {
-    option_t *options;
+    struct option *options;
     struct option_list *next;
 };
 
@@ -195,7 +208,7 @@ static struct option_list *extra_options = NULL;
 /*
  * Valid arguments.
  */
-option_t general_options[] = {
+struct option general_options[] = {
     { "debug", o_int, &debug,
       "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
     { "-d", o_int, &debug,
@@ -209,6 +222,11 @@ 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 },
@@ -246,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,
@@ -287,7 +309,7 @@ option_t general_options[] = {
 
     { "ifname", o_string, req_ifname,
       "Set PPP interface name",
-      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXIFNAMELEN },
+      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, IFNAMSIZ },
 
     { "dump", o_bool, &dump_options,
       "Print out option values after parsing all options", 1 },
@@ -309,7 +331,23 @@ option_t general_options[] = {
       "Metric to use for the default route (Linux only; -1 for default behavior)",
       OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 },
 
-#ifdef HAVE_MULTILINK
+    { "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 PPP_WITH_MULTILINK
     { "multilink", o_bool, &multilink,
       "Enable multilink operation", OPT_PRIO | 1 },
     { "mp", o_bool, &multilink,
@@ -321,14 +359,14 @@ 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
+#ifdef PPP_WITH_FILTER
     { "pass-filter", o_special, setpassfilter,
       "set filter for packets to pass", OPT_PRIO },
 
@@ -336,7 +374,6 @@ option_t general_options[] = {
       "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 },
@@ -347,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 }
 };
@@ -356,34 +395,117 @@ option_t general_options[] = {
 #define IMPLEMENTATION ""
 #endif
 
-static char *usage_string = "\
-pppd version %s\n\
-Usage: %s [ options ], where options are:\n\
-       <device>        Communicate over the named device\n\
-       <speed>         Set the baud rate to <speed>\n\
-       <loc>:<rem>     Set the local and/or remote interface IP\n\
-                       addresses.  Either one may be omitted.\n\
-       asyncmap <n>    Set the desired async map to hex <n>\n\
-       auth            Require authentication from peer\n\
-        connect <p>     Invoke shell command <p> to set up the serial line\n\
-       crtscts         Use hardware RTS/CTS flow control\n\
-       defaultroute    Add default route through interface\n\
-       file <f>        Take options from file <f>\n\
-       modem           Use modem control lines\n\
-       mru <n>         Set MRU value to <n> for negotiation\n\
-See pppd(8) for more options.\n\
-";
+int
+ppp_get_max_idle_time()
+{
+    return idle_time_limit;
+}
+
+void
+ppp_set_max_idle_time(unsigned int max)
+{
+    idle_time_limit = max;
+}
+
+int
+ppp_get_max_connect_time()
+{
+    return maxconnect;
+}
+
+void
+ppp_set_max_connect_time(unsigned int max)
+{
+    maxconnect = max;
+}
+
+void
+ppp_set_session_limit(unsigned int octets)
+{
+    maxoctets = octets;
+}
+
+void
+ppp_set_session_limit_dir(unsigned int dir)
+{
+    if (dir > 4)
+        dir = PPP_OCTETS_DIRECTION_SUM;
+    maxoctets_dir = (session_limit_dir_t) dir;
+}
+
+bool
+debug_on()
+{
+    return !!debug;
+}
+
+int
+ppp_get_path(ppp_path_t type, char *buf, size_t bufsz)
+{
+    const char *path;
+
+    if (buf && bufsz > 0) {
+        switch (type) {
+        case PPP_DIR_LOG:
+            path = PPP_PATH_VARLOG;
+            break;
+        case PPP_DIR_RUNTIME:
+            path = PPP_PATH_VARRUN;
+            break;
+#ifdef PPP_WITH_PLUGINS
+        case PPP_DIR_PLUGIN:
+            path = PPP_PATH_PLUGIN;
+            break;
+#endif
+        case PPP_DIR_CONF:
+            path = PPP_PATH_CONFDIR;
+            break;
+        }
+        return strlcpy(buf, path, bufsz);
+    }
+    return -1;
+}
+
+int
+ppp_get_filepath(ppp_path_t type, const char *name, char *buf, size_t bufsz)
+{
+    const char *path;
+
+    if (buf && bufsz > 0) {
+        switch (type) {
+        case PPP_DIR_LOG:
+            path = PPP_PATH_VARLOG;
+            break;
+        case PPP_DIR_RUNTIME:
+            path = PPP_PATH_VARRUN;
+            break;
+#ifdef PPP_WITH_PLUGINS
+        case PPP_DIR_PLUGIN:
+            path = PPP_PATH_PLUGIN;
+            break;
+#endif
+       case PPP_DIR_CONF:
+            path = PPP_PATH_CONFDIR;
+            break;
+        }
+        return slprintf(buf, bufsz, "%s/%s", path, name);
+    }
+    return -1;
+}
+
+bool ppp_persist()
+{
+    return !!persist;
+}
 
 /*
  * 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;
+    struct option *opt;
     int n;
 
     privileged_option = privileged;
@@ -394,13 +516,13 @@ parse_args(argc, argv)
        --argc;
        opt = find_option(arg);
        if (opt == NULL) {
-           option_error("unrecognized option '%s'", arg);
+           ppp_option_error("unrecognized option '%s'", arg);
            usage();
            return 0;
        }
        n = n_arguments(opt);
        if (argc < n) {
-           option_error("too few parameters for option %s", arg);
+           ppp_option_error("too few parameters for option %s", arg);
            return 0;
        }
        if (!process_option(opt, arg, argv))
@@ -416,15 +538,11 @@ 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;
+ppp_options_from_file(char *filename, int must_exist, int check_prot, int priv)
 {
     FILE *f;
     int i, newline, ret, err;
-    option_t *opt;
+    struct option *opt;
     int oldpriv, n;
     char *oldsource;
     uid_t euid;
@@ -434,7 +552,7 @@ options_from_file(filename, must_exist, check_prot, priv)
 
     euid = geteuid();
     if (check_prot && seteuid(getuid()) == -1) {
-       option_error("unable to drop privileges to open %s: %m", filename);
+       ppp_option_error("unable to drop privileges to open %s: %m", filename);
        return 0;
     }
     f = fopen(filename, "r");
@@ -448,7 +566,7 @@ options_from_file(filename, must_exist, check_prot, priv)
                warn("Warning: can't open options file %s: %m", filename);
            return 1;
        }
-       option_error("Can't open options file %s: %m", filename);
+       ppp_option_error("Can't open options file %s: %m", filename);
        return 0;
     }
 
@@ -462,14 +580,14 @@ options_from_file(filename, must_exist, check_prot, priv)
     while (getword(f, cmd, &newline, filename)) {
        opt = find_option(cmd);
        if (opt == NULL) {
-           option_error("In file %s: unrecognized option '%s'",
+           ppp_option_error("In file %s: unrecognized option '%s'",
                         filename, cmd);
            goto err;
        }
        n = n_arguments(opt);
        for (i = 0; i < n; ++i) {
            if (!getword(f, args[i], &newline, filename)) {
-               option_error(
+               ppp_option_error(
                        "In file %s: too few parameters for option '%s'",
                        filename, cmd);
                goto err;
@@ -483,6 +601,7 @@ options_from_file(filename, must_exist, check_prot, priv)
 
 err:
     fclose(f);
+    free(option_source);
     privileged_option = oldpriv;
     option_source = oldsource;
     return ret;
@@ -493,7 +612,7 @@ err:
  * and if so, interpret options from it.
  */
 int
-options_from_user()
+options_from_user(void)
 {
     char *user, *path, *file;
     int ret;
@@ -503,14 +622,14 @@ 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)
        novm("init file name");
     slprintf(path, pl, "%s/%s", user, file);
     option_priority = OPRIO_CFGFILE;
-    ret = options_from_file(path, 0, 1, privileged);
+    ret = ppp_options_from_file(path, 0, 1, privileged);
     free(path);
     return ret;
 }
@@ -524,7 +643,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;
@@ -535,17 +654,17 @@ 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;
-    ret = options_from_file(path, 0, 0, 1);
+    ret = ppp_options_from_file(path, 0, 0, 1);
     free(path);
     return ret;
 }
@@ -554,12 +673,10 @@ 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;
+    struct option *opt;
     int i, n, ret = 0;
     struct wordlist *w0;
 
@@ -570,7 +687,7 @@ options_from_list(w, priv)
     while (w != NULL) {
        opt = find_option(w->word);
        if (opt == NULL) {
-           option_error("In secrets file: unrecognized option '%s'",
+           ppp_option_error("In secrets file: unrecognized option '%s'",
                         w->word);
            goto err;
        }
@@ -579,7 +696,7 @@ options_from_list(w, priv)
        for (i = 0; i < n; ++i) {
            w = w->next;
            if (w == NULL) {
-               option_error(
+               ppp_option_error(
                        "In secrets file: too few parameters for option '%s'",
                        w0->word);
                goto err;
@@ -597,21 +714,18 @@ err:
 }
 
 /*
- * match_option - see if this option matches an option_t structure.
+ * match_option - see if this option matches an option structure.
  */
 static int
-match_option(name, opt, dowild)
-    char *name;
-    option_t *opt;
-    int dowild;
+match_option(char *name, struct option *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);
 }
 
@@ -620,11 +734,10 @@ match_option(name, opt, dowild)
  * looking for an entry with the given name.
  * This could be optimized by using a hash table.
  */
-static option_t *
-find_option(name)
-    const char *name;
+static struct option *
+find_option(char *name)
 {
-       option_t *opt;
+       struct option *opt;
        struct option_list *list;
        int i, dowild;
 
@@ -655,19 +768,16 @@ 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(struct option *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;
+    struct option *mainopt = opt;
 
     current_option = opt->name;
     if ((opt->flags & OPT_PRIVFIX) && privileged_option)
@@ -678,7 +788,7 @@ process_option(opt, cmd, argv)
        if (prio < mainopt->priority) {
            /* new value doesn't override old */
            if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
-               option_error("%s%s set in %s cannot be overridden\n",
+               ppp_option_error("%s%s set in %s cannot be overridden\n",
                             opt->name, optopt, mainopt->source);
                return 0;
            }
@@ -689,22 +799,22 @@ process_option(opt, cmd, argv)
                 opt->name, optopt, option_source);
     }
 
-    if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
-       option_error("%s%s cannot be changed after initialization",
+    if ((opt->flags & OPT_INITONLY) && !in_phase(PHASE_INITIALIZE)) {
+       ppp_option_error("%s%s cannot be changed after initialization",
                     opt->name, optopt);
        return 0;
     }
     if ((opt->flags & OPT_PRIV) && !privileged_option) {
-       option_error("using the %s%s requires root privilege",
+       ppp_option_error("using the %s%s requires root privilege",
                     opt->name, optopt);
        return 0;
     }
     if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
-       option_error("%s%s is disabled", opt->name, optopt);
+       ppp_option_error("%s%s is disabled", opt->name, optopt);
        return 0;
     }
     if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
-       option_error("the %s%s may not be changed in %s",
+       ppp_option_error("the %s%s may not be changed in %s",
                     opt->name, optopt, option_source);
        return 0;
     }
@@ -726,7 +836,7 @@ process_option(opt, cmd, argv)
     case o_int:
        iv = 0;
        if ((opt->flags & OPT_NOARG) == 0) {
-           if (!int_option(*argv, &iv))
+           if (!ppp_int_option(*argv, &iv))
                return 0;
            if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
                 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
@@ -734,15 +844,15 @@ process_option(opt, cmd, argv)
                char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
                switch (opt->flags & OPT_LIMITS) {
                case OPT_LLIMIT:
-                   option_error("%s value must be%s >= %d",
+                   ppp_option_error("%s value must be%s >= %d",
                                 opt->name, zok, opt->lower_limit);
                    break;
                case OPT_ULIMIT:
-                   option_error("%s value must be%s <= %d",
+                   ppp_option_error("%s value must be%s <= %d",
                                 opt->name, zok, opt->upper_limit);
                    break;
                case OPT_LIMITS:
-                   option_error("%s value must be%s between %d and %d",
+                   ppp_option_error("%s value must be%s between %d and %d",
                                opt->name, zok, opt->lower_limit, opt->upper_limit);
                    break;
                }
@@ -759,7 +869,7 @@ process_option(opt, cmd, argv)
            int oldv = *(int *)(opt->addr);
            if ((opt->flags & OPT_ZEROINF) ?
                (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
-               option_error("%s value cannot be increased", opt->name);
+               ppp_option_error("%s value cannot be increased", opt->name);
                return 0;
            }
        }
@@ -794,11 +904,16 @@ process_option(opt, cmd, argv)
                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;
@@ -822,7 +937,7 @@ process_option(opt, cmd, argv)
        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;
@@ -849,12 +964,9 @@ 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;
+       struct option *opt;
 
        opt = find_option(option);
        if (opt == NULL)
@@ -873,8 +985,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(struct option *opt)
 {
        return (opt->type == o_bool || opt->type == o_special_noarg
                || (opt->flags & OPT_NOARG))? 0: 1;
@@ -884,8 +995,7 @@ n_arguments(opt)
  * add_options - add a list of options to the set we grok.
  */
 void
-add_options(opt)
-    option_t *opt;
+ppp_add_options(struct option *opt)
 {
     struct option_list *list;
 
@@ -901,7 +1011,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);
@@ -911,10 +1021,7 @@ check_options()
  * print_option - print out an option and its value
  */
 static void
-print_option(opt, mainopt, printer, arg)
-    option_t *opt, *mainopt;
-    printer_func printer;
-    void *arg;
+print_option(struct option *opt, struct option *mainopt, printer_func printer, void *arg)
 {
        int i, v;
        char *p;
@@ -976,15 +1083,15 @@ print_option(opt, mainopt, printer, arg)
                        printer(arg, " ");
                }
                if (opt->flags & OPT_A2PRINTER) {
-                       void (*oprt) __P((option_t *, printer_func, void *));
-                       oprt = (void (*) __P((option_t *, printer_func,
-                                        void *)))opt->addr2;
+                       void (*oprt)(struct option *, printer_func, void *);
+                       oprt = (void (*)(struct option *, 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;
 
@@ -1013,10 +1120,7 @@ print_option(opt, mainopt, printer, arg)
  * array of options.
  */
 static void
-print_option_list(opt, printer, arg)
-    option_t *opt;
-    printer_func printer;
-    void *arg;
+print_option_list(struct option *opt, printer_func printer, void *arg)
 {
        while (opt->name != NULL) {
                if (opt->priority != OPRIO_DEFAULT
@@ -1032,9 +1136,7 @@ print_option_list(opt, printer, arg)
  * print_options - print out what options are in effect.
  */
 void
-print_options(printer, arg)
-    printer_func printer;
-    void *arg;
+print_options(printer_func printer, void *arg)
 {
        struct option_list *list;
        int i;
@@ -1053,20 +1155,44 @@ 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 (in_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 <https://opensource.org/licenses/BSD-3-Clause>\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, "   <device>        Communicate over the named device\n");
+        fprintf(fp, "   <speed>         Set the baud rate to <speed>\n");
+        fprintf(fp, "   <loc>:<rem>     Set the local and/or remote interface IP\n");
+        fprintf(fp, "                   addresses.  Either one may be omitted.\n");
+        fprintf(fp, "   asyncmap <n>    Set the desired async map to hex <n>\n");
+        fprintf(fp, "   auth            Require authentication from peer\n");
+        fprintf(fp, "   connect <p>     Invoke shell command <p> 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 <f>        Take options from file <f>\n");
+        fprintf(fp, "   modem           Use modem control lines\n");
+        fprintf(fp, "   mru <n>         Set MRU value to <n> 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) {
+    if (in_phase(PHASE_INITIALIZE)) {
        usage();
        exit(0);
     }
@@ -1077,37 +1203,85 @@ 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);
+    if (in_phase(PHASE_INITIALIZE)) {
+       fprintf(stdout, "pppd version %s\n", VERSION);
        exit(0);
     }
     return 0;
 }
 
 /*
- * option_error - print a message about an error in an option.
+ * Print a set of options including the name of the group of options
+ */
+static void
+showopts_list(FILE *fp, const char *title, struct option *list, ...)
+{
+       struct option *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);
+        }
+    }
+}
+
+/*
+ * ppp_option_error - print a message about an error in an option.
  * The message is logged, and also sent to
- * stderr if phase == PHASE_INITIALIZE.
+ * stderr if in_phase(PHASE_INITIALIZE).
  */
 void
-option_error __V((char *fmt, ...))
+ppp_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)
+    if (in_phase(PHASE_INITIALIZE))
        fprintf(stderr, "%s: %s\n", progname, buf);
     syslog(LOG_ERR, "%s", buf);
 }
@@ -1117,8 +1291,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;
@@ -1147,11 +1320,7 @@ readable(fd)
  * \<newline> 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;
@@ -1350,6 +1519,7 @@ getword(f, word, newlinep, filename)
 
        c = getc(f);
     }
+    word[MAXWORDLEN-1] = 0;    /* make sure word is null-terminated */
 
     /*
      * End of the word: check for errors.
@@ -1358,7 +1528,7 @@ getword(f, word, newlinep, filename)
        if (ferror(f)) {
            if (errno == 0)
                errno = EIO;
-           option_error("Error reading %s: %m", filename);
+           ppp_option_error("Error reading %s: %m", filename);
            die(1);
        }
        /*
@@ -1368,7 +1538,7 @@ getword(f, word, newlinep, filename)
        if (len == 0)
            return 0;
        if (quoted)
-           option_error("warning: quoted word runs to end of file (%.20s...)",
+           ppp_option_error("warning: quoted word runs to end of file (%.20s...)",
                         filename, word);
     }
 
@@ -1376,7 +1546,7 @@ getword(f, word, newlinep, filename)
      * Warn if the word was too long, and append a terminating null.
      */
     if (len >= MAXWORDLEN) {
-       option_error("warning: word in file %s too long (%.20s...)",
+       ppp_option_error("warning: word in file %s too long (%.20s...)",
                     filename, word);
        len = MAXWORDLEN - 1;
     }
@@ -1392,16 +1562,13 @@ 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;
 
     *valp = strtoul(str, &ptr, base);
     if (ptr == str) {
-       option_error("invalid numeric parameter '%s' for %s option",
+       ppp_option_error("invalid numeric parameter '%s' for %s option",
                     str, current_option);
        return 0;
     }
@@ -1415,9 +1582,7 @@ number_option(str, valp, base)
  * if there is an error.
  */
 int
-int_option(str, valp)
-    char *str;
-    int *valp;
+ppp_int_option(char *str, int *valp)
 {
     u_int32_t v;
 
@@ -1436,10 +1601,9 @@ 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);
+    return ppp_options_from_file(*argv, 1, 1, privileged_option);
 }
 
 /*
@@ -1447,8 +1611,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;
@@ -1470,35 +1633,35 @@ callfile(argv)
        }
     }
     if (!ok) {
-       option_error("call option value may not contain .. or start with /");
+       ppp_option_error("call option value may not contain .. or start with /");
        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);
+    ppp_script_setenv("CALL_FILE", arg, 0);
 
-    ok = options_from_file(fname, 1, 1, 1);
+    ok = ppp_options_from_file(fname, 1, 1, 1);
 
     free(fname);
     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 = 1;
 
     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",
+       ppp_option_error("error in pass-filter expression: %s\n",
                     pcap_geterr(pc));
        ret = 0;
     }
@@ -1511,15 +1674,14 @@ setpassfilter(argv)
  * setactivefilter - Set the active filter for packets
  */
 static int
-setactivefilter(argv)
-    char **argv;
+setactivefilter(char **argv)
 {
     pcap_t *pc;
     int ret = 1;
 
     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",
+       ppp_option_error("error in active-filter expression: %s\n",
                     pcap_geterr(pc));
        ret = 0;
     }
@@ -1533,8 +1695,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) {
@@ -1548,15 +1709,14 @@ setdomain(argv)
 }
 
 static int
-setlogfile(argv)
-    char **argv;
+setlogfile(char **argv)
 {
     int fd, err;
     uid_t euid;
 
     euid = geteuid();
     if (!privileged_option && seteuid(getuid()) == -1) {
-       option_error("unable to drop permissions to open %s: %m", *argv);
+       ppp_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);
@@ -1567,7 +1727,7 @@ setlogfile(argv)
        fatal("unable to regain privileges: %m");
     if (fd < 0) {
        errno = err;
-       option_error("Can't open log file %s: %m", *argv);
+       ppp_option_error("Can't open log file %s: %m", *argv);
        return 0;
     }
     strlcpy(logfile_name, *argv, sizeof(logfile_name));
@@ -1579,10 +1739,8 @@ setlogfile(argv)
     return 1;
 }
 
-#ifdef MAXOCTETS
 static int
-setmodir(argv)
-    char **argv;
+setmodir(char **argv)
 {
     if(*argv == NULL)
        return 0;
@@ -1597,22 +1755,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)
@@ -1625,25 +1781,27 @@ loadplugin(argv)
     if (handle == 0) {
        err = dlerror();
        if (err != 0)
-           option_error("%s", err);
-       option_error("Couldn't load plugin %s", arg);
+           ppp_option_error("%s", err);
+       ppp_option_error("Couldn't load plugin %s", arg);
        goto err;
     }
     init = (void (*)(void))dlsym(handle, "plugin_init");
     if (init == 0) {
-       option_error("%s has no initialization entry point", arg);
+       ppp_option_error("%s has no initialization entry point", arg);
        goto errclose;
     }
     vers = (const char *) dlsym(handle, "pppd_version");
     if (vers == 0) {
        warn("Warning: plugin %s has no version information", arg);
     } else if (strcmp(vers, VERSION) != 0) {
-       option_error("Plugin %s is for pppd version %s, this is %s",
+       ppp_option_error("Plugin %s is for pppd version %s, this is %s",
                     arg, vers, VERSION);
        goto errclose;
     }
     info("Plugin %s loaded.", arg);
     (*init)();
+    if (path != arg)
+       free(path);
     return 1;
 
  errclose:
@@ -1653,25 +1811,24 @@ loadplugin(argv)
        free(path);
     return 0;
 }
-#endif /* PLUGIN */
+#endif /* PPP_WITH_PLUGINS */
 
 /*
  * Set an environment variable specified by the user.
  */
 static int
-user_setenv(argv)
-    char **argv;
+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);
+       ppp_option_error("missing = in name=value: %s", arg);
        return 0;
     }
     if (eqp == arg) {
-       option_error("missing variable name: %s", arg);
+       ppp_option_error("missing variable name: %s", arg);
        return 0;
     }
     for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
@@ -1686,6 +1843,10 @@ user_setenv(argv)
     /* The name never changes, so allocate it with the structure */
     if (uep == NULL) {
        uep = malloc(sizeof (*uep) + (eqp-arg));
+       if (uep == NULL) {
+               novm("environment variable");
+               return 1;
+       }
        strncpy(uep->ue_name, arg, eqp-arg);
        uep->ue_name[eqp-arg] = '\0';
        uep->ue_next = NULL;
@@ -1712,10 +1873,7 @@ user_setenv(argv)
 }
 
 static void
-user_setprint(opt, printer, arg)
-    option_t *opt;
-    printer_func printer;
-    void *arg;
+user_setprint(struct option *opt, printer_func printer, void *arg)
 {
     struct userenv *uep, *uepnext;
 
@@ -1735,18 +1893,17 @@ user_setprint(opt, printer, arg)
 }
 
 static int
-user_unsetenv(argv)
-    char **argv;
+user_unsetenv(char **argv)
 {
     struct userenv *uep, **insp;
     char *arg = argv[0];
 
     if (strchr(arg, '=') != NULL) {
-       option_error("unexpected = in name: %s", arg);
+       ppp_option_error("unexpected = in name: %s", arg);
        return 0;
     }
-    if (arg == '\0') {
-       option_error("missing variable name for unset");
+    if (*arg == '\0') {
+       ppp_option_error("missing variable name for unset");
        return 0;
     }
     for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
@@ -1759,6 +1916,10 @@ user_unsetenv(argv)
     /* The name never changes, so allocate it with the structure */
     if (uep == NULL) {
        uep = malloc(sizeof (*uep) + strlen(arg));
+       if (uep == NULL) {
+               novm("environment variable");
+               return 1;
+       }
        strcpy(uep->ue_name, arg);
        uep->ue_next = NULL;
        insp = &userenv_list;
@@ -1784,10 +1945,7 @@ user_unsetenv(argv)
 }
 
 static void
-user_unsetprint(opt, printer, arg)
-    option_t *opt;
-    printer_func printer;
-    void *arg;
+user_unsetprint(struct option *opt, printer_func printer, void *arg)
 {
     struct userenv *uep, *uepnext;