Skip to content

Commit 35f8342

Browse files
committed
smb3: fix broken reconnect when password changing on the server by allowing password rotation
There are various use cases that are becoming more common in which password changes are scheduled on a server(s) periodically but the clients connected to this server need to stay connected (even in the face of brief network reconnects) due to mounts which can not be easily unmounted and mounted at will, and servers that do password rotation do not always have the ability to tell the clients exactly when to the new password will be effective, so add support for an alt password ("password2=") on mount (and also remount) so that we can anticipate the upcoming change to the server without risking breaking existing mounts. An alternative would have been to use the kernel keyring for this but the processes doing the reconnect do not have access to the keyring but do have access to the ses structure. Reviewed-by: Bharath SM <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent c6ff459 commit 35f8342

File tree

6 files changed

+44
-0
lines changed

6 files changed

+44
-0
lines changed

fs/smb/client/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ struct cifs_ses {
10771077
and after mount option parsing we fill it */
10781078
char *domainName;
10791079
char *password;
1080+
char *password2; /* When key rotation used, new password may be set before it expires */
10801081
char workstation_name[CIFS_MAX_WORKSTATION_LEN];
10811082
struct session_key auth_key;
10821083
struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */

fs/smb/client/connect.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
21832183
}
21842184

21852185
++delim;
2186+
/* BB consider adding support for password2 (Key Rotation) for multiuser in future */
21862187
ctx->password = kstrndup(delim, len, GFP_KERNEL);
21872188
if (!ctx->password) {
21882189
cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n",
@@ -2206,6 +2207,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
22062207
kfree(ctx->username);
22072208
ctx->username = NULL;
22082209
kfree_sensitive(ctx->password);
2210+
/* no need to free ctx->password2 since not allocated in this path */
22092211
ctx->password = NULL;
22102212
goto out_key_put;
22112213
}
@@ -2317,6 +2319,12 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
23172319
if (!ses->password)
23182320
goto get_ses_fail;
23192321
}
2322+
/* ctx->password freed at unmount */
2323+
if (ctx->password2) {
2324+
ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
2325+
if (!ses->password2)
2326+
goto get_ses_fail;
2327+
}
23202328
if (ctx->domainname) {
23212329
ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL);
23222330
if (!ses->domainName)

fs/smb/client/fs_context.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
162162
fsparam_string("username", Opt_user),
163163
fsparam_string("pass", Opt_pass),
164164
fsparam_string("password", Opt_pass),
165+
fsparam_string("password2", Opt_pass2),
165166
fsparam_string("ip", Opt_ip),
166167
fsparam_string("addr", Opt_ip),
167168
fsparam_string("domain", Opt_domain),
@@ -345,6 +346,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
345346
new_ctx->nodename = NULL;
346347
new_ctx->username = NULL;
347348
new_ctx->password = NULL;
349+
new_ctx->password2 = NULL;
348350
new_ctx->server_hostname = NULL;
349351
new_ctx->domainname = NULL;
350352
new_ctx->UNC = NULL;
@@ -357,6 +359,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
357359
DUP_CTX_STR(prepath);
358360
DUP_CTX_STR(username);
359361
DUP_CTX_STR(password);
362+
DUP_CTX_STR(password2);
360363
DUP_CTX_STR(server_hostname);
361364
DUP_CTX_STR(UNC);
362365
DUP_CTX_STR(source);
@@ -905,6 +908,8 @@ static int smb3_reconfigure(struct fs_context *fc)
905908
else {
906909
kfree_sensitive(ses->password);
907910
ses->password = kstrdup(ctx->password, GFP_KERNEL);
911+
kfree_sensitive(ses->password2);
912+
ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
908913
}
909914
STEAL_STRING(cifs_sb, ctx, domainname);
910915
STEAL_STRING(cifs_sb, ctx, nodename);
@@ -1305,6 +1310,18 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
13051310
goto cifs_parse_mount_err;
13061311
}
13071312
break;
1313+
case Opt_pass2:
1314+
kfree_sensitive(ctx->password2);
1315+
ctx->password2 = NULL;
1316+
if (strlen(param->string) == 0)
1317+
break;
1318+
1319+
ctx->password2 = kstrdup(param->string, GFP_KERNEL);
1320+
if (ctx->password2 == NULL) {
1321+
cifs_errorf(fc, "OOM when copying password2 string\n");
1322+
goto cifs_parse_mount_err;
1323+
}
1324+
break;
13081325
case Opt_ip:
13091326
if (strlen(param->string) == 0) {
13101327
ctx->got_ip = false;
@@ -1608,6 +1625,8 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
16081625
cifs_parse_mount_err:
16091626
kfree_sensitive(ctx->password);
16101627
ctx->password = NULL;
1628+
kfree_sensitive(ctx->password2);
1629+
ctx->password2 = NULL;
16111630
return -EINVAL;
16121631
}
16131632

@@ -1713,6 +1732,8 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
17131732
ctx->username = NULL;
17141733
kfree_sensitive(ctx->password);
17151734
ctx->password = NULL;
1735+
kfree_sensitive(ctx->password2);
1736+
ctx->password2 = NULL;
17161737
kfree(ctx->server_hostname);
17171738
ctx->server_hostname = NULL;
17181739
kfree(ctx->UNC);

fs/smb/client/fs_context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ enum cifs_param {
145145
Opt_source,
146146
Opt_user,
147147
Opt_pass,
148+
Opt_pass2,
148149
Opt_ip,
149150
Opt_domain,
150151
Opt_srcaddr,
@@ -177,6 +178,7 @@ struct smb3_fs_context {
177178

178179
char *username;
179180
char *password;
181+
char *password2;
180182
char *domainname;
181183
char *source;
182184
char *server_hostname;

fs/smb/client/misc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
9898
kfree(buf_to_free->serverDomain);
9999
kfree(buf_to_free->serverNOS);
100100
kfree_sensitive(buf_to_free->password);
101+
kfree_sensitive(buf_to_free->password2);
101102
kfree(buf_to_free->user_name);
102103
kfree(buf_to_free->domainName);
103104
kfree_sensitive(buf_to_free->auth_key.response);

fs/smb/client/smb2pdu.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,17 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
367367
}
368368

369369
rc = cifs_setup_session(0, ses, server, nls_codepage);
370+
if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
371+
/*
372+
* Try alternate password for next reconnect (key rotation
373+
* could be enabled on the server e.g.) if an alternate
374+
* password is available and the current password is expired,
375+
* but do not swap on non pwd related errors like host down
376+
*/
377+
if (ses->password2)
378+
swap(ses->password2, ses->password);
379+
}
380+
370381
if ((rc == -EACCES) && !tcon->retry) {
371382
mutex_unlock(&ses->session_mutex);
372383
rc = -EHOSTDOWN;

0 commit comments

Comments
 (0)