Enzo Matsumiya 017511
From: Paulo Alcantara <pc@cjr.nz>
Enzo Matsumiya 017511
Date: Tue, 7 Dec 2021 22:51:04 -0300
Enzo Matsumiya 017511
Subject: [PATCH] cifs: fix ntlmssp auth when there is no key exchange
Enzo Matsumiya 017511
Git-commit: 9de0737d5ba0425c3154d5d83da12a8fa8595c0f
Enzo Matsumiya 017511
References: bsc#1193629
Enzo Matsumiya 017511
Patch-mainline: v5.16-rc5
Enzo Matsumiya 017511
Enzo Matsumiya 017511
Warn on the lack of key exchange during NTLMSSP authentication rather
Enzo Matsumiya 017511
than aborting it as there are some servers that do not set it in
Enzo Matsumiya 017511
CHALLENGE message.
Enzo Matsumiya 017511
Enzo Matsumiya 017511
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Enzo Matsumiya 017511
Acked-by: Ronnie Sahlberg <lsahlber@redhat.com>
Enzo Matsumiya 017511
Signed-off-by: Steve French <stfrench@microsoft.com>
Enzo Matsumiya 017511
Acked-by: Enzo Matsumiya <ematsumiya@suse.de>
Enzo Matsumiya 017511
---
Enzo Matsumiya 017511
 fs/cifs/sess.c | 54 +++++++++++++++++++++++++++++++++-----------------
Enzo Matsumiya 017511
 1 file changed, 36 insertions(+), 18 deletions(-)
Enzo Matsumiya 017511
Enzo Matsumiya 017511
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
Enzo Matsumiya 017511
index af63548eaf26..035dc3e245dc 100644
Enzo Matsumiya 017511
--- a/fs/cifs/sess.c
Enzo Matsumiya 017511
+++ b/fs/cifs/sess.c
Enzo Matsumiya 017511
@@ -590,8 +590,8 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
Enzo Matsumiya 017511
 {
Enzo Matsumiya 017511
 	unsigned int tioffset; /* challenge message target info area */
Enzo Matsumiya 017511
 	unsigned int tilen; /* challenge message target info area length  */
Enzo Matsumiya 017511
-
Enzo Matsumiya 017511
 	CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
Enzo Matsumiya 017511
+	__u32 server_flags;
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
 	if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
Enzo Matsumiya 017511
 		cifs_dbg(VFS, "challenge blob len %d too small\n", blob_len);
Enzo Matsumiya 017511
@@ -609,12 +609,37 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
Enzo Matsumiya 017511
 		return -EINVAL;
Enzo Matsumiya 017511
 	}
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
+	server_flags = le32_to_cpu(pblob->NegotiateFlags);
Enzo Matsumiya 017511
+	cifs_dbg(FYI, "%s: negotiate=0x%08x challenge=0x%08x\n", __func__,
Enzo Matsumiya 017511
+		 ses->ntlmssp->client_flags, server_flags);
Enzo Matsumiya 017511
+
Enzo Matsumiya 017511
+	if ((ses->ntlmssp->client_flags & (NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN)) &&
Enzo Matsumiya 017511
+	    (!(server_flags & NTLMSSP_NEGOTIATE_56) && !(server_flags & NTLMSSP_NEGOTIATE_128))) {
Enzo Matsumiya 017511
+		cifs_dbg(VFS, "%s: requested signing/encryption but server did not return either 56-bit or 128-bit session key size\n",
Enzo Matsumiya 017511
+			 __func__);
Enzo Matsumiya 017511
+		return -EINVAL;
Enzo Matsumiya 017511
+	}
Enzo Matsumiya 017511
+	if (!(server_flags & NTLMSSP_NEGOTIATE_NTLM) && !(server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) {
Enzo Matsumiya 017511
+		cifs_dbg(VFS, "%s: server does not seem to support either NTLMv1 or NTLMv2\n", __func__);
Enzo Matsumiya 017511
+		return -EINVAL;
Enzo Matsumiya 017511
+	}
Enzo Matsumiya 017511
+	if (ses->server->sign && !(server_flags & NTLMSSP_NEGOTIATE_SIGN)) {
Enzo Matsumiya 017511
+		cifs_dbg(VFS, "%s: forced packet signing but server does not seem to support it\n",
Enzo Matsumiya 017511
+			 __func__);
Enzo Matsumiya 017511
+		return -EOPNOTSUPP;
Enzo Matsumiya 017511
+	}
Enzo Matsumiya 017511
+	if ((ses->ntlmssp->client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
Enzo Matsumiya 017511
+	    !(server_flags & NTLMSSP_NEGOTIATE_KEY_XCH))
Enzo Matsumiya 017511
+		pr_warn_once("%s: authentication has been weakened as server does not support key exchange\n",
Enzo Matsumiya 017511
+			     __func__);
Enzo Matsumiya 017511
+
Enzo Matsumiya 017511
+	ses->ntlmssp->server_flags = server_flags;
Enzo Matsumiya 017511
+
Enzo Matsumiya 017511
 	memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
Enzo Matsumiya 017511
-	/* BB we could decode pblob->NegotiateFlags; some may be useful */
Enzo Matsumiya 017511
 	/* In particular we can examine sign flags */
Enzo Matsumiya 017511
 	/* BB spec says that if AvId field of MsvAvTimestamp is populated then
Enzo Matsumiya 017511
 		we must set the MIC field of the AUTHENTICATE_MESSAGE */
Enzo Matsumiya 017511
-	ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags);
Enzo Matsumiya 017511
+
Enzo Matsumiya 017511
 	tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset);
