diff mbox

[v2,1/2] cifs: Make session key from per smb connection to per smb session

Message ID 1375973628-6218-1-git-send-email-shirishpargaonkar@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shirish Pargaonkar Aug. 8, 2013, 2:53 p.m. UTC
From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>

Change session key from per smb connection to per smb session for
smb2 onwards.
perconnkey is defined for only cifs/smb.
For smb3, generate signing key per smb session.


Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
---
 fs/cifs/cifsencrypt.c | 20 ++++++++++++++++++++
 fs/cifs/cifsglob.h    |  2 ++
 fs/cifs/cifsproto.h   |  3 +++
 fs/cifs/connect.c     | 27 +++++++++++++++++++--------
 fs/cifs/sess.c        |  6 ++++--
 fs/cifs/smb1ops.c     |  1 +
 fs/cifs/smb2pdu.c     |  1 +
 7 files changed, 50 insertions(+), 10 deletions(-)

Comments

Jeff Layton Aug. 8, 2013, 8:39 p.m. UTC | #1
On Thu,  8 Aug 2013 09:53:48 -0500
shirishpargaonkar@gmail.com wrote:

> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> 
> Change session key from per smb connection to per smb session for
> smb2 onwards.
> perconnkey is defined for only cifs/smb.
> For smb3, generate signing key per smb session.
> 

This description is pretty sparse. Seriously, be more verbose here. Ok,
so perconnkey is only defined for cifs/smb1, but what _is_ it? What
does it do, and why? Why do we want to change this to per-smb session
for smb2 and onwards? (yes, I know the reason, but other people trawling
through git log might not)

It's worth it to spend the time and describe your patches properly.
Otherwise in 2-3 years, we'll have no idea why some of these changes
were made in this way.

> 
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> ---
>  fs/cifs/cifsencrypt.c | 20 ++++++++++++++++++++
>  fs/cifs/cifsglob.h    |  2 ++
>  fs/cifs/cifsproto.h   |  3 +++
>  fs/cifs/connect.c     | 27 +++++++++++++++++++--------
>  fs/cifs/sess.c        |  6 ++++--
>  fs/cifs/smb1ops.c     |  1 +
>  fs/cifs/smb2pdu.c     |  1 +
>  7 files changed, 50 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> index 45e57cc..f9ef57a 100644
> --- a/fs/cifs/cifsencrypt.c
> +++ b/fs/cifs/cifsencrypt.c
> @@ -720,6 +720,26 @@ setup_ntlmv2_rsp_ret:
>  	return rc;
>  }
>  
> +void
> +free_authkey(struct cifs_ses *ses)
> +{
> +	kfree(ses->auth_key.response);
> +	ses->auth_key.response = NULL;
> +	ses->auth_key.len = 0;
> +}
> +
> +int
> +perconnkey(struct TCP_Server_Info *server, struct cifs_ses *ses)
> +{
> +	server->session_key.response = kmemdup(ses->auth_key.response,
> +		ses->auth_key.len, GFP_KERNEL);
> +	if (!server->session_key.response)
> +		return -ENOMEM;
> +	server->session_key.len = ses->auth_key.len;
> +
> +	return 0;
> +}
> +

If you move "perconnkey" into smb1ops.c then it can be static. It could
also benefit from a more desciptive name, such as "smb1_set_conn_key"
or something.

>  int
>  calc_seckey(struct cifs_ses *ses)
>  {
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 1fdc370..2909380 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -365,6 +365,8 @@ struct smb_version_operations {
>  	void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
>  	/* generate new lease key */
>  	void (*new_lease_key)(struct cifs_fid *fid);
> +	int (*perconnkey)(struct TCP_Server_Info *server,
> +					struct cifs_ses *ses);

A name like this sounds like an operation that returns the (already
existing) per-connection key. How about something like
"generate_perconn_key" instead?

Also, the ses->server pointer should already be set at this point,
right? So, it seems like there's probably no need to pass in both as
parms. Might it make more sense to just pass in "ses"?

>  	/* The next two functions will need to be changed to per smb session */
>  	void (*generate_signingkey)(struct TCP_Server_Info *server);
>  	int (*calc_signature)(struct smb_rqst *rqst,
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index f7e584d..b6c1d03 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -437,6 +437,9 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
>  extern int calc_seckey(struct cifs_ses *);
>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
>  
> +extern int perconnkey(struct TCP_Server_Info *, struct cifs_ses *);
> +extern void free_authkey(struct cifs_ses *);
> +
>  #ifdef CONFIG_CIFS_WEAK_PW_HASH
>  extern int calc_lanman_hash(const char *password, const char *cryptkey,
>  				bool encrypt, char *lnm_session_key);
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index fa68813..98deb98 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -2117,6 +2117,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>  		goto out_err_crypto_release;
>  	}
>  
> +	tcp_ses->session_key.response = NULL;
> +	tcp_ses->session_key.len = 0;

This is kzalloc'ed so these are not necessary.

>  	tcp_ses->noblocksnd = volume_info->noblocksnd;
>  	tcp_ses->noautotune = volume_info->noautotune;
>  	tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
> @@ -2270,6 +2272,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
>  		server->ops->logoff(xid, ses);
>  		_free_xid(xid);
>  	}
> +	if (!server->ops->perconnkey)
> +		free_authkey(ses);

Hrm...so the SMB1 perconnkey operation that you have now kmemdups it.

Why do you skip freeing it here? Doesn't the TCP_Server_Info have its
own copy and won't doing this cause a leak?

>  	sesInfoFree(ses);
>  	cifs_put_tcp_session(server);
>  }
> @@ -2484,6 +2488,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
>  	ses->sectype = volume_info->sectype;
>  	ses->sign = volume_info->sign;
>  
> +	ses->auth_key.response = NULL;
> +	ses->auth_key.len = 0;
> +

Again, these are kzalloced -- no need to do this here...and in any case
this would belong in sesInfoAlloc rather than here, I think.

