Skip to contentSkip to conversation

cifs: set client time as MsvAvTimestamp from CHALLENGE_MESSAGE.TargetInfo

PATCH Superseded Namjae Jeon 4 participants 7 messages Aug 25, 2014 – Aug 26, 2014 3 messages not in the archive

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 cifs: set client time as MsvAvTimestamp from CHALLENGE_MESSAGE.TargetInfo

Windows machine has extended security feature which refuse to allow authentication when there is time difference between server time and client time when ntlmv2 negotiation is used. This problem is prevalent in embedded enviornment where system time is set to default 1970.

Modern servers send the server timestamp in the TargetInfo Av_Pair structure in the challenge message [see MS-NLMP 2.2.2.1]
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must use the server provided timestamp if present OR current time if it is not.

---
 fs/cifs/cifsencrypt.c |    6 ++++--
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/sess.c        |   21 +++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)
fs/cifs/cifsencrypt.c +4 -2
index 4934347..3ec44f8 100644
@@ -671,8 +671,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
 	ntlmv2->blob_signature = cpu_to_le32(0x00000101);
 	ntlmv2->reserved = 0;
-	/* Must be within 5 minutes of the server */
-	ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+	if (ses->serverTime)
+		ntlmv2->time = ses->serverTime;
+	else
+		ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
 	get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
 	ntlmv2->reserved2 = 0;
 
fs/cifs/cifsglob.h +2 -0
index ce24c1f..1102822 100644
@@ -796,6 +796,8 @@ struct cifs_ses {
 	enum securityEnum sectype; /* what security flavor was specified? */
 	bool sign;		/* is signing required? */
 	bool need_reconnect:1; /* connection reset, uid now invalid */
+	__u64   serverTime;	/* Keeps a track of server time sent by server
+				   during NTLM challenge in little endian */
 #ifdef CONFIG_CIFS_SMB2
 	__u16 session_flags;
 	char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
fs/cifs/sess.c +21 -0
index 07fe97a..0762377 100644
@@ -277,6 +277,26 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 	cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
 }
 
+static void
+get_ntlmv2_server_time(struct cifs_ses *ses)
+{
+#define MsvAvEOL	0x0000
+#define MsvAvTimestamp	0x0007
+	char *payload = ses->auth_key.response;
+	u16 AvId, AvLen;
+
+	do {
+		AvId = le16_to_cpu(*payload);
+		AvLen = le16_to_cpu(*(payload + sizeof(u16)));
+		payload += AvLen + (2 * sizeof(u16));
+	} while (AvId != MsvAvTimestamp && AvId != MsvAvEOL);
+
+	if (AvId == MsvAvTimestamp)
+		memcpy(&(ses->serverTime), (payload - AvLen), sizeof(__u64));
+	else
+		ses->serverTime = 0;
+}
+
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 				    struct cifs_ses *ses)
 {
@@ -322,6 +342,7 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 			return -ENOMEM;
 		}
 		ses->auth_key.len = tilen;
+		get_ntlmv2_server_time(ses);
 	}
 
 	return 0;
Signature · 1 line
1.7.7
#1 lore raw
Quoted 82 lines · Namjae Jeon

Windows machine has extended security feature which refuse to allow authentication when there is time difference between server time and client time when ntlmv2 negotiation is used. This problem is prevalent in embedded enviornment where system time is set to default 1970.

Modern servers send the server timestamp in the TargetInfo Av_Pair structure in the challenge message [see MS-NLMP 2.2.2.1]
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must use the server provided timestamp if present OR current time if it is not.

---
 fs/cifs/cifsencrypt.c |    6 ++++--
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/sess.c        |   21 +++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)
fs/cifs/cifsencrypt.c +4 -2
index 4934347..3ec44f8 100644
@@ -671,8 +671,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
 	ntlmv2->blob_signature = cpu_to_le32(0x00000101);
 	ntlmv2->reserved = 0;
-	/* Must be within 5 minutes of the server */
-	ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+	if (ses->serverTime)
+		ntlmv2->time = ses->serverTime;
+	else
+		ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
 	get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
 	ntlmv2->reserved2 = 0;
 
fs/cifs/cifsglob.h +2 -0
index ce24c1f..1102822 100644
@@ -796,6 +796,8 @@ struct cifs_ses {
 	enum securityEnum sectype; /* what security flavor was specified? */
 	bool sign;		/* is signing required? */
 	bool need_reconnect:1; /* connection reset, uid now invalid */
+	__u64   serverTime;	/* Keeps a track of server time sent by server
+				   during NTLM challenge in little endian */
 #ifdef CONFIG_CIFS_SMB2
 	__u16 session_flags;
 	char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
fs/cifs/sess.c +20 -0
index 07fe97a..0762377 100644
@@ -277,6 +277,26 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 	cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
 }
 
+static void
+get_ntlmv2_server_time(struct cifs_ses *ses)
+{
+#define MsvAvEOL	0x0000
+#define MsvAvTimestamp	0x0007
+	char *payload = ses->auth_key.response;
+	u16 AvId, AvLen;
+
+	do {
+		AvId = le16_to_cpu(*payload);
+		AvLen = le16_to_cpu(*(payload + sizeof(u16)));
+		payload += AvLen + (2 * sizeof(u16));
+	} while (AvId != MsvAvTimestamp && AvId != MsvAvEOL);
+
+	if (AvId == MsvAvTimestamp)
+		memcpy(&(ses->serverTime), (payload - AvLen), sizeof(__u64));
+	else
+		ses->serverTime = 0;
+}
+
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 				    struct cifs_ses *ses)
 {

fs/cifs/sess.c int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, · line 348

Quoted 7 lines
fs/cifs/sess.c +1 -0
@@ -322,6 +342,7 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 			return -ENOMEM;
 		}
 		ses->auth_key.len = tilen;
+		get_ntlmv2_server_time(ses);
 	}
 
 	return 0;

I'll let a cifs maintainer ack or nack the implementation, but from a logic pov it looks good.

Simo.

A message that is not in the archive (sent off-list or not yet received): 1408972359.11134.26.camel-fj0lwfvWodpMy5p6ylGyhR2eb7JE58TQ@public.gmane.org

#3 lore raw
Quoted 12 lines
Quoted 12 lines
fs/cifs/sess.c +2 -0
+
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 				    struct cifs_ses *ses)
 {
@@ -322,6 +342,7 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 			return -ENOMEM;
 		}
 		ses->auth_key.len = tilen;
+		get_ntlmv2_server_time(ses);
 	}
 
Quoted 4 lines

fs/cifs/sess.c int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, · line 348

Quoted 1 line
fs/cifs/sess.c +0 -0
 	return 0;

I'll let a cifs maintainer ack or nack the implementation, but from a logic pov it looks good.

Thanks for your review!

Quoted 2 lines

Simo.

#4 lore raw
In reply to Namjae Jeon
Quoted 55 lines · Namjae Jeon

Windows machine has extended security feature which refuse to allow authentication when there is time difference between server time and client time when ntlmv2 negotiation is used. This problem is prevalent in embedded enviornment where system time is set to default 1970.

Modern servers send the server timestamp in the TargetInfo Av_Pair structure in the challenge message [see MS-NLMP 2.2.2.1]
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must use the server provided timestamp if present OR current time if it is not.

---
 fs/cifs/cifsencrypt.c |    6 ++++--
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/sess.c        |   21 +++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)
fs/cifs/cifsencrypt.c +4 -2
index 4934347..3ec44f8 100644
@@ -671,8 +671,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                        (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
        ntlmv2->blob_signature = cpu_to_le32(0x00000101);
        ntlmv2->reserved = 0;
-       /* Must be within 5 minutes of the server */
-       ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       if (ses->serverTime)
+               ntlmv2->time = ses->serverTime;
+       else
+               ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
        get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
        ntlmv2->reserved2 = 0;
 
fs/cifs/cifsglob.h +2 -0
index ce24c1f..1102822 100644
@@ -796,6 +796,8 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
+       __u64   serverTime;     /* Keeps a track of server time sent by server
+                                  during NTLM challenge in little endian */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
        char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
fs/cifs/sess.c +0 -0
index 07fe97a..0762377 100644

fs/cifs/sess.c static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft, · line 284

Quoted 8 lines
fs/cifs/sess.c +5 -0
@@ -277,6 +277,26 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
        cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
 }
 
+static void
+get_ntlmv2_server_time(struct cifs_ses *ses)
+{
+#define MsvAvEOL       0x0000
+#define MsvAvTimestamp 0x0007

This patch looks correct but we have these defines in ntlmssp.h.

Quoted 33 lines
fs/cifs/sess.c +16 -1
+       char *payload = ses->auth_key.response;
+       u16 AvId, AvLen;
+
+       do {
+               AvId = le16_to_cpu(*payload);
+               AvLen = le16_to_cpu(*(payload + sizeof(u16)));
+               payload += AvLen + (2 * sizeof(u16));
+       } while (AvId != MsvAvTimestamp && AvId != MsvAvEOL);
+
+       if (AvId == MsvAvTimestamp)
+               memcpy(&(ses->serverTime), (payload - AvLen), sizeof(__u64));
+       else
+               ses->serverTime = 0;
+}
+
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
                                    struct cifs_ses *ses)
 {
@@ -322,6 +342,7 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
                        return -ENOMEM;
                }
                ses->auth_key.len = tilen;
+               get_ntlmv2_server_time(ses);
        }
 
        return 0;
--

1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): CADT32eKrh_ZGa3kEeGvz2MSm8qeY+F7VK0d94w2yazJtxk1x8w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#6 lore raw
Quoted 59 lines · Namjae Jeon
Quoted 58 lines

Windows machine has extended security feature which refuse to allow authentication when there is time difference between server time and client time when ntlmv2 negotiation is used. This problem is prevalent in embedded enviornment where system time is set to default 1970.

Modern servers send the server timestamp in the TargetInfo Av_Pair structure in the challenge message [see MS-NLMP 2.2.2.1]
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must use the server provided timestamp if present OR current time if it is not.

---
 fs/cifs/cifsencrypt.c |    6 ++++--
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/sess.c        |   21 +++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)
fs/cifs/cifsencrypt.c +4 -2
index 4934347..3ec44f8 100644
@@ -671,8 +671,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                        (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
        ntlmv2->blob_signature = cpu_to_le32(0x00000101);
        ntlmv2->reserved = 0;
-       /* Must be within 5 minutes of the server */
-       ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       if (ses->serverTime)
+               ntlmv2->time = ses->serverTime;
+       else
+               ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
        get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
        ntlmv2->reserved2 = 0;
 
fs/cifs/cifsglob.h +2 -0
index ce24c1f..1102822 100644
@@ -796,6 +796,8 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
+       __u64   serverTime;     /* Keeps a track of server time sent by server
+                                  during NTLM challenge in little endian */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
        char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
fs/cifs/sess.c +0 -0
index 07fe97a..0762377 100644
@@ -277,6 +277,26 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
        cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
 }
 
Quoted 7 lines

fs/cifs/sess.c static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft, · line 284

Quoted 5 lines
fs/cifs/sess.c +5 -0
+static void
+get_ntlmv2_server_time(struct cifs_ses *ses)
+{
+#define MsvAvEOL       0x0000
+#define MsvAvTimestamp 0x0007

This patch looks correct but we have these defines in ntlmssp.h.

Okay, I will send v2 patch.
Thanks for your reivew!

Quoted 1 line
#7 lore raw

Would be helpful as well to note in the patch description whether this was observed so far only to Windows servers (or whether it affects mounts to Samba as well e.g.)

Quoted 70 lines · Namjae Jeon
Quoted 59 lines · Namjae Jeon
Quoted 58 lines

Windows machine has extended security feature which refuse to allow authentication when there is time difference between server time and client time when ntlmv2 negotiation is used. This problem is prevalent in embedded enviornment where system time is set to default 1970.

Modern servers send the server timestamp in the TargetInfo Av_Pair structure in the challenge message [see MS-NLMP 2.2.2.1]
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must use the server provided timestamp if present OR current time if it is not.

---
 fs/cifs/cifsencrypt.c |    6 ++++--
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/sess.c        |   21 +++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)
fs/cifs/cifsencrypt.c +4 -2
index 4934347..3ec44f8 100644
@@ -671,8 +671,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                        (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
        ntlmv2->blob_signature = cpu_to_le32(0x00000101);
        ntlmv2->reserved = 0;
-       /* Must be within 5 minutes of the server */
-       ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       if (ses->serverTime)
+               ntlmv2->time = ses->serverTime;
+       else
+               ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
        get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
        ntlmv2->reserved2 = 0;
 
fs/cifs/cifsglob.h +2 -0
index ce24c1f..1102822 100644
@@ -796,6 +796,8 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
+       __u64   serverTime;     /* Keeps a track of server time sent by server
+                                  during NTLM challenge in little endian */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
        char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
fs/cifs/sess.c +0 -0
index 07fe97a..0762377 100644
@@ -277,6 +277,26 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
        cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
 }
 
Quoted 7 lines

fs/cifs/sess.c static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft, · line 284

Quoted 5 lines
fs/cifs/sess.c +5 -0
+static void
+get_ntlmv2_server_time(struct cifs_ses *ses)
+{
+#define MsvAvEOL       0x0000
+#define MsvAvTimestamp 0x0007

This patch looks correct but we have these defines in ntlmssp.h.

Okay, I will send v2 patch.
Thanks for your reivew!

Quoted 1 line
Signature · 3 lines
Thanks,

Steve

A message that is not in the archive (sent off-list or not yet received): CAH2r5muK8t6GmU5k0jN3MCkzUW02GuOpvYH3K6szYmiNBgEFNQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#9 lore raw
Quoted 3 lines

Would be helpful as well to note in the patch description whether this was observed so far only to Windows servers (or whether it affects mounts to Samba as well e.g.)

Okay, I will update patch description also. :)

Thanks.

Quoted 79 lines · Namjae Jeon
Quoted 66 lines
Quoted 59 lines · Namjae Jeon
Quoted 58 lines

Windows machine has extended security feature which refuse to allow authentication when there is time difference between server time and client time when ntlmv2 negotiation is used. This problem is prevalent in embedded enviornment where system time is set to default 1970.

Modern servers send the server timestamp in the TargetInfo Av_Pair structure in the challenge message [see MS-NLMP 2.2.2.1]
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must use the server provided timestamp if present OR current time if it is not.

---
 fs/cifs/cifsencrypt.c |    6 ++++--
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/sess.c        |   21 +++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)
fs/cifs/cifsencrypt.c +4 -2
index 4934347..3ec44f8 100644
@@ -671,8 +671,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                        (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
        ntlmv2->blob_signature = cpu_to_le32(0x00000101);
        ntlmv2->reserved = 0;
-       /* Must be within 5 minutes of the server */
-       ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       if (ses->serverTime)
+               ntlmv2->time = ses->serverTime;
+       else
+               ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
        get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
        ntlmv2->reserved2 = 0;
 
fs/cifs/cifsglob.h +2 -0
index ce24c1f..1102822 100644
@@ -796,6 +796,8 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
+       __u64   serverTime;     /* Keeps a track of server time sent by server
+                                  during NTLM challenge in little endian */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
        char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
fs/cifs/sess.c +0 -0
index 07fe97a..0762377 100644
@@ -277,6 +277,26 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
        cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
 }
 
Quoted 7 lines

fs/cifs/sess.c static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft, · line 284

Quoted 5 lines
fs/cifs/sess.c +5 -0
+static void
+get_ntlmv2_server_time(struct cifs_ses *ses)
+{
+#define MsvAvEOL       0x0000
+#define MsvAvTimestamp 0x0007

This patch looks correct but we have these defines in ntlmssp.h.

Quoted 4 lines

Okay, I will send v2 patch.
Thanks for your reivew!

Quoted 1 line

--
Thanks,

Steve