[SCM] Samba Shared Repository - branch v4-16-test updated

Jule Anger janger at samba.org
Mon Jan 16 10:48:02 UTC 2023


The branch, v4-16-test has been updated
       via  7b49569afcb s4: libcli: Ignore errors when getting A records after fetching AAAA records.
       via  627a9886da8 s3: smbd: In synthetic_pathref() change DBG_ERR -> DBG_NOTICE to avoid spamming the logs.
       via  e5e39bbc77f s3: smbd: Cause SMB2_OP_FLUSH to go synchronous in a compound anywhere but the last operation in the list.
       via  bfadcc893e6 s3: smbd: Add utility function smbd_smb2_is_last_in_compound().
       via  9b357c947fd s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_FLUSH test to smb2.compound_async.
       via  c9ed55b39ef s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
       via  d7bcdfa6b88 nsswitch:libwbclient - fix leak in wbcCtxPingDc2
       via  113536e0d73 s3: libsmbclient: Fix smbc_getxattr() to return 0 on success.
       via  628a1c33827 s4: torture: Show return value for smbc_getxattr() is incorrect (returns >0 for success, should return zero).
      from  a1fa2c18e56 s4:lib/messaging: fix interaction between imessaging_context_destructor and irpc_destructor

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-16-test


- Log -----------------------------------------------------------------
commit 7b49569afcb968a5ac4b4fdd96480bb7b8ab01b7
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Nov 8 10:13:18 2022 -0800

    s4: libcli: Ignore errors when getting A records after fetching AAAA records.
    
    The target may only be available over IPv6.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15226
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Wed Nov  9 20:34:07 UTC 2022 on sn-devel-184
    
    (cherry picked from commit 10537a89bb0b461ba31d614b7c9ed56a842422e7)
    
    Autobuild-User(v4-16-test): Jule Anger <janger at samba.org>
    Autobuild-Date(v4-16-test): Mon Jan 16 10:47:49 UTC 2023 on sn-devel-184

commit 627a9886da8fa8c2dbd0aa4cf273a5ebc70879ed
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Nov 15 13:29:46 2022 -0800

    s3: smbd: In synthetic_pathref() change DBG_ERR -> DBG_NOTICE to avoid spamming the logs.
    
    Can easily be seen by doing make test TESTS=fruit
    and looking in st/nt4_dc/smbd_test.log.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15210
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Wed Nov 16 06:00:56 UTC 2022 on sn-devel-184
    
    (cherry picked from commit f0ca9546102acf09f1834c03f8907ed26bfc80f8)

commit e5e39bbc77f5f842b69f0789f3dbfa58bfbdd010
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Oct 20 15:19:05 2022 -0700

    s3: smbd: Cause SMB2_OP_FLUSH to go synchronous in a compound anywhere but the last operation in the list.
    
    Async read and write go synchronous in the same case,
    so do the same here.
    
    Remove knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Thu Nov 17 05:55:42 UTC 2022 on sn-devel-184
    
    (cherry picked from commit 26adf3344337f4e8d5d2107e6ba42e5ea7656372)

commit bfadcc893e6ff2cd7f34896a194e7029fd6a76f5
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Oct 20 15:08:14 2022 -0700

    s3: smbd: Add utility function smbd_smb2_is_last_in_compound().
    
    Not yet used. Returns true if we're processing the last SMB2 request in a
    compound.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit e668c3a82cd566b405c976d45659dd79786948de)

commit 9b357c947fd6c36779f49dc37f9c81392c9c81fb
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Oct 20 14:22:25 2022 -0700

    s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_FLUSH test to smb2.compound_async.
    
    Shows we fail sending an SMB2_OP_FLUSH + SMB2_OP_FLUSH
    compound if we immediately close the file afterward.
    
    Internally the flushes go async and we free the req, then
    we process the close. When the flushes complete they try to access
    already freed data.
    
    Extra test which will allow me to test when the final
    component (flush) of the compound goes async and returns
    NT_STATUS_PENDING.
    
    Add knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 6f149dfd9d8d2619a9e18975ebcf5e69df2b7766)

