Large patch from Frank Cusack <fcusack@fcusack.com> to add proper
authorDavid F. Skoll <dfs@roaringpenguin.com>
Fri, 1 Mar 2002 14:39:19 +0000 (14:39 +0000)
committerDavid F. Skoll <dfs@roaringpenguin.com>
Fri, 1 Mar 2002 14:39:19 +0000 (14:39 +0000)
support for MS-CHAP (client and server are now supported.)

Allow another plugin to select a different RADIUS server.

Modified radiusclient library to include two new APIs:
rc_acct_using_server and rc_auth_using_server in which caller specifies
which RADIUS servers to use, instead of using the default ones in the
config file.  The /etc/radiusclient/servers file must still contain
secrets for those servers.

14 files changed:
README.MSCHAP80
pppd/auth.c
pppd/chap.c
pppd/chap.h
pppd/chap_ms.c
pppd/chap_ms.h
pppd/lcp.c
pppd/lcp.h
pppd/options.c
pppd/plugins/radius/radius.c
pppd/plugins/radius/radiusclient/include/radiusclient.h
pppd/plugins/radius/radiusclient/lib/buildreq.c
pppd/pppd.8
pppd/pppd.h

index d3ed291b73a757febcbcff04756e9e1fda1614ad..fe7a019416dd70032500244bdf302d75fff565e5 100644 (file)
@@ -1,10 +1,11 @@
-PPP Client Support for Microsoft's CHAP-80
-==========================================
+PPP Support for Microsoft's CHAP-80
+===================================
 
 Eric Rosenquist          rosenqui@strataware.com
 (updated by Paul Mackerras)
 (updated by Al Longyear)
 (updated by Farrell Woods)
+(updated by Frank Cusack)
 
 INTRODUCTION
 
@@ -16,7 +17,7 @@ by a bogus client to gain access to the server just as easily as if
 the password were stored in cleartext.)  The details of the Microsoft
 extensions can be found in the document:
 
-    <ftp://ftp.microsoft.com/developr/rfc/chapexts.txt>
+    <http://www.ietf.org/rfc/rfc2433.txt>
 
 In short, MS-CHAP is identified as <auth chap 80> since the hex value
 of 80 is used to designate Microsoft's scheme.  Standard PPP CHAP uses
@@ -35,12 +36,7 @@ MS-CHAP by NAKing it:
 Windows NT Server systems are often configured to "Accept only
 Microsoft Authentication" (this is intended to enhance security).  Up
 until now, that meant that you couldn't use this version of PPPD to
-connect to such a system.  I've managed to get a client-only
-implementation of MS-CHAP working; it will authenticate itself to
-another system using MS-CHAP, but if you're using PPPD as a dial-in
-server, you won't be able to use MS-CHAP to authenticate the clients.
-This would not be a lot of extra work given that the framework is in
-place, but I didn't need it myself so I didn't implement it.
+connect to such a system.
 
 
 BUILDING THE PPPD
@@ -275,10 +271,5 @@ to be used in chap-secrets in place of the password.  The code to do this
 could quite easily be lifted from chap_ms.c (you have to convert the
 password to Unicode before hashing it).  The chap_ms.c file would also have
 to be changed to recognize a password hash (16 binary bytes == 32 ASCII hex
-characters) and skip the hashing stage.
-
-A server implementation would allow MS-CHAP to be used with Windows NT and
-Windows 95 clients for enhanced security.  Some new command-line options
-would be required, as would code to generate the Challenge packet and
-verify the response.  Most of the helper functions are in place, so this
-shouldn't be too hard for someone to add.
+characters) and skip the hashing stage.  This would have no real security
+value as the hash is plaintext-equivalent.
index a5fc1bd6bc32dfaaea6af37ada412400df08c572..4f9c29788940905657e6eaf50dc3d6ffbdf6cf5e 100644 (file)
@@ -32,7 +32,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: auth.c,v 1.73 2002/01/22 16:02:58 dfs Exp $"
+#define RCSID  "$Id: auth.c,v 1.74 2002/03/01 14:39:18 dfs Exp $"
 
 #include <stdio.h>
 #include <stddef.h>
@@ -169,6 +169,11 @@ 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 */
+#ifdef CHAPMS
+bool refuse_mschap = 0;                /* Don't wanna auth. ourselves with MS-CHAP */
+#else
+bool refuse_mschap = 1;                /* Don't wanna auth. ourselves with MS-CHAP */
+#endif
 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 */
