/* * ntpwdhash converts Unicode password to 16-byte NT hash * with MD4 */ void mschap_ntpwdhash (uint8_t *szHash, char const *szPassword) { unsigned char unicodePass[512]; size_t nPasswordLen; utf8_to_ucs2(szPassword, strlen(szPassword), unicodePass, sizeof(unicodePass), &nPasswordLen); /* Encrypt Unicode password to a 16-byte MD4 hash */ nPasswordLen *= 2; fr_md4_calc(szHash, (uint8_t *) unicodePass, nPasswordLen); }
/** Converts Unicode password to 16-byte NT hash with MD4 * * @param[out] out Pointer to 16 byte output buffer. * @param[in] password to encode. * @return 0 on success else -1 on failure. */ int mschap_ntpwdhash(uint8_t *out, char const *password) { ssize_t len; uint8_t ucs2_password[512]; len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), password, strlen(password)); if (len < 0) { *out = '\0'; return -1; } fr_md4_calc(out, (uint8_t *) ucs2_password, len); return 0; }
/* * 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) ); }
/* * Do the MS-CHAP stuff. * * This function is here so that all of the MS-CHAP related * authentication is in one place, and we can perhaps later replace * it with code to call winbindd, or something similar. */ static int do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password, uint8_t *challenge, uint8_t *response, uint8_t *nthashhash, int do_ntlm_auth) { uint8_t calculated[24]; /* * Do normal authentication. */ if (!do_ntlm_auth) { /* * No password: can't do authentication. */ if (!password) { RDEBUG2("FAILED: No NT/LM-Password. Cannot perform authentication."); return -1; } 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)) { fr_md4_calc(nthashhash, password->vp_octets, 16); } else { memset(nthashhash, 0, 16); } } else { /* run ntlm_auth */ int result; char buffer[256]; memset(nthashhash, 0, 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, 1); if (result != 0) { RDEBUG2("External script failed."); return -1; } /* * Parse the answer as an nthashhash. * * ntlm_auth currently returns: * NT_KEY: 000102030405060708090a0b0c0d0e0f */ if (memcmp(buffer, "NT_KEY: ", 8) != 0) { RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY"); return -1; } /* * Check the length. It should be at least 32, * with an LF at the end. */ if (strlen(buffer + 8) < 32) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length"); return -1; } /* * Update the NT hash hash, from the NT key. */ if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } return 0; }
/* * Do the MS-CHAP stuff. * * This function is here so that all of the MS-CHAP related * authentication is in one place, and we can perhaps later replace * it with code to call winbindd, or something similar. */ static int do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password, uint8_t *challenge, uint8_t *response, uint8_t *nthashhash, int do_ntlm_auth) { uint8_t calculated[24]; /* * Do normal authentication. */ if (!do_ntlm_auth) { /* * No password: can't do authentication. */ if (!password) { RDEBUG2("FAILED: No NT/LM-Password. Cannot perform authentication."); return -1; } smbdes_mschap(password->vp_strvalue, challenge, calculated); if (rad_digest_cmp(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)) { fr_md4_calc(nthashhash, password->vp_octets, 16); } else { memset(nthashhash, 0, 16); } } else { /* run ntlm_auth */ int result; char buffer[256]; memset(nthashhash, 0, 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, 1); if (result != 0) { 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; } /* * Parse the answer as an nthashhash. * * ntlm_auth currently returns: * NT_KEY: 000102030405060708090a0b0c0d0e0f */ if (memcmp(buffer, "NT_KEY: ", 8) != 0) { RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY"); return -1; } /* * Check the length. It should be at least 32, * with an LF at the end. */ if (strlen(buffer + 8) < 32) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length"); return -1; } /* * Update the NT hash hash, from the NT key. */ if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } return 0; }
/* * Do the MS-CHAP stuff. * * This function is here so that all of the MS-CHAP related * authentication is in one place, and we can perhaps later replace * it with code to call winbindd, or something similar. */ static int do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password, uint8_t *challenge, uint8_t *response, uint8_t *nthashhash) { 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) { RDEBUG2("Asked to use ntlm_auth, but it was not configured in the mschap{} section."); return -1; } /* * Do normal authentication. */ if (!do_ntlm_auth) { /* * No password: can't do authentication. */ if (!password) { RDEBUG2("FAILED: No NT/LM-Password. Cannot perform authentication."); return -1; } 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)) { fr_md4_calc(nthashhash, password->vp_octets, 16); } else { memset(nthashhash, 0, 16); } } else { /* run ntlm_auth */ int result; char buffer[256]; memset(nthashhash, 0, 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, 1); if (result != 0) { RDEBUG2("External script failed."); return -1; } /* * Parse the answer as an nthashhash. * * ntlm_auth currently returns: * NT_KEY: 000102030405060708090a0b0c0d0e0f */ if (memcmp(buffer, "NT_KEY: ", 8) != 0) { RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY"); return -1; } /* * Check the length. It should be at least 32, * with an LF at the end. */ if (strlen(buffer + 8) < 32) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length"); return -1; } /* * Update the NT hash hash, from the NT key. */ if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } return 0; }