From 6d71edab5a70ab5c62e08ed5a6bb000259e18f21 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 27 Nov 2024 14:35:32 +0100 Subject: [PATCH] smbd: use fsctl_get_reparse_point() in smb3_file_posix_information_init() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This allows returning the POSIX type info from fsctl_get_reparse_point(). Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Wed Nov 27 19:32:45 UTC 2024 on atb-devel-224 --- .../knownfail.d/samba.tests.reparsepoints | 1 - source3/smbd/smb2_posix.c | 99 +++++++++++++++++-- 2 files changed, 93 insertions(+), 7 deletions(-) delete mode 100644 selftest/knownfail.d/samba.tests.reparsepoints diff --git a/selftest/knownfail.d/samba.tests.reparsepoints b/selftest/knownfail.d/samba.tests.reparsepoints deleted file mode 100644 index 4266aa50861..00000000000 --- a/selftest/knownfail.d/samba.tests.reparsepoints +++ /dev/null @@ -1 +0,0 @@ -^samba.tests.reparsepoints.samba.tests.reparsepoints.ReparsePoints.test_reparsepoint_posix_type\(fileserver_smb1\) diff --git a/source3/smbd/smb2_posix.c b/source3/smbd/smb2_posix.c index 7d184988ca3..8797b266260 100644 --- a/source3/smbd/smb2_posix.c +++ b/source3/smbd/smb2_posix.c @@ -24,6 +24,66 @@ #include "librpc/gen_ndr/smb3posix.h" #include "libcli/security/security.h" #include "source3/modules/util_reparse.h" +#include "libcli/smb/reparse.h" + +static NTSTATUS reparse_buffer_parse_posix_type(uint32_t reparse_tag, + uint8_t *data, + uint32_t len, + mode_t *type) +{ + struct reparse_data_buffer *reparse = NULL; + NTSTATUS status; + + if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { + *type = S_IFLNK; + return NT_STATUS_OK; + } + if (reparse_tag != IO_REPARSE_TAG_NFS) { + /* + * Clients can create reparse points with arbitrary tags, return + * anything that is not a NFS one (or symlink) as S_IFREG. + */ + DBG_INFO("Unhandled NFS reparse tag: 0x%" PRIx32 "\n", + reparse->tag); + *type = S_IFREG; + return NT_STATUS_OK; + } + + reparse = talloc_zero(talloc_tos(), struct reparse_data_buffer); + if (reparse == NULL) { + DBG_ERR("talloc_zero() failed\n"); + return NT_STATUS_NO_MEMORY; + } + + status = reparse_data_buffer_parse(reparse, reparse, data, len); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(reparse); + return status; + } + + switch (reparse->parsed.nfs.type) { + case NFS_SPECFILE_CHR: + *type = S_IFCHR; + break; + case NFS_SPECFILE_BLK: + *type = S_IFBLK; + break; + case NFS_SPECFILE_FIFO: + *type = S_IFIFO; + break; + case NFS_SPECFILE_SOCK: + *type = S_IFSOCK; + break; + default: + DBG_ERR("Unhandled NFS reparse type: 0x%" PRIx64 "\n", + reparse->parsed.nfs.type); + TALLOC_FREE(reparse); + return NT_STATUS_REPARSE_POINT_NOT_RESOLVED; + } + + TALLOC_FREE(reparse); + return status; +} NTSTATUS smb3_file_posix_information_init( connection_struct *conn, @@ -32,10 +92,11 @@ NTSTATUS smb3_file_posix_information_init( struct smb3_file_posix_information *dst) { const struct stat_ex *st = &smb_fname->st; + mode_t mode = st->st_ex_mode; uint32_t reparse_tag = 0; NTSTATUS status; - switch (st->st_ex_mode & S_IFMT) { + switch (mode & S_IFMT) { case S_IFREG: case S_IFDIR: break; @@ -51,15 +112,41 @@ NTSTATUS smb3_file_posix_information_init( } if (dos_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { - status = fsctl_get_reparse_tag(smb_fname->fsp, - &reparse_tag); + uint8_t *reparse_data = NULL; + uint32_t reparse_len; + mode_t type = S_IFREG; + + status = fsctl_get_reparse_point(smb_fname->fsp, + talloc_tos(), + &reparse_tag, + &reparse_data, + UINT32_MAX, + &reparse_len); if (!NT_STATUS_IS_OK(status)) { - DBG_DEBUG("Could not get reparse " - "tag for %s: %s\n", + DBG_DEBUG("Could not get reparse point for %s: %s\n", smb_fname_str_dbg(smb_fname), nt_errstr(status)); return status; } + + status = reparse_buffer_parse_posix_type(reparse_tag, + reparse_data, + reparse_len, + &type); + TALLOC_FREE(reparse_data); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("Could not parse reparse data for %s: %s\n", + smb_fname_str_dbg(smb_fname), + nt_errstr(status)); + return status; + } + + /* + * Remove the type info we got via stat() and use what + * we got from the reparse point. + */ + mode &= ~S_IFMT; + mode |= type; } *dst = (struct smb3_file_posix_information) { @@ -74,7 +161,7 @@ NTSTATUS smb3_file_posix_information_init( .file_attributes = dos_attributes, .cc.nlinks = st->st_ex_nlink, .cc.reparse_tag = reparse_tag, - .cc.posix_mode = unix_mode_to_wire(st->st_ex_mode), + .cc.posix_mode = unix_mode_to_wire(mode), .cc.owner = global_sid_NULL, .cc.group = global_sid_NULL, }; -- 2.47.2