]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: Implement fsctl_get_reparse_point
authorVolker Lendecke <vl@samba.org>
Sun, 5 May 2024 09:14:45 +0000 (11:14 +0200)
committerJeremy Allison <jra@samba.org>
Mon, 6 May 2024 20:55:37 +0000 (20:55 +0000)
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/util_reparse.c

index 1e61dcf67e4b0105eef52d110d371ef013790a04..9a13c11f957fda3af08a877c29ef878425e537ed 100644 (file)
 #include "util_reparse.h"
 #include "libcli/smb/reparse.h"
 
+static NTSTATUS fsctl_get_reparse_point_reg(struct files_struct *fsp,
+                                           TALLOC_CTX *ctx,
+                                           uint8_t **_out_data,
+                                           uint32_t max_out_len,
+                                           uint32_t *_out_len)
+{
+       uint8_t *val = NULL;
+       ssize_t sizeret;
+       NTSTATUS status;
+
+       /*
+        * 64k+8 bytes is the maximum reparse point length
+        * possible
+        */
+
+       val = talloc_array(ctx, uint8_t, MIN(max_out_len, 65536 + 8));
+       if (val == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       sizeret = SMB_VFS_FGETXATTR(fsp,
+                                   SAMBA_XATTR_REPARSE_ATTRIB,
+                                   val,
+                                   talloc_get_size(val));
+
+       if ((sizeret == -1) && (errno == ERANGE)) {
+               status = NT_STATUS_BUFFER_TOO_SMALL;
+               goto fail;
+       }
+
+       if ((sizeret == -1) && (errno == ENOATTR)) {
+               DBG_DEBUG(SAMBA_XATTR_REPARSE_ATTRIB " does not exist\n");
+               status = NT_STATUS_NOT_A_REPARSE_POINT;
+               goto fail;
+       }
+
+       if (sizeret == -1) {
+               status = map_nt_error_from_unix(errno);
+               DBG_DEBUG("SMB_VFS_FGETXATTR failed: %s\n", strerror(errno));
+               goto fail;
+       }
+
+       *_out_data = val;
+       *_out_len = sizeret;
+       return NT_STATUS_OK;
+fail:
+       TALLOC_FREE(val);
+       return status;
+}
+
 NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
                                 TALLOC_CTX *mem_ctx,
                                 uint32_t *_reparse_tag,
@@ -29,8 +79,45 @@ NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
                                 uint32_t max_out_len,
                                 uint32_t *_out_len)
 {
-       DBG_DEBUG("Called on %s\n", fsp_str_dbg(fsp));
-       return NT_STATUS_NOT_A_REPARSE_POINT;
+       uint32_t dos_mode;
+       uint8_t *out_data = NULL;
+       uint32_t out_len = 0;
+       uint32_t reparse_tag = 0;
+       const uint8_t *reparse_data = NULL;
+       size_t reparse_data_length;
+       NTSTATUS status = NT_STATUS_NOT_A_REPARSE_POINT;
+
+       dos_mode = fdos_mode(fsp);
+       if ((dos_mode & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
+               return NT_STATUS_NOT_A_REPARSE_POINT;
+       }
+
+       if (S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
+               DBG_DEBUG("%s is a regular file\n", fsp_str_dbg(fsp));
+               status = fsctl_get_reparse_point_reg(
+                       fsp, mem_ctx, &out_data, max_out_len, &out_len);
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = reparse_buffer_check(out_data,
+                                     out_len,
+                                     &reparse_tag,
+                                     &reparse_data,
+                                     &reparse_data_length);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("Invalid reparse data: %s\n", nt_errstr(status));
+               TALLOC_FREE(out_data);
+               return status;
+       }
+
+       *_reparse_tag = reparse_tag;
+       *_out_data = out_data;
+       *_out_len = out_len;
+
+       return NT_STATUS_OK;
 }
 
 NTSTATUS fsctl_set_reparse_point(struct files_struct *fsp,