From patchwork Fri Jan 29 03:44:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 12055111 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F56AC433DB for ; Fri, 29 Jan 2021 03:45:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B105764E00 for ; Fri, 29 Jan 2021 03:45:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229786AbhA2DpT (ORCPT ); Thu, 28 Jan 2021 22:45:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44386 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229757AbhA2DpS (ORCPT ); Thu, 28 Jan 2021 22:45:18 -0500 Received: from mail-lf1-x12d.google.com (mail-lf1-x12d.google.com [IPv6:2a00:1450:4864:20::12d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 99DABC061573 for ; Thu, 28 Jan 2021 19:44:37 -0800 (PST) Received: by mail-lf1-x12d.google.com with SMTP id m22so10572274lfg.5 for ; Thu, 28 Jan 2021 19:44:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to:cc; bh=8udyT3BcMxT6mSw0BNcjrdpUFUQkm64PYmtNRAXOD1c=; b=jR+UTsN/ZNXUdK0O1nDIjIleef5YWfeMbfO5tkoNyfuivO0mGBgk0hsTrNdmCYRQw5 1awHA6Tra0VrfNwPLLyeIUTKPnAh+ECE83PrrF8EU+TItuqwaO5+e3DJbnBZ5rs87+2K NedJT7AOboBDGGi3SLKopkjqYooDw/M5UfJdIfRKgBLNkgzlI8z3QTurtIKSQuZL+CW4 o3Rrpf8ZoKmTGxC1qWEGAOi4P1UrgbWkvE1Tn0tyxc0Y+nlpc0Gt1EE7h4zKrkpCYjA0 Z0Y2AGc7fTn4X/IGRd2Rg6bwgAZLJXO/y969tj+bVYCnWHyAFOmtz7X+qn0e039R3TjC EI9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to:cc; bh=8udyT3BcMxT6mSw0BNcjrdpUFUQkm64PYmtNRAXOD1c=; b=MCnXPjcj0DpIxCU1Mz6h4Ge3P9vLr9is1qPqKuf3HrI20Gp91M8Wl63fhpUMotsAT3 IP4lF0DMhjnbnJEzL3RMJ/Ahd6UAvXFuv+Nv3wnrAGMaSSYHwNtb/jp5VT4VomjzyMfg xduYpaTOiFR+wrCF6HiYEFqGAXxz8eHiL/U7JYmiB9orrdYeBe/8xsaycdDvIvxggH1H sEjOAOoVcgHeqU7UBTNtoWPvesZXQb2g+07dJoznNdEjBvcvD2Ev508LO+xmjfPSQYlR 0ESQCuBn/OdN6+B+x4ttmSK4pyA86ycv/gadO/C6DhvuSCDzGgD7ehnk93TMi60aMLIE 6onw== X-Gm-Message-State: AOAM532pOjMzDJ2zHbSiZIQoKFgyUuh8KMZbUnRknSKoQKDC0txXfrdy au5n6cvoGUU8eKlaoGSGxp8prq3MDDlySgsGWzH21qdC2l7nuQ== X-Google-Smtp-Source: ABdhPJx/W7F1dvhk+PMLGeTiIgCqrkceirMS0aURjfeHqFXwSzvamDdiclFODIXo+ddKz5UQusH60kr7tsPvjt5muXw= X-Received: by 2002:a05:6512:3254:: with SMTP id c20mr1138847lfr.282.1611891875585; Thu, 28 Jan 2021 19:44:35 -0800 (PST) MIME-Version: 1.0 From: Steve French Date: Thu, 28 Jan 2021 21:44:24 -0600 Message-ID: Subject: [PATCH] cifs: fix dfs domain referrals To: CIFS Cc: ronnie sahlberg , Paulo Alcantara Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Lightly updated patch from Ronnie/Paulo tentatively merged to cifs-2.6.git for-next (still waiting on the 2nd half of this - to fix DFS links, but this should fix some DFS problems - see below). The new mount API requires additional changes to how DFS is handled. Additional testing of DFS uncovered problems with domain based DFS referrals (a follow on patch addresses DFS links) which this patch addresses. Signed-off-by: Ronnie Sahlberg Signed-off-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 12 ++++++++---- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsproto.h | 6 ++++-- fs/cifs/connect.c | 32 ++++++++++++++++++++++++++------ fs/cifs/dfs_cache.c | 8 +++++--- fs/cifs/fs_context.c | 31 +++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 16 deletions(-) * fields with the result. Returns 0 on success and an error otherwise -- From 0d4873f9aa4ff8fc1d63a5755395b794d32ce046 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 28 Jan 2021 21:35:10 -0600 Subject: [PATCH] cifs: fix dfs domain referrals The new mount API requires additional changes to how DFS is handled. Additional testing of DFS uncovered problems with domain based DFS referrals (a follow on patch addresses DFS links) which this patch addresses. Signed-off-by: Ronnie Sahlberg Signed-off-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 12 ++++++++---- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsproto.h | 6 ++++-- fs/cifs/connect.c | 32 ++++++++++++++++++++++++++------ fs/cifs/dfs_cache.c | 8 +++++--- fs/cifs/fs_context.c | 31 +++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 16 deletions(-) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index e4c6ae47a796..6b1ce4efb591 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -133,8 +133,9 @@ cifs_build_devname(char *nodename, const char *prepath) * Caller is responsible for freeing returned value if it is not error. */ char *cifs_compose_mount_options(const char *sb_mountdata, - const char *fullpath, - const struct dfs_info3_param *ref) + const char *fullpath, + const struct dfs_info3_param *ref, + char **devname) { int rc; char *name; @@ -231,7 +232,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata, strcat(mountdata, "ip="); strcat(mountdata, srvIP); - kfree(name); + if (devname) + *devname = name; + else + kfree(name); /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/ /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/ @@ -278,7 +282,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt, /* strip first '\' from fullpath */ mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, - fullpath + 1, NULL); + fullpath + 1, NULL, NULL); if (IS_ERR(mountdata)) { kfree(devname); return (struct vfsmount *)mountdata; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ce0d0037fd0a..e46da536ed33 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -822,7 +822,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out; } - rc = cifs_setup_volume_info(cifs_sb->ctx); + rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, old_ctx->UNC); if (rc) { root = ERR_PTR(rc); goto out; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 340ff81ee87b..32f7a013402e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -78,7 +78,8 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx, int add_treename); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *cifs_compose_mount_options(const char *sb_mountdata, - const char *fullpath, const struct dfs_info3_param *ref); + const char *fullpath, const struct dfs_info3_param *ref, + char **devname); /* extern void renew_parental_timestamps(struct dentry *direntry);*/ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server); @@ -89,6 +90,7 @@ extern void cifs_wake_up_task(struct mid_q_entry *mid); extern int cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid); extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); +extern int smb3_parse_opt(const char *options, const char *key, char **val); extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); extern int cifs_discard_remaining_data(struct TCP_Server_Info *server); extern int cifs_call_async(struct TCP_Server_Info *server, @@ -549,7 +551,7 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); extern int -cifs_setup_volume_info(struct smb3_fs_context *ctx); +cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname); extern struct TCP_Server_Info * cifs_find_tcp_session(struct smb3_fs_context *ctx); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c8ef24bac94f..10fe6d6d2dee 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2972,17 +2972,20 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ref_path, &referral, NULL); if (!rc) { + char *fake_devname = NULL; + mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, - full_path + 1, &referral); + full_path + 1, &referral, + &fake_devname); free_dfs_info_param(&referral); if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); mdata = NULL; } else { - smb3_cleanup_fs_context_contents(ctx); - rc = cifs_setup_volume_info(ctx); + rc = cifs_setup_volume_info(ctx, mdata, fake_devname); } + kfree(fake_devname); kfree(cifs_sb->ctx->mount_options); cifs_sb->ctx->mount_options = mdata; } @@ -3036,6 +3039,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, struct dfs_info3_param ref = {0}; char *mdata = NULL; struct smb3_fs_context fake_ctx = {NULL}; + char *fake_devname = NULL; cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); @@ -3044,16 +3048,18 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, return rc; mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, - full_path + 1, &ref); + full_path + 1, &ref, + &fake_devname); free_dfs_info_param(&ref); if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); mdata = NULL; } else - rc = cifs_setup_volume_info(&fake_ctx); + rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname); kfree(mdata); + kfree(fake_devname); if (!rc) { /* @@ -3122,10 +3128,24 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ * we should pass a clone of the original context? */ int -cifs_setup_volume_info(struct smb3_fs_context *ctx) +cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname) { int rc = 0; + smb3_parse_devname(devname, ctx); + + if (mntopts) { + char *ip; + + cifs_dbg(FYI, "%s: mntopts=%s\n", __func__, mntopts); + rc = smb3_parse_opt(mntopts, "ip", &ip); + if (!rc && !cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip, + strlen(ip))) { + cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__); + return -EINVAL; + } + } + if (ctx->nullauth) { cifs_dbg(FYI, "Anonymous login\n"); kfree(ctx->username); diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 0fdb0de7ff86..4950ab0486ae 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -1417,7 +1417,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, int rc; struct cache_entry *ce; struct dfs_info3_param ref = {0}; - char *mdata = NULL; + char *mdata = NULL, *devname = NULL; struct TCP_Server_Info *server; struct cifs_ses *ses; struct smb3_fs_context ctx = {NULL}; @@ -1444,7 +1444,8 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, up_read(&htable_rw_lock); - mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref); + mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref, + &devname); free_dfs_info_param(&ref); if (IS_ERR(mdata)) { @@ -1453,7 +1454,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, goto out; } - rc = cifs_setup_volume_info(&ctx); + rc = cifs_setup_volume_info(&ctx, NULL, devname); if (rc) { ses = ERR_PTR(rc); @@ -1472,6 +1473,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, smb3_cleanup_fs_context_contents(&ctx); kfree(mdata); kfree(rpath); + kfree(devname); return ses; } diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 27354417e988..5111aadfdb6b 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -401,6 +401,37 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) return 0; } +int smb3_parse_opt(const char *options, const char *key, char **val) +{ + int rc = -ENOENT; + char *opts, *orig, *p; + + orig = opts = kstrdup(options, GFP_KERNEL); + if (!opts) + return -ENOMEM; + + while ((p = strsep(&opts, ","))) { + char *nval; + + if (!*p) + continue; + if (strncasecmp(p, key, strlen(key))) + continue; + nval = strchr(p, '='); + if (nval) { + if (nval == p) + continue; + *nval++ = 0; + *val = kstrndup(nval, strlen(nval), GFP_KERNEL); + rc = !*val ? -ENOMEM : 0; + goto out; + } + } +out: + kfree(orig); + return rc; +} + /* * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath * fields with the result. Returns 0 on success and an error otherwise -- 2.27.0