The branch, v4-5-test has been updated via 80185ce s3: ntlm_auth: Don't corrupt the output stream with debug messages. via 234de87 s3: torture: Adds regression test case for se_access_check() owner rights issue. via 0b4e710 lib: security: se_access_check() incorrectly processes owner rights (S-1-3-4) DENY ace entries via 692f7d0 s3: torture: Regression test case for permissions check on rename. via 55fb639 s3: smbd: Add missing permissions check on destination folder. via b6d53b6 s3: smbd: Make check_parent_access() available to rename code. via f66b4b0 s3: smbd: rename - missing early error exit if source and destination prefixes are different. from bcc2c63 manpages/vfs_fruit: add warning to fruit:resoure=stream
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-5-test - Log ----------------------------------------------------------------- commit 80185ce75bf1e12dd810fccada63f8eef331c709 Author: Jeremy Allison <j...@samba.org> Date: Sat Dec 10 13:56:18 2016 -0800 s3: ntlm_auth: Don't corrupt the output stream with debug messages. Calling programs expect to cleanly read from STDOUT. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12467 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Uri Simchoni <u...@samba.org> Reviewed-by: Volker Lendecke <v...@samba.org> (cherry picked from commit 9fbd544b90c2b27985637a9bb3fa520f891f8696) Autobuild-User(v4-5-test): Karolin Seeger <ksee...@samba.org> Autobuild-Date(v4-5-test): Wed Dec 14 16:37:10 CET 2016 on sn-devel-144 commit 234de8727ee36197c2a73e7fae38fe4da17cf160 Author: Jeremy Allison <j...@samba.org> Date: Thu Dec 8 10:40:27 2016 -0800 s3: torture: Adds regression test case for se_access_check() owner rights issue. This test passes against Win2K12 but fails against smbd without the previous commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12466 Signed-off-by: Jeremy Allison <j...@samba.org> Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Sat Dec 10 10:11:10 CET 2016 on sn-devel-144 (cherry picked from commit b5c0745b0c99d6cef21b5e7eb695e15aae5d4e38) commit 0b4e710f9baa35def3e1e9457ea16b900ce9ffca Author: Jeremy Allison <j...@samba.org> Date: Thu Dec 8 10:40:18 2016 -0800 lib: security: se_access_check() incorrectly processes owner rights (S-1-3-4) DENY ace entries Reported and proposed fix by Shilpa K <shilpa.krishnare...@gmail.com>. When processing DENY ACE entries for owner rights SIDs (S-1-3-4) the code OR's in the deny access mask bits without taking into account if they were being requested in the requested access mask. E.g. The current logic has: An ACL containining: [0] SID: S-1-3-4 TYPE: DENY MASK: WRITE_DATA [1] SID: S-1-3-4 TYPE: ALLOW MASK: ALLOW_ALL prohibits an open request by the owner for READ_DATA - even though this is explicitly allowed. Furthermore a non-canonical ACL containing: [0] SID: User SID 1-5-21-something TYPE: ALLOW MASK: READ_DATA [1] SID: S-1-3-4 TYPE: DENY MASK: READ_DATA [2] SID: User SID 1-5-21-something TYPE: ALLOW MASK: WRITE_DATA prohibits an open request by the owner for READ_DATA|WRITE_DATA - even though READ_DATA is explicitly allowed in ACE no 0 and is thus already filtered out of the "access-still-needed" mask when the deny ACE no 1 is evaluated. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12466 Signed-off-by: Jeremy Allison <j...@samba.org> Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> (cherry picked from commit 29b02cf22f3c0f2d556408e9e768d68c1efc3b96) commit 692f7d080d5ae8dd85e1201d886a0e89bdacfde2 Author: Jeremy Allison <j...@samba.org> Date: Mon Dec 5 14:34:18 2016 -0800 s3: torture: Regression test case for permissions check on rename. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12460 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Autobuild-User(master): Ralph Böhme <s...@samba.org> Autobuild-Date(master): Wed Dec 7 11:52:03 CET 2016 on sn-devel-144 (cherry picked from commit 52fad16f1c20109f352c25832d841ff778b2518a) commit 55fb639a617f81e74771c69cfbae0c4398206bbe Author: Jeremy Allison <j...@samba.org> Date: Mon Dec 5 14:32:55 2016 -0800 s3: smbd: Add missing permissions check on destination folder. Based on code from Michael Zeis <mzeis.quan...@gmail.com>. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12460 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> (cherry picked from commit 91b591224ab7f8ea7b4594da9f61efef14353f7f) commit b6d53b69b390ffeb6f2aafd917c21601301969e4 Author: Jeremy Allison <j...@samba.org> Date: Mon Dec 5 14:32:03 2016 -0800 s3: smbd: Make check_parent_access() available to rename code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12460 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> (cherry picked from commit beb8a73e95e768565760f79c2a16586bafb4e58c) commit f66b4b06fac16ae3ec6880da529aa63c75388408 Author: Jeremy Allison <j...@samba.org> Date: Mon Dec 5 14:13:14 2016 -0800 s3: smbd: rename - missing early error exit if source and destination prefixes are different. Noticed by Michael Zeis <mzeis.quan...@gmail.com>. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12460 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> (cherry picked from commit 2bfad1c9d3237ad8d174b7dc2d1e6e3c53fdb8dc) ----------------------------------------------------------------------- Summary of changes: libcli/security/access_check.c | 2 +- selftest/skip | 2 + source3/selftest/tests.py | 7 +- source3/smbd/open.c | 2 +- source3/smbd/proto.h | 3 + source3/smbd/reply.c | 18 ++ source3/torture/torture.c | 578 +++++++++++++++++++++++++++++++++++++++++ source3/utils/ntlm_auth.c | 6 +- 8 files changed, 612 insertions(+), 6 deletions(-) Changeset truncated at 500 lines: diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c index 2be5928..b4c850b 100644 --- a/libcli/security/access_check.c +++ b/libcli/security/access_check.c @@ -220,7 +220,7 @@ NTSTATUS se_access_check(const struct security_descriptor *sd, owner_rights_allowed |= ace->access_mask; owner_rights_default = false; } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) { - owner_rights_denied |= ace->access_mask; + owner_rights_denied |= (bits_remaining & ace->access_mask); owner_rights_default = false; } continue; diff --git a/selftest/skip b/selftest/skip index ba6718a..a61e970 100644 --- a/selftest/skip +++ b/selftest/skip @@ -48,6 +48,8 @@ ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-EA # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-OFD-LOCK # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-STREAM-DELETE # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).RENAME-ACCESS # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).OWNER-RIGHTS # Don't test against the s4 ntvfs server anymore ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).PIDHIGH # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).NTTRANS-FSCTL # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).SMB2-NEGPROT # Fails against the s4 ntvfs server diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 7cfebd6..9a2d586 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -49,7 +49,7 @@ tests = ["FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7" "OPLOCK1", "OPLOCK2", "OPLOCK4", "STREAMERROR", "DIR", "DIR1", "DIR-CREATETIME", "TCON", "TCONDEV", "RW1", "RW2", "RW3", "LARGE_READX", "RW-SIGNING", "OPEN", "XCOPY", "RENAME", "DELETE", "DELETE-LN", "WILDDELETE", "PROPERTIES", "W2K", - "TCON2", "IOCTL", "CHKPATH", "FDSESS", "CHAIN1", "CHAIN2", + "TCON2", "IOCTL", "CHKPATH", "FDSESS", "CHAIN1", "CHAIN2", "OWNER-RIGHTS", "CHAIN3", "PIDHIGH", "GETADDRINFO", "UID-REGRESSION-TEST", "SHORTNAME-TEST", "CASE-INSENSITIVE-CREATE", "SMB2-BASIC", "NTTRANS-FSCTL", "SMB2-NEGPROT", @@ -68,6 +68,11 @@ for t in tests: plantestsuite("samba3.smbtorture_s3.crypt_server(nt4_dc).%s" % t, "nt4_dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/tmpenc', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) plantestsuite("samba3.smbtorture_s3.plain(ad_dc_ntvfs).%s" % t, "ad_dc_ntvfs", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/tmp', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) +# +# RENAME-ACCESS needs to run against a special share - acl_xattr_ign_sysacl_windows +# +plantestsuite("samba3.smbtorture_s3.plain(nt4_dc).%s" % "RENAME-ACCESS","nt4_dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), "RENAME-ACCESS", '//$SERVER_IP/acl_xattr_ign_sysacl_windows', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) +plantestsuite("samba3.smbtorture_s3.crypt_client(nt4_dc).%s" % "RENAME-ACCESS", "nt4_dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), "RENAME-ACCESS", '//$SERVER_IP/acl_xattr_ign_sysacl_windows', '$USERNAME', '$PASSWORD', smbtorture3, "-e", "-l $LOCAL_PATH"]) # non-crypt only tests = ["OPLOCK-CANCEL"] diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 9d10d19..e9bfdec 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -235,7 +235,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn, return NT_STATUS_OK; } -static NTSTATUS check_parent_access(struct connection_struct *conn, +NTSTATUS check_parent_access(struct connection_struct *conn, struct smb_filename *smb_fname, uint32_t access_mask) { diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 352d28c..50ede9d 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -642,6 +642,9 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn, const struct smb_filename *smb_fname, bool use_privs, uint32_t access_mask); +NTSTATUS check_parent_access(struct connection_struct *conn, + struct smb_filename *smb_fname, + uint32_t access_mask); NTSTATUS fd_open(struct connection_struct *conn, files_struct *fsp, int flags, mode_t mode); NTSTATUS fd_close(files_struct *fsp); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 0aec433..6acbaca 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -6615,6 +6615,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, struct smb_filename *smb_fname_dst = NULL; NTSTATUS status = NT_STATUS_OK; struct share_mode_lock *lck = NULL; + uint32_t access_mask = SEC_DIR_ADD_FILE; bool dst_exists, old_is_stream, new_is_stream; status = check_name(conn, smb_fname_dst_in->base_name); @@ -6812,6 +6813,23 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) { status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + /* Do we have rights to move into the destination ? */ + if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) { + /* We're moving a directory. */ + access_mask = SEC_DIR_ADD_SUBDIR; + } + status = check_parent_access(conn, + smb_fname_dst, + access_mask); + if (!NT_STATUS_IS_OK(status)) { + DBG_INFO("check_parent_access on " + "dst %s returned %s\n", + smb_fname_str_dbg(smb_fname_dst), + nt_errstr(status)); + goto out; } lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); diff --git a/source3/torture/torture.c b/source3/torture/torture.c index ecacd1a..c978741 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -4898,6 +4898,582 @@ static bool run_rename(int dummy) return correct; } +/* + Test rename into a directory with an ACL denying it. + */ +static bool run_rename_access(int dummy) +{ + static struct cli_state *cli = NULL; + static struct cli_state *posix_cli = NULL; + const char *src = "test.txt"; + const char *dname = "dir"; + const char *dst = "dir\\test.txt"; + const char *dsrc = "test.dir"; + const char *ddst = "dir\\test.dir"; + uint16_t fnum = (uint16_t)-1; + struct security_descriptor *sd = NULL; + struct security_descriptor *newsd = NULL; + NTSTATUS status; + TALLOC_CTX *frame = NULL; + + frame = talloc_stackframe(); + printf("starting rename access test\n"); + + /* Windows connection. */ + if (!torture_open_connection(&cli, 0)) { + goto fail; + } + + smbXcli_conn_set_sockopt(cli->conn, sockops); + + /* Posix connection. */ + if (!torture_open_connection(&posix_cli, 0)) { + goto fail; + } + + smbXcli_conn_set_sockopt(posix_cli->conn, sockops); + + status = torture_setup_unix_extensions(posix_cli); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Start with a clean slate. */ + cli_unlink(cli, src, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + cli_unlink(cli, dst, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + cli_rmdir(cli, dsrc); + cli_rmdir(cli, ddst); + cli_rmdir(cli, dname); + + /* + * Setup the destination directory with a DENY ACE to + * prevent new files within it. + */ + status = cli_ntcreate(cli, + dname, + 0, + FILE_READ_ATTRIBUTES|READ_CONTROL_ACCESS| + WRITE_DAC_ACCESS|FILE_READ_DATA| + WRITE_OWNER_ACCESS, + FILE_ATTRIBUTE_DIRECTORY, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, + FILE_DIRECTORY_FILE, + 0, + &fnum, + NULL); + if (!NT_STATUS_IS_OK(status)) { + printf("Create of %s - %s\n", dname, nt_errstr(status)); + goto fail; + } + + status = cli_query_secdesc(cli, + fnum, + frame, + &sd); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_query_secdesc failed for %s (%s)\n", + dname, nt_errstr(status)); + goto fail; + } + + newsd = security_descriptor_dacl_create(frame, + 0, + NULL, + NULL, + SID_WORLD, + SEC_ACE_TYPE_ACCESS_DENIED, + SEC_DIR_ADD_FILE|SEC_DIR_ADD_SUBDIR, + 0, + NULL); + if (newsd == NULL) { + goto fail; + } + sd->dacl = security_acl_concatenate(frame, + newsd->dacl, + sd->dacl); + if (sd->dacl == NULL) { + goto fail; + } + status = cli_set_secdesc(cli, fnum, sd); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_set_secdesc failed for %s (%s)\n", + dname, nt_errstr(status)); + goto fail; + } + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed for %s (%s)\n", + dname, nt_errstr(status)); + goto fail; + } + /* Now go around the back and chmod to 777 via POSIX. */ + status = cli_posix_chmod(posix_cli, dname, 0777); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_chmod failed for %s (%s)\n", + dname, nt_errstr(status)); + goto fail; + } + + /* Check we can't create a file within dname via Windows. */ + status = cli_openx(cli, dst, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, &fnum); + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + cli_close(posix_cli, fnum); + printf("Create of %s should be ACCESS denied, was %s\n", + dst, nt_errstr(status)); + goto fail; + } + + /* Make the sample file/directory. */ + status = cli_openx(cli, src, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, &fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("open of %s failed (%s)\n", src, nt_errstr(status)); + goto fail; + } + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_close failed (%s)\n", nt_errstr(status)); + goto fail; + } + + status = cli_mkdir(cli, dsrc); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_mkdir of %s failed (%s)\n", + dsrc, nt_errstr(status)); + goto fail; + } + + /* + * OK - renames of the new file and directory into the + * dst directory should fail. + */ + + status = cli_rename(cli, src, dst); + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("rename of %s -> %s should be ACCESS denied, was %s\n", + src, dst, nt_errstr(status)); + goto fail; + } + status = cli_rename(cli, dsrc, ddst); + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("rename of %s -> %s should be ACCESS denied, was %s\n", + src, dst, nt_errstr(status)); + goto fail; + } + + TALLOC_FREE(frame); + return true; + + fail: + + if (posix_cli) { + torture_close_connection(posix_cli); + } + + if (cli) { + if (fnum != -1) { + cli_close(cli, fnum); + } + cli_unlink(cli, src, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + cli_unlink(cli, dst, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + cli_rmdir(cli, dsrc); + cli_rmdir(cli, ddst); + cli_rmdir(cli, dname); + + torture_close_connection(cli); + } + + TALLOC_FREE(frame); + return false; +} + +/* + Test owner rights ACE. + */ +static bool run_owner_rights(int dummy) +{ + static struct cli_state *cli = NULL; + const char *fname = "owner_rights.txt"; + uint16_t fnum = (uint16_t)-1; + struct security_descriptor *sd = NULL; + struct security_descriptor *newsd = NULL; + NTSTATUS status; + TALLOC_CTX *frame = NULL; + + frame = talloc_stackframe(); + printf("starting owner rights test\n"); + + /* Windows connection. */ + if (!torture_open_connection(&cli, 0)) { + goto fail; + } + + smbXcli_conn_set_sockopt(cli->conn, sockops); + + /* Start with a clean slate. */ + cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + + /* Create the test file. */ + /* Now try and open for read and write-dac. */ + status = cli_ntcreate(cli, + fname, + 0, + GENERIC_ALL_ACCESS, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE| + FILE_SHARE_DELETE, + FILE_CREATE, + 0, + 0, + &fnum, + NULL); + if (!NT_STATUS_IS_OK(status)) { + printf("Create of %s - %s\n", fname, nt_errstr(status)); + goto fail; + } + + /* Get the original SD. */ + status = cli_query_secdesc(cli, + fnum, + frame, + &sd); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_query_secdesc failed for %s (%s)\n", + fname, nt_errstr(status)); + goto fail; + } + + /* + * Add an "owner-rights" ACE denying WRITE_DATA, + * and an "owner-rights" ACE allowing READ_DATA. + */ + + newsd = security_descriptor_dacl_create(frame, + 0, + NULL, + NULL, + SID_OWNER_RIGHTS, + SEC_ACE_TYPE_ACCESS_DENIED, + FILE_WRITE_DATA, + 0, + SID_OWNER_RIGHTS, + SEC_ACE_TYPE_ACCESS_ALLOWED, + FILE_READ_DATA, + 0, + NULL); + if (newsd == NULL) { + goto fail; + } + sd->dacl = security_acl_concatenate(frame, + newsd->dacl, + sd->dacl); + if (sd->dacl == NULL) { + goto fail; + } + status = cli_set_secdesc(cli, fnum, sd); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_set_secdesc failed for %s (%s)\n", + fname, nt_errstr(status)); + goto fail; + } + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed for %s (%s)\n", + fname, nt_errstr(status)); + goto fail; + } + fnum = (uint16_t)-1; + + /* Try and open for FILE_WRITE_DATA */ + status = cli_ntcreate(cli, + fname, + 0, + FILE_WRITE_DATA, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE| + FILE_SHARE_DELETE, + FILE_OPEN, + 0, + 0, + &fnum, + NULL); + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("Open of %s - %s\n", fname, nt_errstr(status)); + goto fail; + } + + /* Now try and open for FILE_READ_DATA */ + status = cli_ntcreate(cli, + fname, + 0, + FILE_READ_DATA, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE| + FILE_SHARE_DELETE, + FILE_OPEN, + 0, + 0, + &fnum, + NULL); + if (!NT_STATUS_IS_OK(status)) { + printf("Open of %s - %s\n", fname, nt_errstr(status)); + goto fail; + } + + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed for %s (%s)\n", + fname, nt_errstr(status)); + goto fail; + } + + /* Restore clean slate. */ + TALLOC_FREE(sd); + cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + + /* Create the test file. */ + status = cli_ntcreate(cli, + fname, + 0, + GENERIC_ALL_ACCESS, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE| + FILE_SHARE_DELETE, + FILE_CREATE, + 0, + 0, + &fnum, + NULL); + if (!NT_STATUS_IS_OK(status)) { + printf("Create of %s - %s\n", fname, nt_errstr(status)); + goto fail; + } + + /* Get the original SD. */ + status = cli_query_secdesc(cli, + fnum, + frame, + &sd); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_query_secdesc failed for %s (%s)\n", + fname, nt_errstr(status)); + goto fail; + } + + /* + * Add an "owner-rights ACE denying WRITE_DATA, + * and an "owner-rights ACE allowing READ_DATA|WRITE_DATA. + */ + + newsd = security_descriptor_dacl_create(frame, + 0, + NULL, + NULL, + SID_OWNER_RIGHTS, + SEC_ACE_TYPE_ACCESS_DENIED, + FILE_WRITE_DATA, + 0, + SID_OWNER_RIGHTS, -- Samba Shared Repository