From bccf3f374b984bf327057daa8d03374b70034d3b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 30 Dec 2003 05:02:32 +0000 Subject: Refactor our authentication and authentication testing code. The next move will be to remove our password checking code from the SAM authentication backend, and into a file where other parts of samba can use it. The ntlm_auth changes provide for better use of common code. Andrew Bartlett (This used to be commit 2375abfa0077a884248c84614d5109f57dfdf5b1) --- source3/utils/ntlm_auth.c | 523 ++++++++++++++++------------------------------ 1 file changed, 181 insertions(+), 342 deletions(-) (limited to 'source3/utils/ntlm_auth.c') diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index b2450ffd0c..e33f4c4dee 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -38,6 +38,14 @@ enum stdio_helper_mode { NUM_HELPER_MODES }; +enum ntlm_break { + BREAK_NONE, + BREAK_LM, + BREAK_NT, + NO_LM, + NO_NT +}; + typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, char *buf, int length); @@ -1216,72 +1224,11 @@ static DATA_BLOB get_challenge(void) return chal; } -/* - * Test LM authentication, no NT response supplied - */ - -static BOOL test_lm(void) -{ - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB lm_response = data_blob(NULL, 24); - - uchar lm_key[8]; - uchar nt_key[16]; - uchar lm_hash[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - ZERO_STRUCT(lm_key); - ZERO_STRUCT(nt_key); - - flags |= WBFLAG_PAM_LMKEY; - flags |= WBFLAG_PAM_NTKEY; - - SMBencrypt(opt_password, chall.data, lm_response.data); - E_deshash(opt_password, lm_hash); - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, - &chall, - &lm_response, - NULL, - flags, - lm_key, - nt_key, - &error_string); - - data_blob_free(&lm_response); - - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - return False; - } - - if (memcmp(lm_hash, lm_key, - sizeof(lm_key)) != 0) { - DEBUG(1, ("LM Key does not match expectations!\n")); - DEBUG(1, ("lm_key:\n")); - dump_data(1, (const char *)lm_key, 8); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)lm_hash, 8); - } - if (memcmp(lm_hash, nt_key, 8) != 0) { - DEBUG(1, ("Session Key (first 8, lm hash) does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, (const char *)nt_key, 8); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)lm_hash, 8); - } - return True; -} - /* * Test the normal 'LM and NTLM' combination */ -static BOOL test_lm_ntlm(void) +static BOOL test_lm_ntlm_broken(enum ntlm_break break_which) { BOOL pass = True; NTSTATUS nt_status; @@ -1311,6 +1258,23 @@ static BOOL test_lm_ntlm(void) E_md4hash(opt_password, nt_hash); SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); + switch (break_which) { + case BREAK_NONE: + break; + case BREAK_LM: + lm_response.data[0]++; + break; + case BREAK_NT: + nt_response.data[0]++; + break; + case NO_LM: + data_blob_free(&lm_response); + break; + case NO_NT: + data_blob_free(&nt_response); + break; + } + nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, &chall, @@ -1328,7 +1292,7 @@ static BOOL test_lm_ntlm(void) error_string, NT_STATUS_V(nt_status)); SAFE_FREE(error_string); - return False; + return break_which == BREAK_NT; } if (memcmp(lm_hash, lm_key, @@ -1340,88 +1304,48 @@ static BOOL test_lm_ntlm(void) dump_data(1, (const char *)lm_hash, 8); pass = False; } - if (memcmp(session_key.data, nt_key, - sizeof(nt_key)) != 0) { - DEBUG(1, ("NT Session Key does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, (const char *)nt_key, 16); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)session_key.data, session_key.length); - pass = False; + + if (break_which == NO_NT) { + if (memcmp(lm_hash, nt_key, + 8) != 0) { + DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n")); + DEBUG(1, ("nt_key:\n")); + dump_data(1, (const char *)nt_key, sizeof(nt_key)); + DEBUG(1, ("expected:\n")); + dump_data(1, (const char *)lm_hash, sizeof(lm_hash)); + pass = False; + } + } else { + if (memcmp(session_key.data, nt_key, + sizeof(nt_key)) != 0) { + DEBUG(1, ("NT Session Key does not match expectations!\n")); + DEBUG(1, ("nt_key:\n")); + dump_data(1, (const char *)nt_key, 16); + DEBUG(1, ("expected:\n")); + dump_data(1, (const char *)session_key.data, session_key.length); + pass = False; + } } return pass; } /* - * Test the NTLM response only, no LM. + * Test LM authentication, no NT response supplied */ -static BOOL test_ntlm(void) +static BOOL test_lm(void) { - BOOL pass = True; - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB nt_response = data_blob(NULL, 24); - DATA_BLOB session_key = data_blob(NULL, 16); - - char lm_key[8]; - char nt_key[16]; - char lm_hash[16]; - char nt_hash[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - ZERO_STRUCT(lm_key); - ZERO_STRUCT(nt_key); - flags |= WBFLAG_PAM_LMKEY; - flags |= WBFLAG_PAM_NTKEY; - - SMBNTencrypt(opt_password,chall.data,nt_response.data); - E_md4hash(opt_password, (unsigned char *)nt_hash); - SMBsesskeygen_ntv1((const unsigned char *)nt_hash, NULL, session_key.data); - - E_deshash(opt_password, (unsigned char *)lm_hash); - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &chall, - NULL, - &nt_response, - flags, - (unsigned char *)lm_key, - (unsigned char *)nt_key, - &error_string); - - data_blob_free(&nt_response); + return test_lm_ntlm_broken(NO_NT); +} - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } +/* + * Test the NTLM response only, no LM. + */ - if (memcmp(lm_hash, lm_key, - sizeof(lm_key)) != 0) { - DEBUG(1, ("LM Key does not match expectations!\n")); - DEBUG(1, ("lm_key:\n")); - dump_data(1, lm_key, 8); - DEBUG(1, ("expected:\n")); - dump_data(1, lm_hash, 8); - pass = False; - } - if (memcmp(session_key.data, nt_key, - sizeof(nt_key)) != 0) { - DEBUG(1, ("NT Session Key does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, nt_key, 16); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)session_key.data, session_key.length); - pass = False; - } - return pass; +static BOOL test_ntlm(void) +{ + return test_lm_ntlm_broken(NO_LM); } /* @@ -1565,15 +1489,16 @@ static BOOL test_ntlm_in_both(void) } /* - * Test the NTLMv2 response only + * Test the NTLMv2 and LMv2 responses */ -static BOOL test_ntlmv2(void) +static BOOL test_lmv2_ntlmv2_broken(enum ntlm_break break_which) { BOOL pass = True; NTSTATUS nt_status; uint32 flags = 0; DATA_BLOB ntlmv2_response = data_blob(NULL, 0); + DATA_BLOB lmv2_response = data_blob(NULL, 0); DATA_BLOB nt_session_key = data_blob(NULL, 0); DATA_BLOB names_blob = NTLMv2_generate_names_blob(get_winbind_netbios_name(), get_winbind_domain()); @@ -1587,23 +1512,41 @@ static BOOL test_ntlmv2(void) if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, &names_blob, - NULL, &ntlmv2_response, + &lmv2_response, &ntlmv2_response, &nt_session_key)) { data_blob_free(&names_blob); return False; } data_blob_free(&names_blob); + switch (break_which) { + case BREAK_NONE: + break; + case BREAK_LM: + lmv2_response.data[0]++; + break; + case BREAK_NT: + ntlmv2_response.data[0]++; + break; + case NO_LM: + data_blob_free(&lmv2_response); + break; + case NO_NT: + data_blob_free(&ntlmv2_response); + break; + } + nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, &chall, - NULL, + &lmv2_response, &ntlmv2_response, flags, NULL, nt_key, &error_string); + data_blob_free(&lmv2_response); data_blob_free(&ntlmv2_response); if (!NT_STATUS_IS_OK(nt_status)) { @@ -1611,10 +1554,10 @@ static BOOL test_ntlmv2(void) error_string, NT_STATUS_V(nt_status)); SAFE_FREE(error_string); - return False; + return break_which == BREAK_NT; } - if (memcmp(nt_session_key.data, nt_key, + if (break_which != NO_NT && break_which != BREAK_NT && memcmp(nt_session_key.data, nt_key, sizeof(nt_key)) != 0) { DEBUG(1, ("NT Session Key does not match expectations!\n")); DEBUG(1, ("nt_key:\n")); @@ -1632,62 +1575,7 @@ static BOOL test_ntlmv2(void) static BOOL test_lmv2_ntlmv2(void) { - BOOL pass = True; - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB ntlmv2_response = data_blob(NULL, 0); - DATA_BLOB lmv2_response = data_blob(NULL, 0); - DATA_BLOB nt_session_key = data_blob(NULL, 0); - DATA_BLOB names_blob = NTLMv2_generate_names_blob(get_winbind_netbios_name(), get_winbind_domain()); - - uchar nt_key[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - ZERO_STRUCT(nt_key); - - flags |= WBFLAG_PAM_NTKEY; - - if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, - &names_blob, - &lmv2_response, &ntlmv2_response, - &nt_session_key)) { - data_blob_free(&names_blob); - return False; - } - data_blob_free(&names_blob); - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &chall, - &lmv2_response, - &ntlmv2_response, - flags, - NULL, - nt_key, - &error_string); - - data_blob_free(&lmv2_response); - data_blob_free(&ntlmv2_response); - - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } - - if (memcmp(nt_session_key.data, nt_key, - sizeof(nt_key)) != 0) { - DEBUG(1, ("NT Session Key does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, (const char *)nt_key, 16); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)nt_session_key.data, nt_session_key.length); - pass = False; - } - return pass; + return test_lmv2_ntlmv2_broken(BREAK_NONE); } /* @@ -1696,200 +1584,145 @@ static BOOL test_lmv2_ntlmv2(void) static BOOL test_lmv2(void) { - BOOL pass = True; - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB lmv2_response = data_blob(NULL, 0); - - DATA_BLOB chall = get_challenge(); - char *error_string; - - if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, - NULL, - &lmv2_response, NULL, - NULL)) { - return False; - } - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &chall, - &lmv2_response, - NULL, - flags, - NULL, - NULL, - &error_string); - - data_blob_free(&lmv2_response); - - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } - - return pass; + return test_lmv2_ntlmv2_broken(NO_NT); } /* - * Test the normal 'LM and NTLM' combination but deliberately break one + * Test the NTLMv2 response only */ -static BOOL test_ntlm_broken(BOOL break_lm) +static BOOL test_ntlmv2(void) { - BOOL pass = True; - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB lm_response = data_blob(NULL, 24); - DATA_BLOB nt_response = data_blob(NULL, 24); - DATA_BLOB session_key = data_blob(NULL, 16); - - uchar lm_key[8]; - uchar nt_key[16]; - uchar lm_hash[16]; - uchar nt_hash[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - ZERO_STRUCT(lm_key); - ZERO_STRUCT(nt_key); - - flags |= WBFLAG_PAM_LMKEY; - flags |= WBFLAG_PAM_NTKEY; - - SMBencrypt(opt_password,chall.data,lm_response.data); - E_deshash(opt_password, lm_hash); - - SMBNTencrypt(opt_password,chall.data,nt_response.data); - - E_md4hash(opt_password, nt_hash); - SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); - - if (break_lm) - lm_response.data[0]++; - else - nt_response.data[0]++; - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &chall, - &lm_response, - &nt_response, - flags, - lm_key, - nt_key, - &error_string); - - data_blob_free(&lm_response); - - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } + return test_lmv2_ntlmv2_broken(NO_LM); +} - if (memcmp(lm_hash, lm_key, - sizeof(lm_key)) != 0) { - DEBUG(1, ("LM Key does not match expectations!\n")); - DEBUG(1, ("lm_key:\n")); - dump_data(1, (const char *)lm_key, 8); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)lm_hash, 8); - pass = False; - } - if (memcmp(session_key.data, nt_key, - sizeof(nt_key)) != 0) { - DEBUG(1, ("NT Session Key does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, (const char *)nt_key, 16); - DEBUG(1, ("expected:\n")); - dump_data(1, (const char *)session_key.data, session_key.length); - pass = False; - } - return pass; +static BOOL test_lm_ntlm(void) +{ + return test_lm_ntlm_broken(BREAK_NONE); } static BOOL test_ntlm_lm_broken(void) { - return test_ntlm_broken(True); + return test_lm_ntlm_broken(BREAK_LM); } static BOOL test_ntlm_ntlm_broken(void) { - return test_ntlm_broken(False); + return test_lm_ntlm_broken(BREAK_NT); } -static BOOL test_ntlmv2_broken(BOOL break_lmv2) +static BOOL test_ntlmv2_lmv2_broken(void) +{ + return test_lmv2_ntlmv2_broken(BREAK_LM); +} + +static BOOL test_ntlmv2_ntlmv2_broken(void) +{ + return test_lmv2_ntlmv2_broken(BREAK_NT); +} + +static BOOL test_plaintext(enum ntlm_break break_which) { - BOOL pass = True; NTSTATUS nt_status; uint32 flags = 0; - DATA_BLOB ntlmv2_response = data_blob(NULL, 0); - DATA_BLOB lmv2_response = data_blob(NULL, 0); - DATA_BLOB nt_session_key = data_blob(NULL, 0); - DATA_BLOB names_blob = NTLMv2_generate_names_blob(get_winbind_netbios_name(), get_winbind_domain()); + DATA_BLOB nt_response = data_blob(NULL, 0); + DATA_BLOB lm_response = data_blob(NULL, 0); + char *password; uchar nt_key[16]; - DATA_BLOB chall = get_challenge(); + uchar lm_key[16]; + static const uchar zeros[8]; + DATA_BLOB chall = data_blob(zeros, sizeof(zeros)); char *error_string; ZERO_STRUCT(nt_key); flags |= WBFLAG_PAM_NTKEY; - - if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, - &names_blob, - &lmv2_response, &ntlmv2_response, - &nt_session_key)) { - data_blob_free(&names_blob); - return False; + flags |= WBFLAG_PAM_LMKEY; + + if ((push_ucs2_allocate((smb_ucs2_t **)&nt_response.data, opt_password)) == -1) { + DEBUG(0, ("push_ucs2_allocate failed!\n")); + exit(1); } - data_blob_free(&names_blob); - /* Heh - this should break the appropriate password hash nicely! */ + nt_response.length = strlen_w(((void *)nt_response.data))*sizeof(smb_ucs2_t); - if (break_lmv2) - lmv2_response.data[0]++; - else - ntlmv2_response.data[0]++; + password = strdup_upper(opt_password); + + if ((convert_string_allocate(NULL, CH_UNIX, + CH_DOS, password, + strlen(password)+1, + (void**)&lm_response.data)) == -1) { + DEBUG(0, ("push_ascii_allocate failed!\n")); + exit(1); + } + + SAFE_FREE(password); + + lm_response.length = strlen(lm_response.data); + + switch (break_which) { + case BREAK_NONE: + break; + case BREAK_LM: + lm_response.data[0]++; + break; + case BREAK_NT: + nt_response.data[0]++; + break; + case NO_LM: + SAFE_FREE(lm_response.data); + lm_response.length = 0; + break; + case NO_NT: + SAFE_FREE(nt_response.data); + nt_response.length = 0; + break; + } nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, &chall, - &lmv2_response, - &ntlmv2_response, + &lm_response, + &nt_response, flags, - NULL, + lm_key, nt_key, &error_string); - data_blob_free(&lmv2_response); - data_blob_free(&ntlmv2_response); + SAFE_FREE(nt_response.data); + SAFE_FREE(lm_response.data); + data_blob_free(&chall); if (!NT_STATUS_IS_OK(nt_status)) { d_printf("%s (0x%x)\n", error_string, NT_STATUS_V(nt_status)); SAFE_FREE(error_string); - return False; + return break_which == BREAK_NT; } - return pass; + return break_which != BREAK_NT; } -static BOOL test_ntlmv2_lmv2_broken(void) -{ - return test_ntlmv2_broken(True); +static BOOL test_plaintext_none_broken(void) { + return test_plaintext(BREAK_NONE); } -static BOOL test_ntlmv2_ntlmv2_broken(void) -{ - return test_ntlmv2_broken(False); +static BOOL test_plaintext_lm_broken(void) { + return test_plaintext(BREAK_LM); +} + +static BOOL test_plaintext_nt_broken(void) { + return test_plaintext(BREAK_NT); +} + +static BOOL test_plaintext_nt_only(void) { + return test_plaintext(NO_LM); +} + +static BOOL test_plaintext_lm_only(void) { + return test_plaintext(NO_NT); } /* @@ -1903,7 +1736,8 @@ static BOOL test_ntlmv2_ntlmv2_broken(void) - NTLMv2 - NTLMv2 and LMv2 - LMv2 - + - plaintext tests (in challenge-response feilds) + check we get the correct session key in each case check what values we get for the LM session key @@ -1924,7 +1758,12 @@ struct ntlm_tests { {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken"}, {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken"}, {test_ntlm_lm_broken, "NTLM and LM, LM broken"}, - {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken"} + {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken"}, + {test_plaintext_none_broken, "Plaintext"}, + {test_plaintext_lm_broken, "Plaintext LM broken"}, + {test_plaintext_nt_broken, "Plaintext NT broken"}, + {test_plaintext_nt_only, "Plaintext NT only"}, + {test_plaintext_lm_only, "Plaintext LM only"} }; static BOOL diagnose_ntlm_auth(void) -- cgit