From 5cf546c4cd1f01e852587a2717182d8d399db90e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 Jan 2004 23:22:00 +0000 Subject: (merge from 3.0) 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 0d97b10248347398fbee66767baac0c7adf6889d) --- source3/auth/auth_sam.c | 367 +++++++++++++++++++------------- source3/utils/ntlm_auth.c | 523 ++++++++++++++++------------------------------ 2 files changed, 400 insertions(+), 490 deletions(-) diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c index 7352a9685b..04b587343a 100644 --- a/source3/auth/auth_sam.c +++ b/source3/auth/auth_sam.c @@ -141,96 +141,129 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response, return (memcmp(value_from_encryption, client_response, 16) == 0); } -/**************************************************************************** - Do a specific test for an smb password being correct, given a smb_password and - the lanman and NT responses. -****************************************************************************/ - -static NTSTATUS sam_password_ok(const struct auth_context *auth_context, - TALLOC_CTX *mem_ctx, - SAM_ACCOUNT *sampass, - const auth_usersupplied_info *user_info, - DATA_BLOB *user_sess_key, - DATA_BLOB *lm_sess_key) +/** + * Check a challenge-response password against the value of the NT or + * LM password hash. + * + * @param mem_ctx talloc context + * @param challenge 8-byte challenge. If all zero, forces plaintext comparison + * @param nt_response 'unicode' NT response to the challenge, or unicode password + * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param nt_pw MD4 unicode password from our passdb or similar + * @param lm_pw LANMAN ASCII password from our passdb or similar + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +static NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, + const DATA_BLOB *challenge, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + const char *username, + const char *client_username, + const char *client_domain, + const uint8 *lm_pw, const uint8 *nt_pw, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key) { - uint16 acct_ctrl; - const uint8 *nt_pw, *lm_pw; - uint32 auth_flags; - - acct_ctrl = pdb_get_acct_ctrl(sampass); - if (acct_ctrl & ACB_PWNOTREQ) { - if (lp_null_passwords()) { - DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", pdb_get_username(sampass))); - return(NT_STATUS_OK); - } else { - DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", pdb_get_username(sampass))); - return(NT_STATUS_LOGON_FAILURE); - } + static const unsigned char zeros[8]; + if (nt_pw == NULL) { + DEBUG(3,("sam_password_ok: NO NT password stored for user %s.\n", + username)); } - auth_flags = user_info->auth_flags; + /* Check for cleartext netlogon. Used by Exchange 5.5. */ + if (challenge->length == sizeof(zeros) && + (memcmp(challenge->data, zeros, challenge->length) == 0 )) { - if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) { - DEBUG(3,("sam_password_ok: NO NT password stored for user %s.\n", - pdb_get_username(sampass))); - /* No return, we want to check the LM hash below in this case */ - auth_flags &= (~(AUTH_FLAG_NTLMv2_RESP | AUTH_FLAG_NTLM_RESP)); - } else { - /* Check for cleartext netlogon. Used by Exchange 5.5. */ - unsigned char zeros[8]; - - memset(zeros,'\0',sizeof(zeros)); - if (auth_context->challenge.length == sizeof(zeros) && - (memcmp(auth_context->challenge.data, zeros, auth_context->challenge.length) == 0 ) && - user_info->nt_resp.length) { - if ((nt_pw = pdb_get_nt_passwd(sampass)) != NULL) { - unsigned char pwhash[16]; - mdfour(pwhash, user_info->nt_resp.data, user_info->nt_resp.length); - if (memcmp(pwhash, nt_pw, sizeof(pwhash)) == 0) { - return NT_STATUS_OK; - } + DEBUG(4,("sam_password_ok: checking plaintext passwords for user %s\n", + username)); + if (nt_pw && nt_response->length) { + unsigned char pwhash[16]; + mdfour(pwhash, nt_response->data, nt_response->length); + if (memcmp(pwhash, nt_pw, sizeof(pwhash)) == 0) { + return NT_STATUS_OK; + } else { + DEBUG(3,("sam_password_ok: NT (Unicode) plaintext password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + + } else if (!lp_lanman_auth()) { + DEBUG(3,("sam_password_ok: (plaintext password check) LANMAN passwords NOT PERMITTED for user %s\n", + username)); + + } else if (lm_pw && lm_response->length) { + uchar dospwd[14]; + uchar p16[16]; + ZERO_STRUCT(dospwd); + + DEBUG(100, ("DOS password: %s\n")); + memcpy(dospwd, lm_response->data, MIN(lm_response->length, sizeof(dospwd))); + /* Only the fisrt 14 chars are considered, password need not be null terminated. */ + E_P16((const unsigned char *)dospwd, p16); + + dump_data_pw("DOS password (first buffer)\n", dospwd, 14); + dump_data_pw("DOS password (wire DES hash)\n", p16, 16); + dump_data_pw("DOS password (passdb DES hash)\n", lm_pw, 16); + if (memcmp(p16, lm_pw, sizeof(p16)) == 0) { + return NT_STATUS_OK; + } else { + DEBUG(3,("sam_password_ok: LANMAN (ASCII) plaintext password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; } + } else { + DEBUG(3, ("Plaintext authentication for user %s attempted, but neither NT nor LM passwords available\n", username)); + return NT_STATUS_WRONG_PASSWORD; } } + + if (nt_response->length != 0 && nt_response->length < 24) { + DEBUG(2,("sam_password_ok: invalid NT password length (%lu) for user %s\n", + (unsigned long)nt_response->length, username)); + } - if (auth_flags & AUTH_FLAG_NTLMv2_RESP) { - nt_pw = pdb_get_nt_passwd(sampass); - /* We have the NT MD4 hash challenge available - see if we can - use it (ie. does it exist in the smbpasswd file). - */ - DEBUG(4,("sam_password_ok: Checking NTLMv2 password with domain [%s]\n", user_info->client_domain.str)); - if (smb_pwd_check_ntlmv2( &user_info->nt_resp, - nt_pw, &auth_context->challenge, - user_info->smb_name.str, - user_info->client_domain.str, - user_sess_key)) { - return NT_STATUS_OK; + if (nt_response->length >= 24 && nt_pw) { + if (nt_response->length > 24) { + /* We have the NT MD4 hash challenge available - see if we can + use it (ie. does it exist in the smbpasswd file). + */ + DEBUG(4,("sam_password_ok: Checking NTLMv2 password with domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2( nt_response, + nt_pw, challenge, + client_username, + client_domain, + user_sess_key)) { + return NT_STATUS_OK; + } + + DEBUG(4,("sam_password_ok: Checking NTLMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2( nt_response, + nt_pw, challenge, + client_username, + "", + user_sess_key)) { + return NT_STATUS_OK; + } else { + DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n")); + return NT_STATUS_WRONG_PASSWORD; + } } - DEBUG(4,("sam_password_ok: Checking NTLMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2( &user_info->nt_resp, - nt_pw, &auth_context->challenge, - user_info->smb_name.str, - "", - user_sess_key)) { - return NT_STATUS_OK; - } else { - DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n")); - return NT_STATUS_WRONG_PASSWORD; - } - } else if (auth_flags & AUTH_FLAG_NTLM_RESP) { if (lp_ntlm_auth()) { - nt_pw = pdb_get_nt_passwd(sampass); /* We have the NT MD4 hash challenge available - see if we can use it (ie. does it exist in the smbpasswd file). */ DEBUG(4,("sam_password_ok: Checking NT MD4 password\n")); - if (smb_pwd_check_ntlmv1(&user_info->nt_resp, - nt_pw, &auth_context->challenge, + if (smb_pwd_check_ntlmv1(nt_response, + nt_pw, challenge, user_sess_key)) { /* The LM session key for this response is not very secure, so use it only if we otherwise allow LM authentication */ - lm_pw = pdb_get_lanman_passwd(sampass); if (lp_lanman_auth() && lm_pw) { uint8 first_8_lm_hash[16]; @@ -240,104 +273,142 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context, } return NT_STATUS_OK; } else { - DEBUG(3,("sam_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass))); + DEBUG(3,("sam_password_ok: NT MD4 password check failed for user %s\n", + username)); return NT_STATUS_WRONG_PASSWORD; } } else { - DEBUG(2,("sam_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass))); + DEBUG(2,("sam_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n", + username)); /* no return, becouse we might pick up LMv2 in the LM field */ } } - if (auth_flags & AUTH_FLAG_LM_RESP) { - if (user_info->lm_resp.length != 24) { - DEBUG(2,("sam_password_ok: invalid LanMan password length (%lu) for user %s\n", - (unsigned long)user_info->nt_resp.length, pdb_get_username(sampass))); - } + if (lm_response->length == 0) { + DEBUG(3,("sam_password_ok: NEITHER LanMan nor NT password supplied for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + + if (lm_response->length < 24) { + DEBUG(2,("sam_password_ok: invalid LanMan password length (%lu) for user %s\n", + (unsigned long)nt_response->length, username)); + return NT_STATUS_WRONG_PASSWORD; + } - if (!lp_lanman_auth()) { - DEBUG(3,("sam_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass))); - } else if (IS_SAM_DEFAULT(sampass, PDB_LMPASSWD)) { - DEBUG(3,("sam_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass))); - } else { - lm_pw = pdb_get_lanman_passwd(sampass); - - DEBUG(4,("sam_password_ok: Checking LM password\n")); - if (smb_pwd_check_ntlmv1(&user_info->lm_resp, - lm_pw, &auth_context->challenge, - NULL)) { + if (!lp_lanman_auth()) { + DEBUG(3,("sam_password_ok: Lanman passwords NOT PERMITTED for user %s\n", + username)); + } else if (!lm_pw) { + DEBUG(3,("sam_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n", + username)); + } else { + DEBUG(4,("sam_password_ok: Checking LM password\n")); + if (smb_pwd_check_ntlmv1(lm_response, + lm_pw, challenge, + NULL)) { + uint8 first_8_lm_hash[16]; + memcpy(first_8_lm_hash, lm_pw, 8); + memset(first_8_lm_hash + 8, '\0', 8); + *user_sess_key = data_blob(first_8_lm_hash, 16); + *lm_sess_key = data_blob(first_8_lm_hash, 16); + return NT_STATUS_OK; + } + } + + if (!nt_pw) { + DEBUG(4,("sam_password_ok: LM password check failed for user, no NT password %s\n",username)); + return NT_STATUS_WRONG_PASSWORD; + } + + /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes. + - related to Win9X, legacy NAS pass-though authentication + */ + DEBUG(4,("sam_password_ok: Checking LMv2 password with domain %s\n", client_domain)); + if (smb_pwd_check_ntlmv2( lm_response, + nt_pw, challenge, + client_username, + client_domain, + NULL)) { + return NT_STATUS_OK; + } + + DEBUG(4,("sam_password_ok: Checking LMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2( lm_response, + nt_pw, challenge, + client_username, + "", + NULL)) { + return NT_STATUS_OK; + } + + /* Apparently NT accepts NT responses in the LM field + - I think this is related to Win9X pass-though authentication + */ + DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n")); + if (lp_ntlm_auth()) { + if (smb_pwd_check_ntlmv1(lm_response, + nt_pw, challenge, + NULL)) { + /* The session key for this response is still very odd. + It not very secure, so use it only if we otherwise + allow LM authentication */ + + if (lp_lanman_auth() && lm_pw) { uint8 first_8_lm_hash[16]; memcpy(first_8_lm_hash, lm_pw, 8); memset(first_8_lm_hash + 8, '\0', 8); *user_sess_key = data_blob(first_8_lm_hash, 16); *lm_sess_key = data_blob(first_8_lm_hash, 16); - return NT_STATUS_OK; } - } - - if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) { - DEBUG(4,("sam_password_ok: LM password check failed for user, no NT password %s\n",pdb_get_username(sampass))); - return NT_STATUS_WRONG_PASSWORD; - } - - nt_pw = pdb_get_nt_passwd(sampass); - - /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes. - - related to Win9X, legacy NAS pass-though authentication - */ - DEBUG(4,("sam_password_ok: Checking LMv2 password with domain %s\n", user_info->client_domain.str)); - if (smb_pwd_check_ntlmv2( &user_info->lm_resp, - nt_pw, &auth_context->challenge, - user_info->smb_name.str, - user_info->client_domain.str, - NULL)) { return NT_STATUS_OK; } + DEBUG(3,("sam_password_ok: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username)); + } else { + DEBUG(3,("sam_password_ok: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username)); + } + return NT_STATUS_WRONG_PASSWORD; +} - DEBUG(4,("sam_password_ok: Checking LMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2( &user_info->lm_resp, - nt_pw, &auth_context->challenge, - user_info->smb_name.str, - "", - NULL)) { - return NT_STATUS_OK; - } +/**************************************************************************** + Do a specific test for an smb password being correct, given a smb_password and + the lanman and NT responses. +****************************************************************************/ - /* Apparently NT accepts NT responses in the LM field - - I think this is related to Win9X pass-though authentication - */ - DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n")); - if (lp_ntlm_auth()) { - if (smb_pwd_check_ntlmv1(&user_info->lm_resp, - nt_pw, &auth_context->challenge, - NULL)) { - /* The session key for this response is still very odd. - It not very secure, so use it only if we otherwise - allow LM authentication */ - lm_pw = pdb_get_lanman_passwd(sampass); - - if (lp_lanman_auth() && lm_pw) { - uint8 first_8_lm_hash[16]; - memcpy(first_8_lm_hash, lm_pw, 8); - memset(first_8_lm_hash + 8, '\0', 8); - *user_sess_key = data_blob(first_8_lm_hash, 16); - *lm_sess_key = data_blob(first_8_lm_hash, 16); - } - return NT_STATUS_OK; - } - DEBUG(3,("sam_password_ok: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",pdb_get_username(sampass))); - return NT_STATUS_WRONG_PASSWORD; +static NTSTATUS sam_password_ok(const struct auth_context *auth_context, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *sampass, + const auth_usersupplied_info *user_info, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key) +{ + uint16 acct_ctrl; + const uint8 *lm_pw, *nt_pw; + const char *username = pdb_get_username(sampass); + + acct_ctrl = pdb_get_acct_ctrl(sampass); + if (acct_ctrl & ACB_PWNOTREQ) { + if (lp_null_passwords()) { + DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username)); + return NT_STATUS_OK; } else { - DEBUG(3,("sam_password_ok: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",pdb_get_username(sampass))); - return NT_STATUS_WRONG_PASSWORD; - } + DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", username)); + return NT_STATUS_LOGON_FAILURE; + } } - - /* Should not be reached, but if they send nothing... */ - DEBUG(3,("sam_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass))); - return NT_STATUS_WRONG_PASSWORD; + + lm_pw = pdb_get_lanman_passwd(sampass); + nt_pw = pdb_get_nt_passwd(sampass); + + return ntlm_password_check(mem_ctx, &auth_context->challenge, + &user_info->lm_resp, &user_info->nt_resp, + username, + user_info->smb_name.str, + user_info->client_domain.str, + lm_pw, nt_pw, user_sess_key, lm_sess_key); } + /**************************************************************************** Do a specific test for a SAM_ACCOUNT being vaild for this connection (ie not disabled, expired and the like). diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 132134fd9d..c15a6e8758 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