>  	mutex_lock(&ses->session_mutex);
>  	rc = cifs_negotiate_protocol(xid, ses);
>  	if (!rc)
> @@ -3830,14 +3837,18 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>  	} else {
>  		mutex_lock(&server->srv_mutex);
>  		if (!server->session_estab) {
> -			server->session_key.response = ses->auth_key.response;
> -			server->session_key.len = ses->auth_key.len;
> +			if (server->ops->perconnkey) {
> +				rc = server->ops->perconnkey(server, ses);
> +				if (rc) {
> +					mutex_unlock(&server->srv_mutex);
> +					goto setup_sess_ret;
> +				}
> +			}
>  			server->sequence_number = 0x2;
>  			server->session_estab = true;
> -			ses->auth_key.response = NULL;
> -			if (server->ops->generate_signingkey)
> -				server->ops->generate_signingkey(server);
>  		}
> +		if (server->ops->generate_signingkey)
> +			server->ops->generate_signingkey(server);

It seems a bit strange that you're calling "generate_signingkey" here
after you successfully call "perconnkey", but I'll take it on faith
that you fix that in patch #2.

Still, that's the type of thing that's worth mentioning in the patch
description since it doesn't seem to make much sense on its own.

>  		mutex_unlock(&server->srv_mutex);
>  
>  		cifs_dbg(FYI, "CIFS Session Established successfully\n");
> @@ -3847,9 +3858,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>  		spin_unlock(&GlobalMid_Lock);
>  	}
>  
> -	kfree(ses->auth_key.response);
> -	ses->auth_key.response = NULL;
> -	ses->auth_key.len = 0;
> +setup_sess_ret:
> +	if (server->ops->perconnkey)
> +		free_authkey(ses);
>  	kfree(ses->ntlmssp);
>  	ses->ntlmssp = NULL;
>  
> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> index 79358e3..77642cd 100644
> --- a/fs/cifs/sess.c
> +++ b/fs/cifs/sess.c
> @@ -428,7 +428,8 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
>  		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
>  	if (ses->server->sign) {
>  		flags |= NTLMSSP_NEGOTIATE_SIGN;
> -		if (!ses->server->session_estab)
> +		if ((!ses->server->session_estab) ||
> +				(!ses->server->ops->perconnkey))
>  			flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
>  	}
>  
> @@ -466,7 +467,8 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>  		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
>  	if (ses->server->sign) {
>  		flags |= NTLMSSP_NEGOTIATE_SIGN;
> -		if (!ses->server->session_estab)
> +		if ((!ses->server->session_estab) ||
> +				(!ses->server->ops->perconnkey))
>  			flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
>  	}
>  
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 6457690..331b406 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
>  	.mand_lock = cifs_mand_lock,
>  	.mand_unlock_range = cifs_unlock_range,
>  	.push_mand_locks = cifs_push_mandatory_locks,
> +	.perconnkey = perconnkey,
>  };
>  
>  struct smb_version_values smb1_values = {
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index abc9c28..11de60b 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -477,6 +477,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
>  		return -EIO;
>  	}
>  
> +	free_authkey(ses);

Would it make more sense to instead just move all of this authkey
handling into the session setup routines? It seems a little odd to
allocate a key in the generic part of the session setup code, only
to later free it in the version specific routine.

>  	/*
>  	 * If memory allocation is successful, caller of this function
>  	 * frees it.
Shirish Pargaonkar Aug. 9, 2013, 4:30 a.m. UTC | #2
On Thu, Aug 8, 2013 at 3:39 PM, Jeff Layton <jlayton@redhat.com> wrote:
> On Thu,  8 Aug 2013 09:53:48 -0500
> shirishpargaonkar@gmail.com wrote:
>
>> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>>
>> Change session key from per smb connection to per smb session for
>> smb2 onwards.
>> perconnkey is defined for only cifs/smb.
>> For smb3, generate signing key per smb session.
>>
>
> This description is pretty sparse. Seriously, be more verbose here. Ok,
> so perconnkey is only defined for cifs/smb1, but what _is_ it? What
> does it do, and why? Why do we want to change this to per-smb session
> for smb2 and onwards? (yes, I know the reason, but other people trawling
> through git log might not)
>
> It's worth it to spend the time and describe your patches properly.
> Otherwise in 2-3 years, we'll have no idea why some of these changes
> were made in this way.
>
>>
>> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>> ---
>>  fs/cifs/cifsencrypt.c | 20 ++++++++++++++++++++
>>  fs/cifs/cifsglob.h    |  2 ++
>>  fs/cifs/cifsproto.h   |  3 +++
>>  fs/cifs/connect.c     | 27 +++++++++++++++++++--------
>>  fs/cifs/sess.c        |  6 ++++--
>>  fs/cifs/smb1ops.c     |  1 +
>>  fs/cifs/smb2pdu.c     |  1 +
>>  7 files changed, 50 insertions(+), 10 deletions(-)
>>
>> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
>> index 45e57cc..f9ef57a 100644
>> --- a/fs/cifs/cifsencrypt.c
>> +++ b/fs/cifs/cifsencrypt.c
>> @@ -720,6 +720,26 @@ setup_ntlmv2_rsp_ret:
>>       return rc;
>>  }
>>
>> +void
>> +free_authkey(struct cifs_ses *ses)
>> +{
>> +     kfree(ses->auth_key.response);
>> +     ses->auth_key.response = NULL;
>> +     ses->auth_key.len = 0;
>> +}
>> +
>> +int
>> +perconnkey(struct TCP_Server_Info *server, struct cifs_ses *ses)
>> +{
>> +     server->session_key.response = kmemdup(ses->auth_key.response,
>> +             ses->auth_key.len, GFP_KERNEL);
>> +     if (!server->session_key.response)
>> +             return -ENOMEM;
>> +     server->session_key.len = ses->auth_key.len;
>> +
>> +     return 0;
>> +}
>> +
>
> If you move "perconnkey" into smb1ops.c then it can be static. It could
> also benefit from a more desciptive name, such as "smb1_set_conn_key"
> or something.
>
>>  int
>>  calc_seckey(struct cifs_ses *ses)
>>  {
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 1fdc370..2909380 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -365,6 +365,8 @@ struct smb_version_operations {
>>       void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
>>       /* generate new lease key */
>>       void (*new_lease_key)(struct cifs_fid *fid);
>> +     int (*perconnkey)(struct TCP_Server_Info *server,
>> +                                     struct cifs_ses *ses);
>
> A name like this sounds like an operation that returns the (already
> existing) per-connection key. How about something like
> "generate_perconn_key" instead?
>
> Also, the ses->server pointer should already be set at this point,
> right? So, it seems like there's probably no need to pass in both as
> parms. Might it make more sense to just pass in "ses"?
>
>>       /* The next two functions will need to be changed to per smb session */
>>       void (*generate_signingkey)(struct TCP_Server_Info *server);
>>       int (*calc_signature)(struct smb_rqst *rqst,
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index f7e584d..b6c1d03 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -437,6 +437,9 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
>>  extern int calc_seckey(struct cifs_ses *);
>>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
>>
>> +extern int perconnkey(struct TCP_Server_Info *, struct cifs_ses *);
>> +extern void free_authkey(struct cifs_ses *);
>> +
>>  #ifdef CONFIG_CIFS_WEAK_PW_HASH
>>  extern int calc_lanman_hash(const char *password, const char *cryptkey,
>>                               bool encrypt, char *lnm_session_key);
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index fa68813..98deb98 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -2117,6 +2117,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>>               goto out_err_crypto_release;
>>       }
>>
>> +     tcp_ses->session_key.response = NULL;
>> +     tcp_ses->session_key.len = 0;
>
> This is kzalloc'ed so these are not necessary.
>
>>       tcp_ses->noblocksnd = volume_info->noblocksnd;
>>       tcp_ses->noautotune = volume_info->noautotune;
>>       tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
>> @@ -2270,6 +2272,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
>>               server->ops->logoff(xid, ses);
>>               _free_xid(xid);
>>       }
>> +     if (!server->ops->perconnkey)
>> +             free_authkey(ses);
>
> Hrm...so the SMB1 perconnkey operation that you have now kmemdups it.
>
> Why do you skip freeing it here? Doesn't the TCP_Server_Info have its
> own copy and won't doing this cause a leak?