commit c9ed55b39efc7638b898db6df8352b10950c6c93
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Oct 18 16:22:33 2022 -0700

    s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
    
    Shows we fail sending an SMB2_OP_FLUSH + SMB2_OP_CLOSE
    compound. Internally the flush goes async and
    we free the req, then we process the close.
    When the flush completes it tries to access
    already freed data.
    
    Found using the Apple MacOSX client at SNIA SDC 2022.
    
    Add knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (back-ported from commit 17a110c1b58196eb8ecf3c76eb97e8508976c544)

commit d7bcdfa6b88d639c6d8c4352722b432d93fdb328
Author: Andrew Walker <awalker at ixsystems.com>
Date:   Fri Sep 2 16:31:32 2022 -0400

    nsswitch:libwbclient - fix leak in wbcCtxPingDc2
    
    Memory allocated for response is never freed.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15164
    
    Signed-off-by: Andrew Walker <awalker at ixsystems.com>
    Reviewed-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Christof Schmitt <cs at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Tue Sep  6 20:10:17 UTC 2022 on sn-devel-184
    
    (cherry picked from commit aa9f3a2da97ae13cce3e50fe3d58f143200e9a17)

commit 113536e0d735a5235f8be29d4fd1cfc8177930b1
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Oct 28 15:31:39 2022 -0700

    s3: libsmbclient: Fix smbc_getxattr() to return 0 on success.
    
    Remove knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14808
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: David Mulder <dmulder at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Tue Nov  1 18:31:22 UTC 2022 on sn-devel-184
    
    (cherry picked from commit bdbb38d16c8eaff33484bb747efa639c4d8e7f35)

commit 628a1c338277f3fc4250fd54809bf326ec15c0ef
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Oct 28 15:28:41 2022 -0700

    s4: torture: Show return value for smbc_getxattr() is incorrect (returns >0 for success, should return zero).
    
    Add torture test to show smbc_getxattr() should return -1 on
    failure, 0 on success.
    
    Add knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14808
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: David Mulder <dmulder at samba.org>
    (cherry picked from commit 74636dfe24c15677261fc40c0a4ec62404898cf4)

-----------------------------------------------------------------------

Summary of changes:
 nsswitch/libwbclient/wbc_pam.c              |   1 +
 source3/libsmb/libsmb_xattr.c               |   6 +-
 source3/selftest/tests.py                   |   2 +
 source3/smbd/files.c                        |   2 +-
 source3/smbd/globals.h                      |   1 +
 source3/smbd/smb2_flush.c                   |  14 ++
 source3/smbd/smb2_server.c                  |   6 +
 source4/libcli/resolve/dns_ex.c             |  14 +-
 source4/torture/libsmbclient/libsmbclient.c |  94 +++++++++++
 source4/torture/smb2/compound.c             | 232 ++++++++++++++++++++++++++++
 source4/torture/smb2/smb2.c                 |   1 +
 11 files changed, 365 insertions(+), 8 deletions(-)


Changeset truncated at 500 lines:

diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c
index b4bb2678ad0..4df0ffe2eb5 100644
--- a/nsswitch/libwbclient/wbc_pam.c
+++ b/nsswitch/libwbclient/wbc_pam.c
@@ -731,6 +731,7 @@ wbcErr wbcCtxPingDc2(struct wbcContext *ctx, const char *domain,
 	BAIL_ON_WBC_ERROR(wbc_status);
 
  done:
+	winbindd_free_response(&response);
 	return wbc_status;
 }
 
diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c
index d66ea63617c..c7091ffaca2 100644
--- a/source3/libsmb/libsmb_xattr.c
+++ b/source3/libsmb/libsmb_xattr.c
@@ -2176,7 +2176,11 @@ SMBC_getxattr_ctx(SMBCCTX *context,
                         errno = SMBC_errno(context, srv->cli);
                 }
 		TALLOC_FREE(frame);
