Skip to content

Commit b9aef1b

Browse files
meetakshi253Steve French
authored andcommitted
cifs: support mounting with alternate password to allow password rotation
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: stable@vger.kernel.org Signed-off-by: Meetakshi Setiya <msetiya@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent c353ee4 commit b9aef1b

File tree

1 file changed

+50
-7
lines changed

1 file changed

+50
-7
lines changed

fs/smb/client/connect.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,11 +1897,35 @@ static int match_session(struct cifs_ses *ses,
18971897
CIFS_MAX_USERNAME_LEN))
18981898
return 0;
18991899
if ((ctx->username && strlen(ctx->username) != 0) &&
1900-
ses->password != NULL &&
1901-
strncmp(ses->password,
1902-
ctx->password ? ctx->password : "",
1903-
CIFS_MAX_PASSWORD_LEN))
1904-
return 0;
1900+
ses->password != NULL) {
1901+
1902+
/* New mount can only share sessions with an existing mount if:
1903+
* 1. Both password and password2 match, or
1904+
* 2. password2 of the old mount matches password of the new mount
1905+
* and password of the old mount matches password2 of the new
1906+
* mount
1907+
*/
1908+
if (ses->password2 != NULL && ctx->password2 != NULL) {
1909+
if (!((strncmp(ses->password, ctx->password ?
1910+
ctx->password : "", CIFS_MAX_PASSWORD_LEN) == 0 &&
1911+
strncmp(ses->password2, ctx->password2,
1912+
CIFS_MAX_PASSWORD_LEN) == 0) ||
1913+
(strncmp(ses->password, ctx->password2,
1914+
CIFS_MAX_PASSWORD_LEN) == 0 &&
1915+
strncmp(ses->password2, ctx->password ?
1916+
ctx->password : "", CIFS_MAX_PASSWORD_LEN) == 0)))
1917+
return 0;
1918+
1919+
} else if ((ses->password2 == NULL && ctx->password2 != NULL) ||
1920+
(ses->password2 != NULL && ctx->password2 == NULL)) {
1921+
return 0;
1922+
1923+
} else {
1924+
if (strncmp(ses->password, ctx->password ?
1925+
ctx->password : "", CIFS_MAX_PASSWORD_LEN))
1926+
return 0;
1927+
}
1928+
}
19051929
}
19061930

19071931
if (strcmp(ctx->local_nls->charset, ses->local_nls->charset))
@@ -2244,6 +2268,7 @@ struct cifs_ses *
22442268
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
22452269
{
22462270
int rc = 0;
2271+
int retries = 0;
22472272
unsigned int xid;
22482273
struct cifs_ses *ses;
22492274
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
@@ -2262,6 +2287,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
22622287
cifs_dbg(FYI, "Session needs reconnect\n");
22632288

22642289
mutex_lock(&ses->session_mutex);
2290+
2291+
retry_old_session:
22652292
rc = cifs_negotiate_protocol(xid, ses, server);
22662293
if (rc) {
22672294
mutex_unlock(&ses->session_mutex);
@@ -2274,6 +2301,13 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
22742301
rc = cifs_setup_session(xid, ses, server,
22752302
ctx->local_nls);
22762303
if (rc) {
2304+
if (((rc == -EACCES) || (rc == -EKEYEXPIRED) ||
2305+
(rc == -EKEYREVOKED)) && !retries && ses->password2) {
2306+
retries++;
2307+
cifs_dbg(FYI, "Session reconnect failed, retrying with alternate password\n");
2308+
swap(ses->password, ses->password2);
2309+
goto retry_old_session;
2310+
}
22772311
mutex_unlock(&ses->session_mutex);
22782312
/* problem -- put our reference */
22792313
cifs_put_smb_ses(ses);
@@ -2369,6 +2403,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
23692403
ses->chans_need_reconnect = 1;
23702404
spin_unlock(&ses->chan_lock);
23712405

2406+
retry_new_session:
23722407
mutex_lock(&ses->session_mutex);
23732408
rc = cifs_negotiate_protocol(xid, ses, server);
23742409
if (!rc)
@@ -2381,8 +2416,16 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
23812416
sizeof(ses->smb3signingkey));
23822417
spin_unlock(&ses->chan_lock);
23832418

2384-
if (rc)
2385-
goto get_ses_fail;
2419+
if (rc) {
2420+
if (((rc == -EACCES) || (rc == -EKEYEXPIRED) ||
2421+
(rc == -EKEYREVOKED)) && !retries && ses->password2) {
2422+
retries++;
2423+
cifs_dbg(FYI, "Session setup failed, retrying with alternate password\n");
2424+
swap(ses->password, ses->password2);
2425+
goto retry_new_session;
2426+
} else
2427+
goto get_ses_fail;
2428+
}
23862429

23872430
/*
23882431
* success, put it on the list and add it as first channel

0 commit comments

Comments
 (0)