So for smb/cifs, session key of the very first smb session is used for signing
for this and subsequent smb sessions on this smb connection, so it is
kmemdup'ed as session key in the server structure.  Now there is no need to keep
session key needed so generated during authentication (session setup phase) for
any of the smb sessions on this smb connection anymore.

For smb2 and smb3, since session key is per smb session (and not per
smb connection), we need_to/should keep it thus not free inuntil the session
is in effect and so no need to kmemdup it to the smb connection
(server structure).

So the perconneky function which is defined and declared only for smb1/cifs ops,
is used to gate kmemdup and kfree of the session keys or not.

Is that good enough an explaination?  If so, will put this verbiage as
part of the
next version of this patch in the patchset.

>
>>       sesInfoFree(ses);
>>       cifs_put_tcp_session(server);
>>  }
>> @@ -2484,6 +2488,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
>>       ses->sectype = volume_info->sectype;
>>       ses->sign = volume_info->sign;
>>
>> +     ses->auth_key.response = NULL;
>> +     ses->auth_key.len = 0;
>> +
>
> Again, these are kzalloced -- no need to do this here...and in any case
> this would belong in sesInfoAlloc rather than here, I think.
>
>>       mutex_lock(&ses->session_mutex);
>>       rc = cifs_negotiate_protocol(xid, ses);
>>       if (!rc)
>> @@ -3830,14 +3837,18 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>>       } else {
>>               mutex_lock(&server->srv_mutex);
>>               if (!server->session_estab) {
>> -                     server->session_key.response = ses->auth_key.response;
>> -                     server->session_key.len = ses->auth_key.len;
>> +                     if (server->ops->perconnkey) {
>> +                             rc = server->ops->perconnkey(server, ses);
>> +                             if (rc) {
>> +                                     mutex_unlock(&server->srv_mutex);
>> +                                     goto setup_sess_ret;
>> +                             }
>> +                     }
>>                       server->sequence_number = 0x2;
>>                       server->session_estab = true;
>> -                     ses->auth_key.response = NULL;
>> -                     if (server->ops->generate_signingkey)
>> -                             server->ops->generate_signingkey(server);
>>               }
>> +             if (server->ops->generate_signingkey)
>> +                     server->ops->generate_signingkey(server);
>
> It seems a bit strange that you're calling "generate_signingkey" here
> after you successfully call "perconnkey", but I'll take it on faith
> that you fix that in patch #2.
>

Need to call generate_signingkey for smb3 only and only if signing
is enabled.

> Still, that's the type of thing that's worth mentioning in the patch
> description since it doesn't seem to make much sense on its own.
>
>>               mutex_unlock(&server->srv_mutex);
>>
>>               cifs_dbg(FYI, "CIFS Session Established successfully\n");
>> @@ -3847,9 +3858,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>>               spin_unlock(&GlobalMid_Lock);
>>       }
>>
>> -     kfree(ses->auth_key.response);
>> -     ses->auth_key.response = NULL;
>> -     ses->auth_key.len = 0;
>> +setup_sess_ret:
>> +     if (server->ops->perconnkey)
>> +             free_authkey(ses);
>>       kfree(ses->ntlmssp);
>>       ses->ntlmssp = NULL;
>>
>> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
>> index 79358e3..77642cd 100644
>> --- a/fs/cifs/sess.c
>> +++ b/fs/cifs/sess.c
>> @@ -428,7 +428,8 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
>>               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
>>       if (ses->server->sign) {
>>               flags |= NTLMSSP_NEGOTIATE_SIGN;
>> -             if (!ses->server->session_estab)
>> +             if ((!ses->server->session_estab) ||
>> +                             (!ses->server->ops->perconnkey))
>>                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
>>       }
>>
>> @@ -466,7 +467,8 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>>               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
>>       if (ses->server->sign) {
>>               flags |= NTLMSSP_NEGOTIATE_SIGN;
>> -             if (!ses->server->session_estab)
>> +             if ((!ses->server->session_estab) ||
>> +                             (!ses->server->ops->perconnkey))
>>                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
>>       }
>>
>> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
>> index 6457690..331b406 100644
>> --- a/fs/cifs/smb1ops.c
>> +++ b/fs/cifs/smb1ops.c
>> @@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
>>       .mand_lock = cifs_mand_lock,
>>       .mand_unlock_range = cifs_unlock_range,
>>       .push_mand_locks = cifs_push_mandatory_locks,
>> +     .perconnkey = perconnkey,
>>  };
>>
>>  struct smb_version_values smb1_values = {
>> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
>> index abc9c28..11de60b 100644
>> --- a/fs/cifs/smb2pdu.c
>> +++ b/fs/cifs/smb2pdu.c
>> @@ -477,6 +477,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
>>               return -EIO;
>>       }
>>
>> +     free_authkey(ses);
>
> Would it make more sense to instead just move all of this authkey
> handling into the session setup routines? It seems a little odd to
> allocate a key in the generic part of the session setup code, only
> to later free it in the version specific routine.

