All of lore.kernel.org
 help / color / mirror / Atom feed
* allow ntlmv2 ntlmssp authentication
@ 2010-07-03  3:16 shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w
       [not found] ` <1278126963-16111-1-git-send-email-shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w @ 2010-07-03  3:16 UTC (permalink / raw)
  To: smfrench-Re5JQEeQqe8AvxtiuMwx3w
  Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-N0cyB0Tf/z2923ynj/IuLw,
	samba-technical-w/Ol4Ecudpl8XjKLYN78aQ, Shirish Pargaonkar

Have kept ntlmv1 ntlmssp as a default, ntlmv2 ntlmssp can
be made default only by making code change.


>From 3d8a8960a6d164e2bacd2a4fc96456453042e049 Mon Sep 17 00:00:00 2001
From: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date: Fri, 2 Jul 2010 21:54:51 -0500
Subject: [PATCH] add ntlvm2 ntlmssp authentication

Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 fs/cifs/cifsencrypt.c |   48 ++++++++++++++++++++++++++++++++++++++++++++----
 fs/cifs/cifsglob.h    |    2 ++
 fs/cifs/cifspdu.h     |    1 -
 fs/cifs/sess.c        |   39 +++++++++++++++++++++++++++++++++++++--
 4 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 847628d..ebfafec 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -378,6 +378,44 @@ calc_exit_2:
 	return rc;
 }
 
+static void
+find_domain_name(struct cifsSesInfo *ses)
+{
+	unsigned int attrsize;
+	unsigned int type;
+	unsigned char *blobptr;
+	struct ntlmssp2_name *attrptr;
+
+	if (ses->server->tiblob) {
+		blobptr = ses->server->tiblob;
+		attrptr = (struct ntlmssp2_name *) blobptr;
+
+		while ((type = attrptr->type) != 0) {
+			blobptr += 2; /* advance attr type */
+			attrsize = attrptr->length;
+			blobptr += 2; /* advance attr size */
+			if (type == 0x2) {
+				if (!ses->domainName) {
+					ses->domainName =
+						kmalloc(attrptr->length + 1,
+								GFP_KERNEL);
+					if (!ses->domainName)
+						return;
+					cifs_from_ucs2(ses->domainName,
+						(__le16 *)blobptr,
+						attrptr->length,
+						attrptr->length,
+						load_nls_default(), false);
+				}
+			}
+			blobptr += attrsize; /* advance attr  value */
+			attrptr = (struct ntlmssp2_name *) blobptr;
+		}
+	}
+
+	return;
+}
+
 void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
 		      const struct nls_table *nls_cp)
 {
@@ -390,10 +428,9 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
 	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
 	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
 	buf->reserved2 = 0;
-	buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
-	buf->names[0].length = 0;
-	buf->names[1].type = 0;
-	buf->names[1].length = 0;
+
+	if (!ses->domainName)
+		find_domain_name(ses);
 
 	/* calculate buf->ntlmv2_hash */
 	rc = calc_ntlmv2_hash(ses, nls_cp);
@@ -421,6 +458,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
 
 	hmac_md5_update(v2_session_response+8,
 			sizeof(struct ntlmv2_resp) - 8, &context);
+	if (ses->server->tilen)
+		hmac_md5_update(ses->server->tiblob,
+			ses->server->tilen, &context);
 
 	hmac_md5_final(v2_session_response, &context);
 /*	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3c55e10..db6c5da 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -188,6 +188,8 @@ struct TCP_Server_Info {
 	unsigned long lstrp; /* when we got last response from this server */
 	u16 dialect; /* dialect index that server chose */
 	/* extended security flavors that server supports */
+	unsigned int tilen; /* length of the target info blob */
+	unsigned char *tiblob; /* target info blob in challenge response */
 	bool	sec_kerberos;		/* supports plain Kerberos */
 	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
 	bool	sec_kerberosu2u;	/* supports U2U Kerberos */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 14d036d..b0f4b56 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -663,7 +663,6 @@ struct ntlmv2_resp {
 	__le64  time;
 	__u64  client_chal; /* random */
 	__u32  reserved2;
-	struct ntlmssp2_name names[2];
 	/* array of name entries could follow ending in minimum 4 byte struct */
 } __attribute__((packed));
 
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 0a57cb7..d1ec053 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
 static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 				    struct cifsSesInfo *ses)
 {
+	unsigned int tioffset; /* challeng message target info area */
+	unsigned int tilen; /* challeng message target info area length  */
+
 	CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
 
 	if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
@@ -405,6 +408,18 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 	/* BB spec says that if AvId field of MsvAvTimestamp is populated then
 		we must set the MIC field of the AUTHENTICATE_MESSAGE */
 
+	tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
+	tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
+	ses->server->tilen = tilen;
+	if (tilen) {
+		ses->server->tiblob = kmalloc(tilen, GFP_KERNEL);
+		if (!ses->server->tiblob) {
+			cERROR(1, "Challenge target info allocation failure");
+			return -ENOMEM;
+		}
+		memcpy(ses->server->tiblob,  bcc_ptr + tioffset, tilen);
+	}
+
 	return 0;
 }
 
@@ -451,10 +466,12 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 				   struct cifsSesInfo *ses,
 				   const struct nls_table *nls_cp, bool first)
 {
+	unsigned int size;
 	AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
 	__u32 flags;
 	unsigned char *tmp;
 	char ntlm_session_key[CIFS_SESS_KEY_SIZE];
+	struct ntlmv2_resp ntlmv2_response = {};
 
 	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
 	sec_blob->MessageType = NtLmAuthenticate;
@@ -477,6 +494,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 	sec_blob->LmChallengeResponse.Length = 0;
 	sec_blob->LmChallengeResponse.MaximumLength = 0;
 
+#if 1
 	/* calculate session key,  BB what about adding similar ntlmv2 path? */
 	SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
 	if (first)
@@ -491,6 +509,25 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 
 	tmp += CIFS_SESS_KEY_SIZE;
 
+#else
+	sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
+	setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp);
+	size =  sizeof(struct ntlmv2_resp);
+	memcpy(tmp, (char *)&ntlmv2_response, size);
+	tmp += size;
+	if (ses->server->tilen > 0) {
+		memcpy(tmp, ses->server->tiblob, ses->server->tilen);
+		kfree(ses->server->tiblob);
+		tmp += ses->server->tilen;
+	} else
+		ses->server->tilen = 0;
+
+	sec_blob->NtChallengeResponse.Length = cpu_to_le16(size +
+				ses->server->tilen);
+	sec_blob->NtChallengeResponse.MaximumLength =
+		cpu_to_le16(size + ses->server->tilen);
+#endif
+
 	if (ses->domainName == NULL) {
 		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
 		sec_blob->DomainName.Length = 0;
@@ -501,7 +538,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 		len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
 				    MAX_USERNAME_SIZE, nls_cp);
 		len *= 2; /* unicode is 2 bytes each */
-		len += 2; /* trailing null */
 		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
 		sec_blob->DomainName.Length = cpu_to_le16(len);
 		sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
@@ -518,7 +554,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 		len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
 				    MAX_USERNAME_SIZE, nls_cp);
 		len *= 2; /* unicode is 2 bytes each */
-		len += 2; /* trailing null */
 		sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
 		sec_blob->UserName.Length = cpu_to_le16(len);
 		sec_blob->UserName.MaximumLength = cpu_to_le16(len);
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: allow ntlmv2 ntlmssp authentication
       [not found] ` <1278126963-16111-1-git-send-email-shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2010-07-07 11:25   ` Jeff Layton
       [not found]     ` <20100707072517.1446d70e-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Jeff Layton @ 2010-07-07 11:25 UTC (permalink / raw)
  To: shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w
  Cc: smfrench-Re5JQEeQqe8AvxtiuMwx3w,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-N0cyB0Tf/z2923ynj/IuLw,
	samba-technical-w/Ol4Ecudpl8XjKLYN78aQ