Enzo Matsumiya 017511
 	tilen = le16_to_cpu(pblob->TargetInfoArray.Length);
Enzo Matsumiya 017511
 	if (tioffset > blob_len || tioffset + tilen > blob_len) {
Enzo Matsumiya 017511
@@ -721,13 +746,13 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
Enzo Matsumiya 017511
 	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
Enzo Matsumiya 017511
 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
Enzo Matsumiya 017511
 		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
Enzo Matsumiya 017511
-		NTLMSSP_NEGOTIATE_SEAL;
Enzo Matsumiya 017511
-	if (server->sign)
Enzo Matsumiya 017511
-		flags |= NTLMSSP_NEGOTIATE_SIGN;
Enzo Matsumiya 017511
+		NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL |
Enzo Matsumiya 017511
+		NTLMSSP_NEGOTIATE_SIGN;
Enzo Matsumiya 017511
 	if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
Enzo Matsumiya 017511
 		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
 	tmp = *pbuffer + sizeof(NEGOTIATE_MESSAGE);
Enzo Matsumiya 017511
+	ses->ntlmssp->client_flags = flags;
Enzo Matsumiya 017511
 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
 	/* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
Enzo Matsumiya 017511
@@ -779,15 +804,8 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
Enzo Matsumiya 017511
 	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
Enzo Matsumiya 017511
 	sec_blob->MessageType = NtLmAuthenticate;
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
-	flags = NTLMSSP_NEGOTIATE_56 |
Enzo Matsumiya 017511
-		NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
Enzo Matsumiya 017511
-		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
Enzo Matsumiya 017511
-		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
Enzo Matsumiya 017511
-		NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
Enzo Matsumiya 017511
-	if (ses->server->sign)
Enzo Matsumiya 017511
-		flags |= NTLMSSP_NEGOTIATE_SIGN;
Enzo Matsumiya 017511
-	if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
Enzo Matsumiya 017511
-		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
Enzo Matsumiya 017511
+	flags = ses->ntlmssp->server_flags | NTLMSSP_REQUEST_TARGET |
Enzo Matsumiya 017511
+		NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
 	tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
Enzo Matsumiya 017511
 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
Enzo Matsumiya 017511
@@ -834,9 +852,9 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
Enzo Matsumiya 017511
 				      *pbuffer, &tmp,
Enzo Matsumiya 017511
 				      nls_cp);
Enzo Matsumiya 017511
 
Enzo Matsumiya 017511
-	if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) ||
Enzo Matsumiya 017511
-		(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
Enzo Matsumiya 017511
-			&& !calc_seckey(ses)) {
Enzo Matsumiya 017511
+	if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
Enzo Matsumiya 017511
+	    (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) &&
Enzo Matsumiya 017511
+	    !calc_seckey(ses)) {
Enzo Matsumiya 017511
 		memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
Enzo Matsumiya 017511
 		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
Enzo Matsumiya 017511
 		sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
Enzo Matsumiya 017511
-- 
Enzo Matsumiya 017511
2.34.1
Enzo Matsumiya 017511
Enzo Matsumiya 017511