Let me look into that.  So perhaps then we can skip the need for
a ops specific routine like perconnkey.

>
>>       /*
>>        * If memory allocation is successful, caller of this function
>>        * frees it.
>
> --
> Jeff Layton <jlayton@redhat.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jeff Layton Aug. 12, 2013, 2:05 p.m. UTC | #3
On Thu, 8 Aug 2013 23:30:57 -0500
Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote:

> On Thu, Aug 8, 2013 at 3:39 PM, Jeff Layton <jlayton@redhat.com> wrote:
> > On Thu,  8 Aug 2013 09:53:48 -0500
> > shirishpargaonkar@gmail.com wrote:
> >
> >> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> >>
> >> Change session key from per smb connection to per smb session for
> >> smb2 onwards.
> >> perconnkey is defined for only cifs/smb.
> >> For smb3, generate signing key per smb session.
> >>
> >
> > This description is pretty sparse. Seriously, be more verbose here. Ok,
> > so perconnkey is only defined for cifs/smb1, but what _is_ it? What
> > does it do, and why? Why do we want to change this to per-smb session
> > for smb2 and onwards? (yes, I know the reason, but other people trawling
> > through git log might not)
> >
> > It's worth it to spend the time and describe your patches properly.
> > Otherwise in 2-3 years, we'll have no idea why some of these changes
> > were made in this way.
> >
> >>
> >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> >> ---
> >>  fs/cifs/cifsencrypt.c | 20 ++++++++++++++++++++
> >>  fs/cifs/cifsglob.h    |  2 ++
> >>  fs/cifs/cifsproto.h   |  3 +++
> >>  fs/cifs/connect.c     | 27 +++++++++++++++++++--------
> >>  fs/cifs/sess.c        |  6 ++++--
> >>  fs/cifs/smb1ops.c     |  1 +
> >>  fs/cifs/smb2pdu.c     |  1 +
> >>  7 files changed, 50 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> >> index 45e57cc..f9ef57a 100644
> >> --- a/fs/cifs/cifsencrypt.c
> >> +++ b/fs/cifs/cifsencrypt.c
> >> @@ -720,6 +720,26 @@ setup_ntlmv2_rsp_ret:
> >>       return rc;
> >>  }
> >>
> >> +void
> >> +free_authkey(struct cifs_ses *ses)
> >> +{
> >> +     kfree(ses->auth_key.response);
> >> +     ses->auth_key.response = NULL;
> >> +     ses->auth_key.len = 0;
> >> +}
> >> +
> >> +int
> >> +perconnkey(struct TCP_Server_Info *server, struct cifs_ses *ses)
> >> +{
> >> +     server->session_key.response = kmemdup(ses->auth_key.response,
> >> +             ses->auth_key.len, GFP_KERNEL);
> >> +     if (!server->session_key.response)
> >> +             return -ENOMEM;
> >> +     server->session_key.len = ses->auth_key.len;
> >> +
> >> +     return 0;
> >> +}
> >> +
> >
> > If you move "perconnkey" into smb1ops.c then it can be static. It could
> > also benefit from a more desciptive name, such as "smb1_set_conn_key"
> > or something.
> >
> >>  int
> >>  calc_seckey(struct cifs_ses *ses)
> >>  {
> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> >> index 1fdc370..2909380 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -365,6 +365,8 @@ struct smb_version_operations {
> >>       void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
> >>       /* generate new lease key */
> >>       void (*new_lease_key)(struct cifs_fid *fid);
> >> +     int (*perconnkey)(struct TCP_Server_Info *server,
> >> +                                     struct cifs_ses *ses);
> >
> > A name like this sounds like an operation that returns the (already
> > existing) per-connection key. How about something like
> > "generate_perconn_key" instead?
> >
> > Also, the ses->server pointer should already be set at this point,
> > right? So, it seems like there's probably no need to pass in both as
> > parms. Might it make more sense to just pass in "ses"?
> >
> >>       /* The next two functions will need to be changed to per smb session */
> >>       void (*generate_signingkey)(struct TCP_Server_Info *server);
> >>       int (*calc_signature)(struct smb_rqst *rqst,
> >> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> >> index f7e584d..b6c1d03 100644
> >> --- a/fs/cifs/cifsproto.h
> >> +++ b/fs/cifs/cifsproto.h
> >> @@ -437,6 +437,9 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
> >>  extern int calc_seckey(struct cifs_ses *);
> >>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
> >>
> >> +extern int perconnkey(struct TCP_Server_Info *, struct cifs_ses *);
> >> +extern void free_authkey(struct cifs_ses *);
> >> +
> >>  #ifdef CONFIG_CIFS_WEAK_PW_HASH
> >>  extern int calc_lanman_hash(const char *password, const char *cryptkey,
> >>                               bool encrypt, char *lnm_session_key);
> >> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> >> index fa68813..98deb98 100644
> >> --- a/fs/cifs/connect.c
> >> +++ b/fs/cifs/connect.c
> >> @@ -2117,6 +2117,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
> >>               goto out_err_crypto_release;
> >>       }
> >>
> >> +     tcp_ses->session_key.response = NULL;
> >> +     tcp_ses->session_key.len = 0;
> >
> > This is kzalloc'ed so these are not necessary.
> >
> >>       tcp_ses->noblocksnd = volume_info->noblocksnd;
> >>       tcp_ses->noautotune = volume_info->noautotune;
> >>       tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
> >> @@ -2270,6 +2272,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
> >>               server->ops->logoff(xid, ses);
> >>               _free_xid(xid);
> >>       }
> >> +     if (!server->ops->perconnkey)
> >> +             free_authkey(ses);
> >
> > Hrm...so the SMB1 perconnkey operation that you have now kmemdups it.
> >
> > Why do you skip freeing it here? Doesn't the TCP_Server_Info have its
> > own copy and won't doing this cause a leak?
> 
> So for smb/cifs, session key of the very first smb session is used for signing
> for this and subsequent smb sessions on this smb connection, so it is
> kmemdup'ed as session key in the server structure.  Now there is no need to keep
> session key needed so generated during authentication (session setup phase) for
> any of the smb sessions on this smb connection anymore.
> 
> For smb2 and smb3, since session key is per smb session (and not per
> smb connection), we need_to/should keep it thus not free inuntil the session
> is in effect and so no need to kmemdup it to the smb connection
> (server structure).
> 
> So the perconneky function which is defined and declared only for smb1/cifs ops,
> is used to gate kmemdup and kfree of the session keys or not.
> 
> Is that good enough an explaination?  If so, will put this verbiage as
> part of the
> next version of this patch in the patchset.
> 

