Skip to content

Commit

Permalink
cifs: support mounting with alternate password to allow password rota…
Browse files Browse the repository at this point in the history
…tion

commit b9aef1b upstream.

Fixes the case for example where the password specified on mount is a
recently expired password, but password2 is valid.  Without this patch
this mount scenario would fail.

This patch introduces the following changes to support password rotation on
mount:

1. If an existing session is not found and the new session setup results in
EACCES, EKEYEXPIRED or EKEYREVOKED, swap password and password2 (if
available), and retry the mount.

2. To match the new mount with an existing session, add conditions to check
if a) password and password2 of the new mount and the existing session are
the same, or b) password of the new mount is the same as the password2 of
the existing session, and password2 of the new mount is the same as the
password of the existing session.

3. If an existing session is found, but needs reconnect, retry the session
setup after swapping password and password2 (if available), in case the
previous attempt results in EACCES, EKEYEXPIRED or EKEYREVOKED.

Cc: [email protected]
Signed-off-by: Meetakshi Setiya <[email protected]>
Signed-off-by: Steve French <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
meetakshi253 authored and Sasha Levin committed Dec 7, 2024
1 parent 9c84c84 commit e1bf460
Showing 1 changed file with 50 additions and 7 deletions.
57 changes: 50 additions & 7 deletions fs/smb/client/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1908,11 +1908,35 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
CIFS_MAX_USERNAME_LEN))
return 0;
if ((ctx->username && strlen(ctx->username) != 0) &&
ses->password != NULL &&
strncmp(ses->password,
ctx->password ? ctx->password : "",
CIFS_MAX_PASSWORD_LEN))
return 0;
ses->password != NULL) {

/* New mount can only share sessions with an existing mount if:
* 1. Both password and password2 match, or
* 2. password2 of the old mount matches password of the new mount
* and password of the old mount matches password2 of the new
* mount
*/
if (ses->password2 != NULL && ctx->password2 != NULL) {
if (!((strncmp(ses->password, ctx->password ?
ctx->password : "", CIFS_MAX_PASSWORD_LEN) == 0 &&
strncmp(ses->password2, ctx->password2,
CIFS_MAX_PASSWORD_LEN) == 0) ||
(strncmp(ses->password, ctx->password2,
CIFS_MAX_PASSWORD_LEN) == 0 &&
strncmp(ses->password2, ctx->password ?
ctx->password : "", CIFS_MAX_PASSWORD_LEN) == 0)))
return 0;

} else if ((ses->password2 == NULL && ctx->password2 != NULL) ||
(ses->password2 != NULL && ctx->password2 == NULL)) {
return 0;

} else {
if (strncmp(ses->password, ctx->password ?
ctx->password : "", CIFS_MAX_PASSWORD_LEN))
return 0;
}
}
}

if (strcmp(ctx->local_nls->charset, ses->local_nls->charset))
Expand Down Expand Up @@ -2256,6 +2280,7 @@ struct cifs_ses *
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
{
int rc = 0;
int retries = 0;
unsigned int xid;
struct cifs_ses *ses;
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
Expand All @@ -2274,6 +2299,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
cifs_dbg(FYI, "Session needs reconnect\n");

mutex_lock(&ses->session_mutex);

retry_old_session:
rc = cifs_negotiate_protocol(xid, ses, server);
if (rc) {
mutex_unlock(&ses->session_mutex);
Expand All @@ -2286,6 +2313,13 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
rc = cifs_setup_session(xid, ses, server,
ctx->local_nls);
if (rc) {
if (((rc == -EACCES) || (rc == -EKEYEXPIRED) ||
(rc == -EKEYREVOKED)) && !retries && ses->password2) {
retries++;
cifs_dbg(FYI, "Session reconnect failed, retrying with alternate password\n");
swap(ses->password, ses->password2);
goto retry_old_session;
}
mutex_unlock(&ses->session_mutex);
/* problem -- put our reference */
cifs_put_smb_ses(ses);
Expand Down Expand Up @@ -2361,6 +2395,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
ses->chans_need_reconnect = 1;
spin_unlock(&ses->chan_lock);

retry_new_session:
mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(xid, ses, server);
if (!rc)
Expand All @@ -2373,8 +2408,16 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
sizeof(ses->smb3signingkey));
spin_unlock(&ses->chan_lock);

if (rc)
goto get_ses_fail;
if (rc) {
if (((rc == -EACCES) || (rc == -EKEYEXPIRED) ||
(rc == -EKEYREVOKED)) && !retries && ses->password2) {
retries++;
cifs_dbg(FYI, "Session setup failed, retrying with alternate password\n");
swap(ses->password, ses->password2);
goto retry_new_session;
} else
goto get_ses_fail;
}

/*
* success, put it on the list and add it as first channel
Expand Down

0 comments on commit e1bf460

Please sign in to comment.