]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
add a few defs
[ppp.git] / pppd / auth.c
index c87f4003a244b2328c3aebfdce0602bf4057e67f..1dfb148f28cd3e060de1d24bbb6df91ce045f788 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: auth.c,v 1.25 1996/07/01 01:10:24 paulus Exp $";
+static char rcsid[] = "$Id: auth.c,v 1.32 1997/07/14 03:52:33 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -51,14 +51,6 @@ static char rcsid[] = "$Id: auth.c,v 1.25 1996/07/01 01:10:24 paulus Exp $";
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#ifdef SVR4
-#include <crypt.h>
-#else
-#ifdef SUNOS4
-extern char *crypt();
-#endif
-#endif
-
 #ifdef USE_PAM
 #include <security/pam_appl.h>
 #include <security/pam_modules.h>
@@ -66,7 +58,9 @@ extern char *crypt();
 
 #ifdef HAS_SHADOW
 #include <shadow.h>
+#ifndef SVR4
 #include <shadow/pwauth.h>
+#endif
 #ifndef PW_PPP
 #define PW_PPP PW_LOGIN
 #endif
@@ -78,12 +72,11 @@ extern char *crypt();
 #include "ipcp.h"
 #include "upap.h"
 #include "chap.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
 #include "pathnames.h"
 
-#if defined(sun) && defined(sparc)
-#include <alloca.h>
-#endif /*sparc*/
-
 /* Used for storing a sequence of words.  Usually malloced. */
 struct wordlist {
     struct wordlist    *next;
@@ -129,10 +122,13 @@ static int passwd_from_file;
 #define CHAP_WITHPEER  4
 #define CHAP_PEER      8
 
+extern char *crypt __P((const char *, const char *));
+
 /* Prototypes for procedures local to this file. */
 
 static void network_phase __P((int));
-static void check_idle __P((caddr_t));
+static void check_idle __P((void *));
+static void connect_time_expired __P((void *));
 static int  login __P((char *, char *, char **, int *));
 static void logout __P((void));
 static int  null_login __P((int));
@@ -144,6 +140,10 @@ static int  scan_authfile __P((FILE *, char *, char *, u_int32_t, char *,
                               struct wordlist **, char *));
 static void free_wordlist __P((struct wordlist *));
 static void auth_script __P((char *));
+static void set_allowed_addrs __P((int, struct wordlist *));
+#ifdef CBCP_SUPPORT
+static void callback_phase __P((int));
+#endif
 
 /*
  * An Open on LCP has requested a change from Dead to Establish phase.
@@ -195,7 +195,8 @@ link_down(unit)
     }
     num_np_open = 0;
     num_np_up = 0;
-    phase = PHASE_TERMINATE;
+    if (phase != PHASE_DEAD)
+       phase = PHASE_TERMINATE;
 }
 
 /*
@@ -244,7 +245,7 @@ link_established(unit)
        auth |= PAP_PEER;
     }
     if (ho->neg_chap) {
-       ChapAuthWithPeer(unit, our_name, ho->chap_mdtype);
+       ChapAuthWithPeer(unit, user, ho->chap_mdtype);
        auth |= CHAP_WITHPEER;
     } else if (ho->neg_upap) {
        if (passwd[0] == 0) {
@@ -280,6 +281,17 @@ network_phase(unit)
        did_authup = 1;
     }
 
+#ifdef CBCP_SUPPORT
+    /*
+     * If we negotiated callback, do it now.
+     */
+    if (go->neg_cbcp) {
+       phase = PHASE_CALLBACK;
+       (*cbcp_protent.open)(unit);
+       return;
+    }
+#endif
+
     phase = PHASE_NETWORK;
 #if 0
     if (!demand)
@@ -292,6 +304,10 @@ network_phase(unit)
            if (protp->protocol != PPP_CCP)
                ++num_np_open;
        }
+
+    if (num_np_open == 0)
+       /* nothing to do */
+       lcp_close(0, "No network protocols running");
 }
 
 /*
@@ -341,7 +357,7 @@ auth_peer_success(unit, protocol, name, namelen)
 
     /*
      * If there is no more authentication still to be done,
-     * proceed to the network phase.
+     * proceed to the network (or callback) phase.
      */
     if ((auth_pending[unit] &= ~bit) == 0)
         network_phase(unit);
@@ -389,7 +405,7 @@ auth_withpeer_success(unit, protocol)
 
     /*
      * If there is no more authentication still being done,
-     * proceed to the network phase.
+     * proceed to the network (or callback) phase.
      */
     if ((auth_pending[unit] &= ~bit) == 0)
        network_phase(unit);
