]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/chap.c
Added RADIUS suppport.
[ppp.git] / pppd / chap.c
index 3d7a660618af65dbf1ce71b6f896992a29ffce85..9bd85b5df40476a67707f51fef3af8f01384f8e4 100644 (file)
@@ -33,7 +33,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: chap.c,v 1.25 2001/03/08 05:11:11 paulus Exp $"
+#define RCSID  "$Id: chap.c,v 1.26 2002/01/22 16:02:58 dfs Exp $"
 
 /*
  * TODO:
 #include "chap_ms.h"
 #endif
 
+/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */
+int (*chap_check_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the CHAP password for authenticating us */
+int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
+/* Hook for a plugin to validate CHAP challenge */
+int (*chap_auth_hook) __P((char *user,
+                          u_char *remmd,
+                          int remmd_len,
+                          chap_state *cstate)) = NULL;
+
 static const char rcsid[] = RCSID;
 
 /*
@@ -161,7 +173,7 @@ ChapAuthWithPeer(unit, our_name, digest)
 
     /*
      * We get here as a result of LCP coming up.
-     * So even if CHAP was open before, we will 
+     * So even if CHAP was open before, we will
      * have to re-authenticate ourselves.
      */
     cstate->clientstate = CHAPCS_LISTEN;
@@ -178,7 +190,7 @@ ChapAuthPeer(unit, our_name, digest)
     int digest;
 {
     chap_state *cstate = &chap[unit];
-  
+
     cstate->chal_name = our_name;
     cstate->chal_type = digest;
 
@@ -203,7 +215,7 @@ ChapChallengeTimeout(arg)
     void *arg;
 {
     chap_state *cstate = (chap_state *) arg;
-  
+
     /* if we aren't sending challenges, don't worry.  then again we */
     /* probably shouldn't be here either */
     if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
@@ -268,7 +280,7 @@ ChapLowerUp(unit)
     int unit;
 {
     chap_state *cstate = &chap[unit];
-  
+
     if (cstate->clientstate == CHAPCS_INITIAL)
        cstate->clientstate = CHAPCS_CLOSED;
     else if (cstate->clientstate == CHAPCS_PENDING)
@@ -294,7 +306,7 @@ ChapLowerDown(unit)
     int unit;
 {
     chap_state *cstate = &chap[unit];
-  
+
     /* Timeout(s) pending?  Cancel if so. */
     if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
        cstate->serverstate == CHAPSS_RECHALLENGE)
@@ -342,7 +354,7 @@ ChapInput(unit, inpacket, packet_len)
     u_char *inp;
     u_char code, id;
     int len;
-  
+
     /*
      * Parse header (code, id and length).
      * If packet too short, drop it.
@@ -364,7 +376,7 @@ ChapInput(unit, inpacket, packet_len)
        return;
     }
     len -= CHAP_HEADERLEN;
-  
+
     /*
      * Action depends on code (as in fact it usually does :-).
      */
@@ -372,11 +384,11 @@ ChapInput(unit, inpacket, packet_len)
     case CHAP_CHALLENGE:
        ChapReceiveChallenge(cstate, inp, id, len);
        break;
-    
+
     case CHAP_RESPONSE:
        ChapReceiveResponse(cstate, inp, id, len);
        break;
-    
+
     case CHAP_FAILURE:
        ChapReceiveFailure(cstate, inp, id, len);
        break;
@@ -409,7 +421,7 @@ ChapReceiveChallenge(cstate, inp, id, len)
     char rhostname[256];
     MD5_CTX mdContext;
     u_char hash[MD5_SIGNATURE_SIZE];
+
     if (cstate->clientstate == CHAPCS_CLOSED ||
        cstate->clientstate == CHAPCS_PENDING) {
        CHAPDEBUG(("ChapReceiveChallenge: in state %d", cstate->clientstate));
@@ -457,7 +469,7 @@ ChapReceiveChallenge(cstate, inp, id, len)
     cstate->resp_transmits = 0;
 
     /*  generate MD based on negotiated type */
-    switch (cstate->resp_type) { 
+    switch (cstate->resp_type) {
 
     case CHAP_DIGEST_MD5:
        MD5Init(&mdContext);
@@ -552,34 +564,42 @@ ChapReceiveResponse(cstate, inp, id, len)
      * do the hash ourselves, and compare the result.
      */
     code = CHAP_FAILURE;
-    if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
-                   cstate->chal_name, secret, &secret_len, 1)) {
-       warn("No CHAP secret found for authenticating %q", rhostname);
-    } else {
 
-       /*  generate MD based on negotiated type */
-       switch (cstate->chal_type) { 
-
-       case CHAP_DIGEST_MD5:           /* only MD5 is defined for now */
-           if (remmd_len != MD5_SIGNATURE_SIZE)
-               break;                  /* it's not even the right length */
-           MD5Init(&mdContext);
-           MD5Update(&mdContext, &cstate->chal_id, 1);
-           MD5Update(&mdContext, secret, secret_len);
-           MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
-           MD5Final(hash, &mdContext); 
-
-           /* compare local and remote MDs and send the appropriate status */
-           if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
-               code = CHAP_SUCCESS;    /* they are the same! */
-           break;
-
-       default:
-           CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
+    /* If a plugin will verify the response, let the plugin do it. */
+    if (chap_auth_hook) {
+       code = (*chap_auth_hook) ( (explicit_remote ? remote_name : rhostname),
+                                  remmd, (int) remmd_len,
+                                  cstate );
+    } else {
+       if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
+                       cstate->chal_name, secret, &secret_len, 1)) {
+           warn("No CHAP secret found for authenticating %q", rhostname);
+       } else {
+
+           /*  generate MD based on negotiated type */
+           switch (cstate->chal_type) {
+
+           case CHAP_DIGEST_MD5:               /* only MD5 is defined for now */
+               if (remmd_len != MD5_SIGNATURE_SIZE)
+                   break;                      /* it's not even the right length */
+               MD5Init(&mdContext);
+               MD5Update(&mdContext, &cstate->chal_id, 1);
+               MD5Update(&mdContext, secret, secret_len);
+               MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+               MD5Final(hash, &mdContext);
+
+               /* compare local and remote MDs and send the appropriate status */
+               if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
+                   code = CHAP_SUCCESS;        /* they are the same! */
+               break;
+
+           default:
+               CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
+           }
        }
-    }
 
-    BZERO(secret, sizeof(secret));
+       BZERO(secret, sizeof(secret));
+    }
     ChapSendStatus(cstate, code);
 
     if (code == CHAP_SUCCESS) {
@@ -692,7 +712,7 @@ ChapSendChallenge(cstate)
     BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */
 
     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
-  
+
     TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
     ++cstate->chal_transmits;
 }
@@ -720,7 +740,7 @@ ChapSendStatus(cstate, code)
     outp = outpacket_buf;
 
     MAKEHEADER(outp, PPP_CHAP);        /* paste in a header */
-  
+
     PUTCHAR(code, outp);
     PUTCHAR(cstate->chal_id, outp);
     PUTSHORT(outlen, outp);
@@ -743,8 +763,8 @@ ChapGenChallenge(cstate)
     u_char *ptr = cstate->challenge;
     int i;
 
-    /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
-       MAX_CHALLENGE_LENGTH */  
+    /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+       MAX_CHALLENGE_LENGTH */
     chal_len =  (unsigned) ((drand48() *
                             (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
                            MIN_CHALLENGE_LENGTH);