priv option stuff; fix the way name, user options work.
authorPaul Mackerras <paulus@samba.org>
Wed, 28 Aug 1996 06:41:35 +0000 (06:41 +0000)
committerPaul Mackerras <paulus@samba.org>
Wed, 28 Aug 1996 06:41:35 +0000 (06:41 +0000)
pppd/options.c

index 43f8e3df513569020d6fbb140a41e33f33b73fcb..2db98fcbd4e26e1912513743cce323ed143cc987 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: options.c,v 1.32 1996/07/01 01:18:23 paulus Exp $";
+static char rcsid[] = "$Id: options.c,v 1.33 1996/08/28 06:41:35 paulus Exp $";
 #endif
 
 #include <ctype.h>
@@ -102,6 +102,12 @@ 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
  */
@@ -150,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));
@@ -213,7 +222,6 @@ static int setdnsaddr __P((char **));
 static int number_option __P((char *, u_int32_t *, int));
 static int int_option __P((char *, int *));
 static int readable __P((int fd));
-static void option_error __P((char *fmt, ...));
 
 /*
  * Valid arguments.
@@ -279,11 +287,13 @@ 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 */
@@ -291,6 +301,7 @@ static struct cmd {
     {"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 */
@@ -381,11 +392,11 @@ 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)
@@ -396,6 +407,8 @@ parse_args(argc, argv)
     struct cmd *cmdp;
     int ret;
 
+    privileged_option = privileged;
+    option_source = "command line";
     while (argc > 0) {
        arg = *argv++;
        --argc;
@@ -484,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];
@@ -508,6 +523,9 @@ options_from_file(filename, must_exist, check_prot)
        return 0;
     }
 
+    oldpriv = privileged_option;
+    privileged_option = priv;
+    ret = 0;
     while (getword(f, cmd, &newline, filename)) {
        /*
         * First see if it's a command.
@@ -522,34 +540,35 @@ options_from_file(filename, must_exist, check_prot)
                    option_error(
                        "In file %s: too few parameters for option '%s'",
                        filename, cmd);
-                   fclose(f);
-                   return 0;
+                   goto err;
                }
                argv[i] = args[i];
            }
            current_option = cmd;
-           if (!(*cmdp->cmd_func)(argv)) {
-               fclose(f);
-               return 0;
-           }
+           if (!(*cmdp->cmd_func)(argv))
+               goto err;
 
        } else {
            /*
             * Maybe a tty name, speed or IP address?
             */
-           if ((ret = setdevname(cmd, 0)) == 0
-               && (ret = setspeed(cmd)) == 0
-               && (ret = setipaddr(cmd)) == 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);
-               fclose(f);
-               return 0;
+               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;
 }
 
 /*
@@ -573,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;
 }
@@ -601,7 +620,7 @@ options_for_tty()
     for (p = path + strlen(path); *dev != 0; ++dev)
        *p++ = (*dev == '/'? '.': *dev);
     *p = 0;
-    ret = options_from_file(path, 0, 0);
+    ret = options_from_file(path, 0, 0, 1);
     free(path);
     return ret;
 }
@@ -957,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).
  */
@@ -1150,7 +1214,7 @@ static int
 reqpap()
 {
     lcp_wantoptions[0].neg_upap = 1;
-    auth_required = 1;
+    setauth();
     return 1;
 }
 
@@ -1216,7 +1280,7 @@ static int
 reqchap()
 {
     lcp_wantoptions[0].neg_chap = 1;
-    auth_required = 1;
+    setauth();
     return (1);
 }
 
@@ -1276,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);
 }
 
@@ -1290,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);
 }
@@ -1304,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);
 }
 
@@ -1318,10 +1388,14 @@ setmaxconnect(argv)
     int value;
 
     if (!int_option(*argv, &value))
-      return 0;
+       return 0;
     if (value < 0) {
-      option_error("maxconnect time must be positive");
-      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;
@@ -1334,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 != '.')
@@ -1442,10 +1520,12 @@ setdevname(cp, quiet)
        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;
 }
@@ -1480,10 +1560,6 @@ setipaddr(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)) {
@@ -1609,6 +1685,7 @@ static int
 setdemand()
 {
     demand = 1;
+    persist = 1;
     return 1;
 }
 
@@ -1644,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;
@@ -1673,13 +1754,29 @@ 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) {
+    if (!ipcp_allowoptions[0].default_route && !privileged_option) {
        option_error("defaultroute option is disabled");
        return 0;
     }
@@ -1698,7 +1795,7 @@ setnodefaultroute()
 static int
 setproxyarp()
 {
-    if (!ipcp_allowoptions[0].proxy_arp) {
+    if (!ipcp_allowoptions[0].proxy_arp && !privileged_option) {
        option_error("proxyarp option is disabled");
        return 0;
     }
@@ -1721,6 +1818,13 @@ setpersist()
     return 1;
 }
 
+static int
+setnopersist()
+{
+    persist = 0;
+    return 1;
+}
+
 static int
 setdologin()
 {