[PATCH] cifs: fix MAC signatures when NTLMSSP auth is in use

Jeff Layton jlayton at redhat.com
Wed Apr 14 08:46:00 MDT 2010


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 <jlayton at redhat.com>
---
 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


--MP_/T8om.Woru1SrRLMKS.HbIo+--


More information about the linux-cifs-client mailing list