]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: fix ntlmssp on old servers
authorPaulo Alcantara <pc@cjr.nz>
Wed, 25 May 2022 12:37:04 +0000 (07:37 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jun 2022 08:29:29 +0000 (10:29 +0200)
commit de3a9e943ddecba8d2ac1dde4cfff538e5c6a7b9 upstream.

Some older servers seem to require the workstation name during ntlmssp
to be at most 15 chars (RFC1001 name length), so truncate it before
sending when using insecure dialects.

Link: https://lore.kernel.org/r/e6837098-15d9-acb6-7e34-1923cf8c6fe1@winds.org
Reported-by: Byron Stanoszek <gandalf@winds.org>
Tested-by: Byron Stanoszek <gandalf@winds.org>
Fixes: 49bd49f983b5 ("cifs: send workstation name during ntlmssp session setup")
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/fs_context.c
fs/cifs/fs_context.h
fs/cifs/misc.c
fs/cifs/sess.c

index 8de977c359b1132462c533996187d1cb1b00a873..5024b6792dab6751b0087d67421088d90cab888f 100644 (file)
@@ -944,7 +944,7 @@ struct cifs_ses {
                                   and after mount option parsing we fill it */
        char *domainName;
        char *password;
-       char *workstation_name;
+       char workstation_name[CIFS_MAX_WORKSTATION_LEN];
        struct session_key auth_key;
        struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
        enum securityEnum sectype; /* what security flavor was specified? */
@@ -1979,4 +1979,17 @@ static inline bool cifs_is_referral_server(struct cifs_tcon *tcon,
        return is_tcon_dfs(tcon) || (ref && (ref->flags & DFSREF_REFERRAL_SERVER));
 }
 
+static inline size_t ntlmssp_workstation_name_size(const struct cifs_ses *ses)
+{
+       if (WARN_ON_ONCE(!ses || !ses->server))
+               return 0;
+       /*
+        * Make workstation name no more than 15 chars when using insecure dialects as some legacy
+        * servers do require it during NTLMSSP.
+        */
+       if (ses->server->dialect <= SMB20_PROT_ID)
+               return min_t(size_t, sizeof(ses->workstation_name), RFC1001_NAME_LEN_WITH_NULL);
+       return sizeof(ses->workstation_name);
+}
+
 #endif /* _CIFS_GLOB_H */
index 0505d7782e4255d1c9ae7ada35e1d3b4733ffa57..2a639fc79c300c55632b552b66c658527ae1b904 100644 (file)
@@ -2037,18 +2037,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
                }
        }
 
-       ctx->workstation_name = kstrdup(ses->workstation_name, GFP_KERNEL);
-       if (!ctx->workstation_name) {
-               cifs_dbg(FYI, "Unable to allocate memory for workstation_name\n");
-               rc = -ENOMEM;
-               kfree(ctx->username);
-               ctx->username = NULL;
-               kfree_sensitive(ctx->password);
-               ctx->password = NULL;
-               kfree(ctx->domainname);
-               ctx->domainname = NULL;
-               goto out_key_put;
-       }
+       strscpy(ctx->workstation_name, ses->workstation_name, sizeof(ctx->workstation_name));
 
 out_key_put:
        up_read(&key->sem);
@@ -2157,12 +2146,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
                if (!ses->domainName)
                        goto get_ses_fail;
        }
-       if (ctx->workstation_name) {
-               ses->workstation_name = kstrdup(ctx->workstation_name,
-                                               GFP_KERNEL);
-               if (!ses->workstation_name)
-                       goto get_ses_fail;
-       }
+
+       strscpy(ses->workstation_name, ctx->workstation_name, sizeof(ses->workstation_name));
+
        if (ctx->domainauto)
                ses->domainAuto = ctx->domainauto;
        ses->cred_uid = ctx->cred_uid;
index a92e9eec521f35ede489af492b56a50af48b30f4..fbb0e98c7d2c4b9d99e738e2ff646ec80e048573 100644 (file)
@@ -312,7 +312,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
        new_ctx->password = NULL;
        new_ctx->server_hostname = NULL;
        new_ctx->domainname = NULL;
-       new_ctx->workstation_name = NULL;
        new_ctx->UNC = NULL;
        new_ctx->source = NULL;
        new_ctx->iocharset = NULL;
@@ -327,7 +326,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
        DUP_CTX_STR(UNC);
        DUP_CTX_STR(source);
        DUP_CTX_STR(domainname);
-       DUP_CTX_STR(workstation_name);
        DUP_CTX_STR(nodename);
        DUP_CTX_STR(iocharset);
 
@@ -766,8 +764,7 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
                cifs_errorf(fc, "can not change domainname during remount\n");
                return -EINVAL;
        }
-       if (new_ctx->workstation_name &&
-           (!old_ctx->workstation_name || strcmp(new_ctx->workstation_name, old_ctx->workstation_name))) {
+       if (strcmp(new_ctx->workstation_name, old_ctx->workstation_name)) {
                cifs_errorf(fc, "can not change workstation_name during remount\n");
                return -EINVAL;
        }
@@ -814,7 +811,6 @@ static int smb3_reconfigure(struct fs_context *fc)
        STEAL_STRING(cifs_sb, ctx, username);
        STEAL_STRING(cifs_sb, ctx, password);
        STEAL_STRING(cifs_sb, ctx, domainname);
-       STEAL_STRING(cifs_sb, ctx, workstation_name);
        STEAL_STRING(cifs_sb, ctx, nodename);
        STEAL_STRING(cifs_sb, ctx, iocharset);
 
@@ -1467,22 +1463,15 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
 
 int smb3_init_fs_context(struct fs_context *fc)
 {
-       int rc;
        struct smb3_fs_context *ctx;
        char *nodename = utsname()->nodename;
        int i;
 
        ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
-       if (unlikely(!ctx)) {
-               rc = -ENOMEM;
-               goto err_exit;
-       }
+       if (unlikely(!ctx))
+               return -ENOMEM;
 
-       ctx->workstation_name = kstrdup(nodename, GFP_KERNEL);
-       if (unlikely(!ctx->workstation_name)) {
-               rc = -ENOMEM;
-               goto err_exit;
-       }
+       strscpy(ctx->workstation_name, nodename, sizeof(ctx->workstation_name));
 
        /*
         * does not have to be perfect mapping since field is
@@ -1555,14 +1544,6 @@ int smb3_init_fs_context(struct fs_context *fc)
        fc->fs_private = ctx;
        fc->ops = &smb3_fs_context_ops;
        return 0;
-
-err_exit:
-       if (ctx) {
-               kfree(ctx->workstation_name);
-               kfree(ctx);
-       }
-
-       return rc;
 }
 
 void
@@ -1588,8 +1569,6 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
        ctx->source = NULL;
        kfree(ctx->domainname);
        ctx->domainname = NULL;
-       kfree(ctx->workstation_name);
-       ctx->workstation_name = NULL;
        kfree(ctx->nodename);
        ctx->nodename = NULL;
        kfree(ctx->iocharset);
index e54090d9ef368e7562b17e61384bc600df4cf815..3a156c14392546c4264753a5021e4aff92192b18 100644 (file)
@@ -170,7 +170,7 @@ struct smb3_fs_context {
        char *server_hostname;
        char *UNC;
        char *nodename;
-       char *workstation_name;
+       char workstation_name[CIFS_MAX_WORKSTATION_LEN];
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
        char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
index afaf59c221936f3023c518be2ac6f2d95a9e1e28..114810e563a9baee5b33d55ba36e5c82a14d9561 100644 (file)
@@ -95,7 +95,6 @@ sesInfoFree(struct cifs_ses *buf_to_free)
        kfree_sensitive(buf_to_free->password);
        kfree(buf_to_free->user_name);
        kfree(buf_to_free->domainName);
-       kfree(buf_to_free->workstation_name);
        kfree_sensitive(buf_to_free->auth_key.response);
        kfree(buf_to_free->iface_list);
        kfree_sensitive(buf_to_free);
index 32f478c7a66d86242363ff664b4a632ab277bc52..1a0995bb5d90c73aba194254fa34970b5d150c1e 100644 (file)
@@ -714,9 +714,9 @@ static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
        else
                sz += sizeof(__le16);
 
-       if (ses->workstation_name)
+       if (ses->workstation_name[0])
                sz += sizeof(__le16) * strnlen(ses->workstation_name,
-                       CIFS_MAX_WORKSTATION_LEN);
+                                              ntlmssp_workstation_name_size(ses));
        else
                sz += sizeof(__le16);
 
@@ -960,7 +960,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
 
        cifs_security_buffer_from_str(&sec_blob->WorkstationName,
                                      ses->workstation_name,
-                                     CIFS_MAX_WORKSTATION_LEN,
+                                     ntlmssp_workstation_name_size(ses),
                                      *pbuffer, &tmp,
                                      nls_cp);