]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/options.c
priv option stuff; fix the way name, user options work.
[ppp.git] / pppd / options.c
index e29dbb051f0f7b03413cc55716cdee9822e93374..2db98fcbd4e26e1912513743cce323ed143cc987 100644 (file)
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: options.c,v 1.28 1996/01/18 03:22:22 paulus Exp $";
+static char rcsid[] = "$Id: options.c,v 1.33 1996/08/28 06:41:35 paulus Exp $";
 #endif
 
+#include <ctype.h>
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
@@ -34,6 +35,7 @@ static char rcsid[] = "$Id: options.c,v 1.28 1996/01/18 03:22:22 paulus Exp $";
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "pppd.h"
 #include "pathnames.h"
@@ -97,10 +99,20 @@ char        *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
 int    cryptpap;               /* Passwords in pap-secrets are encrypted */
 int    idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
 int    holdoff = 30;           /* # seconds to pause before reconnecting */
+int    refuse_pap = 0;         /* Set to say we won't do PAP */
+int    refuse_chap = 0;        /* Set to say we won't do CHAP */
+
+struct option_info auth_req_info;
+struct option_info connector_info;
+struct option_info disconnector_info;
+struct option_info welcomer_info;
+struct option_info devnam_info;
 
 /*
  * Prototypes
  */
+static int setdevname __P((char *, int));
+static int setipaddr __P((char *));
 static int setdebug __P((void));
 static int setkdebug __P((char **));
 static int setpassive __P((void));
@@ -111,7 +123,9 @@ static int setnovjccomp __P((void));
 static int setvjslots __P((char **));
 static int reqpap __P((void));
 static int nopap __P((void));
+#ifdef OLD_OPTIONS
 static int setupapfile __P((char **));
+#endif
 static int nochap __P((void));
 static int reqchap __P((void));
 static int setspeed __P((char *));
@@ -142,12 +156,15 @@ static int setname __P((char **));
 static int setuser __P((char **));
 static int setremote __P((char **));
 static int setauth __P((void));
+static int setnoauth __P((void));
 static int readfile __P((char **));
+static int callfile __P((char **));
 static int setdefaultroute __P((void));
 static int setnodefaultroute __P((void));
 static int setproxyarp __P((void));
 static int setnoproxyarp __P((void));
 static int setpersist __P((void));
+static int setnopersist __P((void));
 static int setdologin __P((void));
 static int setusehostname __P((void));
 static int setnoipdflt __P((void));
@@ -169,6 +186,7 @@ static int setipcpaccl __P((void));
 static int setipcpaccr __P((void));
 static int setlcpechointv __P((char **));
 static int setlcpechofails __P((char **));
+static int noccp __P((void));
 static int setbsdcomp __P((char **));
 static int setnobsdcomp __P((void));
 static int setdeflate __P((char **));
@@ -202,10 +220,9 @@ static int setdnsaddr __P((char **));
 #endif
 
 static int number_option __P((char *, u_int32_t *, int));
+static int int_option __P((char *, int *));
 static int readable __P((int fd));
 
-void usage();
-
 /*
  * Valid arguments.
  */
