From 05667d36de78cbc73ed8e182525149b88c1a00c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 19 Jun 2019 11:32:18 -0700 Subject: [PATCH] s3: torture: Add POSIX-ACL-OPLOCK test to check interaction of posix ACL operations with an oplocked Windows handle. (Spoiler alert, it breaks the oplock :-). Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Mon Jun 24 20:05:34 UTC 2019 on sn-devel-184 --- selftest/skip | 1 + source3/selftest/tests.py | 1 + source3/torture/torture.c | 209 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) diff --git a/selftest/skip b/selftest/skip index bdf3c71893d..9ff673e0c92 100644 --- a/selftest/skip +++ b/selftest/skip @@ -49,6 +49,7 @@ ^samba3.smbtorture_s3.plain.POSIX-OFD-LOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.POSIX-STREAM-DELETE\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.POSIX-MKDIR\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain.POSIX-ACL-OPLOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.WINDOWS-BAD-SYMLINK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.RENAME-ACCESS\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 4bdfc0062c6..c7d24f68d6c 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -160,6 +160,7 @@ for s in shares: posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL", "POSIX-SYMLINK-EA", "POSIX-OFD-LOCK", "POSIX-STREAM-DELETE", "WINDOWS-BAD-SYMLINK", "POSIX-MKDIR", "POSIX-BLOCKING-LOCK", + "POSIX-ACL-OPLOCK", ] for t in posix_tests: diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 839acafdcd3..d93a02b2d6a 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -8562,6 +8562,211 @@ static bool run_posix_mkdir_test(int dummy) return correct; } +struct posix_acl_oplock_state { + struct tevent_context *ev; + struct cli_state *cli; + bool *got_break; + bool *acl_ret; + NTSTATUS status; +}; + +static void posix_acl_oplock_got_break(struct tevent_req *req) +{ + struct posix_acl_oplock_state *state = tevent_req_callback_data( + req, struct posix_acl_oplock_state); + uint16_t fnum; + uint8_t level; + NTSTATUS status; + + status = cli_smb_oplock_break_waiter_recv(req, &fnum, &level); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_smb_oplock_break_waiter_recv returned %s\n", + nt_errstr(status)); + return; + } + *state->got_break = true; + + req = cli_oplock_ack_send(state, state->ev, state->cli, fnum, + NO_OPLOCK); + if (req == NULL) { + printf("cli_oplock_ack_send failed\n"); + return; + } +} + +static void posix_acl_oplock_got_acl(struct tevent_req *req) +{ + struct posix_acl_oplock_state *state = tevent_req_callback_data( + req, struct posix_acl_oplock_state); + size_t ret_size = 0; + char *ret_data = NULL; + + state->status = cli_posix_getacl_recv(req, + state, + &ret_size, + &ret_data); + + if (!NT_STATUS_IS_OK(state->status)) { + printf("cli_posix_getacl_recv returned %s\n", + nt_errstr(state->status)); + } + *state->acl_ret = true; +} + +static bool run_posix_acl_oplock_test(int dummy) +{ + struct tevent_context *ev; + struct cli_state *cli1, *cli2; + struct tevent_req *oplock_req, *getacl_req; + const char *fname = "posix_acl_oplock"; + uint16_t fnum; + int saved_use_oplocks = use_oplocks; + NTSTATUS status; + bool correct = true; + bool got_break = false; + bool acl_ret = false; + + struct posix_acl_oplock_state *state; + + printf("starting posix_acl_oplock test\n"); + + if (!torture_open_connection(&cli1, 0)) { + use_level_II_oplocks = false; + use_oplocks = saved_use_oplocks; + return false; + } + + if (!torture_open_connection(&cli2, 1)) { + use_level_II_oplocks = false; + use_oplocks = saved_use_oplocks; + return false; + } + + /* Setup posix on cli2 only. */ + status = torture_setup_unix_extensions(cli2); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + smbXcli_conn_set_sockopt(cli1->conn, sockops); + smbXcli_conn_set_sockopt(cli2->conn, sockops); + + cli_unlink(cli1, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + + /* Create the file on the Windows connection. */ + status = cli_openx(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, + &fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("open of %s failed (%s)\n", fname, nt_errstr(status)); + return false; + } + + status = cli_close(cli1, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close1 failed (%s)\n", nt_errstr(status)); + return false; + } + + cli1->use_oplocks = true; + + /* Open with oplock. */ + status = cli_ntcreate(cli1, + 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 failed (%s)\n", fname, nt_errstr(status)); + return false; + } + + ev = samba_tevent_context_init(talloc_tos()); + if (ev == NULL) { + printf("tevent_context_init failed\n"); + return false; + } + + state = talloc_zero(ev, struct posix_acl_oplock_state); + if (state == NULL) { + printf("talloc failed\n"); + return false; + } + state->ev = ev; + state->cli = cli1; + state->got_break = &got_break; + state->acl_ret = &acl_ret; + + oplock_req = cli_smb_oplock_break_waiter_send( + talloc_tos(), ev, cli1); + if (oplock_req == NULL) { + printf("cli_smb_oplock_break_waiter_send failed\n"); + return false; + } + tevent_req_set_callback(oplock_req, posix_acl_oplock_got_break, state); + + /* Get ACL on POSIX connection - should break oplock. */ + getacl_req = cli_posix_getacl_send(talloc_tos(), + ev, + cli2, + fname); + if (getacl_req == NULL) { + printf("cli_posix_getacl_send failed\n"); + return false; + } + tevent_req_set_callback(getacl_req, posix_acl_oplock_got_acl, state); + + while (!got_break || !acl_ret) { + int ret; + ret = tevent_loop_once(ev); + if (ret == -1) { + printf("tevent_loop_once failed: %s\n", + strerror(errno)); + return false; + } + } + + if (!NT_STATUS_IS_OK(state->status)) { + printf("getacl failed (%s)\n", nt_errstr(state->status)); + correct = false; + } + + status = cli_close(cli1, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close2 failed (%s)\n", nt_errstr(status)); + correct = false; + } + + status = cli_unlink(cli1, + fname, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + if (!NT_STATUS_IS_OK(status)) { + printf("unlink failed (%s)\n", nt_errstr(status)); + correct = false; + } + + if (!torture_close_connection(cli1)) { + correct = false; + } + if (!torture_close_connection(cli2)) { + correct = false; + } + + if (!got_break) { + correct = false; + } + + printf("finished posix acl oplock test\n"); + + return correct; +} static uint32_t open_attrs_table[] = { FILE_ATTRIBUTE_NORMAL, @@ -13299,6 +13504,10 @@ static struct { .name = "POSIX-MKDIR", .fn = run_posix_mkdir_test, }, + { + .name = "POSIX-ACL-OPLOCK", + .fn = run_posix_acl_oplock_test, + }, { .name = "WINDOWS-BAD-SYMLINK", .fn = run_symlink_open_test, -- 2.47.2