I'm sorry, I still don't understand why you're doing it this way.

Why not instead remove the free_authkey call in cifs_setup_session and
just always free it here instead? Won't the effect be the same (and the
lifecycle be simpler?)

> >
> >>       sesInfoFree(ses);
> >>       cifs_put_tcp_session(server);
> >>  }
> >> @@ -2484,6 +2488,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
> >>       ses->sectype = volume_info->sectype;
> >>       ses->sign = volume_info->sign;
> >>
> >> +     ses->auth_key.response = NULL;
> >> +     ses->auth_key.len = 0;
> >> +
> >
> > Again, these are kzalloced -- no need to do this here...and in any case
> > this would belong in sesInfoAlloc rather than here, I think.
> >
> >>       mutex_lock(&ses->session_mutex);
> >>       rc = cifs_negotiate_protocol(xid, ses);
> >>       if (!rc)
> >> @@ -3830,14 +3837,18 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
> >>       } else {
> >>               mutex_lock(&server->srv_mutex);
> >>               if (!server->session_estab) {
> >> -                     server->session_key.response = ses->auth_key.response;
> >> -                     server->session_key.len = ses->auth_key.len;
> >> +                     if (server->ops->perconnkey) {
> >> +                             rc = server->ops->perconnkey(server, ses);
> >> +                             if (rc) {
> >> +                                     mutex_unlock(&server->srv_mutex);
> >> +                                     goto setup_sess_ret;
> >> +                             }
> >> +                     }
> >>                       server->sequence_number = 0x2;
> >>                       server->session_estab = true;
> >> -                     ses->auth_key.response = NULL;
> >> -                     if (server->ops->generate_signingkey)
> >> -                             server->ops->generate_signingkey(server);
> >>               }
> >> +             if (server->ops->generate_signingkey)
> >> +                     server->ops->generate_signingkey(server);
> >
> > It seems a bit strange that you're calling "generate_signingkey" here
> > after you successfully call "perconnkey", but I'll take it on faith
> > that you fix that in patch #2.
> >
> 
> Need to call generate_signingkey for smb3 only and only if signing
> is enabled.
> 
> > Still, that's the type of thing that's worth mentioning in the patch
> > description since it doesn't seem to make much sense on its own.
> >
> >>               mutex_unlock(&server->srv_mutex);
> >>
> >>               cifs_dbg(FYI, "CIFS Session Established successfully\n");
> >> @@ -3847,9 +3858,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
> >>               spin_unlock(&GlobalMid_Lock);
> >>       }
> >>
> >> -     kfree(ses->auth_key.response);
> >> -     ses->auth_key.response = NULL;
> >> -     ses->auth_key.len = 0;
> >> +setup_sess_ret:
> >> +     if (server->ops->perconnkey)
> >> +             free_authkey(ses);
> >>       kfree(ses->ntlmssp);
> >>       ses->ntlmssp = NULL;
> >>
> >> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> >> index 79358e3..77642cd 100644
> >> --- a/fs/cifs/sess.c
> >> +++ b/fs/cifs/sess.c
> >> @@ -428,7 +428,8 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
> >>               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
> >>       if (ses->server->sign) {
> >>               flags |= NTLMSSP_NEGOTIATE_SIGN;
> >> -             if (!ses->server->session_estab)
> >> +             if ((!ses->server->session_estab) ||
> >> +                             (!ses->server->ops->perconnkey))
> >>                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
> >>       }
> >>
> >> @@ -466,7 +467,8 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
> >>               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
> >>       if (ses->server->sign) {
> >>               flags |= NTLMSSP_NEGOTIATE_SIGN;
> >> -             if (!ses->server->session_estab)
> >> +             if ((!ses->server->session_estab) ||
> >> +                             (!ses->server->ops->perconnkey))
> >>                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
> >>       }
> >>
> >> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> >> index 6457690..331b406 100644
> >> --- a/fs/cifs/smb1ops.c
> >> +++ b/fs/cifs/smb1ops.c
> >> @@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
> >>       .mand_lock = cifs_mand_lock,
> >>       .mand_unlock_range = cifs_unlock_range,
> >>       .push_mand_locks = cifs_push_mandatory_locks,
> >> +     .perconnkey = perconnkey,
> >>  };
> >>
> >>  struct smb_version_values smb1_values = {
> >> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> >> index abc9c28..11de60b 100644
> >> --- a/fs/cifs/smb2pdu.c
> >> +++ b/fs/cifs/smb2pdu.c
> >> @@ -477,6 +477,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
> >>               return -EIO;
> >>       }
> >>
> >> +     free_authkey(ses);
> >
> > Would it make more sense to instead just move all of this authkey
> > handling into the session setup routines? It seems a little odd to
> > allocate a key in the generic part of the session setup code, only
> > to later free it in the version specific routine.
> 
> Let me look into that.  So perhaps then we can skip the need for
> a ops specific routine like perconnkey.
> 

I think that would make much more sense. All of this could be done
much more cleanly under the aegis of the session_setup routines.