@@ -218,30 +223,53 @@ option_t auth_options[] = {
     { "auth", o_bool, &auth_required,
       "Require authentication from peer", OPT_PRIO | 1 },
     { "noauth", o_bool, &auth_required,
-      "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
+      "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV | OPT_A2COPY,
       &allow_any_ip },
     { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
       "Require PAP authentication from peer",
-      OPT_PRIOSUB | 1, &auth_required },
+      OPT_PRIOSUB | OPT_A2COPY | 1, &auth_required },
     { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
       "Require PAP authentication from peer",
-      OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+      OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | 1, &auth_required },
     { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
       "Require CHAP authentication from peer",
-      OPT_PRIOSUB | 1, &auth_required },
+      OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MD5,
+      &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
     { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
       "Require CHAP authentication from peer",
-      OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+      OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MD5,
+      &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
+#ifdef CHAPMS
+    { "require-mschap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require MS-CHAP authentication from peer",
+      OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT,
+      &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
+    { "+mschap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require MS-CHAP authentication from peer",
+      OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT,
+      &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
+#endif
 
     { "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", OPT_ALIAS | 1 },
-
     { "refuse-chap", o_bool, &refuse_chap,
-      "Don't agree to auth to peer with CHAP", 1 },
+      "Don't agree to auth to peer with CHAP", OPT_A2CLRB | MDTYPE_MD5,
+      &lcp_allowoptions[0].chap_mdtype },
     { "-chap", o_bool, &refuse_chap,
-      "Don't allow CHAP authentication with peer", OPT_ALIAS | 1 },
+      "Don't allow CHAP authentication with peer",
+      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
+      &lcp_allowoptions[0].chap_mdtype },
+#ifdef CHAPMS
+    { "refuse-mschap", o_bool, &refuse_mschap,
+      "Don't agree to auth to peer with MS-CHAP", OPT_A2CLRB | MDTYPE_MICROSOFT,
+      &lcp_allowoptions[0].chap_mdtype },
+    { "-mschap", o_bool, &refuse_mschap,
+      "Don't allow MS-CHAP authentication with peer",
+      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
+      &lcp_allowoptions[0].chap_mdtype },
+#endif
 
     { "name", o_string, our_name,
       "Set local name for authentication",
@@ -466,12 +494,12 @@ link_established(unit)
            && protp->lowerup != NULL)
            (*protp->lowerup)(unit);
 
-    if (auth_required && !(go->neg_chap || go->neg_upap)) {
+    if (auth_required && !(go->neg_upap || go->neg_chap)) {
        /*
         * We wanted the peer to authenticate itself, and it refused:
         * if we have some address(es) it can use without auth, fine,
         * otherwise treat it as though it authenticated with PAP using
-        * a username of "" and a password of "".  If that's not OK,
+        * a username of "" and a password of "".  If that's not OK,
         * boot it out.
         */
        if (noauth_addrs != NULL) {
@@ -488,14 +516,14 @@ link_established(unit)
     used_login = 0;
     auth = 0;
     if (go->neg_chap) {
-       ChapAuthPeer(unit, our_name, go->chap_mdtype);
+       ChapAuthPeer(unit, our_name, CHAP_DIGEST(go->chap_mdtype));
        auth |= CHAP_PEER;
     } else if (go->neg_upap) {
        upap_authpeer(unit);
        auth |= PAP_PEER;
     }
     if (ho->neg_chap) {
-       ChapAuthWithPeer(unit, user, ho->chap_mdtype);
+       ChapAuthWithPeer(unit, user, CHAP_DIGEST(ho->chap_mdtype));
        auth |= CHAP_WITHPEER;
     } else if (ho->neg_upap) {
        if (passwd[0] == 0) {
@@ -834,11 +862,11 @@ auth_check_options()
     if (auth_required) {
        allow_any_ip = 0;
        if (!wo->neg_chap && !wo->neg_upap) {
-           wo->neg_chap = 1;
+           wo->neg_chap = 1; wo->chap_mdtype = MDTYPE_ALL;
            wo->neg_upap = 1;
        }
     } else {
-       wo->neg_chap = 0;
+       wo->neg_chap = 0; wo->chap_mdtype = MDTYPE_NONE;
        wo->neg_upap = 0;
     }
 
@@ -848,7 +876,7 @@ auth_check_options()
      */
     lacks_ip = 0;
     can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip));
-    if (!can_auth && wo->neg_chap) {
+    if (!can_auth && (wo->neg_chap)) {
        can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
                                    our_name, 1, &lacks_ip);
     }
@@ -889,7 +917,7 @@ auth_reset(unit)
     lcp_options *ao = &lcp_allowoptions[0];
 
     ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
-    ao->neg_chap = !refuse_chap
+    ao->neg_chap = (!refuse_chap || !refuse_mschap)
        && (passwd[0] != 0
            || have_chap_secret(user, (explicit_remote? remote_name: NULL),
                                0, NULL));
index 9bd85b5df40476a67707f51fef3af8f01384f8e4..25427e2d15b133c96ccefd147b4270fe284ea0b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * chap.c - Challenge Handshake Authentication Protocol.
+ * chap_ms.c - Challenge Handshake Authentication Protocol.
  *
  * Copyright (c) 1993 The Australian National University.
  * All rights reserved.
@@ -33,7 +33,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: chap.c,v 1.26 2002/01/22 16:02:58 dfs Exp $"
+#define RCSID  "$Id: chap.c,v 1.27 2002/03/01 14:39:18 dfs Exp $"
 
 /*
  * TODO:
@@ -579,20 +579,48 @@ ChapReceiveResponse(cstate, inp, id, len)
            /*  generate MD based on negotiated type */
            switch (cstate->chal_type) {
 
-           case CHAP_DIGEST_MD5:               /* only MD5 is defined for now */
+           case CHAP_DIGEST_MD5:
                if (remmd_len != MD5_SIGNATURE_SIZE)
-                   break;                      /* it's not even the right length */
+                   break;                      /* 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 */
+               /* compare MDs and send the appropriate status */
                if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
                    code = CHAP_SUCCESS;        /* they are the same! */
                break;
 
+#ifdef CHAPMS
+           case CHAP_MICROSOFT:
+           {
+               int response_offset, response_size;
+
+               if (remmd_len != MS_CHAP_RESPONSE_LEN)
+                   break;                      /* not even the right length */
+               ChapMS(cstate, cstate->challenge, cstate->chal_len,
+                      secret, secret_len);
+
+               /* Determine which part of response to verify against */
+               if ((u_char *) (remmd + offsetof(MS_ChapResponse, UseNT))) {
+                   response_offset = offsetof(MS_ChapResponse, NTResp);
+                   response_size = sizeof(((MS_ChapResponse *) remmd)->NTResp);
+               } else {
+                   response_offset = offsetof(MS_ChapResponse, LANManResp);
+                   response_size =
+                       sizeof(((MS_ChapResponse *) remmd)->LANManResp);
+               }
+
+               /* compare MDs and send the appropriate status */
+               if (memcmp(cstate->response + response_offset,
+                   remmd + response_offset, response_size) == 0)
+                   code = CHAP_SUCCESS;        /* they are the same! */
+               break;
+           }
+#endif /* CHAPMS */
+
            default:
                CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
            }
@@ -759,15 +787,33 @@ static void
 ChapGenChallenge(cstate)
     chap_state *cstate;
 {
-    int chal_len;
+    int chal_len = 0; /* Avoid compiler warning */
     u_char *ptr = cstate->challenge;
     int i;
 
-    /* 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);
+    switch (cstate->chal_type) {
+    case CHAP_DIGEST_MD5:
+       /*
+        * 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);
+       break;
+
+#ifdef CHAPMS
+    case CHAP_MICROSOFT:
+       /* MS-CHAP is fixed to an 8 octet challenge. */
+       chal_len = 8;
+       break;
+#endif
+    default:
+       fatal("ChapGenChallenge: Unsupported challenge type %d",
+             (int) cstate->chal_type);
+       break;
+    }
+
     cstate->chal_len = chal_len;
     cstate->chal_id = ++cstate->id;
     cstate->chal_transmits = 0;
index 37d166566f19b6f8614279212d59115509ea081c..d15b948c22780d1c6ff61cea8283a63621b726d2 100644 (file)
@@ -30,7 +30,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: chap.h,v 1.9 2002/01/22 16:02:58 dfs Exp $
+ * $Id: chap.h,v 1.10 2002/03/01 14:39:18 dfs Exp $
  */
 
 #ifndef __CHAP_INCLUDE__
 #define CHAP_DIGEST_MD5                5       /* use MD5 algorithm */
 #define MD5_SIGNATURE_SIZE     16      /* 16 bytes in a MD5 message digest */
 #define CHAP_MICROSOFT         0x80    /* use Microsoft-compatible alg. */
-#define MS_CHAP_RESPONSE_LEN   49      /* Response length for MS-CHAP */
+
+/*
+ * Digest type and selection.
+ */
+
+/* bitmask of supported algorithms */
+#define MDTYPE_MD5             0x1
+#define MDTYPE_MICROSOFT       0x2
+
+#ifdef CHAPMS
+#define MDTYPE_ALL (MDTYPE_MD5 | MDTYPE_MICROSOFT)
+#else
+#define MDTYPE_ALL (MDTYPE_MD5)
+#endif
+#define MDTYPE_NONE 0
+
+/* Return the digest alg. ID for the most preferred digest type. */
+#define CHAP_DIGEST(mdtype) \
+    ((mdtype) & MDTYPE_MD5)? CHAP_DIGEST_MD5: \
+    ((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \
+    0
+
+/* Return the bit flag (lsb set) for our most preferred digest type. */
+#define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype)
+
+/* Return the bit flag for a given digest algorithm ID. */
+#define CHAP_MDTYPE_D(digest) \
+    ((digest) == CHAP_DIGEST_MD5)? MDTYPE_MD5: \
+    ((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \
+    0
+
+/* Can we do the requested digest? */
+#define CHAP_CANDIGEST(mdtype, digest) \
+    ((digest) == CHAP_DIGEST_MD5)? (mdtype) & MDTYPE_MD5: \
+    ((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \
+    0
 
 #define CHAP_CHALLENGE         1
 #define CHAP_RESPONSE          2
index eb0c2c14e5d3b6c7b55fe5840fa5ef236133fd31..9a7002ced4201e572762951ec376371bedcd4c56 100644 (file)
@@ -31,7 +31,7 @@
  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
  */
 
-#define RCSID  "$Id: chap_ms.c,v 1.15 1999/08/13 06:46:12 paulus Exp $"
+#define RCSID  "$Id: chap_ms.c,v 1.16 2002/03/01 14:39:18 dfs Exp $"
 
 #ifdef CHAPMS
 
 
 static const char rcsid[] = RCSID;
 
-typedef struct {
-    u_char LANManResp[24];
-    u_char NTResp[24];
-    u_char UseNT;              /* If 1, ignore the LANMan response field */
-} MS_ChapResponse;
-/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
-   in case this struct gets padded. */
-
 
 static void    ChallengeResponse __P((u_char *, u_char *, u_char *));
 static void    DesEncrypt __P((u_char *, u_char *, u_char *));
index 1f0ea2b4e234e68a5a2df426821bb10668470fd4..e673f8aa24f9730efebc7368bbd9163412442a10 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * chap.h - Challenge Handshake Authentication Protocol definitions.
+ * chap_ms.h - Challenge Handshake Authentication Protocol definitions.
  *
  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
  * http://www.strataware.com/
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: chap_ms.h,v 1.2 1997/11/27 06:08:10 paulus Exp $
+ * $Id: chap_ms.h,v 1.3 2002/03/01 14:39:18 dfs Exp $
  */
 
 #ifndef __CHAPMS_INCLUDE__
 
 #define MD4_SIGNATURE_SIZE     16      /* 16 bytes in a MD4 message digest */
-#define MAX_NT_PASSWORD        256     /* Maximum number of (Unicode) chars in an NT password */
+#define MAX_NT_PASSWORD                256     /* Max (Unicode) chars in an NT pass */
+
+#define MS_CHAP_RESPONSE_LEN   49      /* Response length for MS-CHAP */
+
+/*
+ * Use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+ * in case this struct gets padded.
+ */
+typedef struct {
+    u_char LANManResp[24];
+    u_char NTResp[24];
+    u_char UseNT;              /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
 
 void ChapMS __P((chap_state *, char *, int, char *, int));
 
index d708c2709eacab958780c41e703942ed73957261..8cf6029c8ec4ad586674912f4832bea09b8f512a 100644 (file)
@@ -17,7 +17,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: lcp.c,v 1.57 2001/03/08 05:11:14 paulus Exp $"
+#define RCSID  "$Id: lcp.c,v 1.58 2002/03/01 14:39:18 dfs Exp $"
 
 /*
  * TODO:
@@ -327,7 +327,6 @@ lcp_init(unit)
     wo->neg_mru = 1;
     wo->mru = DEFMRU;
     wo->neg_asyncmap = 1;
-    wo->chap_mdtype = CHAP_DIGEST_MD5;
     wo->neg_magicnumber = 1;
     wo->neg_pcompression = 1;
     wo->neg_accompression = 1;
@@ -337,7 +336,7 @@ lcp_init(unit)
     ao->mru = MAXMRU;
     ao->neg_asyncmap = 1;
     ao->neg_chap = 1;
-    ao->chap_mdtype = CHAP_DIGEST_MD5;
+    ao->chap_mdtype = MDTYPE_ALL;
     ao->neg_upap = 1;
     ao->neg_magicnumber = 1;
     ao->neg_pcompression = 1;
@@ -679,10 +678,10 @@ lcp_addci(f, ucp, lenp)
     }
 #define ADDCICHAP(opt, neg, val, digest) \
     if (neg) { \
-       PUTCHAR(opt, ucp); \
+       PUTCHAR((opt), ucp); \
        PUTCHAR(CILEN_CHAP, ucp); \
-       PUTSHORT(val, ucp); \
-       PUTCHAR(digest, ucp); \
+       PUTSHORT((val), ucp); \
+       PUTCHAR((digest), ucp); \
     }
 #define ADDCILONG(opt, neg, val) \
     if (neg) { \
@@ -716,7 +715,7 @@ lcp_addci(f, ucp, lenp)
     ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
     ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
              go->asyncmap);
-    ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP,CHAP_DIGEST(go->chap_mdtype));
     ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
     ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
     ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
@@ -802,13 +801,13 @@ lcp_ackci(f, p, len)
        GETCHAR(citype, p); \
        GETCHAR(cilen, p); \
        if (cilen != CILEN_CHAP || \
-           citype != opt) \
+           citype != (opt)) \
            goto bad; \
        GETSHORT(cishort, p); \
-       if (cishort != val) \
+       if (cishort != (val)) \
            goto bad; \
        GETCHAR(cichar, p); \
-       if (cichar != digest) \
+       if (cichar != (digest)) \
          goto bad; \
     }
 #define ACKCILONG(opt, neg, val) \
@@ -863,7 +862,7 @@ lcp_ackci(f, p, len)
     ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
     ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
              go->asyncmap);
-    ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP,CHAP_DIGEST(go->chap_mdtype));
     ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
     ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
     ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
@@ -1035,7 +1034,7 @@ lcp_nakci(f, p, len)
        no.neg_chap = go->neg_chap;
        no.neg_upap = go->neg_upap;
        INCPTR(2, p);
-        GETSHORT(cishort, p);
+       GETSHORT(cishort, p);
        if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
            /*
             * If we were asking for CHAP, they obviously don't want to do it.
@@ -1050,18 +1049,25 @@ lcp_nakci(f, p, len)
            GETCHAR(cichar, p);
            if (go->neg_chap) {
                /*
-                * We were asking for CHAP/MD5; they must want a different
-                * algorithm.  If they can't do MD5, we can ask for M$-CHAP
-                * if we support it, otherwise we'll have to stop
-                * asking for CHAP.
+                * We were asking for our preferred algorithm, they must
+                * want something different.
                 */
-               if (cichar != go->chap_mdtype) {
-#ifdef CHAPMS
-                   if (cichar == CHAP_MICROSOFT)
-                       go->chap_mdtype = CHAP_MICROSOFT;
-                   else
-#endif /* CHAPMS */
-                       try.neg_chap = 0;
+               if (cichar != CHAP_DIGEST(go->chap_mdtype)) {
+                   if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) {
+                       /* Use their suggestion if we support it ... */
+                       go->chap_mdtype = CHAP_MDTYPE_D(cichar);
+                   } else {
+                       /* ... otherwise, try our next-preferred algorithm. */
+                       go->chap_mdtype &= ~(CHAP_MDTYPE(go->chap_mdtype));
+                       if (go->chap_mdtype == MDTYPE_NONE) /* out of algos */
+                           try.neg_chap = 0;
+                   }
+               } else {
+                   /*
+                    * Whoops, they Nak'd our algorithm of choice
+                    * but then suggested it back to us.
+                    */
+                   goto bad;
                }
            } else {
                /*
@@ -1304,7 +1310,7 @@ lcp_rejci(f, p, len)
        GETSHORT(cishort, p); \
        GETCHAR(cichar, p); \
        /* Check rejected value. */ \
-       if (cishort != val || cichar != digest) \
+       if ((cishort != (val)) || (cichar != (digest))) \
            goto bad; \
        try.neg = 0; \
        try.neg_upap = 0; \
@@ -1370,7 +1376,7 @@ lcp_rejci(f, p, len)
 
     REJCISHORT(CI_MRU, neg_mru, go->mru);
     REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
-    REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+    REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, CHAP_DIGEST(go->chap_mdtype));
     if (!go->neg_chap) {
        REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
     }
@@ -1527,7 +1533,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
             * for UPAP, then we will reject the second request.
             * Whether we end up doing CHAP or UPAP depends then on
             * the ordering of the CIs in the peer's Configure-Request.
-            */
+             */
 
            if (cishort == PPP_PAP) {
                if (ho->neg_chap ||     /* we've already accepted CHAP */
@@ -1541,9 +1547,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
                    PUTCHAR(CI_AUTHTYPE, nakp);
                    PUTCHAR(CILEN_CHAP, nakp);
                    PUTSHORT(PPP_CHAP, nakp);
-                   PUTCHAR(ao->chap_mdtype, nakp);
-                   /* XXX if we can do CHAP_MICROSOFT as well, we should
-                      probably put in another option saying so */
+                   PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
                    break;
                }
                ho->neg_upap = 1;
@@ -1563,20 +1567,20 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
                    PUTSHORT(PPP_PAP, nakp);
                    break;
                }
-               GETCHAR(cichar, p);     /* get digest type*/
-               if (cichar != CHAP_DIGEST_MD5
-#ifdef CHAPMS
-                   && cichar != CHAP_MICROSOFT
-#endif
-                   ) {
+               GETCHAR(cichar, p);     /* get digest type */
+               if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) {
+                   /*
+                    * We can't/won't do the requested type,
+                    * suggest something else.
+                    */
                    orc = CONFNAK;
                    PUTCHAR(CI_AUTHTYPE, nakp);
                    PUTCHAR(CILEN_CHAP, nakp);
                    PUTSHORT(PPP_CHAP, nakp);
-                   PUTCHAR(ao->chap_mdtype, nakp);
+                   PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
                    break;
                }
-               ho->chap_mdtype = cichar; /* save md type */
+               ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */
                ho->neg_chap = 1;
                break;
            }
@@ -1591,7 +1595,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
            if (ao->neg_chap) {
                PUTCHAR(CILEN_CHAP, nakp);
                PUTSHORT(PPP_CHAP, nakp);
-               PUTCHAR(ao->chap_mdtype, nakp);
+               PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
            } else {
                PUTCHAR(CILEN_SHORT, nakp);
                PUTSHORT(PPP_PAP, nakp);
index 5122b7bb2fed9179b072167de8fdc2c99eb95461..95260bb387d02a9f8cde10b6ac40a96a1e24111f 100644 (file)
@@ -16,7 +16,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: lcp.h,v 1.16 2001/03/08 05:11:14 paulus Exp $
+ * $Id: lcp.h,v 1.17 2002/03/01 14:39:18 dfs Exp $
  */
 
 /*
@@ -64,7 +64,7 @@ typedef struct lcp_options {
     bool neg_endpoint;         /* negotiate endpoint discriminator */
     int  mru;                  /* Value of MRU */
     int         mrru;                  /* Value of MRRU, and multilink enable */
-    u_char chap_mdtype;                /* which MD type (hashing algorithm) */
+    u_char chap_mdtype;                /* which MD types (hashing algorithm) */
     u_int32_t asyncmap;                /* Value of async map */
     u_int32_t magicnumber;
     int  numloops;             /* Number of loops during magic number neg. */
index 3c1a2950f7cd998f42e83e157fb6954300f78bb4..3779b289419ca491fb8baeedb26d07053ec5a367 100644 (file)
@@ -17,7 +17,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: options.c,v 1.81 2002/01/11 18:11:51 etbe Exp $"
+#define RCSID  "$Id: options.c,v 1.82 2002/03/01 14:39:18 dfs Exp $"
 
 #include <ctype.h>
 #include <stdio.h>
@@ -623,6 +623,12 @@ process_option(opt, cmd, argv)
        *(bool *)(opt->addr) = v;
        if (opt->addr2 && (opt->flags & OPT_A2COPY))
            *(bool *)(opt->addr2) = v;
+       else if (opt->addr2 && (opt->flags & OPT_A2CLR))
+           *(bool *)(opt->addr2) = 0;
+       else if (opt->addr2 && (opt->flags & OPT_A2CLRB))
+           *(u_char *)(opt->addr2) &= ~v;
+       if (opt->addr3 && (opt->flags & OPT_A3OR))
+           *(u_char *)(opt->addr3) |= v;
        break;
 
     case o_int:
index 3dc69aeae92b2a2b42d97fed65afcf8e8af2d052..c192bbb2684e69691a3e0c28dabbdfd99e4753ea 100644 (file)
@@ -21,7 +21,7 @@
 *
 ***********************************************************************/
 static char const RCSID[] =
-"$Id: radius.c,v 1.2 2002/02/08 17:28:31 dfs Exp $";
+"$Id: radius.c,v 1.3 2002/03/01 14:39:18 dfs Exp $";
 
 #include "pppd.h"
 #include "chap.h"
@@ -61,9 +61,6 @@ static int radius_init(char *msg);
 static int get_client_port(char *ifname);
 static int radius_allowed_address(u_int32_t addr);
 
-void (*radius_attributes_hook)(VALUE_PAIR *) = NULL;
-void (*radius_pre_auth_hook)(char const *user) = NULL;
-
 #ifndef MAXSESSIONID
 #define MAXSESSIONID 32
 #endif
@@ -80,8 +77,18 @@ struct radius_state {
     char config_file[MAXPATHLEN];
     char session_id[MAXSESSIONID + 1];
     time_t start_time;
+    SERVER *authserver;                /* Authentication server to use */
+    SERVER *acctserver;                /* Accounting server to use */
 };
 
+void (*radius_attributes_hook)(VALUE_PAIR *) = NULL;
+
+/* The pre_auth_hook MAY set authserver and acctserver if it wants.
+   In that case, they override the values in the radiusclient.conf file */
+void (*radius_pre_auth_hook)(char const *user,
+                            SERVER **authserver,
+                            SERVER **acctserver) = NULL;
+
 static struct radius_state rstate;
 
 char pppd_version[] = VERSION;
@@ -189,7 +196,9 @@ radius_pap_auth(char *user,
     make_username_realm(user);
 
     if (radius_pre_auth_hook) {
-       radius_pre_auth_hook(rstate.user);
+       radius_pre_auth_hook(rstate.user,
+                            &rstate.authserver,
+                            &rstate.acctserver);
     }
 
     send = NULL;
@@ -212,7 +221,13 @@ radius_pap_auth(char *user,
                       VENDOR_NONE);
     }
 
-    result = rc_auth(rstate.client_port, send, &received, radius_msg);
+    if (rstate.authserver) {
+       result = rc_auth_using_server(rstate.authserver,
+                                     rstate.client_port, send,
+                                     &received, radius_msg);
+    } else {
+       result = rc_auth(rstate.client_port, send, &received, radius_msg);
+    }
 
     if (result == OK_RC) {
        if (radius_setparams(received, radius_msg) < 0) {
@@ -268,7 +283,9 @@ radius_chap_auth(char *user,
        make_username_realm(user);
        rstate.client_port = get_client_port (ifname);
        if (radius_pre_auth_hook) {
-           radius_pre_auth_hook(rstate.user);
+           radius_pre_auth_hook(rstate.user,
+                                &rstate.authserver,
+                                &rstate.acctserver);
        }
     }
 
@@ -298,7 +315,13 @@ radius_chap_auth(char *user,
      * make authentication with RADIUS server
      */
 
-    result = rc_auth (rstate.client_port, send, &received, radius_msg);
+    if (rstate.authserver) {
+       result = rc_auth_using_server(rstate.authserver,
+                                     rstate.client_port, send,
+                                     &received, radius_msg);
+    } else {
+       result = rc_auth(rstate.client_port, send, &received, radius_msg);
+    }
 
     if (result == OK_RC) {
        if (!rstate.done_chap_once) {
@@ -474,7 +497,12 @@ radius_acct_start(void)
     av_type = htonl(hisaddr);
     rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
 
-    result = rc_acct(rstate.client_port, send);
+    if (rstate.acctserver) {
+       result = rc_acct_using_server(rstate.acctserver,
+                                     rstate.client_port, send);
+    } else {
+       result = rc_acct(rstate.client_port, send);
+    }
 
     rc_avpair_free(send);
 
@@ -561,7 +589,13 @@ radius_acct_stop(void)
     av_type = htonl(hisaddr);
     rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
 
-    result = rc_acct(rstate.client_port, send);
+    if (rstate.acctserver) {
+       result = rc_acct_using_server(rstate.acctserver,
+                                     rstate.client_port, send);
+    } else {
+       result = rc_acct(rstate.client_port, send);
+    }
+
     if (result != OK_RC) {
        /* RADIUS server could be down so make this a warning */
        syslog(LOG_WARNING,
index cff68227bf6d7a6dbd6dc79a80cedabf006af73a..5604987f8b950fb399a2d0722b3335f28d9b01cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: radiusclient.h,v 1.2 2002/02/27 15:51:19 dfs Exp $
+ * $Id: radiusclient.h,v 1.3 2002/03/01 14:39:19 dfs Exp $
  *
  * Copyright (C) 1995,1996,1997,1998 Lars Fenneberg
  *
@@ -379,8 +379,10 @@ VALUE_PAIR *rc_avpair_readin __P((FILE *));
 void rc_buildreq __P((SEND_DATA *, int, char *, unsigned short, int, int));
 unsigned char rc_get_seqnbr __P((void));
 int rc_auth __P((UINT4, VALUE_PAIR *, VALUE_PAIR **, char *));
+int rc_auth_using_server __P((SERVER *, UINT4, VALUE_PAIR *, VALUE_PAIR **, char *));
 int rc_auth_proxy __P((VALUE_PAIR *, VALUE_PAIR **, char *));
 int rc_acct __P((UINT4, VALUE_PAIR *));
+int rc_acct_using_server __P((SERVER *, UINT4, VALUE_PAIR *));
 int rc_acct_proxy __P((VALUE_PAIR *));
 int rc_check __P((char *, unsigned short, char *));
 
index 507a25c63fce0d869dcfa54ad6e07bea3744af38..b7ca07ecd2946a59e29ee2b04dc69a034648c405 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: buildreq.c,v 1.1 2002/01/22 16:03:02 dfs Exp $
+ * $Id: buildreq.c,v 1.2 2002/03/01 14:39:19 dfs Exp $
  *
  * Copyright (C) 1995,1997 Lars Fenneberg
  *
@@ -121,12 +121,37 @@ unsigned char rc_get_seqnbr(void)
 
 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
            char *msg)
+{
+    SERVER *authserver = rc_conf_srv("authserver");
+
+    if (!authserver) {
+       return (ERROR_RC);
+    }
+    return rc_auth_using_server(authserver, client_port, send, received, msg);
+}
+
+/*
+ * Function: rc_auth_using_server
+ *
+ * Purpose: Builds an authentication request for port id client_port
+ *         with the value_pairs send and submits it to a server.  You
+ *          explicitly supply a server list.
+ *
+ * Returns: received value_pairs in received, messages from the server in msg
+ *         and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_auth_using_server(SERVER *authserver,
+                        UINT4 client_port,
+                        VALUE_PAIR *send,
+                        VALUE_PAIR **received,
+                        char *msg)
 {
        SEND_DATA       data;
        UINT4           client_id;
        int             result;
        int             i;
-       SERVER          *authserver = rc_conf_srv("authserver");
        int             timeout = rc_conf_int("radius_timeout");
        int             retries = rc_conf_int("radius_retries");
 
@@ -215,16 +240,18 @@ int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
 
 
 /*
- * Function: rc_acct
+ * Function: rc_acct_using_server
  *
  * Purpose: Builds an accounting request for port id client_port
- *         with the value_pairs send
+ *         with the value_pairs send.  You explicitly supply server list.
  *
  * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
  *         in by this function, the rest has to be supplied.
  */
 
-int rc_acct(UINT4 client_port, VALUE_PAIR *send)
+int rc_acct_using_server(SERVER *acctserver,
+                        UINT4 client_port,
+                        VALUE_PAIR *send)
 {
        SEND_DATA       data;
        VALUE_PAIR      *adt_vp;
@@ -233,7 +260,6 @@ int rc_acct(UINT4 client_port, VALUE_PAIR *send)
        time_t          start_time, dtime;
        char            msg[4096];
        int             i;
-       SERVER          *acctserver = rc_conf_srv("acctserver");
        int             timeout = rc_conf_int("radius_timeout");
        int             retries = rc_conf_int("radius_retries");
 
@@ -288,6 +314,24 @@ int rc_acct(UINT4 client_port, VALUE_PAIR *send)
        return result;
 }
 
+/*
+ * Function: rc_acct
+ *
+ * Purpose: Builds an accounting request for port id client_port
+ *         with the value_pairs send
+ *
+ * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
+ *         in by this function, the rest has to be supplied.
+ */
+
+int rc_acct(UINT4 client_port, VALUE_PAIR *send)
+{
+    SERVER *acctserver = rc_conf_srv("acctserver");
+    if (!acctserver) return (ERROR_RC);
+
+    return rc_acct_using_server(acctserver, client_port, send);
+}
+
 /*
  * Function: rc_acct_proxy
  *
index e468994d3dc746ecaa9196f13f32046b4011a67c..229708a12b1cfa5947cb6af24e00cae18f283a73 100644 (file)
@@ -1,5 +1,5 @@
 .\" manual page [] for pppd 2.4
-.\" $Id: pppd.8,v 1.59 2002/01/11 18:04:37 etbe Exp $
+.\" $Id: pppd.8,v 1.60 2002/03/01 14:39:18 dfs Exp $
 .\" SH section heading
 .\" SS subsection heading
 .\" LP paragraph
@@ -853,6 +853,10 @@ to \fIname\fR.
 With this option, pppd will not agree to authenticate itself to the
 peer using CHAP.
 .TP
+.B refuse-mschap
+With this option, pppd will not agree to authenticate itself to the
+peer using MS-CHAP.
+.TP
 .B refuse-pap
 With this option, pppd will not agree to authenticate itself to the
 peer using PAP.
@@ -861,6 +865,10 @@ peer using PAP.
 Require the peer to authenticate itself using CHAP [Challenge
 Handshake Authentication Protocol] authentication.
 .TP
+.B require-mschap
+Require the peer to authenticate itself using MS-CHAP [Microsft Challenge
+Handshake Authentication Protocol] authentication.
+.TP
 .B require-pap
 Require the peer to authenticate itself using PAP [Password
 Authentication Protocol] authentication.
@@ -1012,7 +1020,7 @@ pppd will not agree to authenticate itself with a particular protocol
 if it has no secrets which could be used to do so.
 .LP
 Pppd stores secrets for use in authentication in secrets
-files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
+files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP/MS-CHAP).
 Both secrets files have the same format.  The secrets files can
 contain secrets for pppd to use in authenticating itself to other
 systems, as well as secrets for pppd to use when authenticating other
@@ -1500,7 +1508,7 @@ file should be owned by root and not readable or writable by any other
 user.  Pppd will log a warning if this is not the case.
 .TP
 .B /etc/ppp/chap-secrets
-Names, secrets and IP addresses for CHAP authentication.  As for
+Names, secrets and IP addresses for CHAP/MS-CHAP authentication.  As for
 /etc/ppp/pap-secrets, this file should be owned by root and not
 readable or writable by any other user.  Pppd will log a warning if
 this is not the case.
index 5d287d6b4649d4a1cd46c40a0bddb65d217c0d2a..d75a6fd8161d2876bfc24057d733c07e151ec627 100644 (file)
@@ -16,7 +16,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: pppd.h,v 1.65 2002/02/12 20:07:09 dfs Exp $
+ * $Id: pppd.h,v 1.66 2002/03/01 14:39:18 dfs Exp $
  */
 
 /*
@@ -86,6 +86,7 @@ typedef struct {
        const char *source;
        short int priority;
        short int winner;
+       void    *addr3;
 } option_t;
 
 /* Values for flags */
@@ -102,6 +103,7 @@ typedef struct {
 #define OPT_ZEROOK     0x10000 /* 0 value is OK even if not within limits */
 #define OPT_HIDE       0x10000 /* for o_string, print value as ?????? */
 #define OPT_A2LIST     0x10000 /* for o_special, keep list of values */
+#define OPT_A2CLRB     0x10000 /* o_bool, clr val bits in *(u_char *)addr2 */
 #define OPT_NOINCR     0x20000 /* value mustn't be increased */
 #define OPT_ZEROINF    0x40000 /* with OPT_NOINCR, 0 == infinity */
 #define OPT_PRIO       0x80000 /* process option priorities for this option */
@@ -117,6 +119,7 @@ typedef struct {
 #define OPT_A2PRINTER  0x10000000 /* *addr2 is a fn for printing option */
 #define OPT_A2STRVAL   0x20000000 /* *addr2 points to current string value */
 #define OPT_NOPRINT    0x40000000 /* don't print this option at all */
+#define OPT_A3OR       0x80000000 /* addr3 -> third location to rcv | value */
 
 #define OPT_VAL(x)     ((x) & OPT_VALUE)
 
@@ -808,4 +811,8 @@ extern void (*snoop_send_hook) __P((unsigned char *p, int len));
 #define MAX(a, b)      ((a) > (b)? (a): (b))
 #endif
 
+#ifndef offsetof
+#define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
 #endif /* __PPP_H__ */