diff options
-rw-r--r-- | source4/auth/ntlm_check.c | 167 | ||||
-rwxr-xr-x | source4/script/tests/test_rpc.sh | 6 | ||||
-rw-r--r-- | source4/torture/rpc/samlogon.c | 62 |
3 files changed, 178 insertions, 57 deletions
diff --git a/source4/auth/ntlm_check.c b/source4/auth/ntlm_check.c index 474742bee0..b308741970 100644 --- a/source4/auth/ntlm_check.c +++ b/source4/auth/ntlm_check.c @@ -58,11 +58,6 @@ static BOOL smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, } SMBOWFencrypt(part_passwd, sec_blob->data, p24); - if (user_sess_key != NULL) { - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv1(part_passwd, user_sess_key->data); - } - #if DEBUG_PASSWORD DEBUG(100,("Part password (P16) was |\n")); @@ -74,7 +69,14 @@ static BOOL smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, DEBUGADD(100,("Value from encryption was |\n")); dump_data(100, p24, 24); #endif - return (memcmp(p24, nt_response->data, 24) == 0); + if (memcmp(p24, nt_response->data, 24) == 0) { + if (user_sess_key != NULL) { + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv1(part_passwd, user_sess_key->data); + } + return True; + } + return False; } /**************************************************************************** @@ -93,7 +95,6 @@ static BOOL smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, /* Finish the encryption of part_passwd. */ uint8_t kr[16]; uint8_t value_from_encryption[16]; - uint8_t client_response[16]; DATA_BLOB client_key_data; if (part_passwd == NULL) { @@ -123,17 +124,11 @@ static BOOL smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, but for NTLMv2 it is meant to contain the current time etc. */ - memcpy(client_response, ntv2_response->data, sizeof(client_response)); - if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { return False; } SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); - if (user_sess_key != NULL) { - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); - } #if DEBUG_PASSWORD DEBUG(100,("Part password (P16) was |\n")); @@ -148,7 +143,65 @@ static BOOL smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, dump_data(100, value_from_encryption, 16); #endif data_blob_clear_free(&client_key_data); - return (memcmp(value_from_encryption, client_response, 16) == 0); + if (memcmp(value_from_encryption, ntv2_response->data, 16) == 0) { + if (user_sess_key != NULL) { + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); + } + return True; + } + return False; +} + +/**************************************************************************** + Core of smb password checking routine. (NTLMv2, LMv2) + Note: The same code works with both NTLMv2 and LMv2. +****************************************************************************/ + +static BOOL smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx, + const DATA_BLOB *ntv2_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + const char *user, const char *domain, + BOOL upper_case_domain, /* should the domain be transformed into upper case? */ + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t kr[16]; + uint8_t value_from_encryption[16]; + DATA_BLOB client_key_data; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always False */ + return False; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_sess_key_ntlmv2: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return False; + } + + if (ntv2_response->length < 24) { + /* We MUST have more than 16 bytes, or the stuff below will go + crazy. No known implementation sends less than the 24 bytes + for LMv2, let alone NTLMv2. */ + DEBUG(0, ("smb_sess_key_ntlmv2: incorrect password length (%lu)\n", + (unsigned long)ntv2_response->length)); + return False; + } + + client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); + + if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { + return False; + } + + SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); + return True; } /** @@ -182,6 +235,8 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, DATA_BLOB *lm_sess_key) { static const uint8_t zeros[8]; + DATA_BLOB tmp_sess_key; + if (nt_pw == NULL) { DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", username)); @@ -299,7 +354,9 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, user_sess_key)) { if (lm_sess_key) { *lm_sess_key = *user_sess_key; - lm_sess_key->length = 8; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } } return NT_STATUS_OK; } @@ -314,7 +371,9 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, user_sess_key)) { if (lm_sess_key) { *lm_sess_key = *user_sess_key; - lm_sess_key->length = 8; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } } return NT_STATUS_OK; } @@ -329,7 +388,9 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, user_sess_key)) { if (lm_sess_key) { *lm_sess_key = *user_sess_key; - lm_sess_key->length = 8; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } } return NT_STATUS_OK; } else { @@ -418,10 +479,28 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, client_username, client_domain, False, - user_sess_key)) { - if (lm_sess_key) { + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + nt_pw, challenge, + client_username, + client_domain, + False, + user_sess_key); + } else if (user_sess_key) { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + if (user_sess_key && lm_sess_key) { *lm_sess_key = *user_sess_key; - lm_sess_key->length = 8; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } } return NT_STATUS_OK; } @@ -433,10 +512,28 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, client_username, client_domain, True, - user_sess_key)) { - if (lm_sess_key) { + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + nt_pw, challenge, + client_username, + client_domain, + True, + user_sess_key); + } else if (user_sess_key) { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + if (user_sess_key && lm_sess_key) { *lm_sess_key = *user_sess_key; - lm_sess_key->length = 8; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } } return NT_STATUS_OK; } @@ -448,10 +545,28 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, client_username, "", False, - user_sess_key)) { - if (lm_sess_key) { + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + nt_pw, challenge, + client_username, + "", + False, + user_sess_key); + } else if (user_sess_key) { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + if (user_sess_key && lm_sess_key) { *lm_sess_key = *user_sess_key; - lm_sess_key->length = 8; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } } return NT_STATUS_OK; } diff --git a/source4/script/tests/test_rpc.sh b/source4/script/tests/test_rpc.sh index a1181cab42..c15ce87b05 100755 --- a/source4/script/tests/test_rpc.sh +++ b/source4/script/tests/test_rpc.sh @@ -2,9 +2,9 @@ # add tests to this list as they start passing, so we test # that they stay passing -ncacn_np_tests="RPC-SCHANNEL RPC-ECHO RPC-DSSETUP" -ncalrpc_tests="RPC-SCHANNEL RPC-ECHO RPC-DSSETUP" -ncacn_ip_tcp_tests="RPC-SCHANNEL RPC-ECHO" +ncacn_np_tests="RPC-SCHANNEL RPC-ECHO RPC-DSSETUP RPC-SAMLOGON" +ncalrpc_tests="RPC-SCHANNEL RPC-ECHO RPC-DSSETUP RPC-SAMLOGON" +ncacn_ip_tcp_tests="RPC-SCHANNEL RPC-ECHO RPC-SAMLOGON" if [ $# -lt 4 ]; then cat <<EOF diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c index 0c5afd44fe..7e5579b213 100644 --- a/source4/torture/rpc/samlogon.c +++ b/source4/torture/rpc/samlogon.c @@ -582,7 +582,7 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum switch (break_which) { case NO_NT: - if (memcmp(lmv2_session_key.data, user_session_key, + if (memcmp(lmv2_session_key.data, user_session_key, sizeof(user_session_key)) != 0) { printf("USER (LMv2) Session Key does not match expectations!\n"); printf("user_session_key:\n"); @@ -604,21 +604,42 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum default: if (memcmp(ntlmv2_session_key.data, user_session_key, sizeof(user_session_key)) != 0) { - printf("USER (NTLMv2) Session Key does not match expectations!\n"); - printf("user_session_key:\n"); - dump_data(1, user_session_key, 16); - printf("expected:\n"); - dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length); - pass = False; + if (memcmp(lmv2_session_key.data, user_session_key, + sizeof(user_session_key)) == 0) { + printf("USER (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n"); + printf("user_session_key:\n"); + dump_data(1, user_session_key, 16); + printf("expected:\n"); + dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length); + pass = False; + + } else { + printf("USER (NTLMv2) Session Key does not match expectations!\n"); + printf("user_session_key:\n"); + dump_data(1, user_session_key, 16); + printf("expected:\n"); + dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length); + pass = False; + } } if (memcmp(ntlmv2_session_key.data, lm_session_key, sizeof(lm_session_key)) != 0) { - printf("LM (NTLMv2) Session Key does not match expectations!\n"); - printf("lm_session_key:\n"); - dump_data(1, lm_session_key, 8); - printf("expected:\n"); - dump_data(1, ntlmv2_session_key.data, 8); - pass = False; + if (memcmp(lmv2_session_key.data, lm_session_key, + sizeof(lm_session_key)) == 0) { + printf("LM (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n"); + printf("user_session_key:\n"); + dump_data(1, lm_session_key, 8); + printf("expected:\n"); + dump_data(1, ntlmv2_session_key.data, 8); + pass = False; + } else { + printf("LM (NTLMv2) Session Key does not match expectations!\n"); + printf("lm_session_key:\n"); + dump_data(1, lm_session_key, 8); + printf("expected:\n"); + dump_data(1, ntlmv2_session_key.data, 8); + pass = False; + } } } @@ -1267,21 +1288,6 @@ BOOL torture_rpc_samlogon(void) } } - for (i=0; i < 32; i++) { - if (!test_SetupCredentials2(p, mem_ctx, 1 << i, - TEST_MACHINE_NAME, machine_password, creds)) { - return False; - } - - if (!test_InteractiveLogon(p, mem_ctx, creds)) { - ret = False; - } - - if (!test_SamLogon(p, mem_ctx, creds)) { - ret = False; - } - } - failed: talloc_destroy(mem_ctx); |