From 6fae0415d55c7204c6eb4a29345b61e45710f7b4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 28 Jan 2020 09:51:17 -0800 Subject: [PATCH] s3: VFS: Add SMB_VFS_READ_DFS_PATHAT(). Not yet used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14282 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Boehme (cherry picked from commit 96bc3298fc025d1d76fc06833fece6c62faa5e1a) --- examples/VFS/skel_opaque.c | 11 ++++ examples/VFS/skel_transparent.c | 16 ++++++ source3/include/vfs.h | 19 +++++++ source3/include/vfs_macros.h | 14 +++++ source3/modules/vfs_default.c | 103 ++++++++++++++++++++++++++++++++++ source3/modules/vfs_not_implemented.c | 11 ++++ source3/smbd/vfs.c | 16 ++++++ 7 files changed, 190 insertions(+) diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index 71c34de8013..c1b5923b752 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -112,6 +112,16 @@ static NTSTATUS skel_create_dfs_pathat(struct vfs_handle_struct *handle, return NT_STATUS_NOT_IMPLEMENTED; } +static NTSTATUS skel_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + static DIR *skel_opendir(vfs_handle_struct *handle, const struct smb_filename *smb_fname, const char *mask, @@ -1042,6 +1052,7 @@ static struct vfs_fn_pointers skel_opaque_fns = { .fs_capabilities_fn = skel_fs_capabilities, .get_dfs_referrals_fn = skel_get_dfs_referrals, .create_dfs_pathat_fn = skel_create_dfs_pathat, + .read_dfs_pathat_fn = skel_read_dfs_pathat, .snap_check_path_fn = skel_snap_check_path, .snap_create_fn = skel_snap_create, .snap_delete_fn = skel_snap_delete, diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index 4b91f64f15e..d2d05673fb4 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -113,6 +113,21 @@ static NTSTATUS skel_create_dfs_pathat(struct vfs_handle_struct *handle, referral_count); } +static NTSTATUS skel_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + return SMB_VFS_NEXT_READ_DFS_PATHAT(handle, + mem_ctx, + dirfsp, + smb_fname, + ppreflist, + preferral_count); +} + static DIR *skel_opendir(vfs_handle_struct *handle, const struct smb_filename *smb_fname, const char *mask, @@ -1344,6 +1359,7 @@ static struct vfs_fn_pointers skel_transparent_fns = { .fs_capabilities_fn = skel_fs_capabilities, .get_dfs_referrals_fn = skel_get_dfs_referrals, .create_dfs_pathat_fn = skel_create_dfs_pathat, + .read_dfs_pathat_fn = skel_read_dfs_pathat, .snap_check_path_fn = skel_snap_check_path, .snap_create_fn = skel_snap_create, .snap_delete_fn = skel_snap_delete, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 656fad8b5ee..fec38f20644 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -289,6 +289,7 @@ /* Version 42 - Remove struct write_cache *wcp from files_struct */ /* Version 42 - SMB_VFS_NTIMES() receives null times based on UTIMES_OMIT */ /* Version 42 - Add SMB_VFS_CREATE_DFS_PATHAT() */ +/* Version 42 - Add SMB_VFS_READ_DFS_PATHAT() */ #define SMB_VFS_INTERFACE_VERSION 42 @@ -716,6 +717,12 @@ struct vfs_fn_pointers { const struct smb_filename *smb_fname, const struct referral *reflist, size_t referral_count); + NTSTATUS (*read_dfs_pathat_fn)(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count); /* Directory operations */ @@ -1224,6 +1231,12 @@ NTSTATUS smb_vfs_call_create_dfs_pathat(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, const struct referral *reflist, size_t referral_count); +NTSTATUS smb_vfs_call_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count); DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, const char *mask, @@ -1666,6 +1679,12 @@ NTSTATUS vfs_not_implemented_create_dfs_pathat(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, const struct referral *reflist, size_t referral_count); +NTSTATUS vfs_not_implemented_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count); DIR *vfs_not_implemented_opendir(vfs_handle_struct *handle, const struct smb_filename *smb_fname, const char *mask, diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index d4ccb8f5c73..112169ab83b 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -90,6 +90,20 @@ (smb_fname), \ (reflist), \ (count)) +#define SMB_VFS_READ_DFS_PATHAT(conn, mem_ctx, dirfsp, smb_fname, ppreflist, pcount) \ + smb_vfs_call_read_dfs_pathat((conn)->vfs_handles, \ + (mem_ctx), \ + (dirfsp), \ + (smb_fname), \ + (ppreflist), \ + (pcount)) +#define SMB_VFS_NEXT_READ_DFS_PATHAT(handle, mem_ctx, dirfsp, smb_fname, ppreflist, pcount) \ + smb_vfs_call_read_dfs_pathat((handle)->next, \ + (mem_ctx), \ + (dirfsp), \ + (smb_fname), \ + (ppreflist), \ + (pcount)) /* Directory operations */ #define SMB_VFS_OPENDIR(conn, smb_fname, mask, attr) \ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index f0c92f873e4..37b59d8c3c0 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -404,6 +404,108 @@ static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle, return status; } +/* + * Read and return the contents of a DFS redirect given a + * pathname. A caller can pass in NULL for ppreflist and + * preferral_count but still determine if this was a + * DFS redirect point by getting NT_STATUS_OK back + * without incurring the overhead of reading and parsing + * the referral contents. + */ + +static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + NTSTATUS status = NT_STATUS_NO_MEMORY; + size_t bufsize; + char *link_target = NULL; + int referral_len; + bool ok; +#if defined(HAVE_BROKEN_READLINK) + char link_target_buf[PATH_MAX]; +#else + char link_target_buf[7]; +#endif + + SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp); + + if (ppreflist == NULL && preferral_count == NULL) { + /* + * We're only checking if this is a DFS + * redirect. We don't need to return data. + */ + bufsize = sizeof(link_target_buf); + link_target = link_target_buf; + } else { + bufsize = PATH_MAX; + link_target = talloc_array(mem_ctx, char, bufsize); + if (!link_target) { + goto err; + } + } + + referral_len = readlinkat(dirfsp->fh->fd, + smb_fname->base_name, + link_target, + bufsize - 1); + if (referral_len == -1) { + if (errno == EINVAL) { + /* + * If the path isn't a link, readlinkat + * returns EINVAL. Allow the caller to + * detect this. + */ + DBG_INFO("%s is not a link.\n", smb_fname->base_name); + status = NT_STATUS_OBJECT_TYPE_MISMATCH; + } else { + status = map_nt_error_from_unix(errno); + DBG_ERR("Error reading " + "msdfs link %s: %s\n", + smb_fname->base_name, + strerror(errno)); + } + goto err; + } + link_target[referral_len] = '\0'; + + DBG_INFO("%s -> %s\n", + smb_fname->base_name, + link_target); + + if (!strnequal(link_target, "msdfs:", 6)) { + status = NT_STATUS_OBJECT_TYPE_MISMATCH; + goto err; + } + + if (ppreflist == NULL && preferral_count == NULL) { + /* Early return for checking if this is a DFS link. */ + return NT_STATUS_OK; + } + + ok = parse_msdfs_symlink(mem_ctx, + lp_msdfs_shuffle_referrals(SNUM(handle->conn)), + link_target, + ppreflist, + preferral_count); + + if (ok) { + status = NT_STATUS_OK; + } else { + status = NT_STATUS_NO_MEMORY; + } + + err: + + if (link_target != link_target_buf) { + TALLOC_FREE(link_target); + } + return status; +} + static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, const char *service_path, @@ -3517,6 +3619,7 @@ static struct vfs_fn_pointers vfs_default_fns = { .fs_capabilities_fn = vfswrap_fs_capabilities, .get_dfs_referrals_fn = vfswrap_get_dfs_referrals, .create_dfs_pathat_fn = vfswrap_create_dfs_pathat, + .read_dfs_pathat_fn = vfswrap_read_dfs_pathat, .snap_check_path_fn = vfswrap_snap_check_path, .snap_create_fn = vfswrap_snap_create, .snap_delete_fn = vfswrap_snap_delete, diff --git a/source3/modules/vfs_not_implemented.c b/source3/modules/vfs_not_implemented.c index 2bdab503d2c..5861e20d88d 100644 --- a/source3/modules/vfs_not_implemented.c +++ b/source3/modules/vfs_not_implemented.c @@ -106,6 +106,16 @@ NTSTATUS vfs_not_implemented_create_dfs_pathat(struct vfs_handle_struct *handle, return NT_STATUS_NOT_IMPLEMENTED; } +NTSTATUS vfs_not_implemented_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + DIR *vfs_not_implemented_opendir(vfs_handle_struct *handle, const struct smb_filename *smb_fname, const char *mask, @@ -1047,6 +1057,7 @@ static struct vfs_fn_pointers vfs_not_implemented_fns = { .fs_capabilities_fn = vfs_not_implemented_fs_capabilities, .get_dfs_referrals_fn = vfs_not_implemented_get_dfs_referrals, .create_dfs_pathat_fn = vfs_not_implemented_create_dfs_pathat, + .read_dfs_pathat_fn = vfs_not_implemented_read_dfs_pathat, .snap_check_path_fn = vfs_not_implemented_snap_check_path, .snap_create_fn = vfs_not_implemented_snap_create, .snap_delete_fn = vfs_not_implemented_snap_delete, diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index e007a57fa01..7dc15158ccb 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1577,6 +1577,22 @@ NTSTATUS smb_vfs_call_create_dfs_pathat(struct vfs_handle_struct *handle, referral_count); } +NTSTATUS smb_vfs_call_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + VFS_FIND(read_dfs_pathat); + return handle->fns->read_dfs_pathat_fn(handle, + mem_ctx, + dirfsp, + smb_fname, + ppreflist, + preferral_count); +} + DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, const char *mask, -- 2.11.4.GIT