Module-Failure-Message goes in request, not in reply
[freeradius.git] / src / modules / rlm_mschap / rlm_mschap.c
index 19aabb5..62d45ac 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2000,2001  The FreeRADIUS server project
- */
-
-
-/*
- *  mschap.c    MS-CHAP module
- *
- *  This implements MS-CHAP, as described in RFC 2548
- *
- *  http://www.freeradius.org/rfc/rfc2548.txt
- *
- */
-
-/*
- *  If you have any questions on NTLM (Samba) passwords
- *  support, LM authentication and MS-CHAP v2 support
- *  please contact
- *
- *  Vladimir Dubrovin  vlad@sandy.ru
- *  aka
- *  ZARAZA             3APA3A@security.nnov.ru
+ * Copyright 2000,2001,2006  The FreeRADIUS server project
  */
 
 /*  MPPE support from Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp> */
 
-#include       "autoconf.h"
-#include       "libradius.h"
+#include       <freeradius-devel/ident.h>
+RCSID("$Id$")
 
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <string.h>
-#include       <ctype.h>
-
-#include       "radiusd.h"
-#include       "modules.h"
+#include       <freeradius-devel/radiusd.h>
+#include       <freeradius-devel/modules.h>
+#include       <freeradius-devel/rad_assert.h>
+#include        <freeradius-devel/md5.h>
+#include        <freeradius-devel/sha1.h>
 
-#include        "md4.h"
-#include        "md5.h"
-#include       "sha1.h"
-#include       "rad_assert.h"
+#include       <ctype.h>
 
+#include       "mschap.h"
 #include       "smbdes.h"
 
-static const char rcsid[] = "$Id$";
-
-static const char *letters = "0123456789ABCDEF";
-
-/*
- *     hex2bin converts hexadecimal strings into binary
- */
-static int hex2bin (const char *szHex, unsigned char* szBin, int len)
-{
-       char * c1, * c2;
-       int i;
-
-       for (i = 0; i < len; i++) {
-               if( !(c1 = memchr(letters, toupper((int) szHex[i << 1]), 16)) ||
-                   !(c2 = memchr(letters, toupper((int) szHex[(i << 1) + 1]), 16)))
-                    break;
-                 szBin[i] = ((c1-letters)<<4) + (c2-letters);
-        }
-        return i;
-}
-
-/*
- *     bin2hex creates hexadecimal presentation
- *     of binary data
- */
-static void bin2hex (const unsigned char *szBin, char *szHex, int len)
-{
-       int i;
-       for (i = 0; i < len; i++) {
-               szHex[i<<1] = letters[szBin[i] >> 4];
-               szHex[(i<<1) + 1] = letters[szBin[i] & 0x0F];
-       }
-}
-
+#ifdef __APPLE__
+extern int od_mschap_auth(REQUEST *request, VALUE_PAIR *challenge, VALUE_PAIR * usernamepair);
+#endif
 
 /* Allowable account control bits */
 #define ACB_DISABLED   0x0001  /* 1 = User account disabled */
@@ -183,112 +128,18 @@ static int pdb_decode_acct_ctrl(const char *p)
 }
 
 
-/*
- *     ntpwdhash converts Unicode password to 16-byte NT hash
- *     with MD4
- */
-static void ntpwdhash (unsigned char *szHash, const char *szPassword)
-{
-       char szUnicodePass[513];
-       int nPasswordLen;
-       int i;
-
-       /*
-        *      NT passwords are unicode.  Convert plain text password
-        *      to unicode by inserting a zero every other byte
-        */
-       nPasswordLen = strlen(szPassword);
-       for (i = 0; i < nPasswordLen; i++) {
-               szUnicodePass[i << 1] = szPassword[i];
-               szUnicodePass[(i << 1) + 1] = 0;
-       }
-
-       /* Encrypt Unicode password to a 16-byte MD4 hash */
-       md4_calc(szHash, szUnicodePass, (nPasswordLen<<1) );
-}
-
-
-/*
- *     challenge_hash() is used by mschap2() and auth_response()
- *     implements RFC2759 ChallengeHash()
- *     generates 64 bit challenge
- */
-static void challenge_hash( const char *peer_challenge,
-                           const char *auth_challenge,
-                           const char *user_name, char *challenge )
-{
-       SHA1_CTX Context;
-       unsigned char hash[20];
-
-       SHA1Init(&Context);
-       SHA1Update(&Context, peer_challenge, 16);
-       SHA1Update(&Context, auth_challenge, 16);
-       SHA1Update(&Context, user_name, strlen(user_name));
-       SHA1Final(hash, &Context);
-       memcpy(challenge, hash, 8);
-}
-
-/*
- *     auth_response() generates MS-CHAP v2 SUCCESS response
- *     according to RFC 2759 GenerateAuthenticatorResponse()
- *     returns 42-octet response string
- */
-static void auth_response(const char *username,
-                         const unsigned char *nt_hash_hash,
-                         unsigned char *ntresponse,
-                         char *peer_challenge, char *auth_challenge,
-                         char *response)
-{
-       SHA1_CTX Context;
-       const unsigned char magic1[39] =
-       {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
-        0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
-        0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
-        0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
-
-       const unsigned char magic2[41] =
-       {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
-        0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
-        0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
-        0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
-        0x6E};
-
-        char challenge[8];
-       unsigned char digest[20];
-
-       SHA1Init(&Context);
-       SHA1Update(&Context, nt_hash_hash, 16);
-       SHA1Update(&Context, ntresponse, 24);
-       SHA1Update(&Context, magic1, 39);
-       SHA1Final(digest, &Context);
-       challenge_hash(peer_challenge, auth_challenge, username, challenge);
-       SHA1Init(&Context);
-       SHA1Update(&Context, digest, 20);
-       SHA1Update(&Context, challenge, 8);
-       SHA1Update(&Context, magic2, 41);
-       SHA1Final(digest, &Context);
-
-       /*
-        *      Encode the value of 'Digest' as "S=" followed by
-        *      40 ASCII hexadecimal digits and return it in
-        *      AuthenticatorResponse.
-        *      For example,
-        *      "S=0123456789ABCDEF0123456789ABCDEF01234567"
-        */
-       response[0] = 'S';
-       response[1] = '=';
-       bin2hex(digest, response + 2, 20);
-}
-
-
 typedef struct rlm_mschap_t {
        int use_mppe;
        int require_encryption;
         int require_strong;
         int with_ntdomain_hack;        /* this should be in another module */
        char *passwd_file;
-       char *xlat_name;
+       const char *xlat_name;
        char *ntlm_auth;
+       const char *auth_type;
+#ifdef __APPLE__
+       int  open_directory;
+#endif  
 } rlm_mschap_t;
 
 
@@ -298,18 +149,18 @@ typedef struct rlm_mschap_t {
  *     Pulls NT-Response, LM-Response, or Challenge from MSCHAP
  *     attributes.
  */
-static int mschap_xlat(void *instance, REQUEST *request,
+static size_t mschap_xlat(void *instance, REQUEST *request,
                       char *fmt, char *out, size_t outlen,
                       RADIUS_ESCAPE_STRING func)
 {
-       int             i, data_len;
+       size_t          i, data_len;
        uint8_t         *data = NULL;
-       uint8_t         buffer[8];
+       uint8_t         buffer[32];
        VALUE_PAIR      *user_name;
        VALUE_PAIR      *chap_challenge, *response;
        rlm_mschap_t    *inst = instance;
 
-       chap_challenge = response = NULL;
+       response = NULL;
 
        func = func;            /* -Wunused */
 
@@ -317,11 +168,12 @@ static int mschap_xlat(void *instance, REQUEST *request,
         *      Challenge means MS-CHAPv1 challenge, or
         *      hash of MS-CHAPv2 challenge, and peer challenge.
         */
-       if (strcasecmp(fmt, "Challenge") == 0) {
+       if (strncasecmp(fmt, "Challenge", 9) == 0) {
                chap_challenge = pairfind(request->packet->vps,
-                                         PW_MSCHAP_CHALLENGE);
+                                         PW_MSCHAP_CHALLENGE,
+                                         VENDORPEC_MICROSOFT);
                if (!chap_challenge) {
-                       DEBUG2("  rlm_mschap: No MS-CHAP-Challenge in the request.");
+                       RDEBUG2("No MS-CHAP-Challenge in the request.");
                        return 0;
                }
 
@@ -330,8 +182,9 @@ static int mschap_xlat(void *instance, REQUEST *request,
                 *      for MS-CHAPv2
                 */
                if (chap_challenge->length == 8) {
-                       DEBUG2(" mschap1: %02x", chap_challenge->strvalue[0]);
-                       data = chap_challenge->strvalue;
+                       RDEBUG2(" mschap1: %02x",
+                              chap_challenge->vp_octets[0]);
+                       data = chap_challenge->vp_octets;
                        data_len = 8;
 
                        /*
@@ -339,43 +192,73 @@ static int mschap_xlat(void *instance, REQUEST *request,
                         *      for MS-CHAPv2.
                         */
                } else if (chap_challenge->length == 16) {
+                       VALUE_PAIR *name_attr, *response_name;
                        char *username_string;
 
-                       DEBUG2(" mschap2: %02x", chap_challenge->strvalue[0]);
+                       RDEBUG2(" mschap2: %02x", chap_challenge->vp_octets[0]);
                        response = pairfind(request->packet->vps,
-                                           PW_MSCHAP2_RESPONSE);
+                                           PW_MSCHAP2_RESPONSE,
+                                           VENDORPEC_MICROSOFT);
                        if (!response) {
-                               DEBUG2("  rlm_mschap: MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge.");
+                               RDEBUG2("MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge.");
                                return 0;
                        }
 
                        /*
+                        *      FIXME: Much of this is copied from
+                        *      below.  We should put it into a
+                        *      separate function.
+                        */
+
+                       /*
                         *      Responses are 50 octets.
                         */
                        if (response->length < 50) {
-                               radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format.");
+                               radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
                                return 0;
                        }
 
                        user_name = pairfind(request->packet->vps,
-                                            PW_USER_NAME);
+                                            PW_USER_NAME, 0);
                        if (!user_name) {
-                               DEBUG2("  rlm_mschap: User-Name is required to calculateMS-CHAPv1 Challenge.");
+                               RDEBUG2("User-Name is required to calculate MS-CHAPv1 Challenge.");
                                return 0;
                        }
 
+                       /*
+                        *      Check for MS-CHAP-User-Name and if found, use it
+                        *      to construct the MSCHAPv1 challenge.  This is
+                        *      set by rlm_eap_mschap to the MS-CHAP Response
+                        *      packet Name field.
+                        *
+                        *      We prefer this to the User-Name in the
+                        *      packet.
+                        */
+                       response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME, 0);
+                       if (response_name) {
+                               name_attr = response_name;
+                       } else {
+                               name_attr = user_name;
+                       }
+
                        /*
                         *      with_ntdomain_hack moved here, too.
                         */
-                       if ((username_string = strchr(user_name->strvalue, '\\')) != NULL) {
+                       if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
                                if (inst->with_ntdomain_hack) {
                                        username_string++;
                                } else {
-                                       DEBUG2("  rlm_mschap: NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
-                                       username_string = user_name->strvalue;
+                                       RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
+                                       username_string = name_attr->vp_strvalue;
                                }
                        } else {
-                               username_string = user_name->strvalue;
+                               username_string = name_attr->vp_strvalue;
+                       }
+
+                       if (response_name &&
+                           ((user_name->length != response_name->length) ||
+                            (strncasecmp(user_name->vp_strvalue, response_name->vp_strvalue, user_name->length) != 0))) {
+                               RDEBUG("WARNING: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", user_name->vp_strvalue, response_name->vp_strvalue);
                        }
 
                        /*
@@ -383,27 +266,30 @@ static int mschap_xlat(void *instance, REQUEST *request,
                         *      from the MS-CHAPv2 peer challenge,
                         *      our challenge, and the user name.
                         */
-                       challenge_hash(response->strvalue + 2,
-                                      chap_challenge->strvalue,
+                       RDEBUG2("Creating challenge hash with username: %s",
+                               username_string);
+                       mschap_challenge_hash(response->vp_octets + 2,
+                                      chap_challenge->vp_octets,
                                       username_string, buffer);
                        data = buffer;
                        data_len = 8;
                } else {
-                       DEBUG2("  rlm_mschap: Invalid MS-CHAP challenge length");
+                       RDEBUG2("Invalid MS-CHAP challenge length");
                        return 0;
                }
-               
+
                /*
                 *      Get the MS-CHAPv1 response, or the MS-CHAPv2
                 *      response.
                 */
-       } else if (strcasecmp(fmt, "NT-Response") == 0) {
+       } else if (strncasecmp(fmt, "NT-Response", 11) == 0) {
                response = pairfind(request->packet->vps,
-                                   PW_MSCHAP_RESPONSE);
+                                   PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
                if (!response) response = pairfind(request->packet->vps,
-                                                  PW_MSCHAP2_RESPONSE);
+                                                  PW_MSCHAP2_RESPONSE,
+                                                  VENDORPEC_MICROSOFT);
                if (!response) {
-                       DEBUG2("  rlm_mschap: No MS-CHAP-Response or MS-CHAP2-Response was found in the request.");
+                       RDEBUG2("No MS-CHAP-Response or MS-CHAP2-Response was found in the request.");
                        return 0;
                }
 
@@ -412,8 +298,8 @@ static int mschap_xlat(void *instance, REQUEST *request,
                 *      if the second octet says so.
                 */
                if ((response->attribute == PW_MSCHAP_RESPONSE) &&
-                   ((response->strvalue[1] & 0x01) == 0)) {
-                       DEBUG2("  rlm_mschap: No NT-Response in MS-CHAP-Response");
+                   ((response->vp_octets[1] & 0x01) == 0)) {
+                       RDEBUG2("No NT-Response in MS-CHAP-Response");
                        return 0;
                }
 
@@ -422,18 +308,18 @@ static int mschap_xlat(void *instance, REQUEST *request,
                 *      the NT-Response at the same offset, and are
                 *      the same length.
                 */
-               data = response->strvalue + 26;
+               data = response->vp_octets + 26;
                data_len = 24;
-               
+
                /*
                 *      LM-Response is deprecated, and exists only
                 *      in MS-CHAPv1, and not often there.
                 */
-       } else if (strcasecmp(fmt, "LM-Response") == 0) {
+       } else if (strncasecmp(fmt, "LM-Response", 11) == 0) {
                response = pairfind(request->packet->vps,
-                                   PW_MSCHAP_RESPONSE);
+                                   PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
                if (!response) {
-                       DEBUG2("  rlm_mschap: No MS-CHAP-Response was found in the request.");
+                       RDEBUG2("No MS-CHAP-Response was found in the request.");
                        return 0;
                }
 
@@ -441,40 +327,40 @@ static int mschap_xlat(void *instance, REQUEST *request,
                 *      For MS-CHAPv1, the NT-Response exists only
                 *      if the second octet says so.
                 */
-               if ((response->strvalue[1] & 0x01) != 0) {
-                       DEBUG2("  rlm_mschap: No LM-Response in MS-CHAP-Response");
+               if ((response->vp_octets[1] & 0x01) != 0) {
+                       RDEBUG2("No LM-Response in MS-CHAP-Response");
                        return 0;
                }
-               data = response->strvalue + 2;
+               data = response->vp_octets + 2;
                data_len = 24;
 
                /*
                 *      Pull the NT-Domain out of the User-Name, if it exists.
                 */
-       } else if (strcasecmp(fmt, "NT-Domain") == 0) {
+       } else if (strncasecmp(fmt, "NT-Domain", 9) == 0) {
                char *p, *q;
 
-               user_name = pairfind(request->packet->vps, PW_USER_NAME);
+               user_name = pairfind(request->packet->vps, PW_USER_NAME, 0);
                if (!user_name) {
-                       DEBUG2("  rlm_mschap: No User-Name was found in the request.");
+                       RDEBUG2("No User-Name was found in the request.");
                        return 0;
                }
-               
+
                /*
                 *      First check to see if this is a host/ style User-Name
                 *      (a la Kerberos host principal)
                 */
-               if (strncmp(user_name->strvalue, "host/", 5) == 0) {
+               if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) {
                        /*
                         *      If we're getting a User-Name formatted in this way,
                         *      it's likely due to PEAP.  The Windows Domain will be
                         *      the first domain component following the hostname,
                         *      or the machine name itself if only a hostname is supplied
                         */
-                       p = strchr(user_name->strvalue, '.');
+                       p = strchr(user_name->vp_strvalue, '.');
                        if (!p) {
-                               DEBUG2("  rlm_mschap: setting NT-Domain to same as machine name");
-                               strNcpy(out, user_name->strvalue + 5, outlen);
+                               RDEBUG2("setting NT-Domain to same as machine name");
+                               strlcpy(out, user_name->vp_strvalue + 5, outlen);
                        } else {
                                p++;    /* skip the period */
                                q = strchr(p, '.');
@@ -483,13 +369,13 @@ static int mschap_xlat(void *instance, REQUEST *request,
                                 * only if another period was found
                                 */
                                if (q) *q = '\0';
-                               strNcpy(out, p, outlen);
+                               strlcpy(out, p, outlen);
                                if (q) *q = '.';
                        }
                } else {
-                       p = strchr(user_name->strvalue, '\\');
+                       p = strchr(user_name->vp_strvalue, '\\');
                        if (!p) {
-                               DEBUG2("  rlm_mschap: No NT-Domain was found in the User-Name.");
+                               RDEBUG2("No NT-Domain was found in the User-Name.");
                                return 0;
                        }
 
@@ -497,7 +383,7 @@ static int mschap_xlat(void *instance, REQUEST *request,
                         *      Hack.  This is simpler than the alternatives.
                         */
                        *p = '\0';
-                       strNcpy(out, user_name->strvalue, outlen);
+                       strlcpy(out, user_name->vp_strvalue, outlen);
                        *p = '\\';
                }
 
@@ -506,20 +392,20 @@ static int mschap_xlat(void *instance, REQUEST *request,
                /*
                 *      Pull the User-Name out of the User-Name...
                 */
-       } else if (strcasecmp(fmt, "User-Name") == 0) {
+       } else if (strncasecmp(fmt, "User-Name", 9) == 0) {
                char *p;
 
-               user_name = pairfind(request->packet->vps, PW_USER_NAME);
+               user_name = pairfind(request->packet->vps, PW_USER_NAME, 0);
                if (!user_name) {
-                       DEBUG2("  rlm_mschap: No User-Name was found in the request.");
+                       RDEBUG2("No User-Name was found in the request.");
                        return 0;
                }
-               
+
                /*
                 *      First check to see if this is a host/ style User-Name
                 *      (a la Kerberos host principal)
                 */
-               if (strncmp(user_name->strvalue, "host/", 5) == 0) {
+               if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) {
                        /*
                         *      If we're getting a User-Name formatted in this way,
                         *      it's likely due to PEAP.  When authenticating this against
@@ -530,28 +416,78 @@ static int mschap_xlat(void *instance, REQUEST *request,
                         *      from that point to the first period into a string and appending
                         *      a $ to the end.
                         */
-                       p = strchr(user_name->strvalue, '.');
+                       p = strchr(user_name->vp_strvalue, '.');
                        /*
                         * use the same hack as above
                         * only if a period was found
                         */
                        if (p) *p = '\0';
-                       snprintf(out, outlen, "%s$", user_name->strvalue + 5);
+                       snprintf(out, outlen, "%s$", user_name->vp_strvalue + 5);
                        if (p) *p = '.';
                } else {
-                       p = strchr(user_name->strvalue, '\\');
+                       p = strchr(user_name->vp_strvalue, '\\');
                        if (p) {
                                p++;    /* skip the backslash */
                        } else {
-                               p = user_name->strvalue; /* use the whole User-Name */
+                               p = user_name->vp_strvalue; /* use the whole User-Name */
                        }
-                       strNcpy(out, p, outlen);
+                       strlcpy(out, p, outlen);
                }
 
                return strlen(out);
 
+               /*
+                * Return the NT-Hash of the passed string
+                */
+       } else if (strncasecmp(fmt, "NT-Hash ", 8) == 0) {
+               char *p;
+               char buf2[1024];
+
+               p = fmt + 8;    /* 7 is the length of 'NT-Hash' */
+               if ((p == '\0')  || (outlen <= 32))
+                       return 0;
+
+               while (isspace(*p)) p++;
+
+               if (!radius_xlat(buf2, sizeof(buf2),p,request,NULL)) {
+                       RDEBUG("xlat failed");
+                       *buffer = '\0';
+                       return 0;
+               }
+
+               mschap_ntpwdhash(buffer,buf2);
+
+               fr_bin2hex(buffer, out, 16);
+               out[32] = '\0';
+               RDEBUG("NT-Hash of %s = %s", buf2, out);
+               return 32;
+
+               /*
+                * Return the LM-Hash of the passed string
+                */
+       } else if (strncasecmp(fmt, "LM-Hash ", 8) == 0) {
+               char *p;
+               char buf2[1024];
+
+               p = fmt + 8;    /* 7 is the length of 'LM-Hash' */
+               if ((p == '\0') || (outlen <= 32))
+                       return 0;
+
+               while (isspace(*p)) p++;
+
+               if (!radius_xlat(buf2, sizeof(buf2),p,request,NULL)) {
+                       RDEBUG("xlat failed");
+                       *buffer = '\0';
+                       return 0;
+               }
+
+               smbdes_lmpwdhash(buf2, buffer);
+               fr_bin2hex(buffer, out, 16);
+               out[32] = '\0';
+               RDEBUG("LM-Hash of %s = %s", buf2, out);
+               return 32;
        } else {
-               DEBUG2("  rlm_mschap: Unknown expansion string \"%s\"",
+               RDEBUG2("Unknown expansion string \"%s\"",
                       fmt);
                return 0;
        }
@@ -562,7 +498,7 @@ static int mschap_xlat(void *instance, REQUEST *request,
         *      Didn't set anything: this is bad.
         */
        if (!data) {
-               DEBUG2("  rlm_mschap: Failed to do anything intelligent");
+               RDEBUG2("Failed to do anything intelligent");
                return 0;
        }
 
@@ -574,18 +510,18 @@ static int mschap_xlat(void *instance, REQUEST *request,
        }
 
        /*
-        *      
+        *
         */
        for (i = 0; i < data_len; i++) {
                sprintf(out + (2 * i), "%02x", data[i]);
        }
        out[data_len * 2] = '\0';
-       
+
        return data_len * 2;
 }
 
 
-static CONF_PARSER module_config[] = {
+static const CONF_PARSER module_config[] = {
        /*
         *      Cache the password by default.
         */
@@ -601,6 +537,10 @@ static CONF_PARSER module_config[] = {
          offsetof(rlm_mschap_t, passwd_file), NULL,  NULL },
        { "ntlm_auth",   PW_TYPE_STRING_PTR,
          offsetof(rlm_mschap_t, ntlm_auth), NULL,  NULL },
+#ifdef __APPLE__
+       { "use_open_directory",    PW_TYPE_BOOLEAN,
+         offsetof(rlm_mschap_t,open_directory), NULL, "yes" },
+#endif
 
        { NULL, -1, 0, NULL, NULL }             /* end the list */
 };
@@ -611,8 +551,6 @@ static CONF_PARSER module_config[] = {
  */
 static int mschap_detach(void *instance){
 #define inst ((rlm_mschap_t *)instance)
-       free(inst->passwd_file);
-       free(inst->ntlm_auth);
        if (inst->xlat_name) {
                xlat_unregister(inst->xlat_name, mschap_xlat);
                free(inst->xlat_name);
@@ -628,7 +566,6 @@ static int mschap_detach(void *instance){
  */
 static int mschap_instantiate(CONF_SECTION *conf, void **instance)
 {
-       const char *xlat_name;
        rlm_mschap_t *inst;
 
        inst = *instance = rad_malloc(sizeof(*inst));
@@ -657,12 +594,18 @@ static int mschap_instantiate(CONF_SECTION *conf, void **instance)
        /*
         *      Create the dynamic translation.
         */
-       xlat_name = cf_section_name2(conf);
-       if (xlat_name == NULL)
-               xlat_name = cf_section_name1(conf);
-       if (xlat_name){
-               inst->xlat_name = strdup(xlat_name);
-               xlat_register(xlat_name, mschap_xlat, inst);
+       inst->xlat_name = cf_section_name2(conf);
+       if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
+       inst->xlat_name = strdup(inst->xlat_name);
+       xlat_register(inst->xlat_name, mschap_xlat, inst);
+
+       /*
+        *      For backwards compatibility
+        */
+       if (!dict_valbyname(PW_AUTH_TYPE, 0, inst->xlat_name)) {
+               inst->auth_type = "MS-CHAP";
+       } else {
+               inst->auth_type = inst->xlat_name;
        }
 
        return 0;
@@ -672,18 +615,18 @@ static int mschap_instantiate(CONF_SECTION *conf, void **instance)
  *     add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error
  *     attribute to reply packet
  */
-static void add_reply(VALUE_PAIR** vp, unsigned char ident,
+void mschap_add_reply(REQUEST *request, VALUE_PAIR** vp, unsigned char ident,
                      const char* name, const char* value, int len)
 {
        VALUE_PAIR *reply_attr;
        reply_attr = pairmake(name, "", T_OP_EQ);
        if (!reply_attr) {
-               DEBUG("  rlm_mschap: Failed to create attribute %s: %s\n", name, librad_errstr);
+               RDEBUG("Failed to create attribute %s: %s\n", name, fr_strerror());
                return;
        }
 
-       reply_attr->strvalue[0] = ident;
-       memcpy(reply_attr->strvalue + 1, value, len);
+       reply_attr->vp_octets[0] = ident;
+       memcpy(reply_attr->vp_octets + 1, value, len);
        reply_attr->length = len + 1;
        pairadd(vp, reply_attr);
 }
@@ -691,19 +634,18 @@ static void add_reply(VALUE_PAIR** vp, unsigned char ident,
 /*
  *     Add MPPE attributes to the reply.
  */
-static void mppe_add_reply(VALUE_PAIR **vp,
-                          const char* name, const char* value, int len)
+static void mppe_add_reply(REQUEST *request,
+                          const char* name, const uint8_t * value, int len)
 {
-       VALUE_PAIR *reply_attr;
-       reply_attr = pairmake(name, "", T_OP_EQ);
-       if (!reply_attr) {
-              DEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, librad_errstr);
+       VALUE_PAIR *vp;
+       vp = radius_pairmake(request, &request->reply->vps, name, "", T_OP_EQ);
+       if (!vp) {
+              RDEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, fr_strerror());
               return;
        }
 
-       memcpy(reply_attr->strvalue, value, len);
-       reply_attr->length = len;
-       pairadd(vp, reply_attr);
+       memcpy(vp->vp_octets, value, len);
+       vp->length = len;
 }
 
 
@@ -717,35 +659,9 @@ static void mppe_add_reply(VALUE_PAIR **vp,
 static int do_mschap(rlm_mschap_t *inst,
                     REQUEST *request, VALUE_PAIR *password,
                     uint8_t *challenge, uint8_t *response,
-                    uint8_t *nthashhash)
+                    uint8_t *nthashhash, int do_ntlm_auth)
 {
-       int             do_ntlm_auth = 0;
        uint8_t         calculated[24];
-       VALUE_PAIR      *vp = NULL;
-
-       /*
-        *      If we have ntlm_auth configured, use it unless told
-        *      otherwise
-        */
-       if (inst->ntlm_auth) do_ntlm_auth = 1;
-
-       /*
-        *      If we have an ntlm_auth configuration, then we may
-        *      want to use it.
-        */
-       vp = pairfind(request->config_items,
-                     PW_MS_CHAP_USE_NTLM_AUTH);
-       if (vp) do_ntlm_auth = vp->lvalue;
-
-       /*
-        *      No ntlm_auth configured, attribute to tell us to
-        *      use it exists, and we're told to use it.  We don't
-        *      know what to do...
-        */
-       if (!inst->ntlm_auth && do_ntlm_auth) {
-               DEBUG2("  rlm_mschap: Asked to use ntlm_auth, but it was not configured in the mschap{} section.");
-               return -1;
-       }
 
        /*
         *      Do normal authentication.
@@ -755,22 +671,22 @@ static int do_mschap(rlm_mschap_t *inst,
                 *      No password: can't do authentication.
                 */
                if (!password) {
-                       DEBUG2("  rlm_mschap: FAILED: No NT/LM-Password.  Cannot perform authentication.");
+                       RDEBUG2("FAILED: No NT/LM-Password.  Cannot perform authentication.");
                        return -1;
                }
-               
-               smbdes_mschap(password->strvalue, challenge, calculated);
+
+               smbdes_mschap(password->vp_strvalue, challenge, calculated);
                if (memcmp(response, calculated, 24) != 0) {
                        return -1;
                }
-               
+
                /*
                 *      If the password exists, and is an NT-Password,
                 *      then calculate the hash of the NT hash.  Doing this
                 *      here minimizes work for later.
                 */
                if (password && (password->attribute == PW_NT_PASSWORD)) {
-                       md4_calc(nthashhash, password->strvalue, 16);
+                       fr_md4_calc(nthashhash, password->vp_octets, 16);
                } else {
                        memset(nthashhash, 0, 16);
                }
@@ -781,14 +697,31 @@ static int do_mschap(rlm_mschap_t *inst,
                memset(nthashhash, 0, 16);
 
                /*
-                *      Run the program, and expect that we get 16 
+                *      Run the program, and expect that we get 16
                 */
                result = radius_exec_program(inst->ntlm_auth, request,
                                             TRUE, /* wait */
                                             buffer, sizeof(buffer),
-                                            NULL, NULL);
+                                            NULL, NULL, 1);
                if (result != 0) {
-                       DEBUG2("  rlm_mschap: External script failed.");
+                       char *p;
+                       VALUE_PAIR *vp = NULL;
+
+                       RDEBUG2("External script failed.");
+
+                       vp = pairmake("Module-Failure-Message", "", T_OP_EQ);
+                       if (!vp) {
+                               radlog_request(L_ERR, 0, request, "No memory to allocate Module-Failure-Message");
+                               return RLM_MODULE_FAIL;
+                       }
+
+                       p = strchr(buffer, '\n');
+                       if (p) *p = '\0';
+                       snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue),
+                               "%s: External script says %s",
+                                inst->xlat_name, buffer);
+                       vp->length = strlen(vp->vp_strvalue);
+                       pairadd(&request->request->vps, vp);
                        return -1;
                }
 
@@ -799,7 +732,7 @@ static int do_mschap(rlm_mschap_t *inst,
                 *      NT_KEY: 000102030405060708090a0b0c0d0e0f
                 */
                if (memcmp(buffer, "NT_KEY: ", 8) != 0) {
-                       DEBUG2("  rlm_mschap: Invalid output from ntlm_auth: expecting NT_KEY");
+                       RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY");
                        return -1;
                }
 
@@ -808,15 +741,15 @@ static int do_mschap(rlm_mschap_t *inst,
                 *      with an LF at the end.
                 */
                if (strlen(buffer + 8) < 32) {
-                       DEBUG2("  rlm_mschap: Invalid output from ntlm_auth: NT_KEY has unexpected length");
+                       RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length");
                        return -1;
                }
 
                /*
                 *      Update the NT hash hash, from the NT key.
                 */
-               if (hex2bin(buffer + 8, nthashhash, 16) != 16) {
-                       DEBUG2("  rlm_mschap: Invalid output from ntlm_auth: NT_KEY has non-hex values");
+               if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) {
+                       RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values");
                        return -1;
                }
        }
@@ -872,13 +805,13 @@ static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response,
                              uint8_t *masterkey)
 {
        uint8_t digest[20];
-       SHA1_CTX Context;
+       fr_SHA1_CTX Context;
 
-       SHA1Init(&Context);
-       SHA1Update(&Context,nt_hashhash,16);
-       SHA1Update(&Context,nt_response,24);
-       SHA1Update(&Context,magic1,27);
-       SHA1Final(digest,&Context);
+       fr_SHA1Init(&Context);
+       fr_SHA1Update(&Context,nt_hashhash,16);
+       fr_SHA1Update(&Context,nt_response,24);
+       fr_SHA1Update(&Context,magic1,27);
+       fr_SHA1Final(digest,&Context);
 
        memcpy(masterkey,digest,16);
 }
@@ -889,7 +822,7 @@ static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
 {
        uint8_t digest[20];
        const uint8_t *s;
-       SHA1_CTX Context;
+       fr_SHA1_CTX Context;
 
        memset(digest,0,20);
 
@@ -899,12 +832,12 @@ static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
                s = magic2;
        }
 
-       SHA1Init(&Context);
-       SHA1Update(&Context,masterkey,16);
-       SHA1Update(&Context,SHSpad1,40);
-       SHA1Update(&Context,s,84);
-       SHA1Update(&Context,SHSpad2,40);
-       SHA1Final(digest,&Context);
+       fr_SHA1Init(&Context);
+       fr_SHA1Update(&Context,masterkey,16);
+       fr_SHA1Update(&Context,SHSpad1,40);
+       fr_SHA1Update(&Context,s,84);
+       fr_SHA1Update(&Context,SHSpad2,40);
+       fr_SHA1Final(digest,&Context);
 
        memcpy(sesskey,digest,keylen);
 }
@@ -951,38 +884,47 @@ static void mppe_chap2_gen_keys128(uint8_t *nt_hashhash,uint8_t *response,
 static int mschap_authorize(void * instance, REQUEST *request)
 {
 #define inst ((rlm_mschap_t *)instance)
-       VALUE_PAIR *challenge = NULL;
-       VALUE_PAIR *response = NULL;
-       VALUE_PAIR *vp;
+       VALUE_PAIR *challenge = NULL, *response = NULL;
 
-       challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
+       challenge = pairfind(request->packet->vps,
+                            PW_MSCHAP_CHALLENGE,
+                            VENDORPEC_MICROSOFT);
        if (!challenge) {
                return RLM_MODULE_NOOP;
        }
 
-       response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);
+       response = pairfind(request->packet->vps,
+                           PW_MSCHAP_RESPONSE,
+                           VENDORPEC_MICROSOFT);
        if (!response)
-               response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE);
+               response = pairfind(request->packet->vps,
+                                   PW_MSCHAP2_RESPONSE,
+                                   VENDORPEC_MICROSOFT);
 
        /*
         *      Nothing we recognize.  Don't do anything.
         */
        if (!response) {
-               DEBUG2("  rlm_mschap: Found MS-CHAP-Challenge, but no MS-CHAP-Response.");
+               RDEBUG2("Found MS-CHAP-Challenge, but no MS-CHAP-Response.");
+               return RLM_MODULE_NOOP;
+       }
+
+       if (pairfind(request->config_items, PW_AUTH_TYPE, 0)) {
+               RDEBUG2("WARNING: Auth-Type already set.  Not setting to MS-CHAP");
                return RLM_MODULE_NOOP;
        }
 
-       DEBUG2("  rlm_mschap: Found MS-CHAP attributes.  Setting 'Auth-Type  = %s'", inst->xlat_name);
+       RDEBUG2("Found MS-CHAP attributes.  Setting 'Auth-Type  = %s'", inst->xlat_name);
 
        /*
         *      Set Auth-Type to MS-CHAP.  The authentication code
         *      will take care of turning clear-text passwords into
         *      NT/LM passwords.
         */
-       vp = pairmake("Auth-Type", inst->xlat_name, T_OP_EQ);
-       rad_assert(vp != NULL);
-       pairmove(&request->config_items, &vp);
-       pairfree(&vp);          /* may be NULL */
+       if (!radius_pairmake(request, &request->config_items,
+                            "Auth-Type", inst->auth_type, T_OP_EQ)) {
+               return RLM_MODULE_FAIL;
+       }
 
        return RLM_MODULE_OK;
 #undef inst
@@ -997,7 +939,7 @@ static int mschap_authorize(void * instance, REQUEST *request)
  *
  *     If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
  *     one of:
- *             PAP:      PW_PASSWORD or
+ *             PAP:      PW_USER_PASSWORD or
  *             MS-CHAP:  PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
  *             MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
  *     In case of password mismatch or locked account we MAY return
@@ -1013,24 +955,44 @@ static int mschap_authenticate(void * instance, REQUEST *request)
        VALUE_PAIR *password = NULL;
        VALUE_PAIR *lm_password, *nt_password, *smb_ctrl;
        VALUE_PAIR *username;
-       VALUE_PAIR *reply_attr;
        uint8_t nthashhash[16];
-       uint8_t msch2resp[42];
+       char msch2resp[42];
        char *username_string;
        int chap = 0;
+       int             do_ntlm_auth;
+
+       /*
+        *      If we have ntlm_auth configured, use it unless told
+        *      otherwise
+        */
+       do_ntlm_auth = (inst->ntlm_auth != NULL);
+
+       /*
+        *      If we have an ntlm_auth configuration, then we may
+        *      want to suppress it.
+        */
+       if (do_ntlm_auth) {
+               VALUE_PAIR *vp = pairfind(request->config_items,
+                                         PW_MS_CHAP_USE_NTLM_AUTH, 0);
+               if (vp) do_ntlm_auth = vp->vp_integer;
+       }
 
        /*
         *      Find the SMB-Account-Ctrl attribute, or the
         *      SMB-Account-Ctrl-Text attribute.
         */
-       smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
+       smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL, 0);
        if (!smb_ctrl) {
                password = pairfind(request->config_items,
-                                   PW_SMB_ACCOUNT_CTRL_TEXT);
+                                   PW_SMB_ACCOUNT_CTRL_TEXT, 0);
                if (password) {
-                       smb_ctrl = pairmake("SMB-Account-CTRL", "0", T_OP_SET);
-                       pairadd(&request->config_items, smb_ctrl);
-                       smb_ctrl->lvalue = pdb_decode_acct_ctrl(password->strvalue);
+                       smb_ctrl = radius_pairmake(request,
+                                                  &request->config_items,
+                                                  "SMB-Account-CTRL", "0",
+                                                  T_OP_SET);
+                       if (smb_ctrl) {
+                               smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
+                       }
                }
        }
 
@@ -1042,8 +1004,8 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                /*
                 *      Password is not required.
                 */
-               if ((smb_ctrl->lvalue & ACB_PWNOTREQ) != 0) {
-                       DEBUG2("  rlm_mschap: SMB-Account-Ctrl says no password is required.");
+               if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
+                       RDEBUG2("SMB-Account-Ctrl says no password is required.");
                        return RLM_MODULE_OK;
                }
        }
@@ -1051,84 +1013,89 @@ static int mschap_authenticate(void * instance, REQUEST *request)
        /*
         *      Decide how to get the passwords.
         */
-       password = pairfind(request->config_items, PW_PASSWORD);
+       password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0);
 
        /*
         *      We need an LM-Password.
         */
-       lm_password = pairfind(request->config_items, PW_LM_PASSWORD);
+       lm_password = pairfind(request->config_items, PW_LM_PASSWORD, 0);
        if (lm_password) {
                /*
                 *      Allow raw octets.
                 */
                if ((lm_password->length == 16) ||
                    ((lm_password->length == 32) &&
-                    (hex2bin(lm_password->strvalue,
-                             lm_password->strvalue, 16) == 16))) {
-                       DEBUG2("  rlm_mschap: Found LM-Password");
+                    (fr_hex2bin(lm_password->vp_strvalue,
+                                lm_password->vp_octets, 16) == 16))) {
+                       RDEBUG2("Found LM-Password");
                        lm_password->length = 16;
 
                } else {
-                       radlog(L_ERR, "rlm_mschap: Invalid LM-Password");
+                       radlog_request(L_ERR, 0, request, "Invalid LM-Password");
                        lm_password = NULL;
                }
 
        } else if (!password) {
-               DEBUG2("  rlm_mschap: No User-Password configured.  Cannot create LM-Password.");
+               if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create LM-Password.");
 
-       } else {                /* there is a configured User-Password */
-               lm_password = pairmake("LM-Password", "", T_OP_EQ);
+       } else {                /* there is a configured Cleartext-Password */
+               lm_password = radius_pairmake(request, &request->config_items,
+                                             "LM-Password", "", T_OP_EQ);
                if (!lm_password) {
-                       radlog(L_ERR, "No memory");
+                       radlog_request(L_ERR, 0, request, "No memory");
                } else {
-                       smbdes_lmpwdhash(password->strvalue,
-                                      lm_password->strvalue);
+                       smbdes_lmpwdhash(password->vp_strvalue,
+                                        lm_password->vp_octets);
                        lm_password->length = 16;
-                       pairadd(&request->config_items, lm_password);
                }
        }
 
        /*
         *      We need an NT-Password.
         */
-       nt_password = pairfind(request->config_items, PW_NT_PASSWORD);
+       nt_password = pairfind(request->config_items, PW_NT_PASSWORD, 0);
        if (nt_password) {
                if ((nt_password->length == 16) ||
                    ((nt_password->length == 32) &&
-                    (hex2bin(nt_password->strvalue,
-                             nt_password->strvalue, 16) == 16))) {
-                       DEBUG2("  rlm_mschap: Found NT-Password");
+                    (fr_hex2bin(nt_password->vp_strvalue,
+                                nt_password->vp_octets, 16) == 16))) {
+                       RDEBUG2("Found NT-Password");
                        nt_password->length = 16;
 
                 } else {
-                       radlog(L_ERR, "rlm_mschap: Invalid NT-Password");
+                       radlog_request(L_ERR, 0, request, "Invalid NT-Password");
                        nt_password = NULL;
                }
        } else if (!password) {
-               DEBUG2("  rlm_mschap: No User-Password configured.  Cannot create NT-Password.");
+               if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create NT-Password.");
 
-       } else {                /* there is a configured User-Password */
-               nt_password = pairmake("NT-Password", "", T_OP_EQ);
+       } else {                /* there is a configured Cleartext-Password */
+               nt_password = radius_pairmake(request, &request->config_items,
+                                             "NT-Password", "", T_OP_EQ);
                if (!nt_password) {
-                       radlog(L_ERR, "No memory");
+                       radlog_request(L_ERR, 0, request, "No memory");
                        return RLM_MODULE_FAIL;
                } else {
-                       ntpwdhash(nt_password->strvalue, password->strvalue);
+                       mschap_ntpwdhash(nt_password->vp_octets,
+                                 password->vp_strvalue);
                        nt_password->length = 16;
-                       pairadd(&request->config_items, nt_password);
                }
        }
 
-       challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
+       challenge = pairfind(request->packet->vps,
+                            PW_MSCHAP_CHALLENGE,
+                            VENDORPEC_MICROSOFT);
        if (!challenge) {
-               DEBUG2("  rlm_mschap: No MS-CHAP-Challenge in the request");
+               RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
                return RLM_MODULE_REJECT;
        }
 
        /*
         *      We also require an MS-CHAP-Response.
         */
-       response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);
+       response = pairfind(request->packet->vps,
+                           PW_MSCHAP_RESPONSE,
+                           VENDORPEC_MICROSOFT);
 
        /*
         *      MS-CHAP-Response, means MS-CHAPv1
@@ -1140,7 +1107,7 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                 *      MS-CHAPv1 challenges are 8 octets.
                 */
                if (challenge->length < 8) {
-                       radlog(L_AUTH, "rlm_mschap: MS-CHAP-Challenge has the wrong format.");
+                       radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
                        return RLM_MODULE_INVALID;
                }
 
@@ -1148,7 +1115,7 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                 *      Responses are 50 octets.
                 */
                if (response->length < 50) {
-                       radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format.");
+                       radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
                        return RLM_MODULE_INVALID;
                }
 
@@ -1156,12 +1123,12 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                 *      We are doing MS-CHAP.  Calculate the MS-CHAP
                 *      response
                 */
-               if (response->strvalue[1] & 0x01) {
-                       DEBUG2("  rlm_mschap: Told to do MS-CHAPv1 with NT-Password");
+               if (response->vp_octets[1] & 0x01) {
+                       RDEBUG2("Told to do MS-CHAPv1 with NT-Password");
                        password = nt_password;
                        offset = 26;
                } else {
-                       DEBUG2("  rlm_mschap: Told to do MS-CHAPv1 with LM-Password");
+                       RDEBUG2("Told to do MS-CHAPv1 with LM-Password");
                        password = lm_password;
                        offset = 2;
                }
@@ -1169,24 +1136,27 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                /*
                 *      Do the MS-CHAP authentication.
                 */
-               if (do_mschap(inst, request, password, challenge->strvalue,
-                             response->strvalue + offset, nthashhash) < 0) {
-                       DEBUG2("  rlm_mschap: MS-CHAP-Response is incorrect.");
-                       add_reply(&request->reply->vps, *response->strvalue,
-                                 "MS-CHAP-Error", "E=691 R=1", 9);
+               if (do_mschap(inst, request, password, challenge->vp_octets,
+                             response->vp_octets + offset, nthashhash,
+                             do_ntlm_auth) < 0) {
+                       RDEBUG2("MS-CHAP-Response is incorrect.");
+                       mschap_add_reply(request, &request->reply->vps,
+                                        *response->vp_octets,
+                                        "MS-CHAP-Error", "E=691 R=1", 9);
                        return RLM_MODULE_REJECT;
                }
 
                chap = 1;
 
-       } else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) {
+       } else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT)) != NULL) {
                uint8_t mschapv1_challenge[16];
+               VALUE_PAIR *name_attr, *response_name;
 
                /*
                 *      MS-CHAPv2 challenges are 16 octets.
                 */
                if (challenge->length < 16) {
-                       radlog(L_AUTH, "rlm_mschap: MS-CHAP-Challenge has the wrong format.");
+                       radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
                        return RLM_MODULE_INVALID;
                }
 
@@ -1194,34 +1164,73 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                 *      Responses are 50 octets.
                 */
                if (response->length < 50) {
-                       radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format.");
+                       radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
                        return RLM_MODULE_INVALID;
                }
 
                /*
                 *      We also require a User-Name
                 */
-               username = pairfind(request->packet->vps, PW_USER_NAME);
+               username = pairfind(request->packet->vps, PW_USER_NAME, 0);
                if (!username) {
-                       radlog(L_AUTH, "rlm_mschap: We require a User-Name for MS-CHAPv2");
+                       radlog_request(L_AUTH, 0, request, "We require a User-Name for MS-CHAPv2");
                        return RLM_MODULE_INVALID;
                }
 
-
                /*
-                *      with_ntdomain_hack moved here
+                *      Check for MS-CHAP-User-Name and if found, use it
+                *      to construct the MSCHAPv1 challenge.  This is
+                *      set by rlm_eap_mschap to the MS-CHAP Response
+                *      packet Name field.
+                *
+                *      We prefer this to the User-Name in the
+                *      packet.
                 */
-               if ((username_string = strchr(username->strvalue, '\\')) != NULL) {
-                       if (inst->with_ntdomain_hack) {
-                               username_string++;
+               response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME, 0);
+               if (response_name) {
+                       name_attr = response_name;
+               } else {
+                       name_attr = username;
+               }
+               
+               /*
+                *      with_ntdomain_hack moved here, too.
+                */
+               if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
+                       if (inst->with_ntdomain_hack) {
+                               username_string++;
                        } else {
-                               DEBUG2("  rlm_mschap: NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
-                               username_string = username->strvalue;
+                               RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
+                               username_string = name_attr->vp_strvalue;
                        }
                } else {
-                       username_string = username->strvalue;
+                       username_string = name_attr->vp_strvalue;
+               }
+               
+               if (response_name &&
+                   ((username->length != response_name->length) ||
+                    (strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) {
+                       RDEBUG("ERROR: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", username->vp_strvalue, response_name->vp_strvalue);
+                       return RLM_MODULE_REJECT;
                }
 
+#ifdef __APPLE__
+               /*
+                *  No "known good" NT-Password attribute.  Try to do
+                *  OpenDirectory authentication.
+                *
+                *  If OD determines the user is an AD user it will return noop, which
+                *  indicates the auth process should continue directly to AD.
+                *  Otherwise OD will determine auth success/fail.
+                */
+               if (!nt_password && inst->open_directory) {
+                       RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication.");
+                       int odStatus = od_mschap_auth(request, challenge, username);
+                       if (odStatus != RLM_MODULE_NOOP) {
+                               return odStatus;
+                       }
+               }
+#endif
                /*
                 *      The old "mschapv2" function has been moved to
                 *      here.
@@ -1229,40 +1238,38 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                 *      MS-CHAPv2 takes some additional data to create an
                 *      MS-CHAPv1 challenge, and then does MS-CHAPv1.
                 */
-               challenge_hash(response->strvalue + 2, /* peer challenge */
-                              challenge->strvalue, /* our challenge */
+               RDEBUG2("Creating challenge hash with username: %s",
+                       username_string);
+               mschap_challenge_hash(response->vp_octets + 2, /* peer challenge */
+                              challenge->vp_octets, /* our challenge */
                               username_string, /* user name */
                               mschapv1_challenge); /* resulting challenge */
-               
-               DEBUG2("  rlm_mschap: Told to do MS-CHAPv2 for %s with NT-Password",
+
+               RDEBUG2("Told to do MS-CHAPv2 for %s with NT-Password",
                       username_string);
 
                if (do_mschap(inst, request, nt_password, mschapv1_challenge,
-                             response->strvalue + 26, nthashhash) < 0) {
-                       DEBUG2("  rlm_mschap: FAILED: MS-CHAP2-Response is incorrect");
-                       add_reply(&request->reply->vps, *response->strvalue,
-                                 "MS-CHAP-Error", "E=691 R=1", 9);
+                             response->vp_octets + 26, nthashhash,
+                             do_ntlm_auth) < 0) {
+                       RDEBUG2("FAILED: MS-CHAP2-Response is incorrect");
+                       mschap_add_reply(request, &request->reply->vps,
+                                        *response->vp_octets,
+                                        "MS-CHAP-Error", "E=691 R=1", 9);
                        return RLM_MODULE_REJECT;
                }
 
-               /*
-                *      Get the NT-hash-hash, if necessary
-                */
-               if (nt_password) {
-               }
-
-               auth_response(username_string, /* without the domain */
+               mschap_auth_response(username_string, /* without the domain */
                              nthashhash, /* nt-hash-hash */
-                             response->strvalue + 26, /* peer response */
-                             response->strvalue + 2, /* peer challenge */
-                             challenge->strvalue, /* our challenge */
+                             response->vp_octets + 26, /* peer response */
+                             response->vp_octets + 2, /* peer challenge */
+                             challenge->vp_octets, /* our challenge */
                              msch2resp); /* calculated MPPE key */
-               add_reply( &request->reply->vps, *response->strvalue,
-                          "MS-CHAP2-Success", msch2resp, 42);
+               mschap_add_reply(request, &request->reply->vps, *response->vp_octets,
+                                "MS-CHAP2-Success", msch2resp, 42);
                chap = 2;
 
        } else {                /* Neither CHAPv1 or CHAPv2 response: die */
-               radlog(L_AUTH, "rlm_mschap: No MS-CHAP response found");
+               RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
                return RLM_MODULE_INVALID;
        }
 
@@ -1278,21 +1285,23 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                 *      They're found, but they don't exist, so we
                 *      return 'not found'.
                 */
-               if (((smb_ctrl->lvalue & ACB_DISABLED) != 0) ||
-                   ((smb_ctrl->lvalue & ACB_NORMAL) == 0)) {
-                       DEBUG2("  rlm_mschap: SMB-Account-Ctrl says that the account is disabled, or is not a normal account.");
-                       add_reply( &request->reply->vps, *response->strvalue,
-                                  "MS-CHAP-Error", "E=691 R=1", 9);
+               if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
+                   ((smb_ctrl->vp_integer & ACB_NORMAL) == 0)) {
+                       RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal account.");
+                       mschap_add_reply(request, &request->reply->vps,
+                                         *response->vp_octets,
+                                         "MS-CHAP-Error", "E=691 R=1", 9);
                        return RLM_MODULE_NOTFOUND;
                }
 
                /*
                 *      User is locked out.
                 */
-               if ((smb_ctrl->lvalue & ACB_AUTOLOCK) != 0) {
-                       DEBUG2("  rlm_mschap: SMB-Account-Ctrl says that the account is locked out.");
-                       add_reply( &request->reply->vps, *response->strvalue,
-                                  "MS-CHAP-Error", "E=647 R=0", 9);
+               if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) {
+                       RDEBUG2("SMB-Account-Ctrl says that the account is locked out.");
+                       mschap_add_reply(request, &request->reply->vps,
+                                         *response->vp_octets,
+                                         "MS-CHAP-Error", "E=647 R=0", 9);
                        return RLM_MODULE_USERLOCK;
                }
        }
@@ -1303,10 +1312,10 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                uint8_t mppe_recvkey[34];
 
                if (chap == 1){
-                       DEBUG2("rlm_mschap: adding MS-CHAPv1 MPPE keys");
+                       RDEBUG2("adding MS-CHAPv1 MPPE keys");
                        memset(mppe_sendkey, 0, 32);
                        if (lm_password) {
-                               memcpy(mppe_sendkey, lm_password->strvalue, 8);
+                               memcpy(mppe_sendkey, lm_password->vp_octets, 8);
                        }
 
                        /*
@@ -1323,34 +1332,31 @@ static int mschap_authenticate(void * instance, REQUEST *request)
                         */
                        memcpy(mppe_sendkey + 8,
                               nthashhash, 16);
-                       mppe_add_reply(&request->reply->vps,
+                       mppe_add_reply(request,
                                       "MS-CHAP-MPPE-Keys",
                                       mppe_sendkey, 32);
                } else if (chap == 2) {
-                       DEBUG2("rlm_mschap: adding MS-CHAPv2 MPPE keys");
+                       RDEBUG2("adding MS-CHAPv2 MPPE keys");
                        mppe_chap2_gen_keys128(nthashhash,
-                                              response->strvalue + 26,
+                                              response->vp_octets + 26,
                                               mppe_sendkey, mppe_recvkey);
-                       
-                       mppe_add_reply(&request->reply->vps,
+
+                       mppe_add_reply(request,
                                       "MS-MPPE-Recv-Key",
                                       mppe_recvkey, 16);
-                       mppe_add_reply(&request->reply->vps,
+                       mppe_add_reply(request,
                                       "MS-MPPE-Send-Key",
                                       mppe_sendkey, 16);
 
                }
-               reply_attr = pairmake("MS-MPPE-Encryption-Policy",
-                                     (inst->require_encryption)? "0x00000002":"0x00000001",
-                                     T_OP_EQ);
-               rad_assert(reply_attr != NULL);
-               pairadd(&request->reply->vps, reply_attr);
-               reply_attr = pairmake("MS-MPPE-Encryption-Types",
-                                     (inst->require_strong)? "0x00000004":"0x00000006",
-                                     T_OP_EQ);
-               rad_assert(reply_attr != NULL);
-               pairadd(&request->reply->vps, reply_attr);
-
+               radius_pairmake(request, &request->reply->vps,
+                               "MS-MPPE-Encryption-Policy",
+                               (inst->require_encryption)? "0x00000002":"0x00000001",
+                               T_OP_EQ);
+               radius_pairmake(request, &request->reply->vps,
+                               "MS-MPPE-Encryption-Types",
+                               (inst->require_strong)? "0x00000004":"0x00000006",
+                               T_OP_EQ);
        } /* else we weren't asked to use MPPE */
 
        return RLM_MODULE_OK;
@@ -1358,20 +1364,19 @@ static int mschap_authenticate(void * instance, REQUEST *request)
 }
 
 module_t rlm_mschap = {
-  "MS-CHAP",
-  RLM_TYPE_THREAD_SAFE,                /* type */
-  NULL,                                /* initialize */
-  mschap_instantiate,          /* instantiation */
-  {
-         mschap_authenticate,  /* authenticate */
-         mschap_authorize,     /* authorize */
-         NULL,                 /* pre-accounting */
-         NULL,                 /* accounting */
-         NULL,                 /* checksimul */
-         NULL,                 /* pre-proxy */
-         NULL,                 /* post-proxy */
-         NULL                  /* post-auth */
-  },
-  mschap_detach,               /* detach */
-  NULL,                                /* destroy */
+       RLM_MODULE_INIT,
+       "MS-CHAP",
+       RLM_TYPE_THREAD_SAFE,           /* type */
+       mschap_instantiate,             /* instantiation */
+       mschap_detach,          /* detach */
+       {
+               mschap_authenticate,    /* authenticate */
+               mschap_authorize,       /* authorize */
+               NULL,                   /* pre-accounting */
+               NULL,                   /* accounting */
+               NULL,                   /* checksimul */
+               NULL,                   /* pre-proxy */
+               NULL,                   /* post-proxy */
+               NULL                    /* post-auth */
+       },
 };