]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
syslog -> notice/error/etc.
[ppp.git] / pppd / auth.c
index 7b1ba5ccdd9d4d40d7bb40e3ceb9cf3eac0018c7..3b0e24341292050657c63d99d37d70aab0989c9b 100644 (file)
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: auth.c,v 1.38 1998/11/02 10:55:19 paulus Exp $";
+static char rcsid[] = "$Id: auth.c,v 1.46 1999/03/16 03:15:12 paulus Exp $";
 #endif
 
 #include <stdio.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
 #include <pwd.h>
+#include <grp.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -81,7 +81,7 @@ static char rcsid[] = "$Id: auth.c,v 1.38 1998/11/02 10:55:19 paulus Exp $";
 /* Used for storing a sequence of words.  Usually malloced. */
 struct wordlist {
     struct wordlist    *next;
-    char               word[1];
+    char               *word;
 };
 
 /* Bits in scan_authfile return value */
@@ -104,6 +104,7 @@ static int logged_in;
 
 /* Set if we have run the /etc/ppp/auth-up script. */
 static int did_authup;
+static pid_t authup_pid;       /* process ID of auth-up/down script */
 
 /* List of addresses which the peer may use. */
 static struct wordlist *addresses[NUM_PPP];
@@ -117,6 +118,17 @@ static int num_np_up;
 /* Set if we got the contents of passwd[] from the pap-secrets file. */
 static int passwd_from_file;
 
+/*
+ * Option variables.
+ */
+bool uselogin = 0;             /* Use /etc/passwd for checking PAP */
+bool cryptpap = 0;             /* Passwords in pap-secrets are encrypted */
+bool refuse_pap = 0;           /* Don't wanna auth. ourselves with PAP */
+bool refuse_chap = 0;          /* Don't wanna auth. ourselves with CHAP */
+bool usehostname = 0;          /* Use hostname for our_name */
+bool auth_required = 0;                /* Always require authentication from peer */
+bool allow_any_ip = 0;         /* Allow peer to use any IP address */
+
 /* Bits in auth_pending[] */
 #define PAP_WITHPEER   1
 #define PAP_PEER       2