On Fri,  2 Jul 2010 22:16:03 -0500
shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:

> Have kept ntlmv1 ntlmssp as a default, ntlmv2 ntlmssp can
> be made default only by making code change.
> 
> 
> From 3d8a8960a6d164e2bacd2a4fc96456453042e049 Mon Sep 17 00:00:00 2001
> From: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Date: Fri, 2 Jul 2010 21:54:51 -0500
> Subject: [PATCH] add ntlvm2 ntlmssp authentication
> 
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  fs/cifs/cifsencrypt.c |   48 ++++++++++++++++++++++++++++++++++++++++++++----
>  fs/cifs/cifsglob.h    |    2 ++
>  fs/cifs/cifspdu.h     |    1 -
>  fs/cifs/sess.c        |   39 +++++++++++++++++++++++++++++++++++++--
>  4 files changed, 83 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> index 847628d..ebfafec 100644
> --- a/fs/cifs/cifsencrypt.c
> +++ b/fs/cifs/cifsencrypt.c
> @@ -378,6 +378,44 @@ calc_exit_2:
>  	return rc;
>  }
>  
> +static void
> +find_domain_name(struct cifsSesInfo *ses)
> +{
> +	unsigned int attrsize;
> +	unsigned int type;
> +	unsigned char *blobptr;
> +	struct ntlmssp2_name *attrptr;
> +
> +	if (ses->server->tiblob) {
> +		blobptr = ses->server->tiblob;
> +		attrptr = (struct ntlmssp2_name *) blobptr;
> +
> +		while ((type = attrptr->type) != 0) {
> +			blobptr += 2; /* advance attr type */
> +			attrsize = attrptr->length;
> +			blobptr += 2; /* advance attr size */
> +			if (type == 0x2) {
				    ^^^
		Magic numbers like this should be turned into names.

> +				if (!ses->domainName) {
> +					ses->domainName =
> +						kmalloc(attrptr->length + 1,
> +								GFP_KERNEL);
> +					if (!ses->domainName)
> +						return;
> +					cifs_from_ucs2(ses->domainName,
> +						(__le16 *)blobptr,
> +						attrptr->length,
> +						attrptr->length,
> +						load_nls_default(), false);
> +				}
> +			}
> +			blobptr += attrsize; /* advance attr  value */
> +			attrptr = (struct ntlmssp2_name *) blobptr;
> +		}
> +	}
> +
> +	return;
> +}
> +