> >
> >>       /*
> >>        * If memory allocation is successful, caller of this function
> >>        * frees it.
> >
> > --
> > Jeff Layton <jlayton@redhat.com>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shirish Pargaonkar Aug. 12, 2013, 5:03 p.m. UTC | #4
ok, let me try and code it up that way.
Little bit of the code, where we check for session establishment
and set sequence number etc. under the lock will have to be
repeated in individual smb and smb2/3 session setup functions.

Regards,

Shirish

On Mon, Aug 12, 2013 at 9:05 AM, Jeff Layton <jlayton@redhat.com> wrote:
> On Thu, 8 Aug 2013 23:30:57 -0500
> Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote:
>
>> On Thu, Aug 8, 2013 at 3:39 PM, Jeff Layton <jlayton@redhat.com> wrote:
>> > On Thu,  8 Aug 2013 09:53:48 -0500
>> > shirishpargaonkar@gmail.com wrote:
>> >
>> >> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>> >>
>> >> Change session key from per smb connection to per smb session for
>> >> smb2 onwards.
>> >> perconnkey is defined for only cifs/smb.
>> >> For smb3, generate signing key per smb session.
>> >>
>> >
>> > This description is pretty sparse. Seriously, be more verbose here. Ok,
>> > so perconnkey is only defined for cifs/smb1, but what _is_ it? What
>> > does it do, and why? Why do we want to change this to per-smb session
>> > for smb2 and onwards? (yes, I know the reason, but other people trawling
>> > through git log might not)
>> >
>> > It's worth it to spend the time and describe your patches properly.
>> > Otherwise in 2-3 years, we'll have no idea why some of these changes
>> > were made in this way.
>> >
>> >>
>> >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>> >> ---
>> >>  fs/cifs/cifsencrypt.c | 20 ++++++++++++++++++++
>> >>  fs/cifs/cifsglob.h    |  2 ++
>> >>  fs/cifs/cifsproto.h   |  3 +++
>> >>  fs/cifs/connect.c     | 27 +++++++++++++++++++--------
>> >>  fs/cifs/sess.c        |  6 ++++--
>> >>  fs/cifs/smb1ops.c     |  1 +
>> >>  fs/cifs/smb2pdu.c     |  1 +
>> >>  7 files changed, 50 insertions(+), 10 deletions(-)
>> >>
>> >> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
>> >> index 45e57cc..f9ef57a 100644
>> >> --- a/fs/cifs/cifsencrypt.c
>> >> +++ b/fs/cifs/cifsencrypt.c
>> >> @@ -720,6 +720,26 @@ setup_ntlmv2_rsp_ret:
>> >>       return rc;
>> >>  }
>> >>
>> >> +void
>> >> +free_authkey(struct cifs_ses *ses)
>> >> +{
>> >> +     kfree(ses->auth_key.response);
>> >> +     ses->auth_key.response = NULL;
>> >> +     ses->auth_key.len = 0;
>> >> +}
>> >> +
>> >> +int
>> >> +perconnkey(struct TCP_Server_Info *server, struct cifs_ses *ses)
>> >> +{
>> >> +     server->session_key.response = kmemdup(ses->auth_key.response,
>> >> +             ses->auth_key.len, GFP_KERNEL);
>> >> +     if (!server->session_key.response)
>> >> +             return -ENOMEM;
>> >> +     server->session_key.len = ses->auth_key.len;
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >
>> > If you move "perconnkey" into smb1ops.c then it can be static. It could
>> > also benefit from a more desciptive name, such as "smb1_set_conn_key"
>> > or something.
>> >
>> >>  int
>> >>  calc_seckey(struct cifs_ses *ses)
>> >>  {
>> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> >> index 1fdc370..2909380 100644
>> >> --- a/fs/cifs/cifsglob.h
>> >> +++ b/fs/cifs/cifsglob.h
>> >> @@ -365,6 +365,8 @@ struct smb_version_operations {
>> >>       void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
>> >>       /* generate new lease key */
>> >>       void (*new_lease_key)(struct cifs_fid *fid);
>> >> +     int (*perconnkey)(struct TCP_Server_Info *server,
>> >> +                                     struct cifs_ses *ses);
>> >
>> > A name like this sounds like an operation that returns the (already
>> > existing) per-connection key. How about something like
>> > "generate_perconn_key" instead?
>> >
>> > Also, the ses->server pointer should already be set at this point,
>> > right? So, it seems like there's probably no need to pass in both as
>> > parms. Might it make more sense to just pass in "ses"?
>> >
>> >>       /* The next two functions will need to be changed to per smb session */
>> >>       void (*generate_signingkey)(struct TCP_Server_Info *server);
>> >>       int (*calc_signature)(struct smb_rqst *rqst,
>> >> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> >> index f7e584d..b6c1d03 100644
>> >> --- a/fs/cifs/cifsproto.h
>> >> +++ b/fs/cifs/cifsproto.h
>> >> @@ -437,6 +437,9 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
>> >>  extern int calc_seckey(struct cifs_ses *);
>> >>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
>> >>
>> >> +extern int perconnkey(struct TCP_Server_Info *, struct cifs_ses *);
>> >> +extern void free_authkey(struct cifs_ses *);
>> >> +
>> >>  #ifdef CONFIG_CIFS_WEAK_PW_HASH
>> >>  extern int calc_lanman_hash(const char *password, const char *cryptkey,
>> >>                               bool encrypt, char *lnm_session_key);
>> >> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> >> index fa68813..98deb98 100644
>> >> --- a/fs/cifs/connect.c
>> >> +++ b/fs/cifs/connect.c
>> >> @@ -2117,6 +2117,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>> >>               goto out_err_crypto_release;
>> >>       }
>> >>
>> >> +     tcp_ses->session_key.response = NULL;
>> >> +     tcp_ses->session_key.len = 0;
>> >
>> > This is kzalloc'ed so these are not necessary.
>> >
>> >>       tcp_ses->noblocksnd = volume_info->noblocksnd;
>> >>       tcp_ses->noautotune = volume_info->noautotune;
>> >>       tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
>> >> @@ -2270,6 +2272,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
>> >>               server->ops->logoff(xid, ses);
>> >>               _free_xid(xid);
>> >>       }
>> >> +     if (!server->ops->perconnkey)
>> >> +             free_authkey(ses);
>> >
>> > Hrm...so the SMB1 perconnkey operation that you have now kmemdups it.
>> >
>> > Why do you skip freeing it here? Doesn't the TCP_Server_Info have its
>> > own copy and won't doing this cause a leak?
>>
>> So for smb/cifs, session key of the very first smb session is used for signing
>> for this and subsequent smb sessions on this smb connection, so it is
>> kmemdup'ed as session key in the server structure.  Now there is no need to keep
>> session key needed so generated during authentication (session setup phase) for
>> any of the smb sessions on this smb connection anymore.
>>
>> For smb2 and smb3, since session key is per smb session (and not per
>> smb connection), we need_to/should keep it thus not free inuntil the session
>> is in effect and so no need to kmemdup it to the smb connection
>> (server structure).
>>
>> So the perconneky function which is defined and declared only for smb1/cifs ops,
>> is used to gate kmemdup and kfree of the session keys or not.
>>
>> Is that good enough an explaination?  If so, will put this verbiage as
>> part of the
>> next version of this patch in the patchset.
>>
>
> I'm sorry, I still don't understand why you're doing it this way.
>
> Why not instead remove the free_authkey call in cifs_setup_session and
> just always free it here instead? Won't the effect be the same (and the
> lifecycle be simpler?)
>
>> >
>> >>       sesInfoFree(ses);
>> >>       cifs_put_tcp_session(server);
>> >>  }
>> >> @@ -2484,6 +2488,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
>> >>       ses->sectype = volume_info->sectype;
>> >>       ses->sign = volume_info->sign;
>> >>
>> >> +     ses->auth_key.response = NULL;
>> >> +     ses->auth_key.len = 0;
>> >> +
>> >
>> > Again, these are kzalloced -- no need to do this here...and in any case
>> > this would belong in sesInfoAlloc rather than here, I think.
>> >
>> >>       mutex_lock(&ses->session_mutex);
>> >>       rc = cifs_negotiate_protocol(xid, ses);
>> >>       if (!rc)
>> >> @@ -3830,14 +3837,18 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>> >>       } else {
>> >>               mutex_lock(&server->srv_mutex);
>> >>               if (!server->session_estab) {
>> >> -                     server->session_key.response = ses->auth_key.response;
>> >> -                     server->session_key.len = ses->auth_key.len;
>> >> +                     if (server->ops->perconnkey) {
>> >> +                             rc = server->ops->perconnkey(server, ses);
>> >> +                             if (rc) {
>> >> +                                     mutex_unlock(&server->srv_mutex);
>> >> +                                     goto setup_sess_ret;
>> >> +                             }
>> >> +                     }
>> >>                       server->sequence_number = 0x2;
>> >>                       server->session_estab = true;
>> >> -                     ses->auth_key.response = NULL;
>> >> -                     if (server->ops->generate_signingkey)
>> >> -                             server->ops->generate_signingkey(server);
>> >>               }
>> >> +             if (server->ops->generate_signingkey)
>> >> +                     server->ops->generate_signingkey(server);
>> >
>> > It seems a bit strange that you're calling "generate_signingkey" here
>> > after you successfully call "perconnkey", but I'll take it on faith
>> > that you fix that in patch #2.
>> >
>>
>> Need to call generate_signingkey for smb3 only and only if signing
>> is enabled.
>>
>> > Still, that's the type of thing that's worth mentioning in the patch
>> > description since it doesn't seem to make much sense on its own.
>> >
>> >>               mutex_unlock(&server->srv_mutex);
>> >>
>> >>               cifs_dbg(FYI, "CIFS Session Established successfully\n");
>> >> @@ -3847,9 +3858,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>> >>               spin_unlock(&GlobalMid_Lock);
>> >>       }
>> >>
>> >> -     kfree(ses->auth_key.response);
>> >> -     ses->auth_key.response = NULL;
>> >> -     ses->auth_key.len = 0;
>> >> +setup_sess_ret:
>> >> +     if (server->ops->perconnkey)
>> >> +             free_authkey(ses);
>> >>       kfree(ses->ntlmssp);
>> >>       ses->ntlmssp = NULL;
>> >>
>> >> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
>> >> index 79358e3..77642cd 100644
>> >> --- a/fs/cifs/sess.c
>> >> +++ b/fs/cifs/sess.c
>> >> @@ -428,7 +428,8 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
>> >>               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
>> >>       if (ses->server->sign) {
>> >>               flags |= NTLMSSP_NEGOTIATE_SIGN;
>> >> -             if (!ses->server->session_estab)
>> >> +             if ((!ses->server->session_estab) ||
>> >> +                             (!ses->server->ops->perconnkey))
>> >>                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
>> >>       }
>> >>
>> >> @@ -466,7 +467,8 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
>> >>               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
>> >>       if (ses->server->sign) {
>> >>               flags |= NTLMSSP_NEGOTIATE_SIGN;
>> >> -             if (!ses->server->session_estab)
>> >> +             if ((!ses->server->session_estab) ||
>> >> +                             (!ses->server->ops->perconnkey))
>> >>                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
>> >>       }
>> >>
>> >> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
>> >> index 6457690..331b406 100644
>> >> --- a/fs/cifs/smb1ops.c
>> >> +++ b/fs/cifs/smb1ops.c
>> >> @@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
>> >>       .mand_lock = cifs_mand_lock,
>> >>       .mand_unlock_range = cifs_unlock_range,
>> >>       .push_mand_locks = cifs_push_mandatory_locks,
>> >> +     .perconnkey = perconnkey,
>> >>  };
>> >>
>> >>  struct smb_version_values smb1_values = {
>> >> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
>> >> index abc9c28..11de60b 100644
>> >> --- a/fs/cifs/smb2pdu.c
>> >> +++ b/fs/cifs/smb2pdu.c
>> >> @@ -477,6 +477,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
>> >>               return -EIO;
>> >>       }
>> >>
>> >> +     free_authkey(ses);
>> >
>> > Would it make more sense to instead just move all of this authkey
>> > handling into the session setup routines? It seems a little odd to
>> > allocate a key in the generic part of the session setup code, only
>> > to later free it in the version specific routine.
>>
>> Let me look into that.  So perhaps then we can skip the need for
>> a ops specific routine like perconnkey.
>>
>
> I think that would make much more sense. All of this could be done
> much more cleanly under the aegis of the session_setup routines.
>
>> >
>> >>       /*
>> >>        * If memory allocation is successful, caller of this function
>> >>        * frees it.
>> >
>> > --
>> > Jeff Layton <jlayton@redhat.com>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
> --
> Jeff Layton <jlayton@redhat.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 45e57cc..f9ef57a 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -720,6 +720,26 @@  setup_ntlmv2_rsp_ret:
 	return rc;
 }
 
+void
+free_authkey(struct cifs_ses *ses)
+{
+	kfree(ses->auth_key.response);
+	ses->auth_key.response = NULL;
+	ses->auth_key.len = 0;
+}
+
+int
+perconnkey(struct TCP_Server_Info *server, struct cifs_ses *ses)
+{
+	server->session_key.response = kmemdup(ses->auth_key.response,
+		ses->auth_key.len, GFP_KERNEL);
+	if (!server->session_key.response)
+		return -ENOMEM;
+	server->session_key.len = ses->auth_key.len;
+
+	return 0;
+}
+
 int
 calc_seckey(struct cifs_ses *ses)
 {
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1fdc370..2909380 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -365,6 +365,8 @@  struct smb_version_operations {
 	void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
 	/* generate new lease key */
 	void (*new_lease_key)(struct cifs_fid *fid);