@@ -403,8 +419,21 @@ void
 np_up(unit, proto)
     int unit, proto;
 {
-    if (num_np_up == 0 && idle_time_limit > 0) {
-       TIMEOUT(check_idle, NULL, idle_time_limit);
+    if (num_np_up == 0) {
+       /*
+        * At this point we consider that the link has come up successfully.
+        */
+       need_holdoff = 0;
+
+       if (idle_time_limit > 0)
+           TIMEOUT(check_idle, NULL, idle_time_limit);
+
+       /*
+        * Set a timeout to close the connection once the maximum
+        * connect time has expired.
+        */
+       if (maxconnect > 0)
+           TIMEOUT(connect_time_expired, 0, maxconnect);
     }
     ++num_np_up;
 }
@@ -440,7 +469,7 @@ np_finished(unit, proto)
  */
 static void
 check_idle(arg)
-    caddr_t arg;
+     void *arg;
 {
     struct ppp_idle idle;
     time_t itime;
@@ -457,6 +486,17 @@ check_idle(arg)
     }
 }
 
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void
+connect_time_expired(arg)
+    void *arg;
+{
+    syslog(LOG_INFO, "Connect time expired");
+    lcp_close(0, "Connect time expired");      /* Close connection */
+}
+
 /*
  * auth_check_options - called to check authentication options.
  */
@@ -491,11 +531,32 @@ auth_check_options()
     }
 
     if (auth_required && !can_auth) {
-       fprintf(stderr, "\
-pppd: peer authentication required but no suitable secret(s) found\n");
+       option_error("peer authentication required but no suitable secret(s) found\n");
+       if (remote_name[0] == 0)
+           option_error("for authenticating any peer to us (%s)\n", our_name);
+       else
+           option_error("for authenticating peer %s to us (%s)\n",
+                        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);
+       }
+    }
 }
 
 /*
@@ -514,7 +575,7 @@ auth_reset(unit)
 
     ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
     ao->neg_chap = !refuse_chap
-       && have_chap_secret(our_name, remote_name, (u_int32_t)0);
+       && have_chap_secret(user, remote_name, (u_int32_t)0);
 
     if (go->neg_upap && !uselogin && !have_pap_secret())
        go->neg_upap = 0;
@@ -575,10 +636,8 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
     ret = UPAP_AUTHACK;
     f = fopen(filename, "r");
     if (f == NULL) {
-       if (!uselogin) {
-           syslog(LOG_ERR, "Can't open PAP password file %s: %m", filename);
-           ret = UPAP_AUTHNAK;
-       }
+       syslog(LOG_ERR, "Can't open PAP password file %s: %m", filename);
+       ret = UPAP_AUTHNAK;
 
     } else {
        check_access(f, filename);
@@ -624,9 +683,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
        if (*msg == (char *) 0)
            *msg = "Login ok";
        *msglen = strlen(*msg);
-       if (addresses[unit] != NULL)
-           free_wordlist(addresses[unit]);
-       addresses[unit] = addrs;
+       set_allowed_addrs(unit, addrs);
     }
 
     BZERO(passwd, sizeof(passwd));
@@ -635,68 +692,6 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
     return ret;
 }
 
-#ifdef HAS_SHADOW
-/**************
- * This function was lifted from the shadow-3.3.2 version by John Haugh II.
- * It is included because the function was not in the standard libshadow
- * library. If it is included in the library then I can remove it from here.
- */
-
-#define        DAY     (24L*3600L)
-/*
- * isexpired - determine if account is expired yet
- *
- *     isexpired calculates the expiration date based on the
- *     password expiration criteria.
- */
-
-/*ARGSUSED*/
-int
-isexpired (pw, sp)
-struct passwd  *pw;
-struct spwd    *sp;
-{
-       long    clock;
-
-       clock = time ((time_t *) 0) / DAY;
-
-       /*
-        * Quick and easy - there is an expired account field
-        * along with an inactive account field.  Do the expired
-        * one first since it is worse.
-        */
-
-       if (sp->sp_expire > 0 && sp->sp_expire < clock)
-               return 3;
-
-       if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 &&
-                       sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock)
-               return 2;
-
-       /*
-        * The last and max fields must be present for an account
-        * to have an expired password.  A maximum of >10000 days
-        * is considered to be infinite.
-        */
-
-       if (sp->sp_lstchg == -1 ||
-                       sp->sp_max == -1 || sp->sp_max >= 10000L)
-               return 0;
-
-       /*
-        * Calculate today's day and the day on which the password
-        * is going to expire.  If that date has already passed,
-        * the password has expired.
-        */
-
-       if (sp->sp_lstchg + sp->sp_max < clock)
-               return 1;
-
-       return 0;
-}
-#endif
-
-
 /*
  * This function is needed for PAM. However, it should not be called.
  * If it is, return the error code.
@@ -750,7 +745,7 @@ login(user, passwd, msg, msglen)
  * Define the fields for the credintial validation
  */
     (void) pam_set_item (pamh, PAM_AUTHTOK, passwd);
