From: Volker Lendecke Date: Fri, 4 Mar 2022 13:56:24 +0000 (+0100) Subject: smbd: Simplify non_widelink_open() X-Git-Tag: tevent-0.12.0~474 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=688604a423bb4dbb36ea6bc86e629d6ab0c4082d;p=thirdparty%2Fsamba.git smbd: Simplify non_widelink_open() Don't depend on fsp->fsp_flags.is_directory: We can always take the parent directory fname, chdir into it and openat(O_PATH|O_NOFOLLOW) the relative file name. To properly handle the symlink case without having O_PATH, upon failure we need the call to fstatat(AT_SYMLINK_NOFOLLOW) as a replacement for the fstat-call that we can do when we successfully opened the relative file name with O_NOFOLLOW. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Mar 10 19:19:06 UTC 2022 on sn-devel-184 --- diff --git a/source3/smbd/open.c b/source3/smbd/open.c index baae51f157e..b3df0985239 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -667,39 +667,32 @@ static NTSTATUS non_widelink_open(const struct files_struct *dirfsp, struct smb_filename *oldwd_fname = NULL; struct smb_filename *parent_dir_fname = NULL; bool have_opath = false; + bool is_share_root = false; int ret; #ifdef O_PATH have_opath = true; #endif - if (dirfsp == conn->cwd_fsp) { - if (fsp->fsp_flags.is_directory) { - parent_dir_fname = cp_smb_filename(talloc_tos(), smb_fname); - if (parent_dir_fname == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } + if (smb_fname->base_name[0] == '/') { + const char *connpath = SMB_VFS_CONNECTPATH(conn, smb_fname); + int cmp = strcmp(connpath, smb_fname->base_name); - smb_fname_rel = synthetic_smb_fname(parent_dir_fname, - ".", - smb_fname->stream_name, - &smb_fname->st, - smb_fname->twrp, - smb_fname->flags); - if (smb_fname_rel == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - } else { - status = SMB_VFS_PARENT_PATHNAME(fsp->conn, - talloc_tos(), - smb_fname, - &parent_dir_fname, - &smb_fname_rel); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } + if (cmp == 0) { + is_share_root = true; + } + } + + if (!is_share_root && (dirfsp == conn->cwd_fsp)) { + struct smb_filename *smb_fname_dot = NULL; + + status = SMB_VFS_PARENT_PATHNAME(fsp->conn, + talloc_tos(), + smb_fname, + &parent_dir_fname, + &smb_fname_rel); + if (!NT_STATUS_IS_OK(status)) { + goto out; } if (!ISDOT(parent_dir_fname->base_name)) { @@ -716,8 +709,21 @@ static NTSTATUS non_widelink_open(const struct files_struct *dirfsp, } } + smb_fname_dot = synthetic_smb_fname( + parent_dir_fname, + ".", + NULL, + NULL, + 0, + smb_fname->flags); + if (smb_fname_dot == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + /* Ensure the relative path is below the share. */ - status = check_reduced_name(conn, parent_dir_fname, smb_fname_rel); + status = check_reduced_name(conn, parent_dir_fname, smb_fname_dot); + TALLOC_FREE(smb_fname_dot); if (!NT_STATUS_IS_OK(status)) { goto out; } @@ -765,6 +771,11 @@ static NTSTATUS non_widelink_open(const struct files_struct *dirfsp, smb_fname_rel = smb_fname; } + if (!is_share_root) { + char *slash = strchr_m(smb_fname_rel->base_name, '/'); + SMB_ASSERT(slash == NULL); + } + flags |= O_NOFOLLOW; fd = SMB_VFS_OPENAT(conn, @@ -778,6 +789,25 @@ static NTSTATUS non_widelink_open(const struct files_struct *dirfsp, } fsp_set_fd(fsp, fd); + if ((fd == -1) && + NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) && + fsp->fsp_flags.is_pathref && + !have_opath) { + ret = SMB_VFS_FSTATAT( + fsp->conn, + dirfsp, + smb_fname_rel, + &fsp->fsp_name->st, + AT_SYMLINK_NOFOLLOW); + if (ret == -1) { + status = map_nt_error_from_unix(errno); + DBG_DEBUG("fstatat(%s) failed: %s\n", + smb_fname_str_dbg(smb_fname), + strerror(errno)); + goto out; + } + } + if (fd != -1) { ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); if (ret != 0) {