From: Noel Power Date: Tue, 4 Feb 2020 10:25:21 +0000 (+0000) Subject: s4/torture/smb2: Port raw.streams subtest raw.streams.perms to SMB2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=251ffd832d6f5c8a9cd8b562755211cba479c67c;p=thirdparty%2Fsamba.git s4/torture/smb2: Port raw.streams subtest raw.streams.perms to SMB2 Mostly afaics raw.streams is already ported, the only test I saw that was missing was the perms test. So this is added here. Addionally o add known fail for perms for streams_xattr and ntvfs o move the smb1 raw.streams to _smb1_done env o remove test from todo_smb2_tests_to_port.list o add a known fail for samba3.smb2.streams.perms(simpleserver) simpleserver is using vfs_streams_depot in preference to vfs_acl_xattr and the test seems to pass a check it expects an open of the stream to fail with ACCESS_DENIED but it passes (see https://bugzilla.samba.org/show_bug.cgi?id=16157) Signed-off-by: Noel Power Reviewed-by: Ralph Boehme Autobuild-User(master): Noel Power Autobuild-Date(master): Fri Jul 3 12:02:56 UTC 2026 on atb-devel-224 --- diff --git a/selftest/knownfail b/selftest/knownfail index f68b5b40e29..45afb91e4fd 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -150,6 +150,7 @@ ^samba4.smb2.acls-with-sysacl.*.inheritflags ^samba4.smb2.acls-with-sysacl.*.owner ^samba4.smb2.acls-with-sysacl.*.ACCESSBASED +^samba4.smb2.streams.perms\(ad_dc_ntvfs\) # fails against ntvfs. ^samba4.ldap.dirsync.python.ad_dc_ntvfs..__main__.SimpleDirsyncTests.test_dirsync_deleted_items_OBJECT_SECURITY #^samba4.ldap.dirsync.python.ad_dc_ntvfs..__main__.ExtendedDirsyncTests.* ^samba4.libsmbclient.opendir.(NT1|SMB3).opendir # This requires netbios browsing @@ -206,7 +207,11 @@ ^samba3.smb2.dir.modify ^samba3.smb2.oplock.stream1 ^samba3.smb2.streams.rename2 +# https://bugzilla.samba.org/show_bug.cgi?id=16157 +^samba3.smb2.streams.perms\(simpleserver\) # POSIX ACL backend doesn't apply DENY ACE for S-1-1-0 to all ALLOW ACE ^samba3.smb2.streams streams_xattr.rename2\(nt4_dc\) +^samba3.smb2.streams streams_xattr.attributes\(nt4_dc\) +^samba3.smb2.streams streams_xattr.perms\(nt4_dc\) # We don't run the equiv raw.stream test against the streams_xattr test, but if we did, it would fail in the same way. ^samba3.smb2.getinfo.complex ^samba3.smb2.getinfo.fsinfo # quotas don't work yet ^samba3.smb2.setinfo.setinfo diff --git a/selftest/todo_smb2_tests_to_port.list b/selftest/todo_smb2_tests_to_port.list index 8b24c1e92ff..d1e461be8c5 100644 --- a/selftest/todo_smb2_tests_to_port.list +++ b/selftest/todo_smb2_tests_to_port.list @@ -146,8 +146,6 @@ samba3.raw.sfileinfo.end-of-file(ad_dc_smb1) samba3.raw.sfileinfo.end-of-file(nt4_dc_smb1) samba3.raw.sfileinfo.rename(ad_dc_smb1) samba3.raw.sfileinfo.rename(nt4_dc_smb1) -samba3.raw.streams(ad_dc_smb1) -samba3.raw.streams(nt4_dc_smb1) samba3.raw.unlink(ad_dc_smb1) samba3.raw.unlink(nt4_dc_smb1) samba3.raw.write(ad_dc_smb1) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 44f91203396..d3907422b78 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -1450,12 +1450,11 @@ for t in tests: "raw.sfileinfo.bug", "raw.sfileinfo.end-of-file", "raw.sfileinfo.rename", - "raw.streams", "raw.unlink", "raw.write",]) : plansmbtorture4testsuite(t, "nt4_dc_smb1", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "ad_dc_smb1", '//$SERVER/tmp -U$USERNAME%$PASSWORD') - elif t in ["base.mangle", "base.tcon", "raw.mkdir"]: + elif t in ["base.mangle", "base.tcon", "raw.mkdir", "raw.streams"]: plansmbtorture4testsuite(t, "nt4_dc_smb1_done", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "ad_dc_smb1_done", '//$SERVER/tmp -U$USERNAME%$PASSWORD') elif t == "rpc.samr.passwords.validate": diff --git a/source4/torture/smb2/streams.c b/source4/torture/smb2/streams.c index e8baa582b4f..9f4a5242015 100644 --- a/source4/torture/smb2/streams.c +++ b/source4/torture/smb2/streams.c @@ -30,6 +30,7 @@ #include "system/filesys.h" #include "system/locale.h" #include "lib/util/tsort.h" +#include "libcli/security/dom_sid.h" #include "libcli/security/security_descriptor.h" #define DNAME "teststreams" @@ -2370,6 +2371,240 @@ done: return ret; } +static bool test_stream_permissions(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + bool ret = true; + const char *fname = DNAME "\\stream_permissions.txt"; + const char *stream = "Stream One:$DATA"; + const char *fname_stream = NULL; + union smb_fileinfo finfo; + union smb_setfileinfo sfinfo; + struct security_ace ace = {0}; + struct security_descriptor *sd = NULL; + struct smb2_handle h = {{0}}; + struct smb2_handle h1 = {{0}}; + TALLOC_CTX *mem_ctx = NULL; + + + mem_ctx = talloc_new(tctx); + torture_assert_goto(tctx, + mem_ctx != NULL, + ret, + done, + "out of memory"); + + /* make sure we start clean */ + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, DNAME); + + torture_assert_ntstatus_ok_goto(tctx, + torture_smb2_testdir(tree, DNAME, &h), + ret, + done, + "Failed to setup up test directory: " DNAME); + + torture_comment(tctx, "(%s) testing permissions on streams\n", __location__); + + fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream); + torture_assert_goto(tctx, + fname_stream != NULL, + ret, + done, + "out of memory"); + + + /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */ + torture_assert_goto(tctx, + create_file_with_stream(tctx, + tree, mem_ctx, fname, fname_stream), + ret, + done, + "failed to create stream"); + + /* open base name file */ + status = torture_smb2_open(tree, fname, SEC_RIGHTS_FILE_ALL, &h1); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to open base name for stream"); + + finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION; + finfo.generic.in.file.handle = h1; + status = smb2_getinfo_file(tree, tctx, &finfo); + + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to getinfo for stream"); + + torture_assert_int_equal_goto(tctx, + finfo.basic_info.out.attrib, + FILE_ATTRIBUTE_ARCHIVE, + ret, + done, + "attrib incorrect"); + + sfinfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION; + sfinfo.generic.in.file.handle = h1; + /* Change the attributes on the base file name. */ + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY; + sfinfo.basic_info.in.create_time = finfo.basic_info.out.create_time, + sfinfo.basic_info.in.access_time = finfo.basic_info.out.access_time, + sfinfo.basic_info.in.write_time = finfo.basic_info.out.write_time, + sfinfo.basic_info.in.change_time = finfo.basic_info.out.change_time, + + status = smb2_setinfo_file(tree, &sfinfo); + + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to set readonly attribute for stream"); + + smb2_util_close(tree, h1); + + /* Try and open the stream name for WRITE_DATA. Should + fail with ACCESS_DENIED. */ + + status = torture_smb2_open(tree, fname, SEC_FILE_WRITE_DATA, &h1); + + torture_assert_ntstatus_equal_goto(tctx, + status, + NT_STATUS_ACCESS_DENIED, + ret, + done, + "expected open of stream would fail"); + + status = torture_smb2_open(tree, + fname, + SEC_FILE_READ_DATA | SEC_FILE_WRITE_ATTRIBUTE, + &h1); + + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to open base file for write_attribute"); + + /* Change the attributes on the base file back. */ + + sfinfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION; + sfinfo.generic.in.file.handle = h1; + /* + * this differs from the SMB1 raw.streams test which + * sets the attrib to 0. Setting attrib to 0 here + * results in the setinfo call succeeding but the + * subsequent attempt to (re)open the file fails + * with ACCESS_DENIED. Some deeper examination of the + * SMB1 test shows that after the smb_raw_setpathinfo + * call that sets attrib to 0 if we call smb_raw_pathinfo + * then the attribs returned shows the NORMAL flag is set. + * + * if we set in SMB2 the attrib to FILE_ATTRIBUTE_NORMAL + * (which according to MS-FSCC is the flag used to + * clear all other flags by specifying it with no other flags set.) + * Using that we can open the file and continue the test (which + * will then pass) + */ + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; + + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to change back attributes for stream"); + + smb2_util_close(tree, h1); + + /* Re-open the base file name. */ + + status = torture_smb2_open(tree, fname, + (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA| + SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC| + SEC_FILE_WRITE_ATTRIBUTE), + &h1); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to reopen for stream"); + + /* Get the existing security descriptor. */ + finfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + finfo.query_secdesc.in.file.handle = h1; + finfo.query_secdesc.in.secinfo_flags = + SECINFO_OWNER | + SECINFO_GROUP | + SECINFO_DACL; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "failed to dacl for base file of stream"); + sd = finfo.query_secdesc.out.sd; + + /* Now add a DENY WRITE security descriptor for Everyone. */ + torture_comment(tctx, "add a new ACE to the DACL\n"); + + ace.type = SEC_ACE_TYPE_ACCESS_DENIED; + ace.flags = 0; + ace.access_mask = SEC_FILE_WRITE_DATA; + ace.trustee = *dom_sid_parse_talloc(tctx, SID_WORLD); + + status = security_descriptor_dacl_add(sd, &ace); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "security_descriptor_dacl_add failed"); + + /* security_descriptor_dacl_add adds to the *end* of + the ace array, we need it at the start. Swap.. */ + ace = sd->dacl->aces[0]; + sd->dacl->aces[0] = sd->dacl->aces[sd->dacl->num_aces-1]; + sd->dacl->aces[sd->dacl->num_aces-1] = ace; + + sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; + sfinfo.set_secdesc.in.file.handle = h1; + sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL; + sfinfo.set_secdesc.in.sd = sd; + + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "setinfo_file for new dacl failed"); + + smb2_util_close(tree, h1); + + /* Try and open the stream name for WRITE_DATA. Should + fail with ACCESS_DENIED. */ + status = torture_smb2_open(tree, + fname_stream, SEC_FILE_WRITE_DATA, &h1); + torture_assert_ntstatus_equal_goto(tctx, + status, + NT_STATUS_ACCESS_DENIED, + ret, + done, + "expected open of stream would fail"); + done: + + smb2_util_close(tree, h1); + smb2_util_close(tree,h); + smb2_util_unlink(tree, fname); + smb2_deltree(tree, DNAME); + return ret; +} + + /* * Simple test creating a stream on a share with "inherit permissions" * enabled. This tests specifically bug 15695. @@ -2465,6 +2700,7 @@ struct torture_suite *torture_smb2_streams_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream); torture_suite_add_1smb2_test(suite, "basefile-rename-with-open-stream", test_basefile_rename_with_open_stream); + torture_suite_add_1smb2_test(suite, "perms", test_stream_permissions); suite->description = talloc_strdup(suite, "SMB2-STREAM tests"); return suite;