@@ -142,6 +154,125 @@ static int  scan_authfile __P((FILE *, char *, char *, u_int32_t, char *,
 static void free_wordlist __P((struct wordlist *));
 static void auth_script __P((char *));
 static void set_allowed_addrs __P((int, struct wordlist *));
+static int  setupapfile __P((char **));
+static int  privgroup __P((char **));
+
+/*
+ * Authentication-related options.
+ */
+option_t auth_options[] = {
+    { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
+      "Require PAP authentication from peer", 1, &auth_required },
+    { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
+      "Require PAP authentication from peer", 1, &auth_required },
+    { "refuse-pap", o_bool, &refuse_pap,
+      "Don't agree to auth to peer with PAP", 1 },
+    { "-pap", o_bool, &refuse_pap,
+      "Don't allow PAP authentication with peer", 1 },
+    { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require CHAP authentication from peer", 1, &auth_required },
+    { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require CHAP authentication from peer", 1, &auth_required },
+    { "refuse-chap", o_bool, &refuse_chap,
+      "Don't agree to auth to peer with CHAP", 1 },
+    { "-chap", o_bool, &refuse_chap,
+      "Don't allow CHAP authentication with peer", 1 },
+    { "name", o_string, our_name,
+      "Set local name for authentication",
+      OPT_PRIV|OPT_STATIC, NULL, MAXNAMELEN },
+    { "user", o_string, user,
+      "Set name for auth with peer", OPT_STATIC, NULL, MAXNAMELEN },
+    { "usehostname", o_bool, &usehostname,
+      "Must use hostname for authentication", 1 },
+    { "remotename", o_string, remote_name,
+      "Set remote name for authentication", OPT_STATIC, NULL, MAXNAMELEN },
+    { "auth", o_bool, &auth_required,
+      "Require authentication from peer", 1 },
+    { "noauth", o_bool, &auth_required,
+      "Don't require peer to authenticate", OPT_PRIV, &allow_any_ip },
+    {  "login", o_bool, &uselogin,
+      "Use system password database for PAP", 1 },
+    { "papcrypt", o_bool, &cryptpap,
+      "PAP passwords are encrypted", 1 },
+    { "+ua", o_special, setupapfile,
+      "Get PAP user and password from file" },
+    { "privgroup", o_special, privgroup,
+      "Allow group members to use privileged options", OPT_PRIV },
+    { NULL }
+};
+
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(argv)
+    char **argv;
+{
+    FILE * ufile;
+    int l;
+
+    lcp_allowoptions[0].neg_upap = 1;
+
+    /* open user info file */
+    seteuid(getuid());
+    ufile = fopen(*argv, "r");
+    seteuid(0);
+    if (ufile == NULL) {
+       option_error("unable to open user login data file %s", *argv);
+       return 0;
+    }
+#if 0  /* check done by setting effective UID above */
+    if (!readable(fileno(ufile))) {
+       option_error("%s: access denied", *argv);
+       return 0;
+    }
+#endif
+    check_access(ufile, *argv);
+
+    /* get username */
+    if (fgets(user, MAXNAMELEN - 1, ufile) == NULL
+       || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){
+       option_error("unable to read user login data file %s", *argv);
+       return 0;
+    }
+    fclose(ufile);
+
+    /* get rid of newlines */
+    l = strlen(user);
+    if (l > 0 && user[l-1] == '\n')
+       user[l-1] = 0;
+    l = strlen(passwd);
+    if (l > 0 && passwd[l-1] == '\n')
+       passwd[l-1] = 0;
+
+    return (1);
+}
+
+
+/*
+ * privgroup - allow members of the group to have privileged access.
+ */
+static int
+privgroup(argv)
+    char **argv;
+{
+    struct group *g;
+    int i;
+
+    g = getgrnam(*argv);
+    if (g == 0) {
+       option_error("group %s is unknown", *argv);
+       return 0;
+    }
+    for (i = 0; i < ngroups; ++i) {
+       if (groups[i] == g->gr_gid) {
+           privileged = 1;
+           break;
+       }
+    }
+    return 1;
+}
+
 
 /*
  * An Open on LCP has requested a change from Dead to Establish phase.
@@ -166,7 +297,7 @@ link_terminated(unit)
     if (logged_in)
        plogout();
     phase = PHASE_DEAD;
-    syslog(LOG_NOTICE, "Connection terminated.");
+    notice("Connection terminated.");
 }
 
 /*
@@ -227,7 +358,7 @@ link_established(unit)
         * of "" and a password of "".  If that's not OK, boot it out.
         */
        if (!wo->neg_upap || !null_login(unit)) {
-           syslog(LOG_WARNING, "peer refused to authenticate");
+           warn("peer refused to authenticate: terminating link");
            lcp_close(unit, "peer refused to authenticate");
            return;
        }
@@ -249,7 +380,7 @@ link_established(unit)
        if (passwd[0] == 0) {
            passwd_from_file = 1;
            if (!get_pap_passwd(passwd))
-               syslog(LOG_ERR, "No secret found for PAP login");
+               error("No secret found for PAP login");
        }
        upap_authwithpeer(unit, user, passwd);
        auth |= PAP_WITHPEER;
@@ -340,8 +471,7 @@ auth_peer_success(unit, protocol, name, namelen)
        bit = PAP_PEER;
        break;
     default:
-       syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
-              protocol);
+       warn("auth_peer_success: unknown protocol %x", protocol);
        return;
     }
 
@@ -397,8 +527,7 @@ auth_withpeer_success(unit, protocol)
        bit = PAP_WITHPEER;
        break;
     default:
-       syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
-              protocol);
+       warn("auth_withpeer_success: unknown protocol %x", protocol);
        bit = 0;
     }
 
@@ -437,7 +566,7 @@ np_up(unit, proto)
        /*
         * Detach now, if the updetach option was given.
         */
-       if (nodetach == -1)
+       if (updetach && !nodetach)
            detach();
     }
     ++num_np_up;
