]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: allow changing password during remount
authorSteve French <stfrench@microsoft.com>
Tue, 13 Feb 2024 06:40:01 +0000 (00:40 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Apr 2024 13:11:22 +0000 (15:11 +0200)
[ Upstream commit c1eb537bf4560b3ad4df606c266c665624f3b502 ]

There are cases where a session is disconnected and password has changed
on the server (or expired) for this user and this currently can not
be fixed without unmount and mounting again.  This patch allows
remount to change the password (for the non Kerberos case, Kerberos
ticket refresh is handled differently) when the session is disconnected
and the user can not reconnect due to still using old password.

Future patches should also allow us to setup the keyring (cifscreds)
to have an "alternate password" so we would be able to change
the password before the session drops (without the risk of races
between when the password changes and the disconnect occurs -
ie cases where the old password is still needed because the new
password has not fully rolled out to all servers yet).

Cc: stable@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/cifs_debug.c
fs/smb/client/cifsglob.h
fs/smb/client/fs_context.c
fs/smb/client/smb2pdu.c

index 60027f5aebe87f2050584994ee68699ae7ed6e5b..04a6351a9295bc3143f90ddad4fb42f1a8fecc9f 100644 (file)
@@ -488,6 +488,8 @@ skip_rdma:
                                ses->ses_count, ses->serverOS, ses->serverNOS,
                                ses->capabilities, ses->ses_status);
                        }
+                       if (ses->expired_pwd)
+                               seq_puts(m, "password no longer valid ");
                        spin_unlock(&ses->ses_lock);
 
                        seq_printf(m, "\n\tSecurity type: %s ",
index 57bf6b406c590d770e5bf5343e183bf37151df00..91a4061233f1adeb59007332a86ee30665d77070 100644 (file)
@@ -1052,6 +1052,7 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool domainAuto:1;
+       bool expired_pwd;  /* track if access denied or expired pwd so can know if need to update */
        unsigned int flags;
        __u16 session_flags;
        __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
index 6ecbf48d0f0c6281b9fa1c7bde9d058d40c41b6c..e4a6b240d2263961de5ee9bf044d354d8d5a916f 100644 (file)
@@ -771,7 +771,7 @@ static void smb3_fs_context_free(struct fs_context *fc)
  */
 static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
                                       struct smb3_fs_context *new_ctx,
-                                      struct smb3_fs_context *old_ctx)
+                                      struct smb3_fs_context *old_ctx, bool need_recon)
 {
        if (new_ctx->posix_paths != old_ctx->posix_paths) {
                cifs_errorf(fc, "can not change posixpaths during remount\n");
@@ -797,8 +797,15 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
        }
        if (new_ctx->password &&
            (!old_ctx->password || strcmp(new_ctx->password, old_ctx->password))) {
-               cifs_errorf(fc, "can not change password during remount\n");
-               return -EINVAL;
+               if (need_recon == false) {
+                       cifs_errorf(fc,
+                                   "can not change password of active session during remount\n");
+                       return -EINVAL;
+               } else if (old_ctx->sectype == Kerberos) {
+                       cifs_errorf(fc,
+                                   "can not change password for Kerberos via remount\n");
+                       return -EINVAL;
+               }
        }
        if (new_ctx->domainname &&
            (!old_ctx->domainname || strcmp(new_ctx->domainname, old_ctx->domainname))) {
@@ -842,9 +849,14 @@ static int smb3_reconfigure(struct fs_context *fc)
        struct smb3_fs_context *ctx = smb3_fc2context(fc);
        struct dentry *root = fc->root;
        struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
+       struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
+       bool need_recon = false;
        int rc;
 
-       rc = smb3_verify_reconfigure_ctx(fc, ctx, cifs_sb->ctx);
+       if (ses->expired_pwd)
+               need_recon = true;
+
+       rc = smb3_verify_reconfigure_ctx(fc, ctx, cifs_sb->ctx, need_recon);
        if (rc)
                return rc;
 
@@ -857,7 +869,12 @@ static int smb3_reconfigure(struct fs_context *fc)
        STEAL_STRING(cifs_sb, ctx, UNC);
        STEAL_STRING(cifs_sb, ctx, source);
        STEAL_STRING(cifs_sb, ctx, username);
-       STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
+       if (need_recon == false)
+               STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
+       else  {
+               kfree_sensitive(ses->password);
+               ses->password = kstrdup(ctx->password, GFP_KERNEL);
+       }
        STEAL_STRING(cifs_sb, ctx, domainname);
        STEAL_STRING(cifs_sb, ctx, nodename);
        STEAL_STRING(cifs_sb, ctx, iocharset);
index 9d34a55fdb5e4140e5fb62f6b63a50e8a5218b2a..fca55702b51adacc71b5e4c468a45e705cf08c4e 100644 (file)
@@ -1536,6 +1536,11 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
                            &sess_data->buf0_type,
                            CIFS_LOG_ERROR | CIFS_SESS_OP, &rsp_iov);
        cifs_small_buf_release(sess_data->iov[0].iov_base);
+       if (rc == 0)
+               sess_data->ses->expired_pwd = false;
+       else if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED))
+               sess_data->ses->expired_pwd = true;
+
        memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
 
        return rc;