]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: use fsctl_get_reparse_point() in smb3_file_posix_information_init()
authorRalph Boehme <slow@samba.org>
Wed, 27 Nov 2024 13:35:32 +0000 (14:35 +0100)
committerRalph Boehme <slow@samba.org>
Wed, 27 Nov 2024 19:32:45 +0000 (19:32 +0000)
This allows returning the POSIX type info from fsctl_get_reparse_point().

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Wed Nov 27 19:32:45 UTC 2024 on atb-devel-224

selftest/knownfail.d/samba.tests.reparsepoints [deleted file]
source3/smbd/smb2_posix.c

diff --git a/selftest/knownfail.d/samba.tests.reparsepoints b/selftest/knownfail.d/samba.tests.reparsepoints
deleted file mode 100644 (file)
index 4266aa5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^samba.tests.reparsepoints.samba.tests.reparsepoints.ReparsePoints.test_reparsepoint_posix_type\(fileserver_smb1\)
index 7d184988ca3bb9dfb84567ec13ebf71750d106f2..8797b266260afde888400d09c2c90cdecc8f4f0f 100644 (file)
 #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,
        };