Is it possible that you'll need to pick other UCS2 fields than the
domain out of a NTLMSSP blob? If so, it might be better to turn the
above function into a "copy the field of type X out of the blob"
function.

>  void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
>  		      const struct nls_table *nls_cp)
>  {
> @@ -390,10 +428,9 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
>  	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
>  	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
>  	buf->reserved2 = 0;
> -	buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
> -	buf->names[0].length = 0;
> -	buf->names[1].type = 0;
> -	buf->names[1].length = 0;
> +
> +	if (!ses->domainName)
> +		find_domain_name(ses);
>  
>  	/* calculate buf->ntlmv2_hash */
>  	rc = calc_ntlmv2_hash(ses, nls_cp);
> @@ -421,6 +458,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
>  
>  	hmac_md5_update(v2_session_response+8,
>  			sizeof(struct ntlmv2_resp) - 8, &context);
> +	if (ses->server->tilen)
> +		hmac_md5_update(ses->server->tiblob,
> +			ses->server->tilen, &context);
>  
>  	hmac_md5_final(v2_session_response, &context);
>  /*	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 3c55e10..db6c5da 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -188,6 +188,8 @@ struct TCP_Server_Info {
>  	unsigned long lstrp; /* when we got last response from this server */
>  	u16 dialect; /* dialect index that server chose */
>  	/* extended security flavors that server supports */
> +	unsigned int tilen; /* length of the target info blob */
> +	unsigned char *tiblob; /* target info blob in challenge response */

All of this is for NTLMSSP session setup, correct? If so, is the
TCP_Server_Info really the right place for this? Will this break if I
have more than one session on the same socket?

>  	bool	sec_kerberos;		/* supports plain Kerberos */
>  	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
>  	bool	sec_kerberosu2u;	/* supports U2U Kerberos */
> diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
> index 14d036d..b0f4b56 100644
> --- a/fs/cifs/cifspdu.h
> +++ b/fs/cifs/cifspdu.h
> @@ -663,7 +663,6 @@ struct ntlmv2_resp {
>  	__le64  time;
>  	__u64  client_chal; /* random */
>  	__u32  reserved2;
> -	struct ntlmssp2_name names[2];
>  	/* array of name entries could follow ending in minimum 4 byte struct */
>  } __attribute__((packed));
>  
> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> index 0a57cb7..d1ec053 100644
> --- a/fs/cifs/sess.c
> +++ b/fs/cifs/sess.c
> @@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
>  static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
>  				    struct cifsSesInfo *ses)
>  {
> +	unsigned int tioffset; /* challeng message target info area */
> +	unsigned int tilen; /* challeng message target info area length  */
> +
>  	CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
>  
>  	if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
> @@ -405,6 +408,18 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
>  	/* BB spec says that if AvId field of MsvAvTimestamp is populated then
>  		we must set the MIC field of the AUTHENTICATE_MESSAGE */
>  
> +	tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
> +	tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
> +	ses->server->tilen = tilen;
> +	if (tilen) {
> +		ses->server->tiblob = kmalloc(tilen, GFP_KERNEL);
> +		if (!ses->server->tiblob) {
> +			cERROR(1, "Challenge target info allocation failure");
> +			return -ENOMEM;
> +		}
> +		memcpy(ses->server->tiblob,  bcc_ptr + tioffset, tilen);
> +	}
> +
>  	return 0;
>  }
>  
> @@ -451,10 +466,12 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>  				   struct cifsSesInfo *ses,
>  				   const struct nls_table *nls_cp, bool first)
>  {
> +	unsigned int size;
>  	AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
>  	__u32 flags;
>  	unsigned char *tmp;
>  	char ntlm_session_key[CIFS_SESS_KEY_SIZE];
> +	struct ntlmv2_resp ntlmv2_response = {};
>  
>  	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
>  	sec_blob->MessageType = NtLmAuthenticate;
> @@ -477,6 +494,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>  	sec_blob->LmChallengeResponse.Length = 0;
>  	sec_blob->LmChallengeResponse.MaximumLength = 0;
>  
> +#if 1
  ^^^^^^^
Why are you adding code that's always compiled out?

>  	/* calculate session key,  BB what about adding similar ntlmv2 path? */
>  	SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
>  	if (first)
> @@ -491,6 +509,25 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>  
>  	tmp += CIFS_SESS_KEY_SIZE;
>  
> +#else
> +	sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
> +	setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp);
> +	size =  sizeof(struct ntlmv2_resp);
> +	memcpy(tmp, (char *)&ntlmv2_response, size);
> +	tmp += size;
> +	if (ses->server->tilen > 0) {
> +		memcpy(tmp, ses->server->tiblob, ses->server->tilen);
> +		kfree(ses->server->tiblob);
> +		tmp += ses->server->tilen;
> +	} else
> +		ses->server->tilen = 0;
> +
> +	sec_blob->NtChallengeResponse.Length = cpu_to_le16(size +
> +				ses->server->tilen);
> +	sec_blob->NtChallengeResponse.MaximumLength =
> +		cpu_to_le16(size + ses->server->tilen);
> +#endif
> +
>  	if (ses->domainName == NULL) {
>  		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
>  		sec_blob->DomainName.Length = 0;
> @@ -501,7 +538,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>  		len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
>  				    MAX_USERNAME_SIZE, nls_cp);
>  		len *= 2; /* unicode is 2 bytes each */
> -		len += 2; /* trailing null */
>  		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
>  		sec_blob->DomainName.Length = cpu_to_le16(len);
>  		sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
> @@ -518,7 +554,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>  		len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
>  				    MAX_USERNAME_SIZE, nls_cp);
>  		len *= 2; /* unicode is 2 bytes each */
> -		len += 2; /* trailing null */
>  		sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
>  		sec_blob->UserName.Length = cpu_to_le16(len);
>  		sec_blob->UserName.MaximumLength = cpu_to_le16(len);