@@ -214,23 +231,38 @@ static struct cmd {
     int num_args;
     int (*cmd_func)();
 } cmds[] = {
-    {"-all", 0, noopt},                /* Don't request/allow any options */
+    {"-all", 0, noopt},                /* Don't request/allow any options (useless) */
+    {"noaccomp", 0, noaccomp}, /* Disable Address/Control compression */
     {"-ac", 0, noaccomp},      /* Disable Address/Control compress */
+    {"default-asyncmap", 0, noasyncmap}, /* Disable asyncmap negoatiation */
     {"-am", 0, noasyncmap},    /* Disable asyncmap negotiation */
     {"-as", 1, setasyncmap},   /* set the desired async map */
     {"-d", 0, setdebug},       /* Increase debugging level */
+    {"nodetach", 0, setnodetach}, /* Don't detach from controlling tty */
     {"-detach", 0, setnodetach}, /* don't fork */
+    {"noip", 0, noip},         /* Disable IP and IPCP */
     {"-ip", 0, noip},          /* Disable IP and IPCP */
+    {"nomagic", 0, nomagicnumber}, /* Disable magic number negotiation */
     {"-mn", 0, nomagicnumber}, /* Disable magic number negotiation */
+    {"default-mru", 0, nomru}, /* Disable MRU negotiation */
     {"-mru", 0, nomru},                /* Disable mru negotiation */
     {"-p", 0, setpassive},     /* Set passive mode */
+    {"nopcomp", 0, nopcomp},   /* Disable protocol field compression */
     {"-pc", 0, nopcomp},       /* Disable protocol field compress */
+#if OLD_OPTIONS
     {"+ua", 1, setupapfile},   /* Get PAP user and password from file */
+#endif
+    {"require-pap", 0, reqpap},        /* Require PAP authentication from peer */
     {"+pap", 0, reqpap},       /* Require PAP auth from peer */
+    {"refuse-pap", 0, nopap},  /* Don't agree to auth to peer with PAP */
     {"-pap", 0, nopap},                /* Don't allow UPAP authentication with peer */
+    {"require-chap", 0, reqchap}, /* Require CHAP authentication from peer */
     {"+chap", 0, reqchap},     /* Require CHAP authentication from peer */
+    {"refuse-chap", 0, nochap},        /* Don't agree to auth to peer with CHAP */
     {"-chap", 0, nochap},      /* Don't allow CHAP authentication with peer */
+    {"novj", 0, setnovj},      /* Disable VJ compression */
     {"-vj", 0, setnovj},       /* disable VJ compression */
+    {"novjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
     {"-vjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
     {"vj-max-slots", 1, setvjslots}, /* Set maximum VJ header slots */
     {"asyncmap", 1, setasyncmap}, /* set the desired async map */
@@ -240,6 +272,7 @@ static struct cmd {
     {"welcome", 1, setwelcomer},/* Script to welcome client */
     {"maxconnect", 1, setmaxconnect},  /* specify a maximum connect time */
     {"crtscts", 0, setcrtscts},        /* set h/w flow control */
+    {"nocrtscts", 0, setnocrtscts}, /* clear h/w flow control */
     {"-crtscts", 0, setnocrtscts}, /* clear h/w flow control */
     {"xonxoff", 0, setxonxoff},        /* set s/w flow control */
     {"debug", 0, setdebug},    /* Increase debugging level */
@@ -254,16 +287,21 @@ static struct cmd {
     {"local", 0, setlocal},    /* Don't use modem control lines */
     {"lock", 0, setlock},      /* Lock serial device (with lock file) */
     {"name", 1, setname},      /* Set local name for authentication */
-    {"user", 1, setuser},      /* Set username for PAP auth with peer */
+    {"user", 1, setuser},      /* Set name for auth with peer */
     {"usehostname", 0, setusehostname},        /* Must use hostname for auth. */
     {"remotename", 1, setremote}, /* Set remote name for authentication */
     {"auth", 0, setauth},      /* Require authentication from peer */
+    {"noauth", 0, setnoauth},  /* Don't require peer to authenticate */
     {"file", 1, readfile},     /* Take options from a file */
+    {"call", 1, callfile},     /* Take options from a privileged file */
     {"defaultroute", 0, setdefaultroute}, /* Add default route */
+    {"nodefaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
     {"-defaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
     {"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */
+    {"noproxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
     {"-proxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
     {"persist", 0, setpersist},        /* Keep on reopening connection after close */
+    {"nopersist", 0, setnopersist},  /* Turn off persist option */
     {"demand", 0, setdemand},  /* Dial on demand */
     {"login", 0, setdologin},  /* Use system password database for UPAP */
     {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
@@ -285,11 +323,16 @@ static struct cmd {
     {"chap-interval", 1, setchapintv}, /* Set interval for rechallenge */
     {"ipcp-accept-local", 0, setipcpaccl}, /* Accept peer's address for us */
     {"ipcp-accept-remote", 0, setipcpaccr}, /* Accept peer's address for it */
+    {"noccp", 0, noccp},               /* Disable CCP negotiation */
+    {"-ccp", 0, noccp},                        /* Disable CCP negotiation */
     {"bsdcomp", 1, setbsdcomp},                /* request BSD-Compress */
+    {"nobsdcomp", 0, setnobsdcomp},    /* don't allow BSD-Compress */
     {"-bsdcomp", 0, setnobsdcomp},     /* don't allow BSD-Compress */
     {"deflate", 1, setdeflate},                /* request Deflate compression */
+    {"nodeflate", 0, setnodeflate},    /* don't allow Deflate compression */
     {"-deflate", 0, setnodeflate},     /* don't allow Deflate compression */
     {"predictor1", 0, setpred1comp},   /* request Predictor-1 */
+    {"nopredictor1", 0, setnopred1comp},/* don't allow Predictor-1 */
     {"-predictor1", 0, setnopred1comp},        /* don't allow Predictor-1 */
     {"ipparam", 1, setipparam},                /* set ip script parameter */
     {"papcrypt", 0, setpapcrypt},      /* PAP passwords encrypted */
@@ -311,14 +354,12 @@ static struct cmd {
 #if 0
     {"ipx-compression", 1, setipxcompression}, /* IPX compression number */
 #endif
+    {"ipx",                 0, setipxproto},   /* Enable IPXCP (and IPX) */
+    {"noipx",               0, resetipxproto}, /* Disable IPXCP (and IPX) */
     {"+ipx",                0, setipxproto},   /* Enable IPXCP (and IPX) */
     {"-ipx",                0, resetipxproto}, /* Disable IPXCP (and IPX) */
 #endif /* IPX_CHANGE */
 
-#ifdef _linux_
-    {"idle-disconnect", 1, setidle}, /* seconds for disconnect of idle IP */
-#endif
-
 #ifdef USE_MS_DNS
     {"ms-dns", 1, setdnsaddr}, /* DNS address(es) for the peer's use */
 #endif
@@ -333,7 +374,7 @@ static struct cmd {
 
 static char *usage_string = "\
 pppd version %s patch level %d%s\n\
-Usage: %s [ arguments ], where arguments are:\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\
@@ -350,20 +391,24 @@ Usage: %s [ arguments ], where arguments are:\n\
 See pppd(8) for more options.\n\
 ";
 
+static char *current_option;   /* the name of the option being parsed */
+static int privileged_option;  /* set iff the current option came from root */
+static char *option_source;    /* string saying where the option came from */
 
 /*
- * parse_args - parse a string of arguments, from the command
- * line or from a file.
+ * parse_args - parse a string of arguments from the command line.
  */
 int
 parse_args(argc, argv)
     int argc;
     char **argv;
 {
-    char *arg, *val;
+    char *arg;
     struct cmd *cmdp;
     int ret;
 
+    privileged_option = privileged;
+    option_source = "command line";
     while (argc > 0) {
        arg = *argv++;
        --argc;
@@ -377,9 +422,10 @@ parse_args(argc, argv)
 
        if (cmdp->cmd_name != NULL) {
            if (argc < cmdp->num_args) {
-               fprintf(stderr, "Too few parameters for command %s\n", arg);
+               option_error("too few parameters for option %s", arg);
                return 0;
            }
+           current_option = arg;
            if (!(*cmdp->cmd_func)(argv))
                return 0;
            argc -= cmdp->num_args;
@@ -389,10 +435,10 @@ parse_args(argc, argv)
            /*
             * Maybe a tty name, speed or IP address?
             */
-           if ((ret = setdevname(arg)) == 0
+           if ((ret = setdevname(arg, 0)) == 0
                && (ret = setspeed(arg)) == 0
                && (ret = setipaddr(arg)) == 0) {
-               fprintf(stderr, "%s: unrecognized command\n", arg);
+               option_error("unrecognized option '%s'", arg);
                usage();
                return 0;
            }
@@ -403,14 +449,47 @@ parse_args(argc, argv)
     return 1;
 }
 
+/*
+ * scan_args - scan the command line arguments to get the tty name,
+ * if specified.
+ */
+void
+scan_args(argc, argv)
+    int argc;
+    char **argv;
+{
+    char *arg;
+    struct cmd *cmdp;
+
+    while (argc > 0) {
+       arg = *argv++;
+       --argc;
+
+       /* Skip options and their arguments */
+       for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+           if (!strcmp(arg, cmdp->cmd_name))
+               break;
+
+       if (cmdp->cmd_name != NULL) {
+           argc -= cmdp->num_args;
+           argv += cmdp->num_args;
+           continue;
+       }
+
+       /* Check if it's a tty name and copy it if so */
+       (void) setdevname(arg, 1);
+    }
+}
+
 /*
  * usage - print out a message telling how to use the program.
  */
 void
 usage()
 {
-    fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
-           progname);
+    if (phase == PHASE_INITIALIZE)
+       fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
+               progname);
 }
 
 /*
@@ -418,14 +497,16 @@ usage()
  * and interpret them.
  */
 int
-options_from_file(filename, must_exist, check_prot)
+options_from_file(filename, must_exist, check_prot, priv)
     char *filename;
     int must_exist;
     int check_prot;
+    int priv;
 {
     FILE *f;
     int i, newline, ret;
     struct cmd *cmdp;
+    int oldpriv;
     char *argv[MAXARGS];
     char args[MAXARGS][MAXWORDLEN];
     char cmd[MAXWORDLEN];
@@ -433,15 +514,18 @@ options_from_file(filename, must_exist, check_prot)
     if ((f = fopen(filename, "r")) == NULL) {
        if (!must_exist && errno == ENOENT)
            return 1;
-       perror(filename);
+       option_error("Can't open options file %s: %m", filename);
        return 0;
     }
     if (check_prot && !readable(fileno(f))) {
-       fprintf(stderr, "%s: access denied\n", filename);
+       option_error("Can't open options file %s: access denied", filename);
        fclose(f);
        return 0;
     }
 
+    oldpriv = privileged_option;
+    privileged_option = priv;
+    ret = 0;
     while (getword(f, cmd, &newline, filename)) {
        /*
         * First see if it's a command.
@@ -453,36 +537,38 @@ options_from_file(filename, must_exist, check_prot)
        if (cmdp->cmd_name != NULL) {
            for (i = 0; i < cmdp->num_args; ++i) {
                if (!getword(f, args[i], &newline, filename)) {
-                   fprintf(stderr,
-                           "In file %s: too few parameters for command %s\n",
-                           filename, cmd);
-                   fclose(f);
-                   return 0;
+                   option_error(
+                       "In file %s: too few parameters for option '%s'",
+                       filename, cmd);
+                   goto err;
                }
                argv[i] = args[i];
            }
-           if (!(*cmdp->cmd_func)(argv)) {
-               fclose(f);
-               return 0;
-           }
+           current_option = cmd;
+           if (!(*cmdp->cmd_func)(argv))
+               goto err;
 
        } else {
            /*
             * Maybe a tty name, speed or IP address?
             */
-           if ((ret = setdevname(cmd)) == 0
-               && (ret = setspeed(cmd)) == 0
-               && (ret = setipaddr(cmd)) == 0) {
-               fprintf(stderr, "In file %s: unrecognized command %s\n",
-                       filename, cmd);
-               fclose(f);
-               return 0;
+           if ((i = setdevname(cmd, 0)) == 0
+               && (i = setspeed(cmd)) == 0
+               && (i = setipaddr(cmd)) == 0) {
+               option_error("In file %s: unrecognized option '%s'",
+                            filename, cmd);
+               goto err;
            }
-           if (ret < 0)        /* error */
-               return 0;
+           if (i < 0)          /* error */
+               goto err;
        }
     }
-    return 1;
+    ret = 1;
+
+err:
+    fclose(f);
+    privileged_option = oldpriv;
+    return ret;
 }
 
 /*
@@ -506,7 +592,7 @@ options_from_user()
     strcpy(path, user);
     strcat(path, "/");
     strcat(path, file);
-    ret = options_from_file(path, 0, 1);
+    ret = options_from_file(path, 0, 1, privileged);
     free(path);
     return ret;
 }
@@ -518,26 +604,53 @@ options_from_user()
 int
 options_for_tty()
 {
-    char *dev, *path;
+    char *dev, *path, *p;
     int ret;
 
-    dev = strrchr(devnam, '/');
-    if (dev == NULL)
-       dev = devnam;
-    else
-       ++dev;
+    dev = devnam;
+    if (strncmp(dev, "/dev/", 5) == 0)
+       dev += 5;
     if (strcmp(dev, "tty") == 0)
        return 1;               /* don't look for /etc/ppp/options.tty */
     path = malloc(strlen(_PATH_TTYOPT) + strlen(dev) + 1);
     if (path == NULL)
        novm("tty init file name");
     strcpy(path, _PATH_TTYOPT);
-    strcat(path, dev);
-    ret = options_from_file(path, 0, 0);
+    /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
+    for (p = path + strlen(path); *dev != 0; ++dev)
+       *p++ = (*dev == '/'? '.': *dev);
+    *p = 0;
+    ret = options_from_file(path, 0, 0, 1);
     free(path);
     return ret;
 }
 
+/*
+ * option_error - print a message about an error in an option.
+ * The message is logged, and also sent to
+ * stderr if phase == PHASE_INITIALIZE.
+ */
+void
+option_error __V((char *fmt, ...))
+{
+    va_list args;
+    int n;
+    char buf[256];
+
+#if __STDC__
+    va_start(args, fmt);
+#else
+    char *fmt;
+    va_start(args);
+    fmt = va_arg(args, char *);
+#endif
+    vfmtmsg(buf, sizeof(buf), fmt, args);
+    va_end(args);
+    if (phase == PHASE_INITIALIZE)
+       fprintf(stderr, "%s: %s\n", progname, buf);
+    syslog(LOG_ERR, "%s", buf);
+}
+
 /*
  * readable - check if a file is readable by the real user.
  */
@@ -785,7 +898,7 @@ getword(f, word, newlinep, filename)
        if (ferror(f)) {
            if (errno == 0)
                errno = EIO;
-           perror(filename);
+           option_error("Error reading %s: %m", filename);
            die(1);
        }
        /*
@@ -800,8 +913,8 @@ getword(f, word, newlinep, filename)
      * Warn if the word was too long, and append a terminating null.
      */
     if (len >= MAXWORDLEN) {
-       fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n",
-               progname, filename, word);
+       option_error("warning: word in file %s too long (%.20s...)",
+                    filename, word);
        len = MAXWORDLEN - 1;
     }
     word[len] = 0;
@@ -825,7 +938,8 @@ number_option(str, valp, base)
 
     *valp = strtoul(str, &ptr, base);
     if (ptr == str) {
-       fprintf(stderr, "%s: invalid number: %s\n", progname, str);
+       option_error("invalid numeric parameter '%s' for %s option",
+                    str, current_option);
        return 0;
     }
     return 1;
@@ -852,7 +966,7 @@ int_option(str, valp)
 
 
 /*
- * The following procedures execute commands.
+ * The following procedures parse options.
  */
 
 /*
@@ -862,9 +976,54 @@ static int
 readfile(argv)
     char **argv;
 {
-    return options_from_file(*argv, 1, 1);
+    return options_from_file(*argv, 1, 1, privileged_option);
+}
+
+/*
+ * callfile - take commands from /etc/ppp/peers/<name>.
+ * Name may not contain /../, start with / or ../, or end in /..
+ */
+static int
+callfile(argv)
+    char **argv;
+{
+    char *fname, *arg, *p;
+    int l, ok;
+
+    arg = *argv;
+    ok = 1;
+    if (arg[0] == '/' || arg[0] == 0)
+       ok = 0;
+    else {
+       for (p = arg; *p != 0; ) {
+           if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
+               ok = 0;
+               break;
+           }
+           while (*p != '/' && *p != 0)
+               ++p;
+           if (*p == '/')
+               ++p;
+       }
+    }
+    if (!ok) {
+       option_error("call option value may not contain .. or start with /");
+       return 0;
+    }
+
+    l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
+    if ((fname = (char *) malloc(l)) == NULL)
+       novm("call file name");
+    strcpy(fname, _PATH_PEERFILES);
+    strcat(fname, arg);
+
+    ok = options_from_file(fname, 1, 1, 1);
+
+    free(fname);
+    return ok;
 }
 
+
 /*
  * setdebug - Set debug (command line argument).
  */
@@ -992,8 +1151,8 @@ setmtu(argv)
     if (!number_option(*argv, &mtu, 0))
        return 0;
     if (mtu < MINMRU || mtu > MAXMRU) {
-       fprintf(stderr, "mtu option value of %ld is too %s\n", mtu,
-               (mtu < MINMRU? "small": "large"));
+       option_error("mtu option value of %u is too %s", mtu,
+                    (mtu < MINMRU? "small": "large"));
        return 0;
     }
     lcp_allowoptions[0].mru = mtu;
@@ -1043,7 +1202,7 @@ setsilent()
 static int
 nopap()
 {
-    lcp_allowoptions[0].neg_upap = 0;
+    refuse_pap = 1;
     return (1);
 }
 
@@ -1055,11 +1214,11 @@ static int
 reqpap()
 {
     lcp_wantoptions[0].neg_upap = 1;
-    auth_required = 1;
+    setauth();
     return 1;
 }
 
-
+#if OLD_OPTIONS
 /*
  * setupapfile - specifies UPAP info for authenticating with peer.
  */
@@ -1074,11 +1233,11 @@ setupapfile(argv)
 
     /* open user info file */
     if ((ufile = fopen(*argv, "r")) == NULL) {
-       fprintf(stderr, "unable to open user login data file %s\n", *argv);
+       option_error("unable to open user login data file %s", *argv);
        return 0;
     }
     if (!readable(fileno(ufile))) {
-       fprintf(stderr, "%s: access denied\n", *argv);
+       option_error("%s: access denied", *argv);
        return 0;
     }
     check_access(ufile, *argv);
@@ -1086,7 +1245,7 @@ setupapfile(argv)
     /* get username */
     if (fgets(user, MAXNAMELEN - 1, ufile) == NULL
        || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){
-       fprintf(stderr, "Unable to read user login data file %s.\n", *argv);
+       option_error("unable to read user login data file %s", *argv);
        return 0;
     }
     fclose(ufile);
@@ -1101,7 +1260,7 @@ setupapfile(argv)
 
     return (1);
 }
-
+#endif
 
 /*
  * nochap - Disable CHAP authentication with peer.
@@ -1109,7 +1268,7 @@ setupapfile(argv)
 static int
 nochap()
 {
-    lcp_allowoptions[0].neg_chap = 0;
+    refuse_chap = 1;
     return (1);
 }
 
@@ -1121,7 +1280,7 @@ static int
 reqchap()
 {
     lcp_wantoptions[0].neg_chap = 1;
-    auth_required = 1;
+    setauth();
     return (1);
 }
 
@@ -1162,7 +1321,7 @@ setvjslots(argv)
     if (!int_option(*argv, &value))
        return 0;
     if (value < 2 || value > 16) {
-       fprintf(stderr, "pppd: vj-max-slots value must be between 2 and 16\n");
+       option_error("vj-max-slots value must be between 2 and 16");
        return 0;
     }
     ipcp_wantoptions [0].maxslotindex =
@@ -1181,7 +1340,9 @@ setconnector(argv)
     connector = strdup(*argv);
     if (connector == NULL)
        novm("connect script");
-  
+    connector_info.priv = privileged_option;
+    connector_info.source = option_source;
+
     return (1);
 }
 
@@ -1195,6 +1356,8 @@ setdisconnector(argv)
     disconnector = strdup(*argv);
     if (disconnector == NULL)
        novm("disconnect script");
+    disconnector_info.priv = privileged_option;
+    disconnector_info.source = option_source;
   
     return (1);
 }
@@ -1209,7 +1372,9 @@ setwelcomer(argv)
     welcomer = strdup(*argv);
     if (welcomer == NULL)
        novm("welcome script");
-  
+    welcomer_info.priv = privileged_option;
+    welcomer_info.source = option_source;
+
     return (1);
 }
 
@@ -1223,10 +1388,14 @@ setmaxconnect(argv)
     int value;
 
     if (!int_option(*argv, &value))
-      return 0;
+       return 0;
     if (value < 0) {
-      fprintf(stderr, "pppd: maxconnect time must be positive\n");
-      return 0;
+       option_error("maxconnect time must be positive");
+       return 0;
+    }
+    if (maxconnect > 0 && (value == 0 || value > maxconnect)) {
+       option_error("maxconnect time cannot be increased");
+       return 0;
     }
     maxconnect = value;
     return 1;
@@ -1239,6 +1408,10 @@ static int
 setdomain(argv)
     char **argv;
 {
+    if (!privileged_option) {
+       option_error("using the domain option requires root privilege");
+       return 0;
+    }
     gethostname(hostname, MAXNAMELEN);
     if (**argv != 0) {
        if (**argv != '.')
@@ -1282,12 +1455,13 @@ setescape(argv)
     while (*p) {
        n = strtol(p, &endp, 16);
        if (p == endp) {
-           fprintf(stderr, "%s: invalid hex number: %s\n", progname, p);
+           option_error("escape parameter contains invalid hex number '%s'",
+                        p);
            return 0;
        }
        p = endp;
        if (n < 0 || 0x20 <= n && n <= 0x3F || n == 0x5E || n > 0xFF) {
-           fprintf(stderr, "%s: can't escape character 0x%x\n", progname, n);
+           option_error("can't escape character 0x%x", n);
            ret = 0;
        } else
            xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
@@ -1319,14 +1493,17 @@ setspeed(arg)
 /*
  * setdevname - Set the device name.
  */
-int
-setdevname(cp)
+static int
+setdevname(cp, quiet)
     char *cp;
+    int quiet;
 {
     struct stat statbuf;
-    char *tty, *ttyname();
     char dev[MAXPATHLEN];
-  
+
+    if (*cp == 0)
+       return 0;
+
     if (strncmp("/dev/", cp, 5) != 0) {
        strcpy(dev, "/dev/");
        strncat(dev, cp, MAXPATHLEN - 5);
@@ -1338,15 +1515,17 @@ setdevname(cp)
      * Check if there is a device by this name.
      */
     if (stat(cp, &statbuf) < 0) {
-       if (errno == ENOENT)
+       if (errno == ENOENT || quiet)
            return 0;
-       syslog(LOG_ERR, cp);
+       option_error("Couldn't stat %s: %m", cp);
        return -1;
     }
-  
+
     (void) strncpy(devnam, cp, MAXPATHLEN);
     devnam[MAXPATHLEN-1] = 0;
     default_device = FALSE;
+    devnam_info.priv = privileged_option;
+    devnam_info.source = option_source;
   
     return 1;
 }
@@ -1355,7 +1534,7 @@ setdevname(cp)
 /*
  * setipaddr - Set the IP address
  */
-int
+static int
 setipaddr(arg)
     char *arg;
 {
@@ -1377,18 +1556,14 @@ setipaddr(arg)
        *colon = '\0';
        if ((local = inet_addr(arg)) == -1) {
            if ((hp = gethostbyname(arg)) == NULL) {
-               fprintf(stderr, "unknown host: %s\n", arg);
+               option_error("unknown host: %s", arg);
                return -1;
            } else {
                local = *(u_int32_t *)hp->h_addr;
-               if (our_name[0] == 0) {
-                   strncpy(our_name, arg, MAXNAMELEN);
-                   our_name[MAXNAMELEN-1] = 0;
-               }
            }
        }
        if (bad_ip_adrs(local)) {
-           fprintf(stderr, "bad local IP address %s\n", ip_ntoa(local));
+           option_error("bad local IP address %s", ip_ntoa(local));
            return -1;
        }
        if (local != 0)
@@ -1402,7 +1577,7 @@ setipaddr(arg)
     if (*++colon != '\0') {
        if ((remote = inet_addr(colon)) == -1) {
            if ((hp = gethostbyname(colon)) == NULL) {
-               fprintf(stderr, "unknown host: %s\n", colon);
+               option_error("unknown host: %s", colon);
                return -1;
            } else {
                remote = *(u_int32_t *)hp->h_addr;
@@ -1413,7 +1588,7 @@ setipaddr(arg)
            }
        }
        if (bad_ip_adrs(remote)) {
-           fprintf(stderr, "bad remote IP address %s\n", ip_ntoa(remote));
+           option_error("bad remote IP address %s", ip_ntoa(remote));
            return -1;
        }
        if (remote != 0)
@@ -1467,7 +1642,7 @@ setnetmask(argv)
     u_int32_t mask;
 
     if ((mask = inet_addr(*argv)) == -1 || (netmask & ~mask) != 0) {
-       fprintf(stderr, "Invalid netmask %s\n", *argv);
+       option_error("invalid netmask value '%s'", *argv);
        return 0;
     }
 
@@ -1510,6 +1685,7 @@ static int
 setdemand()
 {
     demand = 1;
+    persist = 1;
     return 1;
 }
 
@@ -1545,6 +1721,10 @@ static int
 setname(argv)
     char **argv;
 {
+    if (!privileged_option) {
+       option_error("using the name option requires root privilege");
+       return 0;
+    }
     if (our_name[0] == 0) {
        strncpy(our_name, argv[0], MAXNAMELEN);
        our_name[MAXNAMELEN-1] = 0;
@@ -1574,14 +1754,30 @@ static int
 setauth()
 {
     auth_required = 1;
+    if (privileged_option > auth_req_info.priv) {
+       auth_req_info.priv = privileged_option;
+       auth_req_info.source = option_source;
+    }
+    return 1;
+}
+
+static int
+setnoauth()
+{
+    if (auth_required && privileged_option < auth_req_info.priv) {
+       option_error("cannot override auth option set by %s",
+                    auth_req_info.source);
+       return 0;
+    }
+    auth_required = 0;
     return 1;
 }
 
 static int
 setdefaultroute()
 {
-    if (!ipcp_allowoptions[0].default_route) {
-       fprintf(stderr, "%s: defaultroute option is disabled\n", progname);
+    if (!ipcp_allowoptions[0].default_route && !privileged_option) {
+       option_error("defaultroute option is disabled");
        return 0;
     }
     ipcp_wantoptions[0].default_route = 1;
@@ -1599,8 +1795,8 @@ setnodefaultroute()
 static int
 setproxyarp()
 {
-    if (!ipcp_allowoptions[0].proxy_arp) {
-       fprintf(stderr, "%s: proxyarp option is disabled\n", progname);
+    if (!ipcp_allowoptions[0].proxy_arp && !privileged_option) {
+       option_error("proxyarp option is disabled");
        return 0;
     }
     ipcp_wantoptions[0].proxy_arp = 1;
@@ -1622,6 +1818,13 @@ setpersist()
     return 1;
 }
 
+static int
+setnopersist()
+{
+    persist = 0;
+    return 1;
+}
+
 static int
 setdologin()
 {
@@ -1748,6 +1951,13 @@ setchapintv(argv)
     return int_option(*argv, &chap[0].chal_interval);
 }
 
+static int
+noccp()
+{
+    ccp_protent.enabled_flag = 0;
+    return 1;
+}
+
 static int
 setbsdcomp(argv)
     char **argv;
@@ -1762,14 +1972,13 @@ setbsdcomp(argv)
        abits = strtol(str, &endp, 0);
     }
     if (*endp != 0 || endp == str) {
-       fprintf(stderr, "%s: invalid argument format for bsdcomp option\n",
-               progname);
+       option_error("invalid parameter '%s' for bsdcomp option", *argv);
        return 0;
     }
     if (rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)
        || abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS)) {
-       fprintf(stderr, "%s: bsdcomp option values must be 0 or %d .. %d\n",
-               progname, BSD_MIN_BITS, BSD_MAX_BITS);
+       option_error("bsdcomp option values must be 0 or %d .. %d",
+                    BSD_MIN_BITS, BSD_MAX_BITS);
        return 0;
     }
     if (rbits > 0) {
@@ -1807,15 +2016,14 @@ setdeflate(argv)
        abits = strtol(str, &endp, 0);
     }
     if (*endp != 0 || endp == str) {
-       fprintf(stderr, "%s: invalid argument format for deflate option\n",
-               progname);
+       option_error("invalid parameter '%s' for deflate option", *argv);
        return 0;
     }
     if (rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE)
        || abits != 0 && (abits < DEFLATE_MIN_SIZE
                          || abits > DEFLATE_MAX_SIZE)) {
-       fprintf(stderr, "%s: deflate option values must be 0 or %d .. %d\n",
-               progname, DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
+       option_error("deflate option values must be 0 or %d .. %d",
+                    DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
        return 0;
     }
     if (rbits > 0) {
@@ -1914,17 +2122,13 @@ setipxname (argv)
     while (*src) {
         ch = *src++;
        if (! isalnum (ch) && ch != '_') {
-           fprintf (stderr,
-                    "%s: IPX router name must be alphanumeric or _\n",
-                    progname);
+           option_error("IPX router name must be alphanumeric or _");
            return 0;
        }
 
        if (count >= sizeof (ipxcp_wantoptions[0].name)) {
-           fprintf (stderr,
-                    "%s: IPX router name is limited to %d characters\n",
-                    progname,
-                    sizeof (ipxcp_wantoptions[0].name) - 1);
+           option_error("IPX router name is limited to %d characters",
+                        sizeof (ipxcp_wantoptions[0].name) - 1);
            return 0;
        }
 
@@ -2035,22 +2239,21 @@ setipxnode(argv)
         return 1;
     }
 
-    fprintf(stderr, "%s: invalid argument for ipx-node option\n",
-           progname);
+    option_error("invalid parameter '%s' for ipx-node option", *argv);
     return 0;
 }
 
 static int
 setipxproto()
 {
-    ipx_enabled = 1;           /* Enable IPXCP and IPX protocol */
+    ipxcp_protent.enabled_flag = 1;
     return 1;
 }
 
 static int
 resetipxproto()
 {
-    ipx_enabled = 0;           /* Disable IPXCP and IPX protocol */
+    ipxcp_protent.enabled_flag = 0;
     return 1;
 }
 #endif /* IPX_CHANGE */
@@ -2070,7 +2273,8 @@ setdnsaddr(argv)
     dns = inet_addr(*argv);
     if (dns == -1) {
        if ((hp = gethostbyname(*argv)) == NULL) {
-           fprintf(stderr, "Invalid DNS Address %s\n", *argv);
+           option_error("invalid address parameter '%s' for ms-dns option",
+                        *argv);
            return 0;
        }
        dns = *(u_int32_t *)hp->h_addr;