@@ -484,7 +613,7 @@ check_idle(arg)
     itime = MIN(idle.xmit_idle, idle.recv_idle);
     if (itime >= idle_time_limit) {
        /* link is idle: shut it down. */
-       syslog(LOG_INFO, "Terminating connection due to lack of activity.");
+       info("Terminating connection due to lack of activity.");
        lcp_close(0, "Link inactive");
     } else {
        TIMEOUT(check_idle, NULL, idle_time_limit - itime);
@@ -498,7 +627,7 @@ static void
 connect_time_expired(arg)
     void *arg;
 {
-    syslog(LOG_INFO, "Connect time expired");
+    info("Connect time expired");
     lcp_close(0, "Connect time expired");      /* Close connection */
 }
 
@@ -515,16 +644,28 @@ auth_check_options()
 
     /* Default our_name to hostname, and user to our_name */
     if (our_name[0] == 0 || usehostname)
-       strcpy(our_name, hostname);
+       strlcpy(our_name, sizeof(our_name), hostname);
     if (user[0] == 0)
-       strcpy(user, our_name);
+       strlcpy(user, sizeof(user), our_name);
 
     /* If authentication is required, ask peer for CHAP or PAP. */
-    if (auth_required && !wo->neg_chap && !wo->neg_upap) {
-       wo->neg_chap = 1;
-       wo->neg_upap = 1;
+    if (auth_required) {
+       if (!wo->neg_chap && !wo->neg_upap) {
+           wo->neg_chap = 1;
+           wo->neg_upap = 1;
+       }
+    } else {
+       wo->neg_chap = 0;
+       wo->neg_upap = 0;
     }
 
+    /*
+     * If we have a default route, require the peer to authenticate
+     * unless the noauth option was given.
+     */
+    if (!auth_required && !allow_any_ip && have_route_to(0))
+       auth_required = 1;
+
     /*
      * Check whether we have appropriate secrets to use
      * to authenticate the peer.
@@ -544,24 +685,6 @@ auth_check_options()
                         remote_name, our_name);
        exit(1);
     }
-
-    /*
-     * Check whether the user tried to override certain values
-     * set by root.
-     */
-    if (!auth_required && auth_req_info.priv > 0) {
-       if (!default_device && devnam_info.priv == 0) {
-           option_error("can't override device name when noauth option used");
-           exit(1);
-       }
-       if ((connector != NULL && connector_info.priv == 0)
-           || (disconnector != NULL && disconnector_info.priv == 0)
-           || (welcomer != NULL && welcomer_info.priv == 0)) {
-           option_error("can't override connect, disconnect or welcome");
-           option_error("option values when noauth option used");
-           exit(1);
-       }
-    }
 }
 
 /*
@@ -640,7 +763,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
     ret = UPAP_AUTHACK;
     f = fopen(filename, "r");
     if (f == NULL) {
-       syslog(LOG_ERR, "Can't open PAP password file %s: %m", filename);
+       error("Can't open PAP password file %s: %m", filename);
        ret = UPAP_AUTHNAK;
 
     } else {
@@ -650,7 +773,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
                          secret, &addrs, filename) < 0
            || (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0)
                && strcmp(crypt(passwd, secret), secret) != 0)) {
-           syslog(LOG_WARNING, "PAP authentication failure for %s", user);
+           warn("PAP authentication failure for %s", user);
            ret = UPAP_AUTHNAK;
        }
        fclose(f);
@@ -659,7 +782,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
     if (uselogin && ret == UPAP_AUTHACK) {
        ret = plogin(user, passwd, msg, msglen);
        if (ret == UPAP_AUTHNAK) {
-           syslog(LOG_WARNING, "PAP login failure for %s", user);
+           warn("PAP login failure for %s", user);
        }
     }
 
@@ -673,8 +796,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
         * On 10'th, drop the connection.
         */
        if (attempts++ >= 10) {
-           syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s",
-                  attempts, devnam, user);
+           warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user);
            quit();
        }
        if (attempts > 3)
@@ -853,7 +975,7 @@ plogin(user, passwd, msg, msglen)
            || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
                && spwd->sp_lstchg >= 0
                && now >= spwd->sp_lstchg + spwd->sp_max)) {
-           syslog(LOG_WARNING, "Password for %s has expired", user);
+           warn("Password for %s has expired", user);
            return (UPAP_AUTHNAK);
        }
        pw->pw_passwd = spwd->sp_pwdp;
