summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2022-09-08 16:42:26 -0700
committerJeremy Allison <jra@samba.org>2022-09-14 17:33:37 +0000
commit84e44cff39b58985f53d6440c508abb7dfb41fd7 (patch)
tree3bdf418aa8d8f95d99af0cca2e8bff07ce094351 /source3
parent8ae0c38d54f065915e927bbfe1b656400a79eb13 (diff)
downloadsamba-84e44cff39b58985f53d6440c508abb7dfb41fd7.tar.gz
s3: smbtorture3: Add a new test SMB2-NON-DFS-SHARE.
This one is tricky. It sends SMB2 DFS pathnames to a non-DFS share, and sets the SMB2 flag FLAGS2_DFS_PATHNAMES in the SMB2 packet. Windows will have non of it and (correctly) treats the pathnames as local paths (they're going to a non-DFS share). Samba fails. This proves the server looks as the share DFS capability to override the flag in the SMB2 packet. Passes against Windows. Added knownfail for Samba. Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: Noel Power <npower@samba.org>
Diffstat (limited to 'source3')
-rwxr-xr-xsource3/selftest/tests.py18
-rw-r--r--source3/torture/proto.h1
-rw-r--r--source3/torture/test_smb2.c162
-rw-r--r--source3/torture/torture.c4
4 files changed, 185 insertions, 0 deletions
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 4b192cf4ad5..b11fedd6c4f 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -247,6 +247,24 @@ plantestsuite("samba3.smbtorture_s3.smb2.SMB2-DFS-PATHS",
"-mSMB2"])
#
+# SMB2-NON-DFS-SHARE needs to run against a special share non-msdfs-pathname-share
+# This is an empty non-DFS share with no links, used merely to test
+# incoming DFS pathnames and how they map to local paths. We are testing
+# what happens if we set the FLAGS2_DFS_PATHNAMES and send DFS paths
+# on a non-DFS share.
+#
+plantestsuite("samba3.smbtorture_s3.smb2.SMB2-NON-DFS-SHARE",
+ "fileserver",
+ [os.path.join(samba3srcdir,
+ "script/tests/test_smbtorture_s3.sh"),
+ 'SMB2-NON-DFS-SHARE',
+ '//$SERVER_IP/non-msdfs-pathname-share',
+ '$USERNAME',
+ '$PASSWORD',
+ smbtorture3,
+ "-mSMB2"])
+
+#
# SMB1-DFS-PATHS needs to run against a special share msdfs-pathname-share
# This is an empty DFS share with no links, used merely to test
# incoming DFS pathnames and how they map to local paths.
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 873543d748c..d5e404eaefa 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -121,6 +121,7 @@ bool run_smb2_sacl(int dummy);
bool run_smb2_quota1(int dummy);
bool run_smb2_stream_acl(int dummy);
bool run_smb2_dfs_paths(int dummy);
+bool run_smb2_non_dfs_share(int dummy);
bool run_smb1_dfs_paths(int dummy);
bool run_smb1_dfs_search_paths(int dummy);
bool run_list_dir_async_test(int dummy);
diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c
index cdd66d4f449..f6206ce5ffe 100644
--- a/source3/torture/test_smb2.c
+++ b/source3/torture/test_smb2.c
@@ -4335,3 +4335,165 @@ bool run_smb2_dfs_paths(int dummy)
(void)smb2_dfs_delete(cli, "BAD\\BAD\\hlink");
return retval;
}
+
+/*
+ * Add a test that sends DFS paths and sets the
+ * SMB2 flag FLAGS2_DFS_PATHNAMES, but to a non-DFS
+ * share. Windows passes this (it just treats the
+ * pathnames as non-DFS and ignores the FLAGS2_DFS_PATHNAMES
+ * bit).
+ */
+
+bool run_smb2_non_dfs_share(int dummy)
+{
+ struct cli_state *cli = NULL;
+ NTSTATUS status;
+ bool dfs_supported = false;
+ uint64_t fid_persistent = 0;
+ uint64_t fid_volatile = 0;
+ bool retval = false;
+ char *dfs_filename = NULL;
+
+ printf("Starting SMB2-DFS-NON-DFS-SHARE\n");
+
+ if (!torture_init_connection(&cli)) {
+ return false;
+ }
+
+ status = smbXcli_negprot(cli->conn,
+ cli->timeout,
+ PROTOCOL_SMB2_02,
+ PROTOCOL_SMB3_11);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("smbXcli_negprot returned %s\n", nt_errstr(status));
+ return false;
+ }
+
+ status = cli_session_setup_creds(cli, torture_creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("cli_session_setup returned %s\n", nt_errstr(status));
+ return false;
+ }
+
+ status = cli_tree_connect(cli, share, "?????", NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("cli_tree_connect returned %s\n", nt_errstr(status));
+ return false;
+ }
+
+ dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
+ if (!dfs_supported) {
+ printf("Server %s does not support DFS\n",
+ smbXcli_conn_remote_name(cli->conn));
+ return false;
+ }
+ /* Ensure this is *NOT* a DFS share. */
+ dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
+ if (dfs_supported) {
+ printf("Share %s is a DFS share.\n",
+ cli->share);
+ return false;
+ }
+ /*
+ * Force the share to be DFS, as far as the client
+ * is concerned.
+ */
+ smb2cli_tcon_set_values(cli->smb2.tcon,
+ cli->smb2.session,
+ smb2cli_tcon_current_id(cli->smb2.tcon),
+ 0,
+ smb2cli_tcon_flags(cli->smb2.tcon),
+ smb2cli_tcon_capabilities(cli->smb2.tcon) |
+ SMB2_SHARE_CAP_DFS,
+ 0);
+
+ /* Come up with a "valid" SMB2 DFS name. */
+ dfs_filename = talloc_asprintf(talloc_tos(),
+ "%s\\%s\\file",
+ smbXcli_conn_remote_name(cli->conn),
+ cli->share);
+ if (dfs_filename == NULL) {
+ printf("Out of memory\n");
+ return false;
+ }
+
+ /* Now try create dfs_filename. */
+ status = smb2cli_create(cli->conn,
+ cli->timeout,
+ cli->smb2.session,
+ cli->smb2.tcon,
+ dfs_filename,
+ SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
+ SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
+ SEC_STD_SYNCHRONIZE|
+ SEC_STD_DELETE |
+ SEC_FILE_READ_DATA|
+ SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
+ FILE_CREATE, /* create_disposition, */
+ 0, /* create_options, */
+ NULL, /* smb2_create_blobs *blobs */
+ &fid_persistent,
+ &fid_volatile,
+ NULL, /* struct smb_create_returns * */
+ talloc_tos(), /* mem_ctx. */
+ NULL); /* struct smb2_create_blobs * */
+ /*
+ * Should fail with NT_STATUS_OBJECT_PATH_NOT_FOUND, as
+ * even though we set the FLAGS2_DFS_PATHNAMES the server
+ * knows this isn't a DFS share and so treats BAD\\BAD as
+ * part of the filename.
+ */
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+ printf("%s:%d create of %s should fail "
+ "with NT_STATUS_OBJECT_PATH_NOT_FOUND. Got %s\n",
+ __FILE__,
+ __LINE__,
+ dfs_filename,
+ nt_errstr(status));
+ goto err;
+ }
+ /*
+ * Prove we can still use non-DFS pathnames, even though
+ * we are setting the FLAGS2_DFS_PATHNAMES in the SMB2
+ * request.
+ */
+ status = smb2cli_create(cli->conn,
+ cli->timeout,
+ cli->smb2.session,
+ cli->smb2.tcon,
+ "file",
+ SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
+ SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
+ SEC_STD_SYNCHRONIZE|
+ SEC_STD_DELETE |
+ SEC_FILE_READ_DATA|
+ SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
+ FILE_CREATE, /* create_disposition, */
+ 0, /* create_options, */
+ NULL, /* smb2_create_blobs *blobs */
+ &fid_persistent,
+ &fid_volatile,
+ NULL, /* struct smb_create_returns * */
+ talloc_tos(), /* mem_ctx. */
+ NULL); /* struct smb2_create_blobs * */
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s:%d smb2cli_create on %s returned %s\n",
+ __FILE__,
+ __LINE__,
+ "file",
+ nt_errstr(status));
+ return false;
+ }
+
+ retval = true;
+
+ err:
+
+ (void)smb2_dfs_delete(cli, dfs_filename);
+ (void)smb2_dfs_delete(cli, "file");
+ return retval;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 8e496320dda..75d0248d773 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -15364,6 +15364,10 @@ static struct {
.fn = run_smb2_dfs_paths,
},
{
+ .name = "SMB2-NON-DFS-SHARE",
+ .fn = run_smb2_non_dfs_share,
+ },
+ {
.name = "SMB1-DFS-PATHS",
.fn = run_smb1_dfs_paths,
},