diff options
author | Andrew Bartlett <abartlet@samba.org> | 2004-05-02 12:42:01 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:51:43 -0500 |
commit | d8bb3d81a6396c4051be00de0808c60839b6945e (patch) | |
tree | 885502119e7fcc429fd968c1d207ae195969b3df /source4/libcli | |
parent | 63a41d7d4dbdf04b9718757886fdd087ad597d30 (diff) | |
download | samba-d8bb3d81a6396c4051be00de0808c60839b6945e.tar.gz samba-d8bb3d81a6396c4051be00de0808c60839b6945e.tar.bz2 samba-d8bb3d81a6396c4051be00de0808c60839b6945e.zip |
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)
Diffstat (limited to 'source4/libcli')
-rw-r--r-- | source4/libcli/auth/ntlmssp.c | 190 | ||||
-rw-r--r-- | source4/libcli/auth/ntlmssp.h | 5 | ||||
-rw-r--r-- | source4/libcli/util/smbencrypt.c | 62 |
3 files changed, 167 insertions, 90 deletions
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 } |