-    (void) pam_set_item (pamh, PAM_TTY, devnam);
+    (void) pam_set_item (pamh, PAM_TTY,     devnam);
 /*
  * Validate the user
  */
@@ -772,55 +767,38 @@ login(user, passwd, msg, msglen)
 #else /* #ifdef USE_PAM */
 
     struct passwd *pw;
-    char *epasswd;
 
 #ifdef HAS_SHADOW
     struct spwd *spwd;
     struct spwd *getspnam();
+    extern int isexpired (struct passwd *, struct spwd *); /* in libshadow.a */
 #endif
 
-    if ((pw = getpwnam(user)) == NULL) {
+    pw = getpwnam(user);
+    if (pw == NULL) {
        return (UPAP_AUTHNAK);
     }
 
 #ifdef HAS_SHADOW
-    if ((spwd = getspnam(user)) == NULL) {
-        pw->pw_passwd = "";
-    } else {
+    spwd = getspnam(user);
+    endspent();
+    if (spwd) {
+       /* check the age of the password entry */
+       if (isexpired(pw, spwd)) {
+           syslog(LOG_WARNING,"Expired password for %s",user);
+           return (UPAP_AUTHNAK);
+       }
        pw->pw_passwd = spwd->sp_pwdp;
     }
 #endif
 
     /*
-     * XXX If no passwd, let them login without one.
+     * If no passwd, don't let them login.
      */
-    if (pw->pw_passwd == '\0') {
-       return (UPAP_AUTHACK);
-    }
-
-#ifdef HAS_SHADOW
-    if (pw->pw_passwd) {
-       if (pw->pw_passwd[0] == '@') {
-           if (pw_auth (pw->pw_passwd+1, pw->pw_name, PW_PPP, NULL)) {
-               return (UPAP_AUTHNAK);
-           }
-       } else {
-           epasswd = pw_encrypt(passwd, pw->pw_passwd);
-           if (strcmp(epasswd, pw->pw_passwd)) {
-               return (UPAP_AUTHNAK);
-           }
-       }
-       /* check the age of the password entry */
-       if (spwd && (isexpired (pw, spwd) != 0)) {
-           return (UPAP_AUTHNAK);
-       }
-    }
-#else
-    epasswd = crypt(passwd, pw->pw_passwd);
-    if (strcmp(epasswd, pw->pw_passwd)) {
+    if (pw->pw_passwd == NULL || *pw->pw_passwd == '\0'
+       || strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
        return (UPAP_AUTHNAK);
-    }
-#endif
+
 #endif /* #ifdef USE_PAM */
 
     syslog(LOG_INFO, "user %s logged in", user);
@@ -883,11 +861,10 @@ null_login(unit)
     ret = i >= 0 && (i & NONWILD_CLIENT) != 0 && secret[0] == 0;
     BZERO(secret, sizeof(secret));
 
-    if (ret) {
-       if (addresses[unit] != NULL)
-           free_wordlist(addresses[unit]);
-       addresses[unit] = addrs;
-    }
+    if (ret)
+       set_allowed_addrs(unit, addrs);
+    else
+       free_wordlist(addrs);
 
     fclose(f);
     return ret;
@@ -900,10 +877,12 @@ null_login(unit)
  * could be found.
  */
 static int
-get_pap_passwd(char *passwd)
+get_pap_passwd(passwd)
+    char *passwd;
 {
     char *filename;
     FILE *f;
+    int ret;
     struct wordlist *addrs;
     char secret[MAXWORDLEN];
 
@@ -913,9 +892,11 @@ get_pap_passwd(char *passwd)
     if (f == NULL)
        return 0;
     check_access(f, filename);
-    if (scan_authfile(f, user,
-                     remote_name[0]? remote_name: NULL,
-                     (u_int32_t)0, secret, NULL, filename) < 0)
+    ret = scan_authfile(f, user,
+                       remote_name[0]? remote_name: NULL,
+                       (u_int32_t)0, secret, NULL, filename);
+    fclose(f);
+    if (ret < 0)
        return 0;
     if (passwd != NULL) {
        strncpy(passwd, secret, MAXSECRETLEN);
@@ -1026,11 +1007,8 @@ get_secret(unit, client, server, secret, secret_len, save_addrs)
     if (ret < 0)
        return 0;
 
-    if (save_addrs) {
-       if (addresses[unit] != NULL)
-           free_wordlist(addresses[unit]);
-       addresses[unit] = addrs;
-    }
+    if (save_addrs)
+       set_allowed_addrs(unit, addrs);
 
     len = strlen(secbuf);
     if (len > MAXSECRETLEN) {
@@ -1044,6 +1022,41 @@ get_secret(unit, client, server, secret, secret_len, save_addrs)
     return 1;
 }
 
+/*
+ * set_allowed_addrs() - set the list of allowed addresses.
+ */
+static void
+set_allowed_addrs(unit, addrs)
+    int unit;
+    struct wordlist *addrs;
+{
+    if (addresses[unit] != NULL)
+       free_wordlist(addresses[unit]);
+    addresses[unit] = addrs;
+
+    /*
+     * If there's only one authorized address we might as well
+     * ask our peer for that one right away
+     */
+    if (addrs != NULL && addrs->next == NULL) {
+       char *p = addrs->word;
+       struct ipcp_options *wo = &ipcp_wantoptions[unit];
+       u_int32_t a;
+       struct hostent *hp;
+
+       if (wo->hisaddr == 0 && *p != '!' && *p != '-'
+           && strchr(p, '/') == NULL) {
+           hp = gethostbyname(p);
+           if (hp != NULL && hp->h_addrtype == AF_INET)
+               a = *(u_int32_t *)hp->h_addr;
+           else
+               a = inet_addr(p);
+           if (a != (u_int32_t) -1)
+               wo->hisaddr = a;
+       }
+    }
+}
+
 /*
  * auth_ip_addr - check whether the peer is authorized to use
  * a given IP address.  Returns 1 if authorized, 0 otherwise.
@@ -1072,13 +1085,15 @@ ip_addr_check(addr, addrs)
        return 0;
 
     if (addrs == NULL)
-       return 1;               /* no restriction */
+       return !auth_required;          /* no addresses authorized */
 
     for (; addrs != NULL; addrs = addrs->next) {
-       /* "-" means no addresses authorized */
+       /* "-" means no addresses authorized, "*" means any address allowed */
        ptr_word = addrs->word;
        if (strcmp(ptr_word, "-") == 0)
            break;
+       if (strcmp(ptr_word, "*") == 0)
+           return 1;
 
        accept = 1;
        if (*ptr_word == '!') {
@@ -1104,34 +1119,36 @@ ip_addr_check(addr, addrs)
 
        hp = gethostbyname(ptr_word);
        if (hp != NULL && hp->h_addrtype == AF_INET) {
-           a    = *(u_int32_t *)hp->h_addr;
-           mask = ~ (u_int32_t) 0;     /* are we sure we want this? */
+           a = *(u_int32_t *)hp->h_addr;
        } else {
            np = getnetbyname (ptr_word);
-           if (np != NULL && np->n_addrtype == AF_INET)
+           if (np != NULL && np->n_addrtype == AF_INET) {
                a = htonl (*(u_int32_t *)np->n_net);
-           else
+               if (ptr_mask == NULL) {
+                   /* calculate appropriate mask for net */
+                   ah = ntohl(a);
+                   if (IN_CLASSA(ah))
+                       mask = IN_CLASSA_NET;
+                   else if (IN_CLASSB(ah))
+                       mask = IN_CLASSB_NET;
+                   else if (IN_CLASSC(ah))
+                       mask = IN_CLASSC_NET;
+               }
+           } else {
                a = inet_addr (ptr_word);
-           if (ptr_mask == NULL) {
-               /* calculate appropriate mask for net */
-               ah = ntohl(a);
-               if (IN_CLASSA(ah))
-                   mask = IN_CLASSA_NET;
-               else if (IN_CLASSB(ah))
-                   mask = IN_CLASSB_NET;
-               else if (IN_CLASSC(ah))
-                   mask = IN_CLASSC_NET;
            }
        }
 
        if (ptr_mask != NULL)
            *ptr_mask = '/';
 
-       if (a == -1L)
+       if (a == (u_int32_t)-1L)
            syslog (LOG_WARNING,
                    "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. */
            if (((addr ^ a) & htonl(mask)) == 0)
                return accept;
     }