-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: allow ntlmv2 ntlmssp authentication
       [not found]     ` <20100707072517.1446d70e-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2010-07-07 16:52       ` Shirish Pargaonkar
       [not found]         ` <AANLkTildpOmttZwCEHMiN9LRLaVuc01Srqe7UaEGu0hu-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Shirish Pargaonkar @ 2010-07-07 16:52 UTC (permalink / raw)
  To: Jeff Layton
  Cc: smfrench-Re5JQEeQqe8AvxtiuMwx3w,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-N0cyB0Tf/z2923ynj/IuLw,
	samba-technical-w/Ol4Ecudpl8XjKLYN78aQ

On Wed, Jul 7, 2010 at 6:25 AM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> On Fri,  2 Jul 2010 22:16:03 -0500
> shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:
>
>> Have kept ntlmv1 ntlmssp as a default, ntlmv2 ntlmssp can
>> be made default only by making code change.
>>
>>
>> From 3d8a8960a6d164e2bacd2a4fc96456453042e049 Mon Sep 17 00:00:00 2001
>> From: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> Date: Fri, 2 Jul 2010 21:54:51 -0500
>> Subject: [PATCH] add ntlvm2 ntlmssp authentication
>>
>> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> ---
>>  fs/cifs/cifsencrypt.c |   48 ++++++++++++++++++++++++++++++++++++++++++++----
>>  fs/cifs/cifsglob.h    |    2 ++
>>  fs/cifs/cifspdu.h     |    1 -
>>  fs/cifs/sess.c        |   39 +++++++++++++++++++++++++++++++++++++--
>>  4 files changed, 83 insertions(+), 7 deletions(-)
>>
>> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
>> index 847628d..ebfafec 100644
>> --- a/fs/cifs/cifsencrypt.c
>> +++ b/fs/cifs/cifsencrypt.c
>> @@ -378,6 +378,44 @@ calc_exit_2:
>>       return rc;
>>  }
>>
>> +static void
>> +find_domain_name(struct cifsSesInfo *ses)
>> +{
>> +     unsigned int attrsize;
>> +     unsigned int type;
>> +     unsigned char *blobptr;
>> +     struct ntlmssp2_name *attrptr;
>> +
>> +     if (ses->server->tiblob) {
>> +             blobptr = ses->server->tiblob;
>> +             attrptr = (struct ntlmssp2_name *) blobptr;
>> +
>> +             while ((type = attrptr->type) != 0) {
>> +                     blobptr += 2; /* advance attr type */
>> +                     attrsize = attrptr->length;
>> +                     blobptr += 2; /* advance attr size */
>> +                     if (type == 0x2) {
>                                    ^^^
>                Magic numbers like this should be turned into names.

Yes, will make the change.

>
>> +                             if (!ses->domainName) {
>> +                                     ses->domainName =
>> +                                             kmalloc(attrptr->length + 1,
>> +                                                             GFP_KERNEL);
>> +                                     if (!ses->domainName)
>> +                                             return;
>> +                                     cifs_from_ucs2(ses->domainName,
>> +                                             (__le16 *)blobptr,
>> +                                             attrptr->length,
>> +                                             attrptr->length,
>> +                                             load_nls_default(), false);
>> +                             }
>> +                     }
>> +                     blobptr += attrsize; /* advance attr  value */
>> +                     attrptr = (struct ntlmssp2_name *) blobptr;
>> +             }
>> +     }
>> +
>> +     return;
>> +}
>> +
>
> Is it possible that you'll need to pick other UCS2 fields than the
> domain out of a NTLMSSP blob? If so, it might be better to turn the
> above function into a "copy the field of type X out of the blob"
> function.

I have not seen enough responses where a server does not
return a domain name field in the AV pairs it sends in type 2
message of NTLMSSP protocol.
NTLM v2 protocol is supposed to use server name in case of
servers of with local accounts.  I will have to do some code
changes and testing to determine whether authentication
succeeds or not using server name instead of domain name
returned in type 2 challenge packet.

>
>>  void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
>>                     const struct nls_table *nls_cp)
>>  {
>> @@ -390,10 +428,9 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
>>       buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
>>       get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
>>       buf->reserved2 = 0;
>> -     buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
>> -     buf->names[0].length = 0;
>> -     buf->names[1].type = 0;
>> -     buf->names[1].length = 0;
>> +
>> +     if (!ses->domainName)
>> +             find_domain_name(ses);
>>
>>       /* calculate buf->ntlmv2_hash */
>>       rc = calc_ntlmv2_hash(ses, nls_cp);
>> @@ -421,6 +458,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
>>
>>       hmac_md5_update(v2_session_response+8,
>>                       sizeof(struct ntlmv2_resp) - 8, &context);
>> +     if (ses->server->tilen)
>> +             hmac_md5_update(ses->server->tiblob,
>> +                     ses->server->tilen, &context);
>>
>>       hmac_md5_final(v2_session_response, &context);
>>  /*   cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 3c55e10..db6c5da 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -188,6 +188,8 @@ struct TCP_Server_Info {
>>       unsigned long lstrp; /* when we got last response from this server */
>>       u16 dialect; /* dialect index that server chose */
>>       /* extended security flavors that server supports */
>> +     unsigned int tilen; /* length of the target info blob */
>> +     unsigned char *tiblob; /* target info blob in challenge response */
>
> All of this is for NTLMSSP session setup, correct? If so, is the
> TCP_Server_Info really the right place for this? Will this break if I
> have more than one session on the same socket?

I think it will not break authentication but will break signing (and
perhaps sealing).
What would be a good place to hang is per session, per user information?

>
>>       bool    sec_kerberos;           /* supports plain Kerberos */
>>       bool    sec_mskerberos;         /* supports legacy MS Kerberos */
>>       bool    sec_kerberosu2u;        /* supports U2U Kerberos */
>> diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
>> index 14d036d..b0f4b56 100644
>> --- a/fs/cifs/cifspdu.h
>> +++ b/fs/cifs/cifspdu.h
>> @@ -663,7 +663,6 @@ struct ntlmv2_resp {
>>       __le64  time;
>>       __u64  client_chal; /* random */
>>       __u32  reserved2;
>> -     struct ntlmssp2_name names[2];
>>       /* array of name entries could follow ending in minimum 4 byte struct */
>>  } __attribute__((packed));
>>
>> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
>> index 0a57cb7..d1ec053 100644
>> --- a/fs/cifs/sess.c
>> +++ b/fs/cifs/sess.c
>> @@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
>>  static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
>>                                   struct cifsSesInfo *ses)
>>  {
>> +     unsigned int tioffset; /* challeng message target info area */
>> +     unsigned int tilen; /* challeng message target info area length  */
>> +
>>       CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
>>
>>       if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
>> @@ -405,6 +408,18 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
>>       /* BB spec says that if AvId field of MsvAvTimestamp is populated then
>>               we must set the MIC field of the AUTHENTICATE_MESSAGE */
>>
>> +     tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
>> +     tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
>> +     ses->server->tilen = tilen;
>> +     if (tilen) {
>> +             ses->server->tiblob = kmalloc(tilen, GFP_KERNEL);
>> +             if (!ses->server->tiblob) {
>> +                     cERROR(1, "Challenge target info allocation failure");
>> +                     return -ENOMEM;
>> +             }
>> +             memcpy(ses->server->tiblob,  bcc_ptr + tioffset, tilen);
>> +     }
>> +
>>       return 0;
>>  }
>>
>> @@ -451,10 +466,12 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>>                                  struct cifsSesInfo *ses,
>>                                  const struct nls_table *nls_cp, bool first)
>>  {
>> +     unsigned int size;
>>       AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
>>       __u32 flags;
>>       unsigned char *tmp;
>>       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
>> +     struct ntlmv2_resp ntlmv2_response = {};
>>
>>       memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
>>       sec_blob->MessageType = NtLmAuthenticate;
>> @@ -477,6 +494,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>>       sec_blob->LmChallengeResponse.Length = 0;
>>       sec_blob->LmChallengeResponse.MaximumLength = 0;
>>
>> +#if 1
>  ^^^^^^^
> Why are you adding code that's always compiled out?

Right now we are using ntlmv1 as a default authentication mechanism in NTLMSSP.
I am not sure whether we can just switch to ntlmv2 as an
authentication mechanism.
I think in case of Windows servers, an LmCompatibilityLevel registry
setting of 0 through 5
will accept NTLMv2 response but not sure how it is handled by other
servers i.e. are
there servers out there who will/can't handle ntlmv2 authentication
mechanism within
NTLMSSP.

>
>>       /* calculate session key,  BB what about adding similar ntlmv2 path? */
>>       SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
>>       if (first)
>> @@ -491,6 +509,25 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>>
>>       tmp += CIFS_SESS_KEY_SIZE;
>>
>> +#else
>> +     sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
>> +     setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp);
>> +     size =  sizeof(struct ntlmv2_resp);
>> +     memcpy(tmp, (char *)&ntlmv2_response, size);
>> +     tmp += size;
>> +     if (ses->server->tilen > 0) {
>> +             memcpy(tmp, ses->server->tiblob, ses->server->tilen);
>> +             kfree(ses->server->tiblob);
>> +             tmp += ses->server->tilen;
>> +     } else
>> +             ses->server->tilen = 0;
>> +
>> +     sec_blob->NtChallengeResponse.Length = cpu_to_le16(size +
>> +                             ses->server->tilen);
>> +     sec_blob->NtChallengeResponse.MaximumLength =
>> +             cpu_to_le16(size + ses->server->tilen);
>> +#endif
>> +
>>       if (ses->domainName == NULL) {
>>               sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
>>               sec_blob->DomainName.Length = 0;
>> @@ -501,7 +538,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>>               len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
>>                                   MAX_USERNAME_SIZE, nls_cp);
>>               len *= 2; /* unicode is 2 bytes each */
>> -             len += 2; /* trailing null */
>>               sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
>>               sec_blob->DomainName.Length = cpu_to_le16(len);
>>               sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
>> @@ -518,7 +554,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>>               len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
>>                                   MAX_USERNAME_SIZE, nls_cp);
>>               len *= 2; /* unicode is 2 bytes each */
>> -             len += 2; /* trailing null */
>>               sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
>>               sec_blob->UserName.Length = cpu_to_le16(len);
>>               sec_blob->UserName.MaximumLength = cpu_to_le16(len);
>
>
> --
> Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: allow ntlmv2 ntlmssp authentication
       [not found]         ` <AANLkTildpOmttZwCEHMiN9LRLaVuc01Srqe7UaEGu0hu-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-07-07 17:35           ` Jeff Layton
  0 siblings, 0 replies; 4+ messages in thread
From: Jeff Layton @ 2010-07-07 17:35 UTC (permalink / raw)
  To: Shirish Pargaonkar
  Cc: smfrench-Re5JQEeQqe8AvxtiuMwx3w,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-N0cyB0Tf/z2923ynj/IuLw,
	samba-technical-w/Ol4Ecudpl8XjKLYN78aQ

On Wed, 7 Jul 2010 11:52:16 -0500
Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> On Wed, Jul 7, 2010 at 6:25 AM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> > On Fri,  2 Jul 2010 22:16:03 -0500
> > shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:
> >
> >> Have kept ntlmv1 ntlmssp as a default, ntlmv2 ntlmssp can
> >> be made default only by making code change.
> >>
> >>
> >> From 3d8a8960a6d164e2bacd2a4fc96456453042e049 Mon Sep 17 00:00:00 2001
> >> From: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> Date: Fri, 2 Jul 2010 21:54:51 -0500
> >> Subject: [PATCH] add ntlvm2 ntlmssp authentication
> >>
> >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> ---
> >>  fs/cifs/cifsencrypt.c |   48 ++++++++++++++++++++++++++++++++++++++++++++----
> >>  fs/cifs/cifsglob.h    |    2 ++
> >>  fs/cifs/cifspdu.h     |    1 -
> >>  fs/cifs/sess.c        |   39 +++++++++++++++++++++++++++++++++++++--
> >>  4 files changed, 83 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> >> index 847628d..ebfafec 100644
> >> --- a/fs/cifs/cifsencrypt.c
> >> +++ b/fs/cifs/cifsencrypt.c
> >> @@ -378,6 +378,44 @@ calc_exit_2:
> >>       return rc;
> >>  }
> >>
> >> +static void
> >> +find_domain_name(struct cifsSesInfo *ses)
> >> +{
> >> +     unsigned int attrsize;
> >> +     unsigned int type;
> >> +     unsigned char *blobptr;
> >> +     struct ntlmssp2_name *attrptr;
> >> +
> >> +     if (ses->server->tiblob) {
> >> +             blobptr = ses->server->tiblob;
> >> +             attrptr = (struct ntlmssp2_name *) blobptr;
> >> +
> >> +             while ((type = attrptr->type) != 0) {
> >> +                     blobptr += 2; /* advance attr type */
> >> +                     attrsize = attrptr->length;
> >> +                     blobptr += 2; /* advance attr size */
> >> +                     if (type == 0x2) {
> >                                    ^^^
> >                Magic numbers like this should be turned into names.
> 
> Yes, will make the change.
> 
> >
> >> +                             if (!ses->domainName) {
> >> +                                     ses->domainName =
> >> +                                             kmalloc(attrptr->length + 1,
> >> +                                                             GFP_KERNEL);
> >> +                                     if (!ses->domainName)
> >> +                                             return;
> >> +                                     cifs_from_ucs2(ses->domainName,
> >> +                                             (__le16 *)blobptr,
> >> +                                             attrptr->length,
> >> +                                             attrptr->length,
> >> +                                             load_nls_default(), false);
> >> +                             }
> >> +                     }
> >> +                     blobptr += attrsize; /* advance attr  value */
> >> +                     attrptr = (struct ntlmssp2_name *) blobptr;
> >> +             }
> >> +     }
> >> +
> >> +     return;
> >> +}
> >> +
> >
> > Is it possible that you'll need to pick other UCS2 fields than the
> > domain out of a NTLMSSP blob? If so, it might be better to turn the
> > above function into a "copy the field of type X out of the blob"
> > function.
> 
> I have not seen enough responses where a server does not
> return a domain name field in the AV pairs it sends in type 2
> message of NTLMSSP protocol.
> NTLM v2 protocol is supposed to use server name in case of
> servers of with local accounts.  I will have to do some code
> changes and testing to determine whether authentication
> succeeds or not using server name instead of domain name
> returned in type 2 challenge packet.
> 

Either way, I think it would be better to make this a generic routine
for pulling a field of type X out of the blob. I imagine other fields
in there will eventually be useful and making a toolkit for this sort
of thing will make it easier to expand on your work.
> >
> >>  void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
> >>                     const struct nls_table *nls_cp)
> >>  {
> >> @@ -390,10 +428,9 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
> >>       buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
> >>       get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
> >>       buf->reserved2 = 0;
> >> -     buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
> >> -     buf->names[0].length = 0;
> >> -     buf->names[1].type = 0;
> >> -     buf->names[1].length = 0;
> >> +
> >> +     if (!ses->domainName)
> >> +             find_domain_name(ses);
> >>
> >>       /* calculate buf->ntlmv2_hash */
> >>       rc = calc_ntlmv2_hash(ses, nls_cp);
> >> @@ -421,6 +458,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
> >>
> >>       hmac_md5_update(v2_session_response+8,
> >>                       sizeof(struct ntlmv2_resp) - 8, &context);
> >> +     if (ses->server->tilen)
> >> +             hmac_md5_update(ses->server->tiblob,
> >> +                     ses->server->tilen, &context);
> >>
> >>       hmac_md5_final(v2_session_response, &context);
> >>  /*   cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> >> index 3c55e10..db6c5da 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -188,6 +188,8 @@ struct TCP_Server_Info {
> >>       unsigned long lstrp; /* when we got last response from this server */
> >>       u16 dialect; /* dialect index that server chose */
> >>       /* extended security flavors that server supports */
> >> +     unsigned int tilen; /* length of the target info blob */
> >> +     unsigned char *tiblob; /* target info blob in challenge response */
> >
> > All of this is for NTLMSSP session setup, correct? If so, is the
> > TCP_Server_Info really the right place for this? Will this break if I
> > have more than one session on the same socket?
> 
> I think it will not break authentication but will break signing (and
> perhaps sealing).
> What would be a good place to hang is per session, per user information?
> 

Per session sounds right to me. IIUC, the first session on the socket
sets the signing key.

> >> @@ -451,10 +466,12 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
> >>                                  struct cifsSesInfo *ses,
> >>                                  const struct nls_table *nls_cp, bool first)
> >>  {
> >> +     unsigned int size;
> >>       AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
> >>       __u32 flags;
> >>       unsigned char *tmp;
> >>       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
> >> +     struct ntlmv2_resp ntlmv2_response = {};
> >>
> >>       memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
> >>       sec_blob->MessageType = NtLmAuthenticate;
> >> @@ -477,6 +494,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
> >>       sec_blob->LmChallengeResponse.Length = 0;
> >>       sec_blob->LmChallengeResponse.MaximumLength = 0;
> >>
> >> +#if 1
> >  ^^^^^^^
> > Why are you adding code that's always compiled out?
> 
> Right now we are using ntlmv1 as a default authentication mechanism in NTLMSSP.
> I am not sure whether we can just switch to ntlmv2 as an
> authentication mechanism.
> I think in case of Windows servers, an LmCompatibilityLevel registry
> setting of 0 through 5
> will accept NTLMv2 response but not sure how it is handled by other
> servers i.e. are
> there servers out there who will/can't handle ntlmv2 authentication
> mechanism within
> NTLMSSP.
> 

Ok, just to be clear -- NAK on this patch as it stands now. Please do
not add code to the kernel that's just commented out. It's confusing
and leads to maintenance headaches.

Either this is ready for merge, in which case you should just replace
the old code or it's not.

-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-07-07 17:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-03  3:16 allow ntlmv2 ntlmssp authentication shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w
     [not found] ` <1278126963-16111-1-git-send-email-shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2010-07-07 11:25   ` Jeff Layton
     [not found]     ` <20100707072517.1446d70e-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2010-07-07 16:52       ` Shirish Pargaonkar
     [not found]         ` <AANLkTildpOmttZwCEHMiN9LRLaVuc01Srqe7UaEGu0hu-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-07-07 17:35           ` Jeff Layton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.