allow ntlmv2 ntlmssp authentication

Jeff Layton jlayton at samba.org
Wed Jul 7 05:25:17 MDT 2010


On Fri,  2 Jul 2010 22:16:03 -0500
shirishpargaonkar at gmail.com 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 at gmail.com>
> Date: Fri, 2 Jul 2010 21:54:51 -0500
> Subject: [PATCH] add ntlvm2 ntlmssp authentication
> 
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar at gmail.com>
> ---
>  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 at samba.org>


More information about the samba-technical mailing list