]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/chap-new.c
Cleanup pppoe-discovery fatal functions
[ppp.git] / pppd / chap-new.c
index 9b8f17643b8113237739985a20e114abc7e7433a..fab82800a7b33950935c8b13a1be41a0982b45dd 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The name(s) of the authors of this software must not be used to
+ * 2. The name(s) of the authors of this software must not be used to
  *    endorse or promote products derived from this software without
  *    prior written permission.
  *
- * 4. Redistributions of any form whatsoever must retain the following
+ * 3. Redistributions of any form whatsoever must retain the following
  *    acknowledgment:
  *    "This product includes software developed by Paul Mackerras
  *     <paulus@samba.org>".
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id"
+#define RCSID  "$Id: chap-new.c,v 1.9 2007/06/19 02:08:35 carlsonj Exp $"
 
 #include <stdlib.h>
 #include <string.h>
 #include "pppd.h"
+#include "session.h"
 #include "chap-new.h"
 #include "chap-md5.h"
 
 #ifdef CHAPMS
 #include "chap_ms.h"
+#define MDTYPE_ALL (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5)
+#else
+#define MDTYPE_ALL (MDTYPE_MD5)
 #endif
 
+int chap_mdtype_all = MDTYPE_ALL;
+
 /* Hook for a plugin to validate CHAP challenge */
 int (*chap_verify_hook)(char *name, char *ourname, int id,
                        struct chap_digest_type *digest,
                        unsigned char *challenge, unsigned char *response,
-                       unsigned char *message, int message_space) = NULL;
+                       char *message, int message_space) = NULL;
 
 /*
  * Option variables.
  */
-int chap_timeout_time = 3;
+int chap_server_timeout_time = 3;
 int chap_max_transmits = 10;
 int chap_rechallenge_time = 0;
+int chap_client_timeout_time = 60;
+int chapms_strip_domain = 0;
 
 /*
  * Command-line options.
  */
 static option_t chap_option_list[] = {
-       { "chap-restart", o_int, &chap_timeout_time,
-         "Set timeout for CHAP", OPT_PRIO },
+       { "chap-restart", o_int, &chap_server_timeout_time,
+         "Set timeout for CHAP (as server)", OPT_PRIO },
        { "chap-max-challenge", o_int, &chap_max_transmits,
          "Set max #xmits for challenge", OPT_PRIO },
        { "chap-interval", o_int, &chap_rechallenge_time,
          "Set interval for rechallenge", OPT_PRIO },
+       { "chap-timeout", o_int, &chap_client_timeout_time,
+         "Set timeout for CHAP (as client)", OPT_PRIO },
+       { "chapms-strip-domain", o_bool, &chapms_strip_domain,
+         "Strip the domain prefix before the Username", 1 },
        { NULL }
 };
 
@@ -96,6 +103,7 @@ static struct chap_server_state {
        int challenge_xmits;
        int challenge_pktlen;
        unsigned char challenge[CHAL_MAX_PKTLEN];
+       char message[256];
 } server;
 
 /* Values for flags in chap_client_state and chap_server_state */
@@ -112,14 +120,15 @@ static struct chap_server_state {
 static void chap_init(int unit);
 static void chap_lowerup(int unit);
 static void chap_lowerdown(int unit);
-static void chap_timeout(void *arg);
+static void chap_server_timeout(void *arg);
+static void chap_client_timeout(void *arg);
 static void chap_generate_challenge(struct chap_server_state *ss);
 static void chap_handle_response(struct chap_server_state *ss, int code,
                unsigned char *pkt, int len);
 static int chap_verify_response(char *name, char *ourname, int id,
                struct chap_digest_type *digest,
                unsigned char *challenge, unsigned char *response,
-               unsigned char *message, int message_space);
+               char *message, int message_space);
 static void chap_respond(struct chap_client_state *cs, int id,
                unsigned char *pkt, int len);
 static void chap_handle_status(struct chap_client_state *cs, int code, int id,
@@ -127,7 +136,7 @@ static void chap_handle_status(struct chap_client_state *cs, int code, int id,
 static void chap_protrej(int unit);
 static void chap_input(int unit, unsigned char *pkt, int pktlen);
 static int chap_print_pkt(unsigned char *p, int plen,
-               void (*printer) __P((void *, char *, ...)), void *arg);
+               void (*printer)(void *, char *, ...), void *arg);
 
 /* List of digest types that we know about */
 static struct chap_digest_type *chap_digests;
@@ -169,7 +178,7 @@ chap_lowerup(int unit)
        cs->flags |= LOWERUP;
        ss->flags |= LOWERUP;
        if (ss->flags & AUTH_STARTED)
-               chap_timeout(ss);
+               chap_server_timeout(ss);
 }
 
 static void
@@ -178,9 +187,11 @@ chap_lowerdown(int unit)
        struct chap_client_state *cs = &client;
        struct chap_server_state *ss = &server;
 
+       if (cs->flags & TIMEOUT_PENDING)
+               UNTIMEOUT(chap_client_timeout, cs);
        cs->flags = 0;
        if (ss->flags & TIMEOUT_PENDING)