@@ -891,7 +1013,7 @@ plogin(user, passwd, msg, msglen)
                (void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
                memset((void *)&ll, 0, sizeof(ll));
                (void)time(&ll.ll_time);
-               (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+               (void)strlcpy(ll.ll_line, sizeof(ll.ll_line), tty);
                (void)write(fd, (char *)&ll, sizeof(ll));
                (void)close(fd);
            }
@@ -900,7 +1022,7 @@ plogin(user, passwd, msg, msglen)
 
 #endif /* #ifdef USE_PAM */
 
-    syslog(LOG_INFO, "user %s logged in", user);
+    info("user %s logged in", user);
     logged_in = TRUE;
 
     return (UPAP_AUTHACK);
@@ -988,6 +1110,7 @@ null_login(unit)
  * get_pap_passwd - get a password for authenticating ourselves with
  * our peer using PAP.  Returns 1 on success, 0 if no suitable password
  * could be found.
+ * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null).
  */
 static int
 get_pap_passwd(passwd)
@@ -1011,10 +1134,8 @@ get_pap_passwd(passwd)
     fclose(f);
     if (ret < 0)
        return 0;
-    if (passwd != NULL) {
-       strncpy(passwd, secret, MAXSECRETLEN);
-       passwd[MAXSECRETLEN-1] = 0;
-    }
+    if (passwd != NULL)
+       strlcpy(passwd, MAXSECRETLEN, secret);
     BZERO(secret, sizeof(secret));
     return 1;
 }
@@ -1109,7 +1230,7 @@ get_secret(unit, client, server, secret, secret_len, save_addrs)
 
     f = fopen(filename, "r");
     if (f == NULL) {
-       syslog(LOG_ERR, "Can't open chap secret file %s: %m", filename);
+       error("Can't open chap secret file %s: %m", filename);
        return 0;
     }
     check_access(f, filename);
@@ -1125,7 +1246,7 @@ get_secret(unit, client, server, secret, secret_len, save_addrs)
 
     len = strlen(secbuf);
     if (len > MAXSECRETLEN) {
-       syslog(LOG_ERR, "Secret for %s on %s is too long", client, server);
+       error("Secret for %s on %s is too long", client, server);
        len = MAXSECRETLEN;
     }
     BCOPY(secbuf, secret, len);
@@ -1178,6 +1299,12 @@ auth_ip_addr(unit, addr)
     int unit;
     u_int32_t addr;
 {
+
+    if (addresses[unit] == NULL) {
+       if (auth_required)
+           return 0;           /* no addresses authorized */
+       return allow_any_ip || !have_route_to(addr);
+    }
     return ip_addr_check(addr, addresses[unit]);
 }
 
@@ -1197,7 +1324,7 @@ ip_addr_check(addr, addrs)
        return 0;
 
     if (addrs == NULL)
-       return !auth_required;          /* no addresses authorized */
+       return 0;               /* no addresses authorized */
 
     for (; addrs != NULL; addrs = addrs->next) {
        /* "-" means no addresses authorized, "*" means any address allowed */
@@ -1220,9 +1347,8 @@ ip_addr_check(addr, addrs)
 
            bit_count = (int) strtol (ptr_mask+1, (char **) 0, 10);
            if (bit_count <= 0 || bit_count > 32) {
-               syslog (LOG_WARNING,
-                       "invalid address length %s in auth. address list",
-                       ptr_mask);
+               warn("invalid address length %v in auth. address list",
+                    ptr_mask);
                continue;
            }
            *ptr_mask = '\0';
@@ -1255,9 +1381,7 @@ ip_addr_check(addr, addrs)
            *ptr_mask = '/';
 
        if (a == (u_int32_t)-1L)
-           syslog (LOG_WARNING,
-                   "unknown host %s in auth. address list",
-                   addrs->word);
+           warn("unknown host %s in auth. address list", addrs->word);
        else
            /* Here a and addr are in network byte order,
               and mask is in host order. */
@@ -1292,9 +1416,10 @@ check_access(f, filename)
     struct stat sbuf;
 
     if (fstat(fileno(f), &sbuf) < 0) {
-       syslog(LOG_WARNING, "cannot stat secret file %s: %m", filename);
+       warn("cannot stat secret file %s: %m", filename);
     } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
-       syslog(LOG_WARNING, "Warning - secret file %s has world and/or group access", filename);
+       warn("Warning - secret file %s has world and/or group access",
+            filename);
     }
 }
 
