[SCM] Samba Shared Repository - branch master updated
Jeremy Allison
jra at samba.org
Mon May 6 21:56:02 UTC 2024
The branch, master has been updated
via 5edd1e7c3ee smbd: Implement FSCTL_DELETE_REPARSE_POINT
via 97c79d47dd7 tests: Test FSCTL_DELETE_REPARSE_POINT
via d80a884f54c tests: Run reparse tests
via 4fa6cffcfae tests: Expected failures in reparse point tests should not be errors
via 8ace45e0da9 smbd: Implement fsctl_set_reparse_point
via 6eba4b794f0 smbd: Implement fsctl_get_reparse_point
via 7dc07710fbe tests: Clean up behind ourselves in test_create_reparse
via 4536cfb1ec1 tests: Codify IO_REPARSE_TAG_MISMATCH behaviour
via fb74b3b5073 tests: Clarify a reparse point test
via 6526f20e42b s3: smbd: smb2-posix: Add SAMBA_XATTR_REPARSE_ATTRIB "user.SmbReparse" name.
via deed7fab03d selftest: Default to "tmp" share in reparsepoints.py
via 1fa7668ee82 smbd: Use reparse_buffer_check() in fsctl_set_reparse_point()
via 4b98f993a25 smbd: Prepare to return the reparse tag from fsctl_get_reparse_point
via db5c23e4be7 smbd: Change the output of fsctl_get_reparse_point to uint8
via fafe29a2640 reparse: Tighten reparse point length check
via 2defbc994de smbd: Return FILE_ATTRIBUTE_REPARSE_POINT from "user.DOSATTRIB"
from c5a1c8d45b9 s4:dsdb: Fix stack use after scope in gkdi_create_root_key()
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 5edd1e7c3ee8aa0e873b98285ddf2344cf96932c
Author: Volker Lendecke <vl at samba.org>
Date: Mon May 6 16:59:44 2024 +0200
smbd: Implement FSCTL_DELETE_REPARSE_POINT
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Autobuild-User(master): Jeremy Allison <jra at samba.org>
Autobuild-Date(master): Mon May 6 21:55:03 UTC 2024 on atb-devel-224
commit 97c79d47dd7294f4f78d9dbc799153afaf5fa03f
Author: Volker Lendecke <vl at samba.org>
Date: Mon May 6 16:35:25 2024 +0200
tests: Test FSCTL_DELETE_REPARSE_POINT
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit d80a884f54c50e8c47c038cb8a7a120f3f142699
Author: Volker Lendecke <vl at samba.org>
Date: Fri May 3 15:03:30 2024 +0200
tests: Run reparse tests
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 4fa6cffcfae68d816ddecb58003775b58b38cfd7
Author: Volker Lendecke <vl at samba.org>
Date: Sun May 5 12:16:39 2024 +0200
tests: Expected failures in reparse point tests should not be errors
We need to put them into knownfail.d individually
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 8ace45e0da9dcfc660e83e9486646723b8eaa015
Author: Volker Lendecke <vl at samba.org>
Date: Fri Dec 2 11:56:08 2022 +0100
smbd: Implement fsctl_set_reparse_point
Store the data in the "user.SmbReparse" xattr. Only allow this on
regular files. Windows does it for directories too, but we can not
allow this: Setting a symlink reparse point in a xattr on a directory
would go unnoticed by our openat2-optimization. If someone really
needs this, we could have a VFS module disallowing openat2 and doing
the appropriate checks on every openat-call.
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 6eba4b794f0bfa9b85dc7ca754a12169d7b89bd5
Author: Volker Lendecke <vl at samba.org>
Date: Sun May 5 11:14:45 2024 +0200
smbd: Implement fsctl_get_reparse_point
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 7dc07710fbede128d0b7064f78d86dfabd47cf5d
Author: Volker Lendecke <vl at samba.org>
Date: Fri May 3 14:52:42 2024 +0200
tests: Clean up behind ourselves in test_create_reparse
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 4536cfb1ec1fdf7dcaf0989d04770512c208e241
Author: Volker Lendecke <vl at samba.org>
Date: Fri May 3 14:49:46 2024 +0200
tests: Codify IO_REPARSE_TAG_MISMATCH behaviour
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit fb74b3b50734838c77a314bb37ef5d7b8dec7fb3
Author: Volker Lendecke <vl at samba.org>
Date: Fri May 3 14:49:24 2024 +0200
tests: Clarify a reparse point test
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 6526f20e42bcc533ad5c8a4c402622dc0a5c0fd8
Author: Jeremy Allison <jra at samba.org>
Date: Tue Sep 18 09:03:22 2018 -0700
s3: smbd: smb2-posix: Add SAMBA_XATTR_REPARSE_ATTRIB "user.SmbReparse" name.
Ensure it's prohibited for normal user access.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
commit deed7fab03d2f2c7865cbdc9ef6c55353714d5a6
Author: Volker Lendecke <vl at samba.org>
Date: Mon Jan 2 13:56:12 2023 +0100
selftest: Default to "tmp" share in reparsepoints.py
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 1fa7668ee827e0ccac4e15c257d73bf5de2ed701
Author: Volker Lendecke <vl at samba.org>
Date: Thu May 2 16:34:43 2024 +0200
smbd: Use reparse_buffer_check() in fsctl_set_reparse_point()
check_reparse_data_buffer() was duplicated code
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 4b98f993a257ca66df0cb42f920377dbe4b2bc91
Author: Volker Lendecke <vl at samba.org>
Date: Sat May 4 11:19:14 2024 +0200
smbd: Prepare to return the reparse tag from fsctl_get_reparse_point
We'll need this in many places, for example when listing directories
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit db5c23e4be79ab501b06ee31bb2a562287eb9dd7
Author: Volker Lendecke <vl at samba.org>
Date: Sat May 4 19:32:03 2024 +0200
smbd: Change the output of fsctl_get_reparse_point to uint8
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit fafe29a26407237d9742cf135a7db759c88656b6
Author: Volker Lendecke <vl at samba.org>
Date: Sat May 4 10:54:27 2024 +0200
reparse: Tighten reparse point length check
test_create_reparse shows that the length checks need to be precise,
not just checking for overflow.
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 2defbc994de3c0ce763c5272bdf23b6054e5af95
Author: Volker Lendecke <vl at samba.org>
Date: Fri Dec 2 15:02:18 2022 +0100
smbd: Return FILE_ATTRIBUTE_REPARSE_POINT from "user.DOSATTRIB"
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
-----------------------------------------------------------------------
Summary of changes:
libcli/smb/reparse.c | 12 +-
libcli/smb/reparse.h | 5 +
python/samba/tests/reparsepoints.py | 104 +++++++++++++--
selftest/knownfail.d/reparse | 2 +
selftest/skip | 1 -
source3/include/smb.h | 2 +
source3/modules/util_reparse.c | 251 ++++++++++++++++++++++++++++++++----
source3/modules/util_reparse.h | 5 +-
source3/modules/vfs_default.c | 3 +-
source3/smbd/dosmode.c | 12 +-
source3/smbd/smb2_trans2.c | 1 +
11 files changed, 352 insertions(+), 46 deletions(-)
create mode 100644 selftest/knownfail.d/reparse
Changeset truncated at 500 lines:
diff --git a/libcli/smb/reparse.c b/libcli/smb/reparse.c
index 49ecc77725d..08071ca85d7 100644
--- a/libcli/smb/reparse.c
+++ b/libcli/smb/reparse.c
@@ -26,11 +26,11 @@
#include "lib/util/charset/charset.h"
#include "smb_util.h"
-static NTSTATUS reparse_buffer_check(const uint8_t *in_data,
- size_t in_len,
- uint32_t *reparse_tag,
- const uint8_t **_reparse_data,
- size_t *_reparse_data_length)
+NTSTATUS reparse_buffer_check(const uint8_t *in_data,
+ size_t in_len,
+ uint32_t *reparse_tag,
+ const uint8_t **_reparse_data,
+ size_t *_reparse_data_length)
{
uint16_t reparse_data_length;
@@ -45,7 +45,7 @@ static NTSTATUS reparse_buffer_check(const uint8_t *in_data,
reparse_data_length = PULL_LE_U16(in_data, 4);
- if (reparse_data_length > (in_len - 8)) {
+ if (reparse_data_length != (in_len - 8)) {
DBG_DEBUG("in_len=%zu, reparse_data_length=%" PRIu16 "\n",
in_len,
reparse_data_length);
diff --git a/libcli/smb/reparse.h b/libcli/smb/reparse.h
index 23274bf3852..e4410d974e4 100644
--- a/libcli/smb/reparse.h
+++ b/libcli/smb/reparse.h
@@ -63,6 +63,11 @@ struct reparse_data_buffer {
} parsed;
};
+NTSTATUS reparse_buffer_check(const uint8_t *in_data,
+ size_t in_len,
+ uint32_t *reparse_tag,
+ const uint8_t **_reparse_data,
+ size_t *_reparse_data_length);
NTSTATUS reparse_data_buffer_parse(TALLOC_CTX *mem_ctx,
struct reparse_data_buffer *dst,
const uint8_t *buf,
diff --git a/python/samba/tests/reparsepoints.py b/python/samba/tests/reparsepoints.py
index cb7421df518..96ca6eefdd5 100644
--- a/python/samba/tests/reparsepoints.py
+++ b/python/samba/tests/reparsepoints.py
@@ -24,7 +24,9 @@ import samba.tests.libsmb
class ReparsePoints(samba.tests.libsmb.LibsmbTests):
def connection(self):
- share = samba.tests.env_get_var_value("SHARENAME")
+ share = samba.tests.env_get_var_value("SHARENAME", allow_missing=True)
+ if not share:
+ share = "tmp"
smb1 = samba.tests.env_get_var_value("SMB1", allow_missing=True)
conn = libsmb.Conn(
self.server_ip,
@@ -72,9 +74,11 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
fd = conn.create(
filename,
- DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE,
+ DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE | sec.SEC_STD_DELETE,
CreateDisposition=libsmb.FILE_CREATE)
+ conn.delete_on_close(fd, 1)
+
with self.assertRaises(NTSTATUSError) as e:
conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b'', 0)
@@ -103,9 +107,16 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
self.assertEqual(e.exception.args[0],
ntstatus.NT_STATUS_IO_REPARSE_DATA_INVALID)
+ # Exact length works
conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
- b = reparse_symlink.put(0x80000026, 0, b'asdfasdfasdfasdfasdfasdf')
- conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
+
+ b = reparse_symlink.put(0x80000026, 0, b'asdf')
+
+ # We can't overwrite an existing reparse point with a different tag
+ with self.assertRaises(NTSTATUSError) as e:
+ conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
+ self.assertEqual(e.exception.args[0],
+ ntstatus.NT_STATUS_IO_REPARSE_TAG_MISMATCH)
# Show that we can write to a reparse point when opened properly
def test_write_reparse(self):
@@ -151,8 +162,20 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
sec.SEC_STD_DELETE,
CreateDisposition=libsmb.FILE_CREATE,
CreateOptions=libsmb.FILE_DIRECTORY_FILE)
+
b = reparse_symlink.put(0x80000025, 0, b'asdfasdfasdfasdfasdfasdf')
- conn.fsctl(dir_fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
+
+ try:
+ conn.fsctl(dir_fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
+ except NTSTATUSError as e:
+ err = e.args[0]
+ if (err != ntstatus.NT_STATUS_ACCESS_DENIED):
+ raise
+
+ if (err == ntstatus.NT_STATUS_ACCESS_DENIED):
+ self.fail("Could not set reparse point on directory")
+ conn.delete_on_close(fd, 1)
+ return
with self.assertRaises(NTSTATUSError) as e:
fd = conn.create(
@@ -188,20 +211,22 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
sec.SEC_STD_DELETE,
CreateDisposition=libsmb.FILE_CREATE)
+
b = reparse_symlink.put(0x80000025, 0, b'asdf')
try:
conn.fsctl(dir_fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
except NTSTATUSError as e:
err = e.args[0]
- ok = (err == ntstatus.NT_STATUS_DIRECTORY_NOT_EMPTY)
- if not ok:
- raise
conn.delete_on_close(fd, 1)
conn.close(fd)
conn.delete_on_close(dir_fd, 1)
conn.close(dir_fd)
+ ok = (err == ntstatus.NT_STATUS_DIRECTORY_NOT_EMPTY)
+ if not ok:
+ self.fail(f'set_reparse on nonempty directory returned {err}')
+
# Show that reparse point opens respect share modes
def test_reparse_share_modes(self):
@@ -236,6 +261,69 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
conn.delete_on_close(fd1, 1)
conn.close(fd1)
+ def test_delete_reparse_point(self):
+ conn = self.connection()
+ filename = 'reparse'
+ self.clean_file(conn, filename)
+
+ fd = conn.create(
+ filename,
+ DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE,
+ CreateDisposition=libsmb.FILE_CREATE)
+ b = reparse_symlink.put(0x80000025, 0, b'asdfasdfasdfasdfasdfasdf')
+ conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
+ conn.close(fd)
+
+ (fd,cr,_) = conn.create_ex(
+ filename,
+ DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE|sec.SEC_STD_DELETE,
+ CreateOptions=libsmb.FILE_OPEN_REPARSE_POINT,
+ CreateDisposition=libsmb.FILE_OPEN)
+
+ self.assertEqual(cr['file_attributes'] &
+ libsmb.FILE_ATTRIBUTE_REPARSE_POINT,
+ libsmb.FILE_ATTRIBUTE_REPARSE_POINT)
+
+ b = reparse_symlink.put(0x80000026, 0, b'')
+ with self.assertRaises(NTSTATUSError) as e:
+ conn.fsctl(fd, libsmb.FSCTL_DELETE_REPARSE_POINT, b, 0)
+ self.assertEqual(e.exception.args[0],
+ ntstatus.NT_STATUS_IO_REPARSE_TAG_MISMATCH)
+
+ b = reparse_symlink.put(0x80000026, 0, b' ')
+ with self.assertRaises(NTSTATUSError) as e:
+ conn.fsctl(fd, libsmb.FSCTL_DELETE_REPARSE_POINT, b, 0)
+ self.assertEqual(e.exception.args[0],
+ ntstatus.NT_STATUS_IO_REPARSE_DATA_INVALID)
+
+ b = reparse_symlink.put(0x80000025, 0, b' ')
+ with self.assertRaises(NTSTATUSError) as e:
+ conn.fsctl(fd, libsmb.FSCTL_DELETE_REPARSE_POINT, b, 0)
+ self.assertEqual(e.exception.args[0],
+ ntstatus.NT_STATUS_IO_REPARSE_DATA_INVALID)
+
+ b = reparse_symlink.put(0x80000025, 0, b'')
+ conn.fsctl(fd, libsmb.FSCTL_DELETE_REPARSE_POINT, b, 0)
+
+ with self.assertRaises(NTSTATUSError) as e:
+ conn.fsctl(fd, libsmb.FSCTL_DELETE_REPARSE_POINT, b, 0)
+ self.assertEqual(e.exception.args[0],
+ ntstatus.NT_STATUS_NOT_A_REPARSE_POINT)
+
+ conn.close(fd)
+
+ (fd,cr,_) = conn.create_ex(
+ filename,
+ DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE|sec.SEC_STD_DELETE,
+ CreateDisposition=libsmb.FILE_OPEN)
+
+ self.assertEqual(cr['file_attributes'] &
+ libsmb.FILE_ATTRIBUTE_REPARSE_POINT,
+ 0)
+
+ conn.delete_on_close(fd, 1)
+ conn.close(fd)
+
if __name__ == '__main__':
import unittest
unittest.main()
diff --git a/selftest/knownfail.d/reparse b/selftest/knownfail.d/reparse
new file mode 100644
index 00000000000..11d094aa5c6
--- /dev/null
+++ b/selftest/knownfail.d/reparse
@@ -0,0 +1,2 @@
+^samba.tests.reparsepoints.samba.tests.reparsepoints.ReparsePoints.test_create_reparse_directory
+^samba.tests.reparsepoints.samba.tests.reparsepoints.ReparsePoints.test_create_reparse_nonempty_directory
diff --git a/selftest/skip b/selftest/skip
index cc2fe8979e8..b5266bb16d8 100644
--- a/selftest/skip
+++ b/selftest/skip
@@ -146,5 +146,4 @@ bench # don't run benchmarks in our selftest
^samba4.smb2.mangle.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test
^samba4.smb2.tcon.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test
^samba4.smb2.mkdir.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test
-^samba.tests.reparsepoints.*
^samba3.blackbox.open-eintr.*
diff --git a/source3/include/smb.h b/source3/include/smb.h
index e47ccd66133..7f3482fe442 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -614,6 +614,8 @@ struct ea_list {
#define SAMBA_XATTR_DOSSTREAM_PREFIX "user.DosStream."
/* Prefix for xattrs storing streams. */
#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS"
+/* EA to use to store reparse points. */
+#define SAMBA_XATTR_REPARSE_ATTRIB "user.SmbReparse"
/* usershare error codes. */
enum usershare_err {
diff --git a/source3/modules/util_reparse.c b/source3/modules/util_reparse.c
index 45cacbdbe22..6f47367a4b8 100644
--- a/source3/modules/util_reparse.c
+++ b/source3/modules/util_reparse.c
@@ -20,40 +20,104 @@
#include "includes.h"
#include "util_reparse.h"
+#include "libcli/smb/reparse.h"
+#include "source3/smbd/proto.h"
-NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
- TALLOC_CTX *mem_ctx,
- char **out_data,
- uint32_t max_out_len,
- uint32_t *out_len)
+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)
{
- DBG_DEBUG("Called on %s\n", fsp_str_dbg(fsp));
- return NT_STATUS_NOT_A_REPARSE_POINT;
+ 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;
}
-static NTSTATUS check_reparse_data_buffer(
- const uint8_t *in_data, size_t in_len)
+NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *_reparse_tag,
+ uint8_t **_out_data,
+ uint32_t max_out_len,
+ uint32_t *_out_len)
{
- uint16_t reparse_data_length;
+ 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;
- if (in_len == 0) {
- DBG_DEBUG("in_len=0\n");
- return NT_STATUS_INVALID_BUFFER_SIZE;
+ dos_mode = fdos_mode(fsp);
+ if ((dos_mode & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
+ return NT_STATUS_NOT_A_REPARSE_POINT;
}
- if (in_len < 8) {
- DBG_DEBUG("in_len=%zu\n", in_len);
- return NT_STATUS_IO_REPARSE_DATA_INVALID;
+
+ 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);
}
- reparse_data_length = PULL_LE_U16(in_data, 4);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- if (reparse_data_length != (in_len - 8)) {
- DBG_DEBUG("in_len=%zu, reparse_data_length=%"PRIu16"\n",
- in_len,
- reparse_data_length);
- return NT_STATUS_IO_REPARSE_DATA_INVALID;
+ 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;
}
@@ -62,16 +126,86 @@ NTSTATUS fsctl_set_reparse_point(struct files_struct *fsp,
const uint8_t *in_data,
uint32_t in_len)
{
+ uint32_t reparse_tag;
+ const uint8_t *reparse_data = NULL;
+ size_t reparse_data_length;
+ uint32_t existing_tag;
+ uint8_t *existing_data = NULL;
+ uint32_t existing_len;
NTSTATUS status;
+ uint32_t dos_mode;
+ int ret;
DBG_DEBUG("Called on %s\n", fsp_str_dbg(fsp));
- status = check_reparse_data_buffer(in_data, in_len);
+ if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
+ DBG_DEBUG("Can only set reparse point for regular files\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = reparse_buffer_check(in_data,
+ in_len,
+ &reparse_tag,
+ &reparse_data,
+ &reparse_data_length);
if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("check_reparse_data_buffer failed: %s\n",
+ nt_errstr(status));
return status;
}
- return NT_STATUS_NOT_A_REPARSE_POINT;
+ DBG_DEBUG("reparse tag=%" PRIX32 ", length=%zu\n",
+ reparse_tag,
+ reparse_data_length);
+
+ status = fsctl_get_reparse_point(fsp,
+ talloc_tos(),
+ &existing_tag,
+ &existing_data,
+ UINT32_MAX,
+ &existing_len);
+ if (NT_STATUS_IS_OK(status)) {
+
+ TALLOC_FREE(existing_data);
+
+ if (existing_tag != reparse_tag) {
+ DBG_DEBUG("Can't overwrite tag %" PRIX32
+ " with tag %" PRIX32 "\n",
+ existing_tag,
+ reparse_tag);
+ return NT_STATUS_IO_REPARSE_TAG_MISMATCH;
+ }
+ }
+
+ /* Store the data */
+ ret = SMB_VFS_FSETXATTR(
+ fsp, SAMBA_XATTR_REPARSE_ATTRIB, in_data, in_len, 0);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ DBG_DEBUG("setxattr fail on %s - %s\n",
+ fsp_str_dbg(fsp),
+ strerror(errno));
+ return status;
+ }
+
+ /*
+ * Files with reparse points don't have the ATTR_NORMAL bit
+ * set
+ */
+ dos_mode = fdos_mode(fsp);
+ dos_mode &= ~FILE_ATTRIBUTE_NORMAL;
+ dos_mode |= FILE_ATTRIBUTE_REPARSE_POINT;
+
+ status = SMB_VFS_FSET_DOS_ATTRIBUTES(fsp->conn, fsp, dos_mode);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("set reparse attr fail on %s - %s\n",
+ fsp_str_dbg(fsp),
+ nt_errstr(status));
+ return status;
+ }
+
+ return NT_STATUS_OK;
}
NTSTATUS fsctl_del_reparse_point(struct files_struct *fsp,
@@ -79,6 +213,71 @@ NTSTATUS fsctl_del_reparse_point(struct files_struct *fsp,
const uint8_t *in_data,
uint32_t in_len)
{
- DBG_DEBUG("Called on %s\n", fsp_str_dbg(fsp));
- return NT_STATUS_NOT_A_REPARSE_POINT;
+ uint32_t existing_tag;
+ uint8_t *existing_data = NULL;
+ uint32_t existing_len;
+ uint32_t reparse_tag;
+ const uint8_t *reparse_data = NULL;
+ size_t reparse_data_length;
+ NTSTATUS status;
+ uint32_t dos_mode;
+ int ret;
+
+ status = fsctl_get_reparse_point(fsp,
+ talloc_tos(),
+ &existing_tag,
+ &existing_data,
+ UINT32_MAX,
+ &existing_len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ TALLOC_FREE(existing_data);
+
+ status = reparse_buffer_check(in_data,
+ in_len,
+ &reparse_tag,
+ &reparse_data,
+ &reparse_data_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (reparse_data_length != 0) {
+ return NT_STATUS_IO_REPARSE_DATA_INVALID;
+ }
--
Samba Shared Repository
More information about the samba-cvs
mailing list