From patchwork Wed Apr 14 15:34:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Linux CIFS NTLMSSP mount failing against win2k8 Date: Wed, 14 Apr 2010 05:34:53 -0000 From: Jeff Layton X-Patchwork-Id: 50165 Message-Id: <20100414113453.6a523b21@tlielax.poochiereds.net> To: Jeff Layton Cc: linux-cifs-client@lists.samba.org, smfrench@gmail.com, samba-technical@lists.samba.org, Andrew Bartlett On Wed, 14 Apr 2010 08:29:44 -0400 Jeff Layton wrote: > On Wed, 14 Apr 2010 09:01:32 +1000 > Andrew Bartlett wrote: > > > On Sun, 2010-04-11 at 19:40 -0400, Jeff Layton wrote: > > > > > I don't think that's right. CIFS_SESS_KEY_SIZE is 24 bytes. According > > > to the MS-NLMP document, the session key should be 16 bytes. The > > > signing key is different with NTLMSSP than with "raw" NTLM and NTLMv2. > > > > So, with NTLMSSP the 24 byte (actually variable, it is much lager for > > NTLMv2) response is not included in the MAC calculation - just use the > > 16 bytes session key only. > > > > Andrew Bartlett > > > > That was it! I was putting the right key into the NTLMSSP response, but > was leaving the saved key used for signing as a 40-byte key. When I > limit the key length to 16 then signing works correctly. > > I'll need to clean up the code a bit, but will post a patch to fix this > soon. > > Many thanks, Sigh, I made a mistake in testing. This didn't actually fix the problem. The tree connect is still rejected after session setup. The odd thing here is that this mount works against my samba server (samba-3.4.7-58.fc12.x86_64). Anyway for the purposes of discussion, here is the current patch I've got. Signing is still busted with this though. Anyone have thoughts on what we're doing wrong here? >From d973ea60245837d2f501ef32f847b917e9bd69aa Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 14 Apr 2010 10:46:00 -0400 Subject: [PATCH] cifs: fix MAC signatures when NTLMSSP auth is in use The session key is not currently sent in the response and isn't calculated properly. Also fix the flags so that keys are properly exchanged. Finally, there's no need to put the NTLM response on the stack and then copy it to the buffer. Just write it directly to the buffer in the first place. Signed-off-by: Jeff Layton --- fs/cifs/cifsencrypt.c | 10 ++++++++++ fs/cifs/cifspdu.h | 3 +++ fs/cifs/cifsproto.h | 1 + fs/cifs/ntlmssp.h | 3 +-- fs/cifs/sess.c | 32 +++++++++++++++----------------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index fbe9864..5d69ac8 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -208,6 +208,16 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } +void +cifs_set_ntlmssp_key(struct mac_key *key, const char *password) +{ + char temp_key[CIFS_NTLMSSP_SIGN_KEY_SIZE]; + + E_md4hash(password, temp_key); + mdfour(key->data.ntlm, temp_key, CIFS_NTLMSSP_SIGN_KEY_SIZE); + key->len = CIFS_NTLMSSP_SIGN_KEY_SIZE; +} + /* We fill in key by putting in 40 byte array which was allocated by caller */ int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *password) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 14d036d..749e161 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -135,6 +135,9 @@ */ #define CIFS_SESS_KEY_SIZE (24) +/* Size of signing key when NTLMSSP is in use. Size of md4 hash. */ +#define CIFS_NTLMSSP_SIGN_KEY_SIZE (16) + /* * Maximum user name length */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 39e47f4..96f8c6f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -346,6 +346,7 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_verify_signature(struct smb_hdr *, const struct mac_key *mac_key, __u32 expected_sequence_number); +extern void cifs_set_ntlmssp_key(struct mac_key *key, const char *password); extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 49c9a4e..6456aec 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -47,9 +47,8 @@ #define NTLMSSP_TARGET_TYPE_SERVER 0x20000 #define NTLMSSP_TARGET_TYPE_SHARE 0x40000 #define NTLMSSP_NEGOTIATE_EXTENDED_SEC 0x80000 /* NB:not related to NTLMv2 pwd*/ -/* #define NTLMSSP_REQUEST_INIT_RESP 0x100000 */ #define NTLMSSP_NEGOTIATE_IDENTIFY 0x100000 -#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 /* reserved5 */ +/* #define reserved5 0x200000 */ #define NTLMSSP_REQUEST_NON_NT_KEY 0x400000 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 /* #define reserved4 0x1000000 */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7c3fd74..b2cb182 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -388,7 +388,7 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, return -EINVAL; } - if (memcmp(pblob->Signature, "NTLMSSP", 8)) { + if (memcmp(pblob->Signature, NTLMSSP_SIGNATURE, 8)) { cERROR(1, ("blob signature incorrect %s", pblob->Signature)); return -EINVAL; } @@ -421,14 +421,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, sec_blob->MessageType = NtLmNegotiate; /* BB is NTLMV2 session security format easier to use here? */ - flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | + flags = NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_KEY_XCH | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) flags |= NTLMSSP_NEGOTIATE_SIGN; - if (ses->server->secMode & SECMODE_SIGN_REQUIRED) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; sec_blob->NegotiateFlags |= cpu_to_le32(flags); @@ -452,20 +450,16 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; __u32 flags; unsigned char *tmp; - char ntlm_session_key[CIFS_SESS_KEY_SIZE]; memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); sec_blob->MessageType = NtLmAuthenticate; - flags = NTLMSSP_NEGOTIATE_56 | - NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | + flags = NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_KEY_XCH | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) flags |= NTLMSSP_NEGOTIATE_SIGN; - if (ses->server->secMode & SECMODE_SIGN_REQUIRED) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); sec_blob->NegotiateFlags |= cpu_to_le32(flags); @@ -476,17 +470,16 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->LmChallengeResponse.MaximumLength = 0; /* calculate session key, BB what about adding similar ntlmv2 path? */ - SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); - if (first) - cifs_calculate_mac_key(&ses->server->mac_signing_key, - ntlm_session_key, ses->password); - - memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); + SMBNTencrypt(ses->password, ses->server->cryptKey, tmp); sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); sec_blob->NtChallengeResponse.MaximumLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); + if (first) + cifs_set_ntlmssp_key(&ses->server->mac_signing_key, + ses->password); + tmp += CIFS_SESS_KEY_SIZE; if (ses->domainName == NULL) { @@ -528,9 +521,14 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->WorkstationName.MaximumLength = 0; tmp += 2; + memcpy(tmp, &ses->server->mac_signing_key.data.ntlm, + CIFS_NTLMSSP_SIGN_KEY_SIZE); sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = 0; - sec_blob->SessionKey.MaximumLength = 0; + sec_blob->SessionKey.Length = cpu_to_le16(CIFS_NTLMSSP_SIGN_KEY_SIZE); + sec_blob->SessionKey.MaximumLength = + cpu_to_le16(CIFS_NTLMSSP_SIGN_KEY_SIZE); + tmp += CIFS_NTLMSSP_SIGN_KEY_SIZE; + return tmp - pbuffer; } -- 1.6.6.1