@@ -1306,7 +1431,8 @@ check_access(f, filename)
  * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
  * NONWILD_SERVER set if the secret didn't have "*" for the server.
  * Any following words on the line (i.e. address authorization
- * info) are placed in a wordlist and returned in *addrs.  
+ * info) are placed in a wordlist and returned in *addrs.
+ * We assume secret is NULL or points to MAXWORDLEN bytes of space.
  */
 static int
 scan_authfile(f, client, server, ipaddr, secret, addrs, filename)
@@ -1384,23 +1510,21 @@ scan_authfile(f, client, server, ipaddr, secret, addrs, filename)
         * Special syntax: @filename means read secret from file.
         */
        if (word[0] == '@') {
-           strcpy(atfile, word+1);
+           strlcpy(atfile, sizeof(atfile), word+1);
            if ((sf = fopen(atfile, "r")) == NULL) {
-               syslog(LOG_WARNING, "can't open indirect secret file %s",
-                      atfile);
+               warn("can't open indirect secret file %s", atfile);
                continue;
            }
            check_access(sf, atfile);
            if (!getword(sf, word, &xxx, atfile)) {
-               syslog(LOG_WARNING, "no secret in indirect secret file %s",
-                      atfile);
+               warn("no secret in indirect secret file %s", atfile);
                fclose(sf);
                continue;
            }
            fclose(sf);
        }
        if (secret != NULL)
-           strcpy(lsecret, word);
+           strlcpy(lsecret, sizeof(lsecret), word);
 
        /*
         * Now read address authorization info and make a wordlist.
@@ -1409,12 +1533,13 @@ scan_authfile(f, client, server, ipaddr, secret, addrs, filename)
        for (;;) {
            if (!getword(f, word, &newline, filename) || newline)
                break;
-           ap = (struct wordlist *) malloc(sizeof(struct wordlist)
-                                           + strlen(word));
+           ap = (struct wordlist *) malloc(sizeof(struct wordlist));
            if (ap == NULL)
                novm("authorized addresses");
            ap->next = NULL;
-           strcpy(ap->word, word);
+           ap->word = strdup(word);
+           if (ap->word == NULL)
+               novm("authorized address");
            if (alist == NULL)
                alist = ap;
            else
@@ -1424,6 +1549,8 @@ scan_authfile(f, client, server, ipaddr, secret, addrs, filename)
 
        /*
         * Check if the given IP address is allowed by the wordlist.
+        * XXX accepts this entry even if it has no allowed IP addresses
+        * if they didn't specify a remote IP address. XXX
         */
        if (ipaddr != 0 && !ip_addr_check(ipaddr, alist)) {
            free_wordlist(alist);
@@ -1438,7 +1565,7 @@ scan_authfile(f, client, server, ipaddr, secret, addrs, filename)
            free_wordlist(addr_list);
        addr_list = alist;
        if (secret != NULL)
-           strcpy(secret, lsecret);
+           strlcpy(secret, MAXWORDLEN, lsecret);
 
        if (!newline)
            break;
@@ -1485,10 +1612,10 @@ auth_script(script)
     if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL)
        user_name = pw->pw_name;
     else {
-       sprintf(struid, "%d", getuid());
+       slprintf(struid, sizeof(struid), "%d", getuid());
        user_name = struid;
     }
-    sprintf(strspeed, "%d", baud_rate);
+    slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
 
     argv[0] = script;
     argv[1] = ifname;
@@ -1498,5 +1625,5 @@ auth_script(script)
     argv[5] = strspeed;
     argv[6] = NULL;
 
-    run_program(script, argv, 0);
+    authup_pid = run_program(script, argv, 0, NULL, NULL);
 }