From 561f82a3a24c96fe84fc7ecac11f02b2afd11031 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Thu, 17 Aug 2023 12:34:03 -0300 Subject: smb: client: rename cifs_dfs_ref.c to namespace.c The automount code will handle both DFS links and reparse files that are mount points. Signed-off-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- fs/smb/client/Makefile | 2 +- fs/smb/client/cifs_dfs_ref.c | 238 ------------------------------------------- fs/smb/client/namespace.c | 238 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+), 239 deletions(-) delete mode 100644 fs/smb/client/cifs_dfs_ref.c create mode 100644 fs/smb/client/namespace.c (limited to 'fs/smb') diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile index 304a7f6cc13a..851e6ba65e9b 100644 --- a/fs/smb/client/Makefile +++ b/fs/smb/client/Makefile @@ -21,7 +21,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o -cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o +cifs-$(CONFIG_CIFS_DFS_UPCALL) += namespace.o dfs_cache.o dfs.o cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o diff --git a/fs/smb/client/cifs_dfs_ref.c b/fs/smb/client/cifs_dfs_ref.c deleted file mode 100644 index b1c2499b1c3b..000000000000 --- a/fs/smb/client/cifs_dfs_ref.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Contains the CIFS DFS referral mounting routines used for handling - * traversal via DFS junction point - * - * Copyright (c) 2007 Igor Mammedov - * Copyright (C) International Business Machines Corp., 2008 - * Author(s): Igor Mammedov (niallain@gmail.com) - * Steve French (sfrench@us.ibm.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include "cifsglob.h" -#include "cifsproto.h" -#include "cifsfs.h" -#include "dns_resolve.h" -#include "cifs_debug.h" -#include "dfs.h" -#include "fs_context.h" - -static LIST_HEAD(cifs_dfs_automount_list); - -static void cifs_dfs_expire_automounts(struct work_struct *work); -static DECLARE_DELAYED_WORK(cifs_dfs_automount_task, - cifs_dfs_expire_automounts); -static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ; - -static void cifs_dfs_expire_automounts(struct work_struct *work) -{ - struct list_head *list = &cifs_dfs_automount_list; - - mark_mounts_for_expiry(list); - if (!list_empty(list)) - schedule_delayed_work(&cifs_dfs_automount_task, - cifs_dfs_mountpoint_expiry_timeout); -} - -void cifs_dfs_release_automount_timer(void) -{ - BUG_ON(!list_empty(&cifs_dfs_automount_list)); - cancel_delayed_work_sync(&cifs_dfs_automount_task); -} - -/** - * cifs_build_devname - build a devicename from a UNC and optional prepath - * @nodename: pointer to UNC string - * @prepath: pointer to prefixpath (or NULL if there isn't one) - * - * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer - * big enough to hold the final thing. Copy the UNC from the nodename, and - * concatenate the prepath onto the end of it if there is one. - * - * Returns pointer to the built string, or a ERR_PTR. Caller is responsible - * for freeing the returned string. - */ -char * -cifs_build_devname(char *nodename, const char *prepath) -{ - size_t pplen; - size_t unclen; - char *dev; - char *pos; - - /* skip over any preceding delimiters */ - nodename += strspn(nodename, "\\"); - if (!*nodename) - return ERR_PTR(-EINVAL); - - /* get length of UNC and set pos to last char */ - unclen = strlen(nodename); - pos = nodename + unclen - 1; - - /* trim off any trailing delimiters */ - while (*pos == '\\') { - --pos; - --unclen; - } - - /* allocate a buffer: - * +2 for preceding "//" - * +1 for delimiter between UNC and prepath - * +1 for trailing NULL - */ - pplen = prepath ? strlen(prepath) : 0; - dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL); - if (!dev) - return ERR_PTR(-ENOMEM); - - pos = dev; - /* add the initial "//" */ - *pos = '/'; - ++pos; - *pos = '/'; - ++pos; - - /* copy in the UNC portion from referral */ - memcpy(pos, nodename, unclen); - pos += unclen; - - /* copy the prefixpath remainder (if there is one) */ - if (pplen) { - *pos = '/'; - ++pos; - memcpy(pos, prepath, pplen); - pos += pplen; - } - - /* NULL terminator */ - *pos = '\0'; - - convert_delimiter(dev, '/'); - return dev; -} - -static int set_dest_addr(struct smb3_fs_context *ctx) -{ - struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; - int rc; - - rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL); - if (!rc) - cifs_set_port(addr, ctx->port); - return rc; -} - -/* - * Create a vfsmount that we can automount - */ -static struct vfsmount *cifs_dfs_do_automount(struct path *path) -{ - int rc; - struct dentry *mntpt = path->dentry; - struct fs_context *fc; - struct cifs_sb_info *cifs_sb; - void *page = NULL; - struct smb3_fs_context *ctx, *cur_ctx; - struct smb3_fs_context tmp; - char *full_path; - struct vfsmount *mnt; - - if (IS_ROOT(mntpt)) - return ERR_PTR(-ESTALE); - - /* - * The MSDFS spec states that paths in DFS referral requests and - * responses must be prefixed by a single '\' character instead of - * the double backslashes usually used in the UNC. This function - * gives us the latter, so we must adjust the result. - */ - cifs_sb = CIFS_SB(mntpt->d_sb); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) - return ERR_PTR(-EREMOTE); - - cur_ctx = cifs_sb->ctx; - - fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt); - if (IS_ERR(fc)) - return ERR_CAST(fc); - - ctx = smb3_fc2context(fc); - - page = alloc_dentry_path(); - full_path = dfs_get_automount_devname(mntpt, page); - if (IS_ERR(full_path)) { - mnt = ERR_CAST(full_path); - goto out; - } - - tmp = *cur_ctx; - tmp.source = NULL; - tmp.leaf_fullpath = NULL; - tmp.UNC = tmp.prepath = NULL; - tmp.dfs_root_ses = NULL; - - rc = smb3_fs_context_dup(ctx, &tmp); - if (rc) { - mnt = ERR_PTR(rc); - goto out; - } - - rc = smb3_parse_devname(full_path, ctx); - if (rc) { - mnt = ERR_PTR(rc); - goto out; - } - - ctx->source = smb3_fs_context_fullpath(ctx, '/'); - if (IS_ERR(ctx->source)) { - mnt = ERR_CAST(ctx->source); - ctx->source = NULL; - goto out; - } - cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n", - __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr); - - rc = set_dest_addr(ctx); - if (!rc) - mnt = fc_mount(fc); - else - mnt = ERR_PTR(rc); - -out: - put_fs_context(fc); - free_dentry_path(page); - return mnt; -} - -/* - * Attempt to automount the referral - */ -struct vfsmount *cifs_dfs_d_automount(struct path *path) -{ - struct vfsmount *newmnt; - - cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry); - - newmnt = cifs_dfs_do_automount(path); - if (IS_ERR(newmnt)) { - cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__); - return newmnt; - } - - mntget(newmnt); /* prevent immediate expiration */ - mnt_set_expiry(newmnt, &cifs_dfs_automount_list); - schedule_delayed_work(&cifs_dfs_automount_task, - cifs_dfs_mountpoint_expiry_timeout); - cifs_dbg(FYI, "leaving %s [ok]\n" , __func__); - return newmnt; -} - -const struct inode_operations cifs_dfs_referral_inode_operations = { -}; diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c new file mode 100644 index 000000000000..b1c2499b1c3b --- /dev/null +++ b/fs/smb/client/namespace.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Contains the CIFS DFS referral mounting routines used for handling + * traversal via DFS junction point + * + * Copyright (c) 2007 Igor Mammedov + * Copyright (C) International Business Machines Corp., 2008 + * Author(s): Igor Mammedov (niallain@gmail.com) + * Steve French (sfrench@us.ibm.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifsfs.h" +#include "dns_resolve.h" +#include "cifs_debug.h" +#include "dfs.h" +#include "fs_context.h" + +static LIST_HEAD(cifs_dfs_automount_list); + +static void cifs_dfs_expire_automounts(struct work_struct *work); +static DECLARE_DELAYED_WORK(cifs_dfs_automount_task, + cifs_dfs_expire_automounts); +static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ; + +static void cifs_dfs_expire_automounts(struct work_struct *work) +{ + struct list_head *list = &cifs_dfs_automount_list; + + mark_mounts_for_expiry(list); + if (!list_empty(list)) + schedule_delayed_work(&cifs_dfs_automount_task, + cifs_dfs_mountpoint_expiry_timeout); +} + +void cifs_dfs_release_automount_timer(void) +{ + BUG_ON(!list_empty(&cifs_dfs_automount_list)); + cancel_delayed_work_sync(&cifs_dfs_automount_task); +} + +/** + * cifs_build_devname - build a devicename from a UNC and optional prepath + * @nodename: pointer to UNC string + * @prepath: pointer to prefixpath (or NULL if there isn't one) + * + * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer + * big enough to hold the final thing. Copy the UNC from the nodename, and + * concatenate the prepath onto the end of it if there is one. + * + * Returns pointer to the built string, or a ERR_PTR. Caller is responsible + * for freeing the returned string. + */ +char * +cifs_build_devname(char *nodename, const char *prepath) +{ + size_t pplen; + size_t unclen; + char *dev; + char *pos; + + /* skip over any preceding delimiters */ + nodename += strspn(nodename, "\\"); + if (!*nodename) + return ERR_PTR(-EINVAL); + + /* get length of UNC and set pos to last char */ + unclen = strlen(nodename); + pos = nodename + unclen - 1; + + /* trim off any trailing delimiters */ + while (*pos == '\\') { + --pos; + --unclen; + } + + /* allocate a buffer: + * +2 for preceding "//" + * +1 for delimiter between UNC and prepath + * +1 for trailing NULL + */ + pplen = prepath ? strlen(prepath) : 0; + dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + pos = dev; + /* add the initial "//" */ + *pos = '/'; + ++pos; + *pos = '/'; + ++pos; + + /* copy in the UNC portion from referral */ + memcpy(pos, nodename, unclen); + pos += unclen; + + /* copy the prefixpath remainder (if there is one) */ + if (pplen) { + *pos = '/'; + ++pos; + memcpy(pos, prepath, pplen); + pos += pplen; + } + + /* NULL terminator */ + *pos = '\0'; + + convert_delimiter(dev, '/'); + return dev; +} + +static int set_dest_addr(struct smb3_fs_context *ctx) +{ + struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; + int rc; + + rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL); + if (!rc) + cifs_set_port(addr, ctx->port); + return rc; +} + +/* + * Create a vfsmount that we can automount + */ +static struct vfsmount *cifs_dfs_do_automount(struct path *path) +{ + int rc; + struct dentry *mntpt = path->dentry; + struct fs_context *fc; + struct cifs_sb_info *cifs_sb; + void *page = NULL; + struct smb3_fs_context *ctx, *cur_ctx; + struct smb3_fs_context tmp; + char *full_path; + struct vfsmount *mnt; + + if (IS_ROOT(mntpt)) + return ERR_PTR(-ESTALE); + + /* + * The MSDFS spec states that paths in DFS referral requests and + * responses must be prefixed by a single '\' character instead of + * the double backslashes usually used in the UNC. This function + * gives us the latter, so we must adjust the result. + */ + cifs_sb = CIFS_SB(mntpt->d_sb); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) + return ERR_PTR(-EREMOTE); + + cur_ctx = cifs_sb->ctx; + + fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt); + if (IS_ERR(fc)) + return ERR_CAST(fc); + + ctx = smb3_fc2context(fc); + + page = alloc_dentry_path(); + full_path = dfs_get_automount_devname(mntpt, page); + if (IS_ERR(full_path)) { + mnt = ERR_CAST(full_path); + goto out; + } + + tmp = *cur_ctx; + tmp.source = NULL; + tmp.leaf_fullpath = NULL; + tmp.UNC = tmp.prepath = NULL; + tmp.dfs_root_ses = NULL; + + rc = smb3_fs_context_dup(ctx, &tmp); + if (rc) { + mnt = ERR_PTR(rc); + goto out; + } + + rc = smb3_parse_devname(full_path, ctx); + if (rc) { + mnt = ERR_PTR(rc); + goto out; + } + + ctx->source = smb3_fs_context_fullpath(ctx, '/'); + if (IS_ERR(ctx->source)) { + mnt = ERR_CAST(ctx->source); + ctx->source = NULL; + goto out; + } + cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n", + __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr); + + rc = set_dest_addr(ctx); + if (!rc) + mnt = fc_mount(fc); + else + mnt = ERR_PTR(rc); + +out: + put_fs_context(fc); + free_dentry_path(page); + return mnt; +} + +/* + * Attempt to automount the referral + */ +struct vfsmount *cifs_dfs_d_automount(struct path *path) +{ + struct vfsmount *newmnt; + + cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry); + + newmnt = cifs_dfs_do_automount(path); + if (IS_ERR(newmnt)) { + cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__); + return newmnt; + } + + mntget(newmnt); /* prevent immediate expiration */ + mnt_set_expiry(newmnt, &cifs_dfs_automount_list); + schedule_delayed_work(&cifs_dfs_automount_task, + cifs_dfs_mountpoint_expiry_timeout); + cifs_dbg(FYI, "leaving %s [ok]\n" , __func__); + return newmnt; +} + +const struct inode_operations cifs_dfs_referral_inode_operations = { +}; -- cgit v1.2.3