+	int (*perconnkey)(struct TCP_Server_Info *server,
+					struct cifs_ses *ses);
 	/* The next two functions will need to be changed to per smb session */
 	void (*generate_signingkey)(struct TCP_Server_Info *server);
 	int (*calc_signature)(struct smb_rqst *rqst,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index f7e584d..b6c1d03 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -437,6 +437,9 @@  extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 extern int calc_seckey(struct cifs_ses *);
 extern void generate_smb3signingkey(struct TCP_Server_Info *);
 
+extern int perconnkey(struct TCP_Server_Info *, struct cifs_ses *);
+extern void free_authkey(struct cifs_ses *);
+
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 extern int calc_lanman_hash(const char *password, const char *cryptkey,
 				bool encrypt, char *lnm_session_key);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index fa68813..98deb98 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2117,6 +2117,8 @@  cifs_get_tcp_session(struct smb_vol *volume_info)
 		goto out_err_crypto_release;
 	}
 
+	tcp_ses->session_key.response = NULL;
+	tcp_ses->session_key.len = 0;
 	tcp_ses->noblocksnd = volume_info->noblocksnd;
 	tcp_ses->noautotune = volume_info->noautotune;
 	tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
@@ -2270,6 +2272,8 @@  cifs_put_smb_ses(struct cifs_ses *ses)
 		server->ops->logoff(xid, ses);
 		_free_xid(xid);
 	}