-                return ret;
+		/*
+		 * static function cacl_get returns a value greater than zero
+		 * on success. Map this to zero meaning success.
+		 */
+                return ret < 0 ? -1 : 0;
         }
 
         /* Unsupported attribute name */
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 31a80b82e87..2865657a912 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -999,6 +999,8 @@ for t in tests:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/aio -U$USERNAME%$PASSWORD', 'aio')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
+    elif t == "smb2.compound_async":
+        plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
     elif t == "rpc.samba3.netlogon" or t == "rpc.samba3.sessionkey":
         plansmbtorture4testsuite(t, "nt4_dc_smb1", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --option=torture:wksname=samba3rpctest')
         plansmbtorture4testsuite(t, "ad_dc_smb1", '//$SERVER/tmp -U$USERNAME%$PASSWORD --option=torture:wksname=samba3rpctest')
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index cbe355c5fba..e5597ba78f3 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -671,7 +671,7 @@ NTSTATUS synthetic_pathref(TALLOC_CTX *mem_ctx,
 
 	status = openat_pathref_fsp(dirfsp, smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
-		DBG_ERR("opening [%s] failed\n",
+		DBG_NOTICE("opening [%s] failed\n",
 			smb_fname_str_dbg(smb_fname));
 		TALLOC_FREE(smb_fname);
 		return status;
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index eef38f00a4e..efd2032ce1a 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -238,6 +238,7 @@ void smbd_server_disconnect_client_ex(struct smbXsrv_client *client,
 const char *smb2_opcode_name(uint16_t opcode);
 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size);
 bool smbd_smb2_is_compound(const struct smbd_smb2_request *req);
+bool smbd_smb2_is_last_in_compound(const struct smbd_smb2_request *req);
 
 NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 			     NTTIME now, struct smbXsrv_connection **_xconn);
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
index e73666f0afc..5c8c171e418 100644
--- a/source3/smbd/smb2_flush.c
+++ b/source3/smbd/smb2_flush.c
@@ -126,6 +126,8 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 	struct tevent_req *subreq;
 	struct smbd_smb2_flush_state *state;
 	struct smb_request *smbreq;
+	bool is_compound = false;
+	bool is_last_in_compound = false;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_flush_state);
@@ -195,6 +197,18 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 
 	tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
 
+	is_compound = smbd_smb2_is_compound(smb2req);
+	is_last_in_compound = smbd_smb2_is_last_in_compound(smb2req);
+
+	if (is_compound && !is_last_in_compound) {
+		/*
+		 * Can't go async if we're not the
+		 * last request in a compound request.
+		 * Cause this request to complete synchronously.
+		 */
+		smb2_request_set_async_internal(state->smb2req, true);
+	}
+
 	/* Ensure any close request knows about this outstanding IO. */
 	if (!aio_add_req_to_fsp(fsp, req)) {
 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index f4e16cb7da9..f0b4814628b 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -229,6 +229,12 @@ bool smbd_smb2_is_compound(const struct smbd_smb2_request *req)
 	return req->in.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ);
 }
 
+bool smbd_smb2_is_last_in_compound(const struct smbd_smb2_request *req)
+{
+	return (req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ ==
+		req->in.vector_count);
+}
+
 static NTSTATUS smbd_initialize_smb2(struct smbXsrv_connection *xconn,
 				     uint64_t expected_seq_low)
 {
diff --git a/source4/libcli/resolve/dns_ex.c b/source4/libcli/resolve/dns_ex.c
index 0bb3ba02287..b8447bec4de 100644
--- a/source4/libcli/resolve/dns_ex.c
+++ b/source4/libcli/resolve/dns_ex.c
@@ -245,13 +245,15 @@ static struct dns_records_container get_a_aaaa_records(TALLOC_CTX *mem_ctx,
 		* Most of the server do it, let's ask for A specificaly.
 		*/
 		err = dns_lookup(tmp_ctx, name, QTYPE_A, &reply);
-		if (!ERR_DNS_IS_OK(err)) {
-			goto done;
-		}
-
-		total = reply_to_addrs(tmp_ctx, &a_num, &addrs, total,
+		if (ERR_DNS_IS_OK(err)) {
+			/*
+			 * Ignore an error here and just return any AAAA
+			 * records we already got. This may be an IPv6-only
+			 * config.
+			 */
+			total = reply_to_addrs(tmp_ctx, &a_num, &addrs, total,
 					reply, port);
-
+		}
 	}
 
 	if (total) {
diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c
index 48a624cb7e2..80545abe10c 100644
--- a/source4/torture/libsmbclient/libsmbclient.c
+++ b/source4/torture/libsmbclient/libsmbclient.c
@@ -1473,6 +1473,98 @@ static bool torture_libsmbclient_getatr(struct torture_context *tctx)
 	return true;
 }
 
+static bool torture_libsmbclient_getxattr(struct torture_context *tctx)
+{
+	const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+	int fhandle = -1;
+	SMBCCTX *ctx = NULL;
+	char *getxattr_name = NULL;
+	char value[4096];
+	bool ok = false;
+	int ret = -1;
+
+	if (smburl == NULL) {
+		torture_fail(tctx,
+			     "option --option=torture:smburl="
+			     "smb://user:password@server missing\n");
+	}
+
+	ok = torture_libsmbclient_init_context(tctx, &ctx);
+	torture_assert(tctx, ok, "Failed to init context");
+	smbc_set_context(ctx);
+
+	getxattr_name = talloc_asprintf(tctx,
+			"%s/getxattr",
+			smburl);
+	if (getxattr_name == NULL) {
+		torture_result(tctx,
+			       TORTURE_FAIL,
+			       __location__": %s",
+			       "talloc fail\n");
+		return false;
+	}
+	/* Ensure the file doesn't exist. */
+	smbc_unlink(getxattr_name);
+
+	/* Create testfile. */
+	fhandle = smbc_creat(getxattr_name, 0666);
+	if (fhandle < 0) {
+		torture_fail_goto(tctx,
+			done,
+			talloc_asprintf(tctx,
+				"failed to create file '%s': %s",
+				getxattr_name,
+				strerror(errno)));
+	}
+	ret = smbc_close(fhandle);
+	torture_assert_int_equal_goto(tctx,
+		ret,
+		0,
+		ok,
+		done,
+		talloc_asprintf(tctx,
+			"failed to close handle for '%s'",
+			getxattr_name));
+
+	/*
+	 * Ensure getting a non-existent attribute returns -1.
+	 */
+	ret = smbc_getxattr(getxattr_name, "foobar", value, sizeof(value));
+	torture_assert_int_equal_goto(tctx,
+		ret,
+		-1,
+		ok,
+		done,
+		talloc_asprintf(tctx,
+			"smbc_getxattr(foobar) on '%s' should "
+			"get -1, got %d\n",
+			getxattr_name,
+			ret));
+
+	/*
+	 * Ensure getting a valid attribute returns 0.
+	 */
+	ret = smbc_getxattr(getxattr_name, "system.*", value, sizeof(value));
+	torture_assert_int_equal_goto(tctx,
+		ret,
+		0,
+		ok,
+		done,
+		talloc_asprintf(tctx,
+			"smbc_getxattr(foobar) on '%s' should "
+			"get -1, got %d\n",
+			getxattr_name,
+			ret));
+
+	ok = true;
+
+  done:
+
+	smbc_unlink(getxattr_name);
+	smbc_free_context(ctx, 1);
+	return ok;
+}
+
 NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite;
@@ -1501,6 +1593,8 @@ NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
 					torture_libsmbclient_rename);
 	torture_suite_add_simple_test(suite, "getatr",
 		torture_libsmbclient_getatr);
+	torture_suite_add_simple_test(suite, "getxattr",
+		torture_libsmbclient_getxattr);
 
 	suite->description = talloc_strdup(suite, "libsmbclient interface tests");
 
diff --git a/source4/torture/smb2/compound.c b/source4/torture/smb2/compound.c
index cf19361130f..47a550f0873 100644
--- a/source4/torture/smb2/compound.c
+++ b/source4/torture/smb2/compound.c
@@ -2057,6 +2057,223 @@ done:
 	return ret;
 }
 
+static bool test_compound_async_flush_close(struct torture_context *tctx,
+					    struct smb2_tree *tree)
+{
+	struct smb2_handle fhandle = { .data = { 0, 0 } };
+	struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
+	struct smb2_close cl;
+	struct smb2_flush fl;
+	const char *fname = "compound_async_flush_close";
+	struct smb2_request *req[2];
+	NTSTATUS status;
+	bool ret = false;
+
+	/* Start clean. */
+	smb2_util_unlink(tree, fname);
+
+	/* Create a file. */
+	status = torture_smb2_testfile_access(tree,
+					      fname,
+					      &fhandle,
+					      SEC_RIGHTS_FILE_ALL);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Now do a compound flush + close handle. */
+	smb2_transport_compound_start(tree->session->transport, 2);
+
+	ZERO_STRUCT(fl);
+	fl.in.file.handle = fhandle;
+
+	req[0] = smb2_flush_send(tree, &fl);
+	torture_assert_not_null_goto(tctx, req[0], ret, done,
+		"smb2_flush_send failed\n");
+
+	smb2_transport_compound_set_related(tree->session->transport, true);
+
+	ZERO_STRUCT(cl);
+	cl.in.file.handle = relhandle;
+	req[1] = smb2_close_send(tree, &cl);
+	torture_assert_not_null_goto(tctx, req[1], ret, done,
+		"smb2_close_send failed\n");
+
+	status = smb2_flush_recv(req[0], &fl);
+	/*
+	 * On Windows, this flush will usually
+	 * succeed as we have nothing to flush,
+	 * so allow NT_STATUS_OK. Once bug #15172
+	 * is fixed Samba will do the flush synchronously
+	 * so allow NT_STATUS_OK.
+	 */
+	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * If we didn't get NT_STATUS_OK, we *must*
+		 * get NT_STATUS_INTERNAL_ERROR if the flush
+		 * goes async.
+		 *
+		 * For pre-bugfix #15172 Samba, the flush goes async and
+		 * we should get NT_STATUS_INTERNAL_ERROR.
+		 */
+		torture_assert_ntstatus_equal_goto(tctx,
+			status,
+			NT_STATUS_INTERNAL_ERROR,
+			ret,
+			done,
+			"smb2_flush_recv didn't return "
+			"NT_STATUS_INTERNAL_ERROR.\n");
+	}
+	status = smb2_close_recv(req[1], &cl);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+			"smb2_close_recv failed.");
+
+	ZERO_STRUCT(fhandle);
+
+	/*
+	 * Do several more operations on the tree, spaced
+	 * out by 1 sec sleeps to make sure the server didn't
+	 * crash on the close. The sleeps are required to
+	 * make test test for a crash reliable, as we ensure
+	 * the pthread fsync internally finishes and accesses
+	 * freed memory. Without them the test occassionally
+	 * passes as we disconnect before the pthread fsync
+	 * finishes.
+	 */
+	status = smb2_util_unlink(tree, fname);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	sleep(1);
+	status = smb2_util_unlink(tree, fname);
+	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+	sleep(1);
+	status = smb2_util_unlink(tree, fname);
+	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+	ret = true;
+
+  done:
+
+	if (fhandle.data[0] != 0) {
+		smb2_util_close(tree, fhandle);
+	}
+
+	smb2_util_unlink(tree, fname);
+	return ret;
+}
+
+static bool test_compound_async_flush_flush(struct torture_context *tctx,
+					    struct smb2_tree *tree)
+{
+	struct smb2_handle fhandle = { .data = { 0, 0 } };
+	struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
+	struct smb2_flush fl1;
+	struct smb2_flush fl2;
+	const char *fname = "compound_async_flush_flush";
+	struct smb2_request *req[2];
+	NTSTATUS status;
+	bool ret = false;
+
+	/* Start clean. */
+	smb2_util_unlink(tree, fname);
+
+	/* Create a file. */
+	status = torture_smb2_testfile_access(tree,
+					      fname,
+					      &fhandle,
+					      SEC_RIGHTS_FILE_ALL);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Now do a compound flush + flush handle. */
+	smb2_transport_compound_start(tree->session->transport, 2);
+
+	ZERO_STRUCT(fl1);
+	fl1.in.file.handle = fhandle;
+
+	req[0] = smb2_flush_send(tree, &fl1);
+	torture_assert_not_null_goto(tctx, req[0], ret, done,
+		"smb2_flush_send (1) failed\n");
+
+	smb2_transport_compound_set_related(tree->session->transport, true);
+
+	ZERO_STRUCT(fl2);
+	fl2.in.file.handle = relhandle;
+
+	req[1] = smb2_flush_send(tree, &fl2);
+	torture_assert_not_null_goto(tctx, req[1], ret, done,
+		"smb2_flush_send (2) failed\n");
+
+	status = smb2_flush_recv(req[0], &fl1);
+	/*
+	 * On Windows, this flush will usually
+	 * succeed as we have nothing to flush,
+	 * so allow NT_STATUS_OK. Once bug #15172
+	 * is fixed Samba will do the flush synchronously
+	 * so allow NT_STATUS_OK.
+	 */
+	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * If we didn't get NT_STATUS_OK, we *must*
+		 * get NT_STATUS_INTERNAL_ERROR if the flush
+		 * goes async.
+		 *
+		 * For pre-bugfix #15172 Samba, the flush goes async and
+		 * we should get NT_STATUS_INTERNAL_ERROR.
+		 */
+		torture_assert_ntstatus_equal_goto(tctx,
+			status,
+			NT_STATUS_INTERNAL_ERROR,
+			ret,
+			done,
+			"smb2_flush_recv (1) didn't return "
+			"NT_STATUS_INTERNAL_ERROR.\n");
+	}
+
+	/*
+	 * If the flush is the last entry in a compound,
+	 * it should always succeed even if it goes async.
+	 */
+	status = smb2_flush_recv(req[1], &fl2);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+		"smb2_flush_recv (2) failed.");
+
+	status = smb2_util_close(tree, fhandle);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+		"smb2_util_close failed.");
+	ZERO_STRUCT(fhandle);
+
+	/*
+	 * Do several more operations on the tree, spaced
+	 * out by 1 sec sleeps to make sure the server didn't
+	 * crash on the close. The sleeps are required to
+	 * make test test for a crash reliable, as we ensure
+	 * the pthread fsync internally finishes and accesses
+	 * freed memory. Without them the test occassionally
+	 * passes as we disconnect before the pthread fsync
+	 * finishes.
+	 */
+	status = smb2_util_unlink(tree, fname);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	sleep(1);
+	status = smb2_util_unlink(tree, fname);
+	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+	sleep(1);
+	status = smb2_util_unlink(tree, fname);
+	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+	ret = true;
+
+  done:
+
+	if (fhandle.data[0] != 0) {
+		smb2_util_close(tree, fhandle);
+	}
+
+	smb2_util_unlink(tree, fname);
+	return ret;
+}
+
 struct torture_suite *torture_smb2_compound_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite = torture_suite_create(ctx, "compound");
@@ -2107,3 +2324,18 @@ struct torture_suite *torture_smb2_compound_find_init(TALLOC_CTX *ctx)
 
 	return suite;
 }
+
+struct torture_suite *torture_smb2_compound_async_init(TALLOC_CTX *ctx)
+{
+	struct torture_suite *suite = torture_suite_create(ctx,
+					"compound_async");
+
+	torture_suite_add_1smb2_test(suite, "flush_close",
+		test_compound_async_flush_close);
+	torture_suite_add_1smb2_test(suite, "flush_flush",
+		test_compound_async_flush_flush);
+
+	suite->description = talloc_strdup(suite, "SMB2-COMPOUND-ASYNC tests");
+
+	return suite;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list