-               UNTIMEOUT(chap_timeout, ss);
+               UNTIMEOUT(chap_server_timeout, ss);
        ss->flags = 0;
 }
 
@@ -212,7 +223,7 @@ chap_auth_peer(int unit, char *our_name, int digest_code)
        ss->id = (unsigned char)(drand48() * 256);
        ss->flags |= AUTH_STARTED;
        if (ss->flags & LOWERUP)
-               chap_timeout(ss);
+               chap_server_timeout(ss);
 }
 
 /*
@@ -238,16 +249,17 @@ chap_auth_with_peer(int unit, char *our_name, int digest_code)
 
        cs->digest = dp;
        cs->name = our_name;
-       cs->flags |= AUTH_STARTED;
+       cs->flags |= AUTH_STARTED | TIMEOUT_PENDING;
+       TIMEOUT(chap_client_timeout, cs, chap_client_timeout_time);
 }
 
 /*
- * chap_timeout - It's time to send another challenge to the peer.
+ * chap_server_timeout - It's time to send another challenge to the peer.
  * This could be either a retransmission of a previous challenge,
  * or a new challenge to start re-authentication.
  */
 static void
-chap_timeout(void *arg)
+chap_server_timeout(void *arg)
 {
        struct chap_server_state *ss = arg;
 
@@ -266,7 +278,19 @@ chap_timeout(void *arg)
        output(0, ss->challenge, ss->challenge_pktlen);
        ++ss->challenge_xmits;
        ss->flags |= TIMEOUT_PENDING;
-       TIMEOUT(chap_timeout, arg, chap_timeout_time);
+       TIMEOUT(chap_server_timeout, arg, chap_server_timeout_time);
+}
+
+/* chap_client_timeout - Authentication with peer timed out. */
+static void
+chap_client_timeout(void *arg)
+{
+       struct chap_client_state *cs = arg;
+
+       cs->flags &= ~TIMEOUT_PENDING;
+       cs->flags |= AUTH_DONE | AUTH_FAILED;
+       error("CHAP authentication timed out");
+       auth_withpeer_fail(0, PPP_CHAP);
 }
 
 /*
@@ -306,30 +330,26 @@ chap_handle_response(struct chap_server_state *ss, int id,
 {
        int response_len, ok, mlen;
        unsigned char *response, *p;
-       unsigned char *name = NULL;     /* initialized to shut gcc up */
+       char *name = NULL;      /* initialized to shut gcc up */
        int (*verifier)(char *, char *, int, struct chap_digest_type *,
-               unsigned char *, unsigned char *, unsigned char *, int);
+               unsigned char *, unsigned char *, char *, int);
        char rname[MAXNAMELEN+1];
-       unsigned char message[256];
 
        if ((ss->flags & LOWERUP) == 0)
                return;
        if (id != ss->challenge[PPP_HDRLEN+1] || len < 2)
                return;