+	if (!server->ops->perconnkey)
+		free_authkey(ses);
 	sesInfoFree(ses);
 	cifs_put_tcp_session(server);
 }
@@ -2484,6 +2488,9 @@  cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 	ses->sectype = volume_info->sectype;
 	ses->sign = volume_info->sign;
 
+	ses->auth_key.response = NULL;
+	ses->auth_key.len = 0;
+
 	mutex_lock(&ses->session_mutex);
 	rc = cifs_negotiate_protocol(xid, ses);
 	if (!rc)
@@ -3830,14 +3837,18 @@  cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 	} else {
 		mutex_lock(&server->srv_mutex);
 		if (!server->session_estab) {
-			server->session_key.response = ses->auth_key.response;
-			server->session_key.len = ses->auth_key.len;
+			if (server->ops->perconnkey) {
+				rc = server->ops->perconnkey(server, ses);
+				if (rc) {
+					mutex_unlock(&server->srv_mutex);
+					goto setup_sess_ret;
+				}
+			}
 			server->sequence_number = 0x2;
 			server->session_estab = true;
-			ses->auth_key.response = NULL;
-			if (server->ops->generate_signingkey)
-				server->ops->generate_signingkey(server);
 		}
+		if (server->ops->generate_signingkey)
+			server->ops->generate_signingkey(server);
 		mutex_unlock(&server->srv_mutex);
 
 		cifs_dbg(FYI, "CIFS Session Established successfully\n");
@@ -3847,9 +3858,9 @@  cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 		spin_unlock(&GlobalMid_Lock);
 	}
 
-	kfree(ses->auth_key.response);
-	ses->auth_key.response = NULL;
-	ses->auth_key.len = 0;
+setup_sess_ret:
+	if (server->ops->perconnkey)
+		free_authkey(ses);
 	kfree(ses->ntlmssp);
 	ses->ntlmssp = NULL;
 
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 79358e3..77642cd 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -428,7 +428,8 @@  void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
 		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 	if (ses->server->sign) {
 		flags |= NTLMSSP_NEGOTIATE_SIGN;
-		if (!ses->server->session_estab)
+		if ((!ses->server->session_estab) ||
+				(!ses->server->ops->perconnkey))
 			flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 	}
 
@@ -466,7 +467,8 @@  int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 	if (ses->server->sign) {
 		flags |= NTLMSSP_NEGOTIATE_SIGN;
-		if (!ses->server->session_estab)
+		if ((!ses->server->session_estab) ||
+				(!ses->server->ops->perconnkey))
 			flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 	}
 
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 6457690..331b406 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -944,6 +944,7 @@  struct smb_version_operations smb1_operations = {
 	.mand_lock = cifs_mand_lock,
 	.mand_unlock_range = cifs_unlock_range,
 	.push_mand_locks = cifs_push_mandatory_locks,
+	.perconnkey = perconnkey,
 };
 
 struct smb_version_values smb1_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index abc9c28..11de60b 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -477,6 +477,7 @@  SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
 		return -EIO;
 	}
 
+	free_authkey(ses);
 	/*
 	 * If memory allocation is successful, caller of this function
 	 * frees it.