]> git.baikalelectronics.ru Git - kernel.git/commitdiff
cifs: fix ntlmssp on old servers
authorPaulo Alcantara <pc@cjr.nz>
Wed, 25 May 2022 12:37:04 +0000 (07:37 -0500)
committerSteve French <stfrench@microsoft.com>
Wed, 25 May 2022 12:41:22 +0000 (07:41 -0500)
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: 27e2b9c1c834 ("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>
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 b6c2a787be06f1f6a7919c15dc7bfd6cc533ef31..68da230c7f11284ecb7444805e63c5ae4a24944e 100644 (file)
@@ -952,7 +952,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? */
@@ -2018,4 +2018,17 @@ static inline u64 cifs_flock_len(struct file_lock *fl)
        return fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1;
 }
 
+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 199b076f7a6429b3071c41858bfc452f820a2221..53373a3649e17efbcb4e022a2685903108e12996 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 ca1d6957a0999aa26d0b68009e64ce97bd753714..8dc0d923ef6a98bb279d883ee01f2b03b6ca2a1a 100644 (file)
@@ -313,7 +313,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;
@@ -328,7 +327,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);
 
@@ -767,8 +765,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;
        }
@@ -815,7 +812,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);
 
@@ -1471,22 +1467,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
@@ -1559,14 +1548,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
@@ -1592,8 +1573,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 6576bb12f5f10ff7fd2c654f2870f5c295a4662b..5f093cb7e9b98ef791de8c01857c7f4136bbe9c5 100644 (file)
@@ -171,7 +171,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 af5e68a778110cae83a86e4fbbb2a34962c5eb78..35962a1a23b90f3775e58f3a642fe7a647253205 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 7c453f8701eb0f543925f66a0755f65bf7ad1b5b..c6214cfc575f3b1cd38e322e34ef04a7829591e5 100644 (file)
@@ -741,9 +741,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);
 
@@ -987,7 +987,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);