-       if ((ss->flags & AUTH_DONE) == 0) {
-               if ((ss->flags & CHALLENGE_VALID) == 0)
-                       return;
+       if (ss->flags & CHALLENGE_VALID) {
                response = pkt;
                GETCHAR(response_len, pkt);
                len -= response_len + 1;        /* length of name */
-               name = pkt + response_len;
+               name = (char *)pkt + response_len;
                if (len < 0)
                        return;
 
-               ss->flags &= ~CHALLENGE_VALID;
                if (ss->flags & TIMEOUT_PENDING) {
                        ss->flags &= ~TIMEOUT_PENDING;
-                       UNTIMEOUT(chap_timeout, ss);
+                       UNTIMEOUT(chap_server_timeout, ss);
                }
 
                if (explicit_remote) {
@@ -338,6 +358,14 @@ chap_handle_response(struct chap_server_state *ss, int id,
                        /* Null terminate and clean remote name. */
                        slprintf(rname, sizeof(rname), "%.*v", len, name);
                        name = rname;
+
+                       /* strip the MS domain name */
+                       if (chapms_strip_domain && strrchr(rname, '\\')) {
+                               char tmp[MAXNAMELEN+1];
+
+                               strcpy(tmp, strrchr(rname, '\\') + 1);
+                               strcpy(rname, tmp);
+                       }
                }
 
                if (chap_verify_hook)
@@ -346,39 +374,59 @@ chap_handle_response(struct chap_server_state *ss, int id,
                        verifier = chap_verify_response;
                ok = (*verifier)(name, ss->name, id, ss->digest,
                                 ss->challenge + PPP_HDRLEN + CHAP_HDRLEN,
-                                response, message, sizeof(message));
+                                response, ss->message, sizeof(ss->message));
                if (!ok || !auth_number()) {
                        ss->flags |= AUTH_FAILED;
                        warn("Peer %q failed CHAP authentication", name);
                }
-       }
+       } else if ((ss->flags & AUTH_DONE) == 0)
+               return;
 
        /* send the response */
        p = outpacket_buf;
        MAKEHEADER(p, PPP_CHAP);
-       mlen = strlen(message);
+       mlen = strlen(ss->message);
        len = CHAP_HDRLEN + mlen;
        p[0] = (ss->flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS;
        p[1] = id;
        p[2] = len >> 8;
        p[3] = len;
        if (mlen > 0)
-               memcpy(p + CHAP_HDRLEN, message, mlen);
+               memcpy(p + CHAP_HDRLEN, ss->message, mlen);
        output(0, outpacket_buf, PPP_HDRLEN + len);
 
-       if ((ss->flags & AUTH_DONE) == 0) {
-               ss->flags |= AUTH_DONE;
+       if (ss->flags & CHALLENGE_VALID) {
+               ss->flags &= ~CHALLENGE_VALID;
+               if (!(ss->flags & AUTH_DONE) && !(ss->flags & AUTH_FAILED)) {
+                   /*
+                    * Auth is OK, so now we need to check session restrictions
+                    * to ensure everything is OK, but only if we used a
+                    * plugin, and only if we're configured to check.  This
+                    * allows us to do PAM checks on PPP servers that
+                    * authenticate against ActiveDirectory, and use AD for
+                    * account info (like when using Winbind integrated with
+                    * PAM).
+                    */
+                   if (session_mgmt &&
+                       session_check(name, NULL, devnam, NULL) == 0) {
+                       ss->flags |= AUTH_FAILED;
+                       warn("Peer %q failed CHAP Session verification", name);
+                   }
+               }
                if (ss->flags & AUTH_FAILED) {
                        auth_peer_fail(0, PPP_CHAP);
                } else {
-                       auth_peer_success(0, PPP_CHAP, ss->digest->code,
-                                         name, strlen(name));
+                       if ((ss->flags & AUTH_DONE) == 0)
+                               auth_peer_success(0, PPP_CHAP,
+                                                 ss->digest->code,
+                                                 name, strlen(name));
                        if (chap_rechallenge_time) {
                                ss->flags |= TIMEOUT_PENDING;
-                               TIMEOUT(chap_timeout, ss,
+                               TIMEOUT(chap_server_timeout, ss,
                                        chap_rechallenge_time);
                        }
                }
+               ss->flags |= AUTH_DONE;
        }
 }
 
@@ -391,14 +439,14 @@ static int
 chap_verify_response(char *name, char *ourname, int id,
                     struct chap_digest_type *digest,
                     unsigned char *challenge, unsigned char *response,
-                    unsigned char *message, int message_space)
+                    char *message, int message_space)
 {
        int ok;
-       char secret[MAXSECRETLEN];
+       unsigned char secret[MAXSECRETLEN];
        int secret_len;
 
        /* Get the secret that the peer is supposed to know */
-       if (!get_secret(0, name, ourname, secret, &secret_len, 1)) {
+       if (!get_secret(0, name, ourname, (char *)secret, &secret_len, 1)) {
                error("No CHAP secret found for authenticating %q", name);
                return 0;
        }
@@ -477,10 +525,13 @@ chap_handle_status(struct chap_client_state *cs, int code, int id,
                return;
        cs->flags |= AUTH_DONE;
 
+       UNTIMEOUT(chap_client_timeout, cs);
+       cs->flags &= ~TIMEOUT_PENDING;
+
        if (code == CHAP_SUCCESS) {
                /* used for MS-CHAP v2 mutual auth, yuck */
                if (cs->digest->check_success != NULL) {
-                       if (!(*cs->digest->check_success)(pkt, len, cs->priv))
+                       if (!(*cs->digest->check_success)(id, pkt, len))
                                code = CHAP_FAILURE;
                } else
                        msg = "CHAP authentication succeeded";
@@ -500,6 +551,7 @@ chap_handle_status(struct chap_client_state *cs, int code, int id,
                auth_withpeer_success(0, PPP_CHAP, cs->digest->code);
        else {
                cs->flags |= AUTH_FAILED;
+               error("CHAP authentication failed");
                auth_withpeer_fail(0, PPP_CHAP);
        }
 }
@@ -543,7 +595,7 @@ chap_protrej(int unit)
 
        if (ss->flags & TIMEOUT_PENDING) {
                ss->flags &= ~TIMEOUT_PENDING;
-               UNTIMEOUT(chap_timeout, ss);
+               UNTIMEOUT(chap_server_timeout, ss);
        }
        if (ss->flags & AUTH_STARTED) {
                ss->flags = 0;
@@ -551,6 +603,7 @@ chap_protrej(int unit)
        }
        if ((cs->flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) {
                cs->flags &= ~AUTH_STARTED;
+               error("CHAP authentication failed due to protocol-reject");
                auth_withpeer_fail(0, PPP_CHAP);
        }
 }
@@ -564,7 +617,7 @@ static char *chap_code_names[] = {
 
 static int
 chap_print_pkt(unsigned char *p, int plen,
-              void (*printer) __P((void *, char *, ...)), void *arg)
+              void (*printer)(void *, char *, ...), void *arg)
 {
        int code, id, len;
        int clen, nlen;