The branch, master has been updated via 6e5d79ff408 shadow_copy2: Remove an intermediate if-statement via f3350bff453 smbd: Remove non_widelink_open() support code via 2c8935cf3d7 smbd: Rewrite non_widelink_open() via 1bf0289b23c smbd: Make readlink_talloc() public via b4445ef9ab1 smbd: Slightly simplify non_widelink_open() via dbf93c9e0f5 shadow_copy2: Use dirfsp if it's around via fbc17c41aeb shadow_copy2: Use dirfsp for connectpath via e1ca4e28d89 vfs: Add dirfsp to connectpath_fn() from 9ef2f7345f0 s3:auth: Flush the GETPWSID in memory cache for NTLM auth
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 6e5d79ff40892b4f8f4962b36c1c3fb2d2ce9d55 Author: Volker Lendecke <v...@samba.org> Date: Thu Sep 15 08:55:01 2022 -0700 shadow_copy2: Remove an intermediate if-statement Now we always pass in a dirfsp from our only caller Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Sat Sep 17 05:15:04 UTC 2022 on sn-devel-184 commit f3350bff4532b35b3c9e99e0d0865ecec55e1be5 Author: Volker Lendecke <v...@samba.org> Date: Tue Sep 13 09:49:31 2022 -0700 smbd: Remove non_widelink_open() support code process_symlink_open() and check_reduced_name() are no longer used, non_widelink_open() was the only user of both. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 2c8935cf3d79dd09bc6d00793cf8fdaf031d21fc Author: Volker Lendecke <v...@samba.org> Date: Mon Sep 12 12:08:13 2022 -0700 smbd: Rewrite non_widelink_open() The previous implementation relied on recursion into non_widelink_open() via process_symlink_open(). The latter used readlink() to just make sure that the opened file is actually a symlink. This implementation now relies on a fstat/fstatat on failure to open a file, removing a little complexity deciphering error codes correctly. It also relies on reading the symlink in user space, turning the recursion into a loop. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 1bf0289b23cae861ec1fa3c4a46e267392315726 Author: Volker Lendecke <v...@samba.org> Date: Wed Sep 7 10:43:23 2022 +0200 smbd: Make readlink_talloc() public Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit b4445ef9ab1b258fbb17bb5aaa9998f14e4adfcc Author: Volker Lendecke <v...@samba.org> Date: Sat Sep 10 01:36:11 2022 -0700 smbd: Slightly simplify non_widelink_open() Avoid the "is_share_root" boolean: One special case less to take care of further down and in callers: Sanitize the relative name so that it can never contain a path separator Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit dbf93c9e0f5d592b3cbac4c705cb10dbc9e20ea6 Author: Volker Lendecke <v...@samba.org> Date: Thu Sep 15 06:11:55 2022 -0700 shadow_copy2: Use dirfsp if it's around Not used yet, and the "if" around dirfsp!=NULL will go away in a later patch. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit fbc17c41aeb8eae4e603aef0fe8822b468b57205 Author: Volker Lendecke <v...@samba.org> Date: Thu Sep 15 03:41:55 2022 +0000 shadow_copy2: Use dirfsp for connectpath Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit e1ca4e28d89237c8910e77146824ecc3444ce272 Author: Volker Lendecke <v...@samba.org> Date: Wed Sep 14 20:18:33 2022 -0700 vfs: Add dirfsp to connectpath_fn() So far we only call CONNECTPATH on full paths. In the future, we'll have a call that will not have converted a relative path to absolute just for efficiency reasons. To give shadow_copy2 the chance to still find the snapshot directory, pass the dirfsp down to it. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: examples/VFS/skel_opaque.c | 6 +- examples/VFS/skel_transparent.c | 8 +- source3/include/vfs.h | 11 +- source3/include/vfs_macros.h | 8 +- source3/modules/vfs_ceph.c | 6 +- source3/modules/vfs_default.c | 1 + source3/modules/vfs_full_audit.c | 8 +- source3/modules/vfs_glusterfs.c | 6 +- source3/modules/vfs_not_implemented.c | 6 +- source3/modules/vfs_shadow_copy2.c | 17 +- source3/modules/vfs_time_audit.c | 8 +- source3/smbd/files.c | 2 +- source3/smbd/open.c | 605 ++++++++++++++++++---------------- source3/smbd/proto.h | 8 +- source3/smbd/vfs.c | 218 +----------- 15 files changed, 391 insertions(+), 527 deletions(-) Changeset truncated at 500 lines: diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index a72ba57e1a7..98b090728f2 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -665,8 +665,10 @@ static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle, return NT_STATUS_NOT_IMPLEMENTED; } -static const char *skel_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static const char *skel_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { errno = ENOSYS; return NULL; diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index 8fb8644ad09..b152f3596c5 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -886,10 +886,12 @@ static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle, handle, dirfsp, name, mem_ctx, found_name); } -static const char *skel_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static const char *skel_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { - return SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname); + return SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname); } static NTSTATUS skel_brl_lock_windows(struct vfs_handle_struct *handle, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index fc7afccfdb3..20b6eb57900 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -377,6 +377,7 @@ * Version 47 - Add VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS for SMB_VFS_OPENAT() * Change to Version 48 - will ship with 4.18 * Version 48 - Add cached_dos_attributes to struct stat_ex + * Version 48 - Add dirfsp to connectpath_fn() */ #define SMB_VFS_INTERFACE_VERSION 48 @@ -1172,6 +1173,7 @@ struct vfs_fn_pointers { char **found_name); const char *(*connectpath_fn)(struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, const struct smb_filename *smb_fname); NTSTATUS (*brl_lock_windows_fn)(struct vfs_handle_struct *handle, @@ -1640,7 +1642,8 @@ NTSTATUS smb_vfs_call_get_real_filename_at(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, char **found_name); const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname); + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname); NTSTATUS smb_vfs_call_brl_lock_windows(struct vfs_handle_struct *handle, struct byte_range_lock *br_lck, struct lock_struct *plock); @@ -2112,8 +2115,10 @@ NTSTATUS vfs_not_implemented_get_real_filename_at( const char *name, TALLOC_CTX *mem_ctx, char **found_name); -const char *vfs_not_implemented_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname); +const char *vfs_not_implemented_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname); NTSTATUS vfs_not_implemented_brl_lock_windows(struct vfs_handle_struct *handle, struct byte_range_lock *br_lck, struct lock_struct *plock); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index c7089b62964..f1a59e1d13a 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -385,10 +385,10 @@ (mem_ctx), \ (found_name)) -#define SMB_VFS_CONNECTPATH(conn, smb_fname) \ - smb_vfs_call_connectpath((conn)->vfs_handles, (smb_fname)) -#define SMB_VFS_NEXT_CONNECTPATH(conn, smb_fname) \ - smb_vfs_call_connectpath((conn)->next, (smb_fname)) +#define SMB_VFS_CONNECTPATH(conn, dirfsp, smb_fname) \ + smb_vfs_call_connectpath((conn)->vfs_handles, (dirfsp), (smb_fname)) +#define SMB_VFS_NEXT_CONNECTPATH(conn, dirfsp, smb_fname) \ + smb_vfs_call_connectpath((conn)->next, (dirfsp), (smb_fname)) #define SMB_VFS_BRL_LOCK_WINDOWS(conn, br_lck, plock) \ smb_vfs_call_brl_lock_windows((conn)->vfs_handles, (br_lck), (plock)) diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index 2186bfdb2ce..b8190fa25e4 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -1292,8 +1292,10 @@ static NTSTATUS cephwrap_get_real_filename_at( return NT_STATUS_NOT_SUPPORTED; } -static const char *cephwrap_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static const char *cephwrap_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { return handle->conn->connectpath; } diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 9481c9f36d5..6cad87152ef 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -3453,6 +3453,7 @@ static NTSTATUS vfswrap_get_real_filename_at( } static const char *vfswrap_connectpath(struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, const struct smb_filename *smb_fname) { return handle->conn->connectpath; diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 25fd0cad326..011e483de2f 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -2115,12 +2115,14 @@ static NTSTATUS smb_full_audit_get_real_filename_at( return result; } -static const char *smb_full_audit_connectpath(vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static const char *smb_full_audit_connectpath( + vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { const char *result; - result = SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname); + result = SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname); do_log(SMB_VFS_OP_CONNECTPATH, result != NULL, diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index ffbe0f414ae..33f941aaca9 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -2348,8 +2348,10 @@ static NTSTATUS vfs_gluster_get_real_filename_at( return NT_STATUS_OK; } -static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static const char *vfs_gluster_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { return handle->conn->connectpath; } diff --git a/source3/modules/vfs_not_implemented.c b/source3/modules/vfs_not_implemented.c index 3c017c68bb8..0d3294658cf 100644 --- a/source3/modules/vfs_not_implemented.c +++ b/source3/modules/vfs_not_implemented.c @@ -735,8 +735,10 @@ NTSTATUS vfs_not_implemented_get_real_filename_at( } _PUBLIC_ -const char *vfs_not_implemented_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +const char *vfs_not_implemented_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { errno = ENOSYS; return NULL; diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index a3a6afbc3ac..43f02488f84 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -2625,13 +2625,16 @@ static NTSTATUS shadow_copy2_get_real_filename_at( return NT_STATUS_OK; } -static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname_in) +static const char *shadow_copy2_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname_in) { time_t timestamp = 0; char *stripped = NULL; char *tmp = NULL; const char *fname = smb_fname_in->base_name; + const struct smb_filename *full = NULL; struct smb_filename smb_fname = {0}; struct smb_filename *result_fname = NULL; char *result = NULL; @@ -2651,12 +2654,18 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, return priv->shadow_connectpath; } - if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname_in, + full = full_path_from_dirfsp_atname( + talloc_tos(), dirfsp, smb_fname_in); + if (full == NULL) { + return NULL; + } + + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, full, ×tamp, &stripped)) { goto done; } if (timestamp == 0) { - return SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname_in); + return SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname_in); } tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp, diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index e7633285607..4942e4b8491 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1743,15 +1743,17 @@ static NTSTATUS smb_time_audit_get_real_filename_at( return result; } -static const char *smb_time_audit_connectpath(vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static const char *smb_time_audit_connectpath( + vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) { const char *result; struct timespec ts1,ts2; double timediff; clock_gettime_mono(&ts1); - result = SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname); + result = SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname); clock_gettime_mono(&ts2); timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 0b071be33f2..9dc4e2a805b 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -679,7 +679,7 @@ static char *path_to_strv(TALLOC_CTX *mem_ctx, const char *path) return result; } -static NTSTATUS readlink_talloc( +NTSTATUS readlink_talloc( TALLOC_CTX *mem_ctx, struct files_struct *dirfsp, struct smb_filename *smb_relname, diff --git a/source3/smbd/open.c b/source3/smbd/open.c index d443a0291f9..0f5be7c1f6a 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -475,204 +475,248 @@ static NTSTATUS check_base_file_access(struct files_struct *fsp, access_mask); } -/**************************************************************************** - Handle differing symlink errno's -****************************************************************************/ +/* + * Take two absolute paths, figure out if "subdir" is a proper + * subdirectory of "parent". Return the component relative to the + * "parent" without the potential "/". Take care of "parent" + * possibly ending in "/". + */ +static bool subdir_of( + const char *parent, + size_t parent_len, + const char *subdir, + const char **_relative) -static NTSTATUS link_errno_convert(int err) { -#if defined(ENOTSUP) && defined(OSF1) - /* handle special Tru64 errno */ - if (err == ENOTSUP) { - err = ELOOP; - } -#endif /* ENOTSUP */ -#ifdef EFTYPE - /* fix broken NetBSD errno */ - if (err == EFTYPE) { - err = ELOOP; - } -#endif /* EFTYPE */ - /* fix broken FreeBSD errno */ - if (err == EMLINK) { - err = ELOOP; - } - if (err == ELOOP) { - return NT_STATUS_STOPPED_ON_SYMLINK; - } - return map_nt_error_from_unix(err); -} + const char *relative = NULL; + bool matched; -static NTSTATUS non_widelink_open(const struct files_struct *dirfsp, - files_struct *fsp, - struct smb_filename *smb_fname, - const struct vfs_open_how *how, - unsigned int link_depth); + SMB_ASSERT(parent[0] == '/'); + SMB_ASSERT(subdir[0] == '/'); -/**************************************************************************** - Follow a symlink in userspace. -****************************************************************************/ - -static NTSTATUS process_symlink_open(const struct files_struct *dirfsp, - files_struct *fsp, - struct smb_filename *smb_fname, - const struct vfs_open_how *how, - unsigned int link_depth) -{ - struct connection_struct *conn = dirfsp->conn; - const char *conn_rootdir = NULL; - struct smb_filename conn_rootdir_fname = { 0 }; - char *link_target = NULL; - int link_len = -1; - struct smb_filename *oldwd_fname = NULL; - size_t rootdir_len = 0; - struct smb_filename *resolved_fname = NULL; - char *resolved_name = NULL; - bool matched = false; - struct smb_filename *full_fname = NULL; - NTSTATUS status; + if (parent_len == 1) { + /* + * Everything is below "/" + */ + *_relative = subdir+1; + return true; + } - conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname); - if (conn_rootdir == NULL) { - return NT_STATUS_NO_MEMORY; + if (parent[parent_len-1] == '/') { + parent_len -= 1; } - /* - * With shadow_copy2 conn_rootdir can be talloc_freed - * whilst we use it in this function. We must take a copy. - */ - conn_rootdir_fname.base_name = talloc_strdup(talloc_tos(), - conn_rootdir); - if (conn_rootdir_fname.base_name == NULL) { - return NT_STATUS_NO_MEMORY; + + matched = (strncmp(subdir, parent, parent_len) == 0); + if (!matched) { + return false; } - /* - * Ensure we don't get stuck in a symlink loop. - */ - link_depth++; - if (link_depth >= 20) { - status = NT_STATUS_STOPPED_ON_SYMLINK; - goto out; + relative = &subdir[parent_len]; + + if (relative[0] == '\0') { + *_relative = relative; /* nothing left */ + return true; } - /* Allocate space for the link target. */ - link_target = talloc_array(talloc_tos(), char, PATH_MAX); - if (link_target == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + if (relative[0] == '/') { + /* End of parent must match a '/' in subdir. */ + *_relative = relative+1; + return true; } - /* - * Read the link target. We do this just to verify that smb_fname indeed - * points at a symbolic link and return NT_STATUS_NOT_A_DIRECTORY - * and failure in case smb_fname is NOT a symlink. - * - * The caller needs this piece of information to distinguish two cases - * where open() fails with errno=ENOTDIR, cf the comment in - * non_widelink_open(). - * - * We rely on SMB_VFS_REALPATH() to resolve the path including the - * symlink. Once we have SMB_VFS_STATX() or something similar in our VFS - * we may want to use that instead of SMB_VFS_READLINKAT(). - */ - link_len = SMB_VFS_READLINKAT(conn, - dirfsp, - smb_fname, - link_target, - PATH_MAX - 1); - if (link_len == -1) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; + return false; +} + +static NTSTATUS chdir_below_conn( + TALLOC_CTX *mem_ctx, + connection_struct *conn, + const char *connectpath, + size_t connectpath_len, + struct smb_filename *dir_fname, + struct smb_filename **_oldwd_fname) +{ + struct smb_filename *oldwd_fname = NULL; + struct smb_filename *smb_fname_dot = NULL; + struct smb_filename *real_fname = NULL; + const char *relative = NULL; + NTSTATUS status; + int ret; + bool ok; + + if (!ISDOT(dir_fname->base_name)) { + + oldwd_fname = vfs_GetWd(talloc_tos(), conn); + if (oldwd_fname == NULL) { + status = map_nt_error_from_unix(errno); + goto out; + } + + /* Pin parent directory in place. */ + ret = vfs_ChDir(conn, dir_fname); + if (ret == -1) { + status = map_nt_error_from_unix(errno); + DBG_DEBUG("chdir to %s failed: %s\n", + dir_fname->base_name, + strerror(errno)); + goto out; + } } - full_fname = full_path_from_dirfsp_atname( - talloc_tos(), dirfsp, smb_fname); - if (full_fname == NULL) { + smb_fname_dot = synthetic_smb_fname( + talloc_tos(), + ".", + NULL, + NULL, + dir_fname->twrp, + dir_fname->flags); + if (smb_fname_dot == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } - /* Convert to an absolute path. */ - resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(), full_fname); - if (resolved_fname == NULL) { + real_fname = SMB_VFS_REALPATH(conn, talloc_tos(), smb_fname_dot); + if (real_fname == NULL) { status = map_nt_error_from_unix(errno); + DBG_DEBUG("realpath in %s failed: %s\n", + dir_fname->base_name, + strerror(errno)); goto out; } - resolved_name = resolved_fname->base_name; + TALLOC_FREE(smb_fname_dot); - /* - * We know conn_rootdir starts with '/' and - * does not end in '/'. FIXME ! Should we - * smb_assert this ? - */ - rootdir_len = strlen(conn_rootdir_fname.base_name); + ok = subdir_of(connectpath, + connectpath_len, + real_fname->base_name, + &relative); + if (ok) { + TALLOC_FREE(real_fname); + *_oldwd_fname = oldwd_fname; + return NT_STATUS_OK; -- Samba Shared Repository