X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_mschap%2Frlm_mschap.c;h=b76783562d234e7deb1dcb57afcc7fa86b7fb832;hb=94dc4bb60ec649ce899c1d5e32b575d9523a48f2;hp=f85b2840d3bdaf02346bb447b47ca22557cb4d6c;hpb=4e7bbd56f954ddab3a9b1ff98f7e6f3a966864e6;p=freeradius.git diff --git a/src/modules/rlm_mschap/rlm_mschap.c b/src/modules/rlm_mschap/rlm_mschap.c index f85b284..b767835 100644 --- a/src/modules/rlm_mschap/rlm_mschap.c +++ b/src/modules/rlm_mschap/rlm_mschap.c @@ -20,26 +20,6 @@ * Copyright 2000,2001,2006 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 - */ - /* MPPE support from Takahiro Wagatsuma */ #include @@ -49,9 +29,11 @@ RCSID("$Id$") #include #include #include +#include #include +#include "mschap.h" #include "smbdes.h" #ifdef __APPLE__ @@ -146,115 +128,6 @@ static int pdb_decode_acct_ctrl(const char *p) } -/* - * ntpwdhash converts Unicode password to 16-byte NT hash - * with MD4 - */ -static void ntpwdhash (uint8_t *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 */ - fr_md4_calc(szHash, (uint8_t *) szUnicodePass, (nPasswordLen<<1) ); -} - - -/* - * challenge_hash() is used by mschap2() and auth_response() - * implements RFC2759 ChallengeHash() - * generates 64 bit challenge - */ -static void challenge_hash( const uint8_t *peer_challenge, - const uint8_t *auth_challenge, - const char *user_name, uint8_t *challenge ) -{ - fr_SHA1_CTX Context; - uint8_t hash[20]; - - fr_SHA1Init(&Context); - fr_SHA1Update(&Context, peer_challenge, 16); - fr_SHA1Update(&Context, auth_challenge, 16); - fr_SHA1Update(&Context, (const uint8_t *) user_name, - strlen(user_name)); - fr_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 uint8_t *nt_hash_hash, - uint8_t *ntresponse, - uint8_t *peer_challenge, uint8_t *auth_challenge, - char *response) -{ - fr_SHA1_CTX Context; - static const uint8_t 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}; - - static const uint8_t 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}; - - static const char hex[16] = "0123456789ABCDEF"; - - size_t i; - uint8_t challenge[8]; - uint8_t digest[20]; - - fr_SHA1Init(&Context); - fr_SHA1Update(&Context, nt_hash_hash, 16); - fr_SHA1Update(&Context, ntresponse, 24); - fr_SHA1Update(&Context, magic1, 39); - fr_SHA1Final(digest, &Context); - challenge_hash(peer_challenge, auth_challenge, username, challenge); - fr_SHA1Init(&Context); - fr_SHA1Update(&Context, digest, 20); - fr_SHA1Update(&Context, challenge, 8); - fr_SHA1Update(&Context, magic2, 41); - fr_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] = '='; - - /* - * The hexadecimal digits [A-F] MUST be uppercase. - */ - for (i = 0; i < sizeof(digest); i++) { - response[2 + (i * 2)] = hex[(digest[i] >> 4) & 0x0f]; - response[3 + (i * 2)] = hex[digest[i] & 0x0f]; - } -} - - typedef struct rlm_mschap_t { int use_mppe; int require_encryption; @@ -287,7 +160,7 @@ static size_t mschap_xlat(void *instance, REQUEST *request, VALUE_PAIR *chap_challenge, *response; rlm_mschap_t *inst = instance; - chap_challenge = response = NULL; + response = NULL; func = func; /* -Wunused */ @@ -297,9 +170,10 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ 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; } @@ -308,7 +182,7 @@ static size_t mschap_xlat(void *instance, REQUEST *request, * for MS-CHAPv2 */ if (chap_challenge->length == 8) { - DEBUG2(" mschap1: %02x", + RDEBUG2(" mschap1: %02x", chap_challenge->vp_octets[0]); data = chap_challenge->vp_octets; data_len = 8; @@ -318,43 +192,73 @@ static size_t 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->vp_octets[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->vp_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->vp_strvalue; + RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?"); + username_string = name_attr->vp_strvalue; } } else { - username_string = user_name->vp_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); } /* @@ -362,13 +266,15 @@ static size_t mschap_xlat(void *instance, REQUEST *request, * from the MS-CHAPv2 peer challenge, * our challenge, and the user name. */ - challenge_hash(response->vp_octets + 2, + 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; } @@ -378,11 +284,12 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ } 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; } @@ -392,7 +299,7 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ if ((response->attribute == PW_MSCHAP_RESPONSE) && ((response->vp_octets[1] & 0x01) == 0)) { - DEBUG2(" rlm_mschap: No NT-Response in MS-CHAP-Response"); + RDEBUG2("No NT-Response in MS-CHAP-Response"); return 0; } @@ -410,9 +317,9 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ } 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; } @@ -421,7 +328,7 @@ static size_t mschap_xlat(void *instance, REQUEST *request, * if the second octet says so. */ if ((response->vp_octets[1] & 0x01) != 0) { - DEBUG2(" rlm_mschap: No LM-Response in MS-CHAP-Response"); + RDEBUG2("No LM-Response in MS-CHAP-Response"); return 0; } data = response->vp_octets + 2; @@ -433,9 +340,9 @@ static size_t mschap_xlat(void *instance, REQUEST *request, } 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; } @@ -452,7 +359,7 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ p = strchr(user_name->vp_strvalue, '.'); if (!p) { - DEBUG2(" rlm_mschap: setting NT-Domain to same as machine name"); + RDEBUG2("setting NT-Domain to same as machine name"); strlcpy(out, user_name->vp_strvalue + 5, outlen); } else { p++; /* skip the period */ @@ -468,7 +375,7 @@ static size_t mschap_xlat(void *instance, REQUEST *request, } else { 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; } @@ -488,9 +395,9 @@ static size_t mschap_xlat(void *instance, REQUEST *request, } 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; } @@ -534,16 +441,25 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ } 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; - DEBUG("rlm_mschap: NT-Hash: %s",p); - ntpwdhash(buffer,p); + + 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'; - DEBUG("rlm_mschap: NT-Hash: Result: %s",out); + RDEBUG("NT-Hash of %s = %s", buf2, out); return 32; /* @@ -551,19 +467,27 @@ static size_t mschap_xlat(void *instance, REQUEST *request, */ } 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; - DEBUG("rlm_mschap: LM-Hash: %s",p); - smbdes_lmpwdhash(p, buffer); + 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'; - DEBUG("rlm_mschap: LM-Hash: Result: %s",out); + 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; } @@ -574,7 +498,7 @@ static size_t 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; } @@ -629,6 +553,7 @@ static int mschap_detach(void *instance){ #define inst ((rlm_mschap_t *)instance) if (inst->xlat_name) { xlat_unregister(inst->xlat_name, mschap_xlat); + free(inst->xlat_name); } free(instance); return 0; @@ -671,12 +596,13 @@ static int mschap_instantiate(CONF_SECTION *conf, void **instance) */ 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, inst->xlat_name)) { + if (!dict_valbyname(PW_AUTH_TYPE, 0, inst->xlat_name)) { inst->auth_type = "MS-CHAP"; } else { inst->auth_type = inst->xlat_name; @@ -689,13 +615,13 @@ static int mschap_instantiate(CONF_SECTION *conf, void **instance) * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error * attribute to reply packet */ -void mschap_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; } @@ -714,7 +640,7 @@ static void mppe_add_reply(REQUEST *request, VALUE_PAIR *vp; vp = radius_pairmake(request, &request->reply->vps, name, "", T_OP_EQ); if (!vp) { - DEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, librad_errstr); + RDEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, fr_strerror()); return; } @@ -733,35 +659,11 @@ static void mppe_add_reply(REQUEST *request, 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->vp_integer; - - /* - * 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; - } + rad_assert(request != NULL); /* * Do normal authentication. @@ -771,11 +673,11 @@ 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->vp_strvalue, challenge, calculated); + smbdes_mschap(password->vp_octets, challenge, calculated); if (memcmp(response, calculated, 24) != 0) { return -1; } @@ -804,7 +706,24 @@ static int do_mschap(rlm_mschap_t *inst, buffer, sizeof(buffer), 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->packet->vps, vp); return -1; } @@ -815,7 +734,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; } @@ -824,7 +743,7 @@ 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; } @@ -832,7 +751,7 @@ static int do_mschap(rlm_mschap_t *inst, * Update the NT hash hash, from the NT key. */ if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) { - DEBUG2(" rlm_mschap: Invalid output from ntlm_auth: NT_KEY has non-hex values"); + RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } @@ -969,29 +888,35 @@ static int mschap_authorize(void * instance, REQUEST *request) #define inst ((rlm_mschap_t *)instance) 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)) { - DEBUG2(" rlm_mschap: Found existing Auth-Type. Not changing it."); + 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 @@ -1036,15 +961,32 @@ static int mschap_authenticate(void * instance, REQUEST *request) 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 = radius_pairmake(request, &request->config_items, @@ -1065,7 +1007,7 @@ static int mschap_authenticate(void * instance, REQUEST *request) * Password is not required. */ if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) { - DEBUG2(" rlm_mschap: SMB-Account-Ctrl says no password is required."); + RDEBUG2("SMB-Account-Ctrl says no password is required."); return RLM_MODULE_OK; } } @@ -1073,12 +1015,12 @@ static int mschap_authenticate(void * instance, REQUEST *request) /* * Decide how to get the passwords. */ - password = pairfind(request->config_items, PW_CLEARTEXT_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. @@ -1087,22 +1029,22 @@ static int mschap_authenticate(void * instance, REQUEST *request) ((lm_password->length == 32) && (fr_hex2bin(lm_password->vp_strvalue, lm_password->vp_octets, 16) == 16))) { - DEBUG2(" rlm_mschap: Found LM-Password"); + 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 Cleartext-Password configured. Cannot create LM-Password."); + if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured. Cannot create LM-Password."); } 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->vp_strvalue, lm_password->vp_octets); @@ -1113,45 +1055,49 @@ static int mschap_authenticate(void * instance, REQUEST *request) /* * 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) && (fr_hex2bin(nt_password->vp_strvalue, nt_password->vp_octets, 16) == 16))) { - DEBUG2(" rlm_mschap: Found NT-Password"); + 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 Cleartext-Password configured. Cannot create NT-Password."); + if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured. Cannot create NT-Password."); } 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->vp_octets, + mschap_ntpwdhash(nt_password->vp_octets, password->vp_strvalue); nt_password->length = 16; } } - 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 @@ -1163,7 +1109,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; } @@ -1171,7 +1117,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; } @@ -1180,11 +1126,11 @@ static int mschap_authenticate(void * instance, REQUEST *request) * response */ if (response->vp_octets[1] & 0x01) { - DEBUG2(" rlm_mschap: Told to do MS-CHAPv1 with NT-Password"); + 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; } @@ -1193,9 +1139,10 @@ static int mschap_authenticate(void * instance, REQUEST *request) * Do the MS-CHAP authentication. */ if (do_mschap(inst, request, password, challenge->vp_octets, - response->vp_octets + offset, nthashhash) < 0) { - DEBUG2(" rlm_mschap: MS-CHAP-Response is incorrect."); - mschap_add_reply(&request->reply->vps, + 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; @@ -1203,14 +1150,15 @@ static int mschap_authenticate(void * instance, REQUEST *request) 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; } @@ -1218,42 +1166,71 @@ 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->vp_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->vp_strvalue; + RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?"); + username_string = name_attr->vp_strvalue; } } else { - username_string = username->vp_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. + * 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) { - DEBUG2(" rlm_mschap: No NT-Password configured. Trying DirectoryService Authentication."); - return od_mschap_auth(request, challenge, username); + RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication."); + int odStatus = od_mschap_auth(request, challenge, username); + if (odStatus != RLM_MODULE_NOOP) { + return odStatus; + } } #endif /* @@ -1263,41 +1240,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->vp_octets + 2, /* peer 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->vp_octets + 26, nthashhash) < 0) { - DEBUG2(" rlm_mschap: FAILED: MS-CHAP2-Response is incorrect"); - mschap_add_reply(&request->reply->vps, + 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->vp_octets + 26, /* peer response */ response->vp_octets + 2, /* peer challenge */ challenge->vp_octets, /* our challenge */ msch2resp); /* calculated MPPE key */ - mschap_add_reply(&request->reply->vps, *response->vp_octets, + 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; } @@ -1315,8 +1289,8 @@ static int mschap_authenticate(void * instance, REQUEST *request) */ if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) || ((smb_ctrl->vp_integer & ACB_NORMAL) == 0)) { - DEBUG2(" rlm_mschap: SMB-Account-Ctrl says that the account is disabled, or is not a normal account."); - mschap_add_reply( &request->reply->vps, + 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; @@ -1326,8 +1300,8 @@ static int mschap_authenticate(void * instance, REQUEST *request) * User is locked out. */ if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) { - DEBUG2(" rlm_mschap: SMB-Account-Ctrl says that the account is locked out."); - mschap_add_reply( &request->reply->vps, + 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; @@ -1340,7 +1314,7 @@ 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->vp_octets, 8); @@ -1364,7 +1338,7 @@ static int mschap_authenticate(void * instance, REQUEST *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->vp_octets + 26, mppe_sendkey, mppe_recvkey);