From d8bb3d81a6396c4051be00de0808c60839b6945e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 2 May 2004 12:42:01 +0000 Subject: r451: More NTLMSSP work. The work here is trying to get the LM_KEY option for NLTMSSP operating, however until that functions properly, it is now controlled by some new smb.conf options, defaulting off. Andrew Bartlett (This used to be commit c63eb35b45c6db6e4c5302d1832bb5cef49a14f6) --- source4/libcli/auth/ntlmssp.c | 190 +++++++++++++++++++++++++++++++-------- source4/libcli/auth/ntlmssp.h | 5 +- source4/libcli/util/smbencrypt.c | 62 +++---------- 3 files changed, 167 insertions(+), 90 deletions(-) (limited to 'source4') diff --git a/source4/libcli/auth/ntlmssp.c b/source4/libcli/auth/ntlmssp.c index 00cf4d380a..161a15023a 100644 --- a/source4/libcli/auth/ntlmssp.c +++ b/source4/libcli/auth/ntlmssp.c @@ -330,10 +330,10 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, ntlmssp_state->unicode = False; } - if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm) { + if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm && !ntlmssp_state->use_ntlmv2) { /* other end forcing us to use LM */ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; - ntlmssp_state->use_ntlmv2 = False; + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; } else { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } @@ -348,6 +348,13 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128; + if (neg_flags & NTLMSSP_NEGOTIATE_56) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; + } + } + + if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) { + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56; } if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { @@ -360,6 +367,32 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, } +/** + Weaken NTLMSSP keys to cope with down-level clients and servers. + + We probably should have some parameters to control this, but as + it only occours for LM_KEY connections, and this is controlled + by the client lanman auth/lanman auth parameters, it isn't too bad. +*/ + +static void ntlmssp_weaken_keys(struct ntlmssp_state *ntlmssp_state) { + /* Key weakening not performed on the master key for NTLM2 + and does not occour for NTLM1. Therefore we only need + to do this for the LM_KEY. + */ + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { + + } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { + ntlmssp_state->session_key.data[7] = 0xa0; + } else { /* forty bits */ + ntlmssp_state->session_key.data[5] = 0xe5; + ntlmssp_state->session_key.data[6] = 0x38; + ntlmssp_state->session_key.data[7] = 0xb0; + } + } +} /** * Next state function for the Negotiate packet @@ -404,7 +437,7 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, debug_ntlmssp_flags(neg_flags); } - ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth()); + ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key); /* Ask our caller what challenge they would like in the packet */ cryptkey = ntlmssp_state->get_challenge(ntlmssp_state); @@ -534,8 +567,8 @@ static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state, &workstation, &ntlmssp_state->encrypted_session_key, &auth_flags)) { - DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n")); - dump_data(2, (const char *)request.data, request.length); + DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n")); + dump_data(10, (const char *)request.data, request.length); SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); @@ -569,7 +602,7 @@ static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state, } if (auth_flags) - ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, lp_lanman_auth()); + ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, ntlmssp_state->allow_lm_key); if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { SAFE_FREE(domain); @@ -636,6 +669,9 @@ static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state, data_blob_free(&ntlmssp_state->encrypted_session_key); return nt_status; } + + /* LM Key is incompatible... */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } } return NT_STATUS_OK; @@ -680,7 +716,10 @@ static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state, DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n")); session_key = data_blob(NULL, 0); } - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { + } else if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) + /* Ensure we can never get here on NTLMv2 */ + && (ntlmssp_state->nt_resp.length == 0 || ntlmssp_state->nt_resp.length == 24)) { + if (lm_session_key && lm_session_key->data && lm_session_key->length >= 8) { if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) { session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); @@ -688,27 +727,47 @@ static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state, session_key.data); DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); dump_data_pw("LM session key:\n", session_key.data, session_key.length); - } else { - /* use the key unmodified - it's - * probably a NULL key from the guest - * login */ - session_key = *lm_session_key; + } else { + + /* When there is no LM response, just use zeros */ + static const uchar zeros[24]; + session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); + SMBsesskeygen_lm_sess_key(zeros, zeros, + session_key.data); + DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); + dump_data_pw("LM session key:\n", session_key.data, session_key.length); } } else { + /* LM Key not selected */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n")); session_key = data_blob(NULL, 0); } + } else if (user_session_key && user_session_key->data) { session_key = *user_session_key; DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n")); dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); + + /* LM Key not selected */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + } else if (lm_session_key && lm_session_key->data) { + /* Very weird to have LM key, but no user session key, but anyway.. */ session_key = *lm_session_key; DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n")); dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); + + /* LM Key not selected */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + } else { DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n")); session_key = data_blob(NULL, 0); + + /* LM Key not selected */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } /* With KEY_EXCH, the client supplies the proposed session key, @@ -741,6 +800,9 @@ static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state, ntlmssp_state->session_key = session_key; } + /* The server might need us to use a partial-strength session key */ + ntlmssp_weaken_keys(ntlmssp_state); + nt_status = ntlmssp_sign_init(ntlmssp_state); data_blob_free(&ntlmssp_state->encrypted_session_key); @@ -824,6 +886,9 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE; + (*ntlmssp_state)->allow_lm_key = (lp_lanman_auth() + && lp_parm_bool(-1, "ntlmssp_server", "allow_lm_key", False)); + (*ntlmssp_state)->ref_count = 1; (*ntlmssp_state)->neg_flags = @@ -895,9 +960,11 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, char *server_domain; const char *chal_parse_string; const char *auth_gen_string; + uchar lm_hash[16]; DATA_BLOB lm_response = data_blob(NULL, 0); DATA_BLOB nt_response = data_blob(NULL, 0); DATA_BLOB session_key = data_blob(NULL, 0); + DATA_BLOB lm_session_key = data_blob(NULL, 0); DATA_BLOB encrypted_session_key = data_blob(NULL, 0); NTSTATUS nt_status; @@ -917,7 +984,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, DEBUG(3, ("Got challenge flags:\n")); debug_ntlmssp_flags(chal_flags); - ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth()); + ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key); if (ntlmssp_state->unicode) { if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { @@ -967,7 +1034,8 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, /* session key is all zeros */ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16); - + lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16); + /* not doing NLTM2 without a password */ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; } else if (ntlmssp_state->use_ntlmv2) { @@ -990,6 +1058,10 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, data_blob_free(&struct_blob); return NT_STATUS_NO_MEMORY; } + + /* LM Key is incompatible... */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { struct MD5Context md5_session_nonce_ctx; uchar nt_hash[16]; @@ -1024,38 +1096,69 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, SMBsesskeygen_ntv1(nt_hash, NULL, user_session_key); hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); + + /* LM Key is incompatible... */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } else { - - - uchar lm_hash[16]; uchar nt_hash[16]; - E_deshash(ntlmssp_state->password, lm_hash); - E_md4hash(ntlmssp_state->password, nt_hash); - + + if (ntlmssp_state->use_nt_response) { + nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); + SMBNTencrypt(ntlmssp_state->password,challenge_blob.data, + nt_response.data); + E_md4hash(ntlmssp_state->password, nt_hash); + session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); + SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); + dump_data_pw("NT session key:\n", session_key.data, session_key.length); + } + /* lanman auth is insecure, it may be disabled */ if (lp_client_lanman_auth()) { lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); - SMBencrypt(ntlmssp_state->password,challenge_blob.data, - lm_response.data); + if (!SMBencrypt(ntlmssp_state->password,challenge_blob.data, + lm_response.data)) { + /* If the LM password was too long (and therefore the LM hash being + of the first 14 chars only), don't send it */ + data_blob_free(&lm_response); + + /* LM Key is incompatible with 'long' passwords */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + } else { + E_deshash(ntlmssp_state->password, lm_hash); + lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); + memcpy(lm_session_key.data, lm_hash, 8); + memset(&lm_session_key.data[8], '\0', 8); + + if (!ntlmssp_state->use_nt_response) { + session_key = lm_session_key; + } + } + } else { + /* LM Key is incompatible... */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } - nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); - SMBNTencrypt(ntlmssp_state->password,challenge_blob.data, - nt_response.data); - - session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); - if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - && lp_client_lanman_auth()) { - SMBsesskeygen_lmv1(lm_hash, lm_response.data, - session_key.data); - dump_data_pw("LM session key\n", session_key.data, session_key.length); + } + + if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) + && lp_client_lanman_auth() && lm_session_key.length == 16) { + DATA_BLOB new_session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); + if (lm_response.length == 24) { + SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data, + new_session_key.data); } else { - SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); - dump_data_pw("NT session key:\n", session_key.data, session_key.length); + static const uchar zeros[24]; + SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros, + new_session_key.data); } + new_session_key.length = 16; + session_key = new_session_key; + dump_data_pw("LM session key\n", session_key.data, session_key.length); } + data_blob_free(&struct_blob); + /* Key exchange encryptes a new client-generated session key with the password-derived key */ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { @@ -1093,10 +1196,14 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, data_blob_free(&ntlmssp_state->chal); + ntlmssp_state->session_key = session_key; + + /* The client might be using 56 or 40 bit weakened keys */ + ntlmssp_weaken_keys(ntlmssp_state); + ntlmssp_state->chal = challenge_blob; ntlmssp_state->lm_resp = lm_response; ntlmssp_state->nt_resp = nt_response; - ntlmssp_state->session_key = session_key; ntlmssp_state->expected_state = NTLMSSP_UNKNOWN; @@ -1128,7 +1235,12 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state) (*ntlmssp_state)->get_global_myname = global_myname; (*ntlmssp_state)->get_domain = lp_workgroup; - (*ntlmssp_state)->unicode = True; + (*ntlmssp_state)->unicode = lp_parm_bool(-1, "ntlmssp_client", "unicode", True); + + (*ntlmssp_state)->use_nt_response = lp_parm_bool(-1, "ntlmssp_client", "send_nt_reponse", True); + + (*ntlmssp_state)->allow_lm_key = (lp_lanman_auth() + && lp_parm_bool(-1, "ntlmssp_client", "allow_lm_key", False)); (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth(); @@ -1145,7 +1257,11 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state) * We need to set this to allow a later SetPassword * via the SAMR pipe to succeed. Strange.... We could * also add NTLMSSP_NEGOTIATE_SEAL here. JRA. - * */ + * + * Without this, Windows will not create the master key + * that it thinks is only used for NTLMSSP signing and + * sealing. (It is actually pulled out and used directly) + */ NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_REQUEST_TARGET; diff --git a/source4/libcli/auth/ntlmssp.h b/source4/libcli/auth/ntlmssp.h index d678e26e21..a5e0951fa8 100644 --- a/source4/libcli/auth/ntlmssp.h +++ b/source4/libcli/auth/ntlmssp.h @@ -61,7 +61,7 @@ enum NTLM_MESSAGE_TYPE #define NTLMSSP_CHAL_TARGET_INFO 0x00800000 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* 128-bit encryption */ #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 -#define NTLMSSP_NEGOTIATE_080000000 0x80000000 +#define NTLMSSP_NEGOTIATE_56 0x80000000 #define NTLMSSP_NAME_TYPE_SERVER 0x01 #define NTLMSSP_NAME_TYPE_DOMAIN 0x02 @@ -80,6 +80,9 @@ typedef struct ntlmssp_state BOOL unicode; BOOL use_ntlmv2; + BOOL use_nt_response; /* Set to 'NO' to debug what happens when the NT response is omited */ + BOOL allow_lm_key; /* The LM_KEY code is not functional at this point, and it's not + very secure anyway */ char *user; char *domain; char *workstation; diff --git a/source4/libcli/util/smbencrypt.c b/source4/libcli/util/smbencrypt.c index 4b2c753637..cefd01bf1c 100644 --- a/source4/libcli/util/smbencrypt.c +++ b/source4/libcli/util/smbencrypt.c @@ -198,25 +198,6 @@ void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24]) E_P24(p21, c8, p24); } -/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ -void NTLMSSPOWFencrypt(const uchar passwd[8], const uchar *ntlmchalresp, uchar p24[24]) -{ - uchar p21[21]; - - memset(p21,'\0',21); - memcpy(p21, passwd, 8); - memset(p21 + 8, 0xbd, 8); - - E_P24(p21, ntlmchalresp, p24); -#ifdef DEBUG_PASSWORD - DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n")); - dump_data(100, (char *)p21, 21); - dump_data(100, (const char *)ntlmchalresp, 8); - dump_data(100, (char *)p24, 24); -#endif -} - - /* Does the NT MD4 hash then des encryption. */ void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24) @@ -288,48 +269,25 @@ void SMBsesskeygen_ntv1(const uchar kr[16], #endif } -void SMBsesskeygen_lmv1(const uchar lm_hash[16], - const uchar lm_resp[24], /* only uses 8 */ - uint8 sess_key[16]) +void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16], + const uchar lm_resp[24], /* only uses 8 */ + uint8 sess_key[16]) { /* Calculate the LM session key (effective length 40 bits, but changes with each session) */ - uchar p24[24]; - uchar partial_lm_hash[16]; - - memcpy(partial_lm_hash, lm_hash, 8); - memset(partial_lm_hash + 8, 0xbd, 8); - - SMBOWFencrypt(lm_hash, lm_resp, p24); - - memcpy(sess_key, p24, 16); - sess_key[5] = 0xe5; - sess_key[6] = 0x38; - sess_key[7] = 0xb0; - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_lmv1:\n")); - dump_data(100, sess_key, 16); -#endif -} + uchar p21[21]; + + memset(p21,'\0',21); + memcpy(p21, lm_hash, 8); + memset(p21 + 8, 0xbd, 8); -void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16], - const uchar lm_resp[24], /* only uses 8 */ - uint8 sess_key[16]) -{ - uchar p24[24]; - uchar partial_lm_hash[16]; - - memcpy(partial_lm_hash, lm_hash, 8); - memset(partial_lm_hash + 8, 0xbd, 8); + E_P24(p21, lm_resp, p24); - SMBOWFencrypt(partial_lm_hash, lm_resp, p24); - memcpy(sess_key, p24, 16); #ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_lmv1_jerry:\n")); + DEBUG(100, ("SMBsesskeygen_lm_sess_key: \n")); dump_data(100, sess_key, 16); #endif } -- cgit