Patches for https://bugzilla.samba.org/show_bug.cgi?id=11182

Stefan (metze) Metzmacher metze at samba.org
Wed May 6 06:27:41 MDT 2015


Hi,

here's an updated patchset renaming smbXsrv_session_shutdown_send/recv
to smb2srv_session_shutdown_send/recv as it only handles smb2/3.

metze

Am 06.05.2015 um 10:19 schrieb Stefan (metze) Metzmacher:
> Hi Jeremy,
> 
> here're the proposed patches for master regarding
> https://bugzilla.samba.org/show_bug.cgi?id=11182
> 
> The main happens when a session setup with a previous session id
> removes the previous session while there's a pending change notify
> request.
> 
> Please review and push, then I'll prepare backports.
> 
> Thanks!
> metze
> 
-------------- next part --------------
From d95e3048e480b222348b10d03b3e31dca4443c8a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:04:55 +0200
Subject: [PATCH 01/17] s3:smbd: add a smbd_notify_cancel_by_map() helper
 function

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/notify.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 3f2d07c..4f4ca2f 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -375,6 +375,17 @@ static void change_notify_remove_request(struct smbd_server_connection *sconn,
 	TALLOC_FREE(req);
 }
 
+static void smbd_notify_cancel_by_map(struct notify_mid_map *map)
+{
+	struct smb_request *smbreq = map->req->req;
+	struct smbd_server_connection *sconn = smbreq->sconn;
+	NTSTATUS notify_status = NT_STATUS_CANCELLED;
+
+	change_notify_reply(smbreq, notify_status,
+			    0, NULL, map->req->reply_fn);
+	change_notify_remove_request(sconn, map->req);
+}
+
 /****************************************************************************
  Delete entries by mid from the change notify pending queue. Always send reply.
 *****************************************************************************/
@@ -394,9 +405,7 @@ void remove_pending_change_notify_requests_by_mid(
 		return;
 	}
 
-	change_notify_reply(map->req->req,
-			    NT_STATUS_CANCELLED, 0, NULL, map->req->reply_fn);
-	change_notify_remove_request(sconn, map->req);
+	smbd_notify_cancel_by_map(map);
 }
 
 void smbd_notify_cancel_by_smbreq(const struct smb_request *smbreq)
@@ -414,9 +423,7 @@ void smbd_notify_cancel_by_smbreq(const struct smb_request *smbreq)
 		return;
 	}
 
-	change_notify_reply(map->req->req,
-			    NT_STATUS_CANCELLED, 0, NULL, map->req->reply_fn);
-	change_notify_remove_request(sconn, map->req);
+	smbd_notify_cancel_by_map(map);
 }
 
 static struct files_struct *smbd_notify_cancel_deleted_fn(
-- 
1.9.1


From 227ed247a33728327dc8bd81124c7a0352deef03 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:02:38 +0200
Subject: [PATCH 02/17] s3:smbd: use STATUS_NOTIFY_CLEANUP when closing a smb2
 directory handle

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 selftest/knownfail   |  1 -
 source3/smbd/close.c | 15 +++++++++++----
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 3262c9c..26aed77 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -189,7 +189,6 @@
 ^samba3.smb2.create.blob
 ^samba3.smb2.create.open
 ^samba3.smb2.notify.valid-req
-^samba3.smb2.notify.dir
 ^samba3.smb2.notify.rec
 ^samba3.smb2.durable-open.delete_on_close2
 ^samba3.smb2.durable-v2-open.app-instance
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index 09be2e7..0e75bf0 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -1050,6 +1050,13 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 	NTSTATUS status1 = NT_STATUS_OK;
 	const struct security_token *del_nt_token = NULL;
 	const struct security_unix_token *del_token = NULL;
+	NTSTATUS notify_status;
+
+	if (fsp->conn->sconn->using_smb2) {
+		notify_status = STATUS_NOTIFY_CLEANUP;
+	} else {
+		notify_status = NT_STATUS_OK;
+	}
 
 	/*
 	 * NT can set delete_on_close of the last open
@@ -1159,8 +1166,8 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 		 * now fail as the directory has been deleted.
 		 */
 
-		if(NT_STATUS_IS_OK(status)) {
-			remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
+		if (NT_STATUS_IS_OK(status)) {
+			notify_status = NT_STATUS_DELETE_PENDING;
 		}
 	} else {
 		if (!del_share_mode(lck, fsp)) {
@@ -1169,10 +1176,10 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 		}
 
 		TALLOC_FREE(lck);
-		remove_pending_change_notify_requests_by_fid(
-			fsp, NT_STATUS_OK);
 	}
 
+	remove_pending_change_notify_requests_by_fid(fsp, notify_status);
+
 	status1 = fd_close(fsp);
 
 	if (!NT_STATUS_IS_OK(status1)) {
-- 
1.9.1


From 8aef6501d53dd38002f1f9531ffd3bacbd5de245 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:02:38 +0200
Subject: [PATCH 03/17] s3:smbd: use STATUS_NOTIFY_CLEANUP on smb2 logoff
 (explicit and implicit) and tdis

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/notify.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 4f4ca2f..b3079d2 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -379,8 +379,22 @@ static void smbd_notify_cancel_by_map(struct notify_mid_map *map)
 {
 	struct smb_request *smbreq = map->req->req;
 	struct smbd_server_connection *sconn = smbreq->sconn;
+	struct smbd_smb2_request *smb2req = smbreq->smb2req;
 	NTSTATUS notify_status = NT_STATUS_CANCELLED;
 
+	if (smb2req != NULL) {
+		if (smb2req->session == NULL) {
+			notify_status = STATUS_NOTIFY_CLEANUP;
+		} else if (!NT_STATUS_IS_OK(smb2req->session->status)) {
+			notify_status = STATUS_NOTIFY_CLEANUP;
+		}
+		if (smb2req->tcon == NULL) {
+			notify_status = STATUS_NOTIFY_CLEANUP;
+		} else if (!NT_STATUS_IS_OK(smb2req->tcon->status)) {
+			notify_status = STATUS_NOTIFY_CLEANUP;
+		}
+	}
+
 	change_notify_reply(smbreq, notify_status,
 			    0, NULL, map->req->reply_fn);
 	change_notify_remove_request(sconn, map->req);
-- 
1.9.1


From 3d9590a8ab4b8fee4e35228020ee6a52b2ce6f16 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:19:42 +0200
Subject: [PATCH 04/17] s4:torture/smb2: verify STATUS_NOTIFY_CLEANUP return
 value

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/torture/smb2/notify.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c
index 0f572b6..6c1bf3a 100644
--- a/source4/torture/smb2/notify.c
+++ b/source4/torture/smb2/notify.c
@@ -1309,6 +1309,7 @@ static bool torture_smb2_notify_tree_disconnect_1(
 	CHECK_STATUS(status, NT_STATUS_OK);
 
 	status = smb2_notify_recv(req, torture, &(notify.smb2));
+	CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
 	CHECK_VAL(notify.smb2.out.num_changes, 0);
 
 done:
@@ -1377,6 +1378,7 @@ static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
 	CHECK_STATUS(status, NT_STATUS_OK);
 
 	status = smb2_notify_recv(req, torture, &(notify.smb2));
+	CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
 	CHECK_VAL(notify.smb2.out.num_changes, 0);
 
 done:
-- 
1.9.1


From a19aca28e87629d519b9a0d9d6cca3c0736d0e23 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:20:50 +0200
Subject: [PATCH 05/17] s4:torture/smb2: add smb2.notify.close test

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/torture/smb2/notify.c | 70 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c
index 6c1bf3a..d2b3594 100644
--- a/source4/torture/smb2/notify.c
+++ b/source4/torture/smb2/notify.c
@@ -1318,6 +1318,75 @@ done:
 }
 
 /*
+  basic testing of change notifies followed by a close
+*/
+
+static bool torture_smb2_notify_close(struct torture_context *torture,
+				struct smb2_tree *tree1)
+{
+	bool ret = true;
+	NTSTATUS status;
+	union smb_notify notify;
+	union smb_open io;
+	struct smb2_handle h1;
+	struct smb2_request *req;
+
+	smb2_deltree(tree1, BASEDIR);
+	smb2_util_rmdir(tree1, BASEDIR);
+
+	torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
+
+	/*
+	  get a handle on the directory
+	*/
+	ZERO_STRUCT(io.smb2);
+	io.generic.level = RAW_OPEN_SMB2;
+	io.smb2.in.create_flags = 0;
+	io.smb2.in.desired_access = SEC_FILE_ALL;
+	io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+				NTCREATEX_SHARE_ACCESS_WRITE;
+	io.smb2.in.alloc_size = 0;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	io.smb2.in.security_flags = 0;
+	io.smb2.in.fname = BASEDIR;
+
+	status = smb2_create(tree1, torture, &(io.smb2));
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+	status = smb2_create(tree1, torture, &(io.smb2));
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h1 = io.smb2.out.file.handle;
+
+	/* ask for a change notify,
+	   on file or directory name changes */
+	ZERO_STRUCT(notify.smb2);
+	notify.smb2.level = RAW_NOTIFY_SMB2;
+	notify.smb2.in.buffer_size = 1000;
+	notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+	notify.smb2.in.file.handle = h1;
+	notify.smb2.in.recursive = true;
+
+	req = smb2_notify_send(tree1, &(notify.smb2));
+
+	WAIT_FOR_ASYNC_RESPONSE(req);
+
+	status = smb2_util_close(tree1, h1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	status = smb2_notify_recv(req, torture, &(notify.smb2));
+	CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
+	CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+	smb2_deltree(tree1, BASEDIR);
+	return ret;
+}
+
+/*
   basic testing of change notifies followed by a ulogoff
 */
 
@@ -2133,6 +2202,7 @@ struct torture_suite *torture_smb2_notify_init(void)
 	torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
 	torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
 	torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
+	torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
 	torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
 	torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
 	torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
-- 
1.9.1


From 20dc433dda00cf9576e8ce553c5ee0a3cc725a47 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:20:50 +0200
Subject: [PATCH 06/17] s4:torture/smb2: add smb2.notify.invalid-reauth test

An invalid reauth closes the session.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/torture/smb2/notify.c | 82 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c
index d2b3594..33df249 100644
--- a/source4/torture/smb2/notify.c
+++ b/source4/torture/smb2/notify.c
@@ -1455,6 +1455,87 @@ done:
 	return ret;
 }
 
+/*
+  basic testing of change notifies followed by an invalid reauth
+*/
+
+static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
+					       struct smb2_tree *tree1,
+					       struct smb2_tree *tree2)
+{
+	bool ret = true;
+	NTSTATUS status;
+	union smb_notify notify;
+	union smb_open io;
+	struct smb2_handle h1;
+	struct smb2_request *req;
+	struct cli_credentials *invalid_creds;
+
+	smb2_deltree(tree2, BASEDIR);
+	smb2_util_rmdir(tree2, BASEDIR);
+
+	torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
+
+	/*
+	  get a handle on the directory
+	*/
+	ZERO_STRUCT(io.smb2);
+	io.generic.level = RAW_OPEN_SMB2;
+	io.smb2.in.create_flags = 0;
+	io.smb2.in.desired_access = SEC_FILE_ALL;
+	io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+				NTCREATEX_SHARE_ACCESS_WRITE;
+	io.smb2.in.alloc_size = 0;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	io.smb2.in.security_flags = 0;
+	io.smb2.in.fname = BASEDIR;
+
+	status = smb2_create(tree1, torture, &(io.smb2));
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+	status = smb2_create(tree1, torture, &(io.smb2));
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h1 = io.smb2.out.file.handle;
+
+	/* ask for a change notify,
+	   on file or directory name changes */
+	ZERO_STRUCT(notify.smb2);
+	notify.smb2.level = RAW_NOTIFY_SMB2;
+	notify.smb2.in.buffer_size = 1000;
+	notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+	notify.smb2.in.file.handle = h1;
+	notify.smb2.in.recursive = true;
+
+	req = smb2_notify_send(tree1, &(notify.smb2));
+
+	WAIT_FOR_ASYNC_RESPONSE(req);
+
+	invalid_creds = cli_credentials_init(torture);
+	torture_assert(torture, (invalid_creds != NULL), "talloc error");
+	cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
+	cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
+	cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
+	cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
+	cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
+
+	status = smb2_session_setup_spnego(tree1->session,
+					   invalid_creds,
+					   0 /* previous_session_id */);
+	CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
+
+	status = smb2_notify_recv(req, torture, &(notify.smb2));
+	CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
+	CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+	smb2_deltree(tree2, BASEDIR);
+	return ret;
+}
+
 static void tcp_dis_handler(struct smb2_transport *t, void *p)
 {
 	struct smb2_tree *tree = (struct smb2_tree *)p;
@@ -2204,6 +2285,7 @@ struct torture_suite *torture_smb2_notify_init(void)
 	torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
 	torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
 	torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
+	torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
 	torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
 	torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
 	torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
-- 
1.9.1


From 4e6d97ee5efbbbd093fd0a966811585a8c305e05 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 09:57:03 +0200
Subject: [PATCH 07/17] s4:torture/smb2: add smb2.notify.session-reconnect test

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/torture/smb2/notify.c | 81 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c
index 33df249..b804ebc 100644
--- a/source4/torture/smb2/notify.c
+++ b/source4/torture/smb2/notify.c
@@ -1456,6 +1456,86 @@ done:
 }
 
 /*
+  basic testing of change notifies followed by a session reconnect
+*/
+
+static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
+				struct smb2_tree *tree1)
+{
+	bool ret = true;
+	NTSTATUS status;
+	union smb_notify notify;
+	union smb_open io;
+	struct smb2_handle h1;
+	struct smb2_request *req;
+	uint64_t previous_session_id = 0;
+	struct smb2_session *session2 = NULL;
+
+	smb2_deltree(tree1, BASEDIR);
+	smb2_util_rmdir(tree1, BASEDIR);
+
+	torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
+
+	/*
+	  get a handle on the directory
+	*/
+	ZERO_STRUCT(io.smb2);
+	io.generic.level = RAW_OPEN_SMB2;
+	io.smb2.in.create_flags = 0;
+	io.smb2.in.desired_access = SEC_FILE_ALL;
+	io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+				NTCREATEX_SHARE_ACCESS_WRITE;
+	io.smb2.in.alloc_size = 0;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	io.smb2.in.security_flags = 0;
+	io.smb2.in.fname = BASEDIR;
+
+	status = smb2_create(tree1, torture, &(io.smb2));
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+	status = smb2_create(tree1, torture, &(io.smb2));
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h1 = io.smb2.out.file.handle;
+
+	/* ask for a change notify,
+	   on file or directory name changes */
+	ZERO_STRUCT(notify.smb2);
+	notify.smb2.level = RAW_NOTIFY_SMB2;
+	notify.smb2.in.buffer_size = 1000;
+	notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+	notify.smb2.in.file.handle = h1;
+	notify.smb2.in.recursive = true;
+
+	req = smb2_notify_send(tree1, &(notify.smb2));
+
+	WAIT_FOR_ASYNC_RESPONSE(req);
+
+	previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
+	torture_assert(torture, torture_smb2_session_setup(torture,
+		       tree1->session->transport,
+		       previous_session_id,
+		       torture, &session2),
+		       "session setup with previous_session_id failed");
+
+	status = smb2_notify_recv(req, torture, &(notify.smb2));
+	CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
+	CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+	status = smb2_logoff(tree1->session);
+	CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+
+	status = smb2_logoff(session2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+done:
+	smb2_deltree(tree1, BASEDIR);
+	return ret;
+}
+
+/*
   basic testing of change notifies followed by an invalid reauth
 */
 
@@ -2285,6 +2365,7 @@ struct torture_suite *torture_smb2_notify_init(void)
 	torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
 	torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
 	torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
+	torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
 	torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
 	torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
 	torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
-- 
1.9.1


From 10c41f4a6635cbfed0df3457604256f0592fe423 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:09:40 +0200
Subject: [PATCH 08/17] s3:smbXsrv_session: clear smb2req->session of pending
 requests in smbXsrv_session_destructor()

This won't be needed typically needed as the caller is supposted to cancel
the requests already, but this makes sure we don't keep dangling pointers.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smbXsrv_session.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index a49e246..41625fc 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -1066,6 +1066,29 @@ NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
 {
 	NTSTATUS status;
+	struct smbXsrv_connection *xconn = NULL;
+
+	if (session->client != NULL) {
+		xconn = session->client->connections;
+	}
+
+	for (; xconn != NULL; xconn = xconn->next) {
+		struct smbd_smb2_request *preq;
+
+		for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
+			if (preq->session != session) {
+				continue;
+			}
+
+			preq->session = NULL;
+			/*
+			 * If we no longer have a session we can't
+			 * sign or encrypt replies.
+			 */
+			preq->do_signing = false;
+			preq->do_encryption = false;
+		}
+	}
 
 	status = smbXsrv_session_logoff(session);
 	if (!NT_STATUS_IS_OK(status)) {
-- 
1.9.1


From 2793e29e742f45db2c05c8e571a9cdfe0d96468e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:17:34 +0200
Subject: [PATCH 09/17] s3:smbXsrv_session: clear smb2req->session of pending
 requests in smbXsrv_session_logoff_all_callback()

smbXsrv_session_logoff_all_callback() is called when the last transport
connection is gone, which means we won't need to sign any response...

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smbXsrv_session.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 41625fc..5ee4bbe 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -1503,6 +1503,7 @@ static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
 	TDB_DATA val;
 	void *ptr = NULL;
 	struct smbXsrv_session *session = NULL;
+	struct smbXsrv_connection *xconn = NULL;
 	NTSTATUS status;
 
 	val = dbwrap_record_get_value(local_rec);
@@ -1519,6 +1520,28 @@ static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
 	session = talloc_get_type_abort(ptr, struct smbXsrv_session);
 
 	session->db_rec = local_rec;
+
+	if (session->client != NULL) {
+		xconn = session->client->connections;
+	}
+	for (; xconn != NULL; xconn = xconn->next) {
+		struct smbd_smb2_request *preq;
+
+		for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
+			if (preq->session != session) {
+				continue;
+			}
+
+			preq->session = NULL;
+			/*
+			 * If we no longer have a session we can't
+			 * sign or encrypt replies.
+			 */
+			preq->do_signing = false;
+			preq->do_encryption = false;
+		}
+	}
+
 	status = smbXsrv_session_logoff(session);
 	if (!NT_STATUS_IS_OK(status)) {
 		if (NT_STATUS_IS_OK(state->first_status)) {
-- 
1.9.1


From 9ef38da3bd9e69e01da1a69fad30d824d355bcdf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 09:57:03 +0200
Subject: [PATCH 10/17] s3:smbXsrv_session: add
 smb2srv_session_shutdown_send/recv helper functions

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/globals.h         |   5 ++
 source3/smbd/smbXsrv_session.c | 121 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index c7e2608..22cf5d6 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -537,6 +537,11 @@ struct smbXsrv_channel_global0;
 NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
 				      const struct smbXsrv_connection *conn,
 				      struct smbXsrv_channel_global0 **_c);
+struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct smbXsrv_session *session,
+					struct smbd_smb2_request *current_req);
+NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req);
 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session);
 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_connection *conn);
 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn);
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 5ee4bbe..f4617f7 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -1327,6 +1327,127 @@ NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
 	return NT_STATUS_USER_SESSION_DELETED;
 }
 
+struct smb2srv_session_shutdown_state {
+	struct tevent_queue *wait_queue;
+};
+
+static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct smbXsrv_session *session,
+					struct smbd_smb2_request *current_req)
+{
+	struct tevent_req *req;
+	struct smb2srv_session_shutdown_state *state;
+	struct tevent_req *subreq;
+	struct smbXsrv_connection *xconn = NULL;
+	size_t len = 0;
+
+	/*
+	 * Make sure that no new request will be able to use this session.
+	 */
+	session->status = NT_STATUS_USER_SESSION_DELETED;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct smb2srv_session_shutdown_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->wait_queue = tevent_queue_create(state, "smb2srv_session_shutdown_queue");
+	if (tevent_req_nomem(state->wait_queue, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	for (xconn = session->client->connections; xconn != NULL; xconn = xconn->next) {
+		struct smbd_smb2_request *preq;
+
+		for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
+			if (preq == current_req) {
+				/* Can't cancel current request. */
+				continue;
+			}
+			if (preq->session != session) {
+				/* Request on different session. */
+				continue;
+			}
+
+			if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+				preq->session = NULL;
+				/*
+				 * If we no longer have a session we can't
+				 * sign or encrypt replies.
+				 */
+				preq->do_signing = false;
+				preq->do_encryption = false;
+
+				if (preq->subreq != NULL) {
+					tevent_req_cancel(preq->subreq);
+				}
+				continue;
+			}
+
+			/*
+			 * Never cancel anything in a compound
+			 * request. Way too hard to deal with
+			 * the result.
+			 */
+			if (!preq->compound_related && preq->subreq != NULL) {
+				tevent_req_cancel(preq->subreq);
+			}
+
+			/*
+			 * Now wait until the request is finished.
+			 *
+			 * We don't set a callback, as we just want to block the
+			 * wait queue and the talloc_free() of the request will
+			 * remove the item from the wait queue.
+			 */
+			subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
+			if (tevent_req_nomem(subreq, req)) {
+				return tevent_req_post(req, ev);
+			}
+		}
+	}
+
+	len = tevent_queue_length(state->wait_queue);
+	if (len == 0) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	/*
+	 * Now we add our own waiter to the end of the queue,
+	 * this way we get notified when all pending requests are finished
+	 * and send to the socket.
+	 */
+	subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, smb2srv_session_shutdown_wait_done, req);
+
+	return req;
+}
+
+static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+
+	tevent_queue_wait_recv(subreq);
+	TALLOC_FREE(subreq);
+
+	tevent_req_done(req);
+}
+
+NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
+
 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
 {
 	struct smbXsrv_session_table *table;
-- 
1.9.1


From db39da8d22db275c913a3b172915510595477397 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:13:27 +0200
Subject: [PATCH 11/17] s3:smbXsrv_session: cancel pending requests when we
 logoff a previous session

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smbXsrv_session.c | 45 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index f4617f7..2ccae0e 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -226,6 +226,8 @@ static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
 	return NT_STATUS_OK;
 }
 
+static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq);
+
 static void smbXsrv_session_close_loop(struct tevent_req *subreq)
 {
 	struct smbXsrv_client *client =
@@ -330,20 +332,22 @@ static void smbXsrv_session_close_loop(struct tevent_req *subreq)
 		goto next;
 	}
 
-	/*
-	 * TODO: cancel all outstanding requests on the session
-	 */
-	status = smbXsrv_session_logoff(session);
-	if (!NT_STATUS_IS_OK(status)) {
+	subreq = smb2srv_session_shutdown_send(session, client->ev_ctx,
+					       session, NULL);
+	if (subreq == NULL) {
+		status = NT_STATUS_NO_MEMORY;
 		DEBUG(0, ("smbXsrv_session_close_loop: "
-			  "smbXsrv_session_logoff(%llu) failed: %s\n",
+			  "smb2srv_session_shutdown_send(%llu) failed: %s\n",
 			  (unsigned long long)session->global->session_wire_id,
 			  nt_errstr(status)));
 		if (DEBUGLVL(1)) {
 			NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
 		}
+		goto next;
 	}
-	TALLOC_FREE(session);
+	tevent_req_set_callback(subreq,
+				smbXsrv_session_close_shutdown_done,
+				session);
 
 next:
 	TALLOC_FREE(rec);
@@ -359,6 +363,33 @@ next:
 	tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
 }
 
+static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq)
+{
+	struct smbXsrv_session *session =
+		tevent_req_callback_data(subreq,
+		struct smbXsrv_session);
+	NTSTATUS status;
+
+	status = smb2srv_session_shutdown_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("smbXsrv_session_close_loop: "
+			  "smb2srv_session_shutdown_recv(%llu) failed: %s\n",
+			  (unsigned long long)session->global->session_wire_id,
+			  nt_errstr(status)));
+	}
+
+	status = smbXsrv_session_logoff(session);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("smbXsrv_session_close_loop: "
+			  "smbXsrv_session_logoff(%llu) failed: %s\n",
+			  (unsigned long long)session->global->session_wire_id,
+			  nt_errstr(status)));
+	}
+
+	TALLOC_FREE(session);
+}
+
 struct smb1srv_session_local_allocate_state {
 	const uint32_t lowest_id;
 	const uint32_t highest_id;
-- 
1.9.1


From 5a25052bca611617fd5bbab4fec493a247186cc5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:20:06 +0200
Subject: [PATCH 12/17] s3:smb2_sesssetup: let smbd_smb2_logoff_* use
 smbXsrv_session_shutdown_*

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smb2_sesssetup.c | 75 +++++++++----------------------------------
 1 file changed, 15 insertions(+), 60 deletions(-)

diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index fb7edce..5cd3446 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -860,95 +860,50 @@ static void smbd_smb2_request_logoff_done(struct tevent_req *subreq)
 	}
 }
 
-struct smbd_smb2_logout_state {
+struct smbd_smb2_logoff_state {
 	struct smbd_smb2_request *smb2req;
-	struct tevent_queue *wait_queue;
 };
 
-static void smbd_smb2_logoff_wait_done(struct tevent_req *subreq);
+static void smbd_smb2_logoff_shutdown_done(struct tevent_req *subreq);
 
 static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbd_smb2_request *smb2req)
 {
 	struct tevent_req *req;
-	struct smbd_smb2_logout_state *state;
+	struct smbd_smb2_logoff_state *state;
 	struct tevent_req *subreq;
-	struct smbd_smb2_request *preq;
-	struct smbXsrv_connection *xconn = smb2req->xconn;
 
 	req = tevent_req_create(mem_ctx, &state,
-			struct smbd_smb2_logout_state);
+			struct smbd_smb2_logoff_state);
 	if (req == NULL) {
 		return NULL;
 	}
 	state->smb2req = smb2req;
 
-	state->wait_queue = tevent_queue_create(state, "logoff_wait_queue");
-	if (tevent_req_nomem(state->wait_queue, req)) {
-		return tevent_req_post(req, ev);
-	}
-
-	/*
-	 * Make sure that no new request will be able to use this session.
-	 */
-	smb2req->session->status = NT_STATUS_USER_SESSION_DELETED;
-
-	for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
-		if (preq == smb2req) {
-			/* Can't cancel current request. */
-			continue;
-		}
-		if (preq->session != smb2req->session) {
-			/* Request on different session. */
-			continue;
-		}
-
-		/*
-		 * Never cancel anything in a compound
-		 * request. Way too hard to deal with
-		 * the result.
-		 */
-		if (!preq->compound_related && preq->subreq != NULL) {
-			tevent_req_cancel(preq->subreq);
-		}
-
-		/*
-		 * Now wait until the request is finished.
-		 *
-		 * We don't set a callback, as we just want to block the
-		 * wait queue and the talloc_free() of the request will
-		 * remove the item from the wait queue.
-		 */
-		subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
-		if (tevent_req_nomem(subreq, req)) {
-			return tevent_req_post(req, ev);
-		}
-	}
-
-	/*
-	 * Now we add our own waiter to the end of the queue,
-	 * this way we get notified when all pending requests are finished
-	 * and send to the socket.
-	 */
-	subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
+	subreq = smb2srv_session_shutdown_send(state, ev,
+					       smb2req->session,
+					       smb2req);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, smbd_smb2_logoff_wait_done, req);
+	tevent_req_set_callback(subreq, smbd_smb2_logoff_shutdown_done, req);
 
 	return req;
 }
 
-static void smbd_smb2_logoff_wait_done(struct tevent_req *subreq)
+static void smbd_smb2_logoff_shutdown_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
 		subreq, struct tevent_req);
-	struct smbd_smb2_logout_state *state = tevent_req_data(
-		req, struct smbd_smb2_logout_state);
+	struct smbd_smb2_logoff_state *state = tevent_req_data(
+		req, struct smbd_smb2_logoff_state);
 	NTSTATUS status;
 
-	tevent_queue_wait_recv(subreq);
+	status = smb2srv_session_shutdown_recv(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
 	TALLOC_FREE(subreq);
 
 	/*
-- 
1.9.1


From f5b8aa1a1b6ca7db1d67af3feecc0ae07fbad32e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:27:26 +0200
Subject: [PATCH 13/17] s3:smb2_sesssetup: always assign smb2req->session when
 a session was created.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smb2_sesssetup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 5cd3446..e7eb414 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -368,7 +368,6 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 	 * we attach the session to the request
 	 * so that the response can be signed
 	 */
-	smb2req->session = session;
 	if (!guest) {
 		smb2req->do_signing = true;
 	}
@@ -587,6 +586,7 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
 		}
+		smb2req->session = state->session;
 	} else {
 		if (smb2req->session == NULL) {
 			tevent_req_nterror(req, NT_STATUS_USER_SESSION_DELETED);
-- 
1.9.1


From 53604c3b1cc52d8ad00133e1c069917a841b47ae Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:21:25 +0200
Subject: [PATCH 14/17] s3:smb2_sesssetup: add
 smbd_smb2_session_setup_wrap_send/recv()

The wrapper calls smbXsrv_session_shutdown_send/recv() in case of an error,
this makes sure a failing reauth shuts down the session like an explicit logoff.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smb2_sesssetup.c | 186 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 171 insertions(+), 15 deletions(-)

diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index e7eb414..5ddaa48 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -29,7 +29,7 @@
 #include "../libcli/security/security.h"
 #include "../lib/util/tevent_ntstatus.h"
 
-static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *smbd_smb2_session_setup_wrap_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbd_smb2_request *smb2req,
 					uint64_t in_session_id,
@@ -37,7 +37,7 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 					uint8_t in_security_mode,
 					uint64_t in_previous_session_id,
 					DATA_BLOB in_security_buffer);
-static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
+static NTSTATUS smbd_smb2_session_setup_wrap_recv(struct tevent_req *req,
 					uint16_t *out_session_flags,
 					TALLOC_CTX *mem_ctx,
 					DATA_BLOB *out_security_buffer,
@@ -87,14 +87,14 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
 	in_security_buffer.data = SMBD_SMB2_IN_DYN_PTR(smb2req);
 	in_security_buffer.length = in_security_length;
 
-	subreq = smbd_smb2_session_setup_send(smb2req,
-					      smb2req->sconn->ev_ctx,
-					      smb2req,
-					      in_session_id,
-					      in_flags,
-					      in_security_mode,
-					      in_previous_session_id,
-					      in_security_buffer);
+	subreq = smbd_smb2_session_setup_wrap_send(smb2req,
+						   smb2req->sconn->ev_ctx,
+						   smb2req,
+						   in_session_id,
+						   in_flags,
+						   in_security_mode,
+						   in_previous_session_id,
+						   in_security_buffer);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
 	}
@@ -118,11 +118,11 @@ static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq)
 	NTSTATUS status;
 	NTSTATUS error; /* transport error */
 
-	status = smbd_smb2_session_setup_recv(subreq,
-					      &out_session_flags,
-					      smb2req,
-					      &out_security_buffer,
-					      &out_session_id);
+	status = smbd_smb2_session_setup_wrap_recv(subreq,
+						   &out_session_flags,
+						   smb2req,
+						   &out_security_buffer,
+						   &out_session_id);
 	TALLOC_FREE(subreq);
 	if (!NT_STATUS_IS_OK(status) &&
 	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -788,6 +788,162 @@ static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
 	return status;
 }
 
+struct smbd_smb2_session_setup_wrap_state {
+	struct tevent_context *ev;
+	struct smbd_smb2_request *smb2req;
+	uint64_t in_session_id;
+	uint8_t in_flags;
+	uint8_t in_security_mode;
+	uint64_t in_previous_session_id;
+	DATA_BLOB in_security_buffer;
+	uint16_t out_session_flags;
+	DATA_BLOB out_security_buffer;
+	uint64_t out_session_id;
+	NTSTATUS error;
+};
+
+static void smbd_smb2_session_setup_wrap_setup_done(struct tevent_req *subreq);
+static void smbd_smb2_session_setup_wrap_shutdown_done(struct tevent_req *subreq);
+
+static struct tevent_req *smbd_smb2_session_setup_wrap_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct smbd_smb2_request *smb2req,
+					uint64_t in_session_id,
+					uint8_t in_flags,
+					uint8_t in_security_mode,
+					uint64_t in_previous_session_id,
+					DATA_BLOB in_security_buffer)
+{
+	struct tevent_req *req;
+	struct smbd_smb2_session_setup_wrap_state *state;
+	struct tevent_req *subreq;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct smbd_smb2_session_setup_wrap_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->smb2req = smb2req;
+	state->in_session_id = in_session_id;
+	state->in_flags = in_flags;
+	state->in_security_mode = in_security_mode;
+	state->in_previous_session_id = in_previous_session_id;
+	state->in_security_buffer = in_security_buffer;
+
+	subreq = smbd_smb2_session_setup_send(state, state->ev,
+					      state->smb2req,
+					      state->in_session_id,
+					      state->in_flags,
+					      state->in_security_mode,
+					      state->in_previous_session_id,
+					      state->in_security_buffer);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq,
+				smbd_smb2_session_setup_wrap_setup_done, req);
+
+	return req;
+}
+
+static void smbd_smb2_session_setup_wrap_setup_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct smbd_smb2_session_setup_wrap_state *state =
+		tevent_req_data(req,
+		struct smbd_smb2_session_setup_wrap_state);
+	NTSTATUS status;
+
+	status = smbd_smb2_session_setup_recv(subreq,
+					      &state->out_session_flags,
+					      state,
+					      &state->out_security_buffer,
+					      &state->out_session_id);
+	TALLOC_FREE(subreq);
+	if (NT_STATUS_IS_OK(status)) {
+		tevent_req_done(req);
+		return;
+	}
+	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+
+	if (state->smb2req->session == NULL) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+
+	state->error = status;
+
+	subreq = smb2srv_session_shutdown_send(state, state->ev,
+					       state->smb2req->session,
+					       state->smb2req);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq,
+				smbd_smb2_session_setup_wrap_shutdown_done,
+				req);
+}
+
+static void smbd_smb2_session_setup_wrap_shutdown_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct smbd_smb2_session_setup_wrap_state *state =
+		tevent_req_data(req,
+		struct smbd_smb2_session_setup_wrap_state);
+	NTSTATUS status;
+
+	status = smb2srv_session_shutdown_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	/*
+	 * we may need to sign the response, so we need to keep
+	 * the session until the response is sent to the wire.
+	 */
+	talloc_steal(state->smb2req, state->smb2req->session);
+
+	tevent_req_nterror(req, state->error);
+}
+
+static NTSTATUS smbd_smb2_session_setup_wrap_recv(struct tevent_req *req,
+					uint16_t *out_session_flags,
+					TALLOC_CTX *mem_ctx,
+					DATA_BLOB *out_security_buffer,
+					uint64_t *out_session_id)
+{
+	struct smbd_smb2_session_setup_wrap_state *state =
+		tevent_req_data(req,
+		struct smbd_smb2_session_setup_wrap_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+			tevent_req_received(req);
+			return nt_status_squash(status);
+		}
+	} else {
+		status = NT_STATUS_OK;
+	}
+
+	*out_session_flags = state->out_session_flags;
+	*out_security_buffer = state->out_security_buffer;
+	*out_session_id = state->out_session_id;
+
+	talloc_steal(mem_ctx, out_security_buffer->data);
+	tevent_req_received(req);
+	return status;
+}
+
 static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbd_smb2_request *smb2req);
-- 
1.9.1


From 5943d75702246d791138092a2b609b95ba674777 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 2 May 2015 16:29:03 +0200
Subject: [PATCH 15/17] s3:smb2_sesssetup: remove unused
 smbd_smb2_session_setup_* destructors

The cleanup of a failing session setup is now handled in
smbd_smb2_session_setup_wrap_*().

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smb2_sesssetup.c | 98 -------------------------------------------
 1 file changed, 98 deletions(-)

diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 5ddaa48..c56e480 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -448,94 +448,12 @@ struct smbd_smb2_session_setup_state {
 	uint16_t out_session_flags;
 	DATA_BLOB out_security_buffer;
 	uint64_t out_session_id;
-	/* The following pointer is owned by state->session. */
-	struct smbd_smb2_session_setup_state **pp_self_ref;
 };
 
-static int pp_self_ref_destructor(struct smbd_smb2_session_setup_state **pp_state)
-{
-	(*pp_state)->session = NULL;
-	/*
-	 * To make things clearer, ensure the pp_self_ref
-	 * pointer is nulled out. We're never going to
-	 * access this again.
-	 */
-	(*pp_state)->pp_self_ref = NULL;
-	return 0;
-}
-
-static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state)
-{
-	struct smbXsrv_connection *xconn;
-	struct smbd_smb2_request *preq;
-
-	/*
-	 * If state->session is not NULL,
-	 * we move the session from the session table to the request on failure
-	 * so that the error response can be correctly signed, but the session
-	 * is then really deleted when the request is done.
-	 */
-
-	if (state->session == NULL) {
-		return 0;
-	}
-
-	state->session->status = NT_STATUS_USER_SESSION_DELETED;
-	state->smb2req->session = talloc_move(state->smb2req, &state->session);
-
-	/*
-	 * We own the session now - we don't need the
-	 * tag talloced on session that keeps track of session independently.
-	 */
-	TALLOC_FREE(state->pp_self_ref);
-
-	/*
-	 * We've made this session owned by the current request.
-	 * Ensure that any outstanding requests don't also refer
-	 * to it.
-	 */
-	xconn = state->smb2req->xconn;
-
-	for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
-		if (preq == state->smb2req) {
-			continue;
-		}
-		if (preq->session == state->smb2req->session) {
-			preq->session = NULL;
-			/*
-			 * If we no longer have a session we can't
-			 * sign or encrypt replies.
-			 */
-			preq->do_signing = false;
-			preq->do_encryption = false;
-		}
-	}
-
-	return 0;
-}
-
 static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq);
 static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq);
 static void smbd_smb2_session_setup_auth_return(struct tevent_req *req);
 
-/************************************************************************
- We have to tag the state->session pointer with memory talloc'ed
- on it to ensure it gets NULL'ed out if the underlying struct smbXsrv_session
- is deleted by shutdown whilst this request is in flight.
-************************************************************************/
-
-static NTSTATUS tag_state_session_ptr(struct smbd_smb2_session_setup_state *state)
-{
-	state->pp_self_ref = talloc_zero(state->session,
-			struct smbd_smb2_session_setup_state *);
-	if (state->pp_self_ref == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	*state->pp_self_ref = state;
-	talloc_set_destructor(state->pp_self_ref, pp_self_ref_destructor);
-	return NT_STATUS_OK;
-}
-
 static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbd_smb2_request *smb2req,
@@ -577,8 +495,6 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	talloc_set_destructor(state, smbd_smb2_session_setup_state_destructor);
-
 	if (state->in_session_id == 0) {
 		/* create a new session */
 		status = smbXsrv_session_create(state->smb2req->xconn,
@@ -609,11 +525,6 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	status = tag_state_session_ptr(state);
-	if (tevent_req_nterror(req, status)) {
-		return tevent_req_post(req, ev);
-	}
-
 	if (state->session->gensec == NULL) {
 		status = auth_generic_prepare(state->session,
 					      state->smb2req->xconn->remote_address,
@@ -668,9 +579,6 @@ static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq)
 
 	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 		state->out_session_id = state->session->global->session_wire_id;
-		/* we want to keep the session */
-		state->session = NULL;
-		TALLOC_FREE(state->pp_self_ref);
 		tevent_req_nterror(req, status);
 		return;
 	}
@@ -735,9 +643,6 @@ static void smbd_smb2_session_setup_auth_return(struct tevent_req *req)
 		if (tevent_req_nterror(req, status)) {
 			return;
 		}
-		/* we want to keep the session */
-		state->session = NULL;
-		TALLOC_FREE(state->pp_self_ref);
 		tevent_req_done(req);
 		return;
 	}
@@ -752,9 +657,6 @@ static void smbd_smb2_session_setup_auth_return(struct tevent_req *req)
 		return;
 	}
 
-	/* we want to keep the session */
-	state->session = NULL;
-	TALLOC_FREE(state->pp_self_ref);
 	tevent_req_done(req);
 	return;
 }
-- 
1.9.1


From b414e5fc8339fbf893aedd5d3f457c17d3e59265 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 16:50:55 +0200
Subject: [PATCH 16/17] s3:smb2_tcon: cancel pending requests on all
 connections on tdis

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/smbd/smb2_tcon.c | 66 +++++++++++++++++++++++++-----------------------
 1 file changed, 35 insertions(+), 31 deletions(-)

diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c
index cf085a5..3750bc1 100644
--- a/source3/smbd/smb2_tcon.c
+++ b/source3/smbd/smb2_tcon.c
@@ -502,8 +502,7 @@ static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx,
 	struct tevent_req *req;
 	struct smbd_smb2_tdis_state *state;
 	struct tevent_req *subreq;
-	struct smbd_smb2_request *preq;
-	struct smbXsrv_connection *xconn = smb2req->xconn;
+	struct smbXsrv_connection *xconn = NULL;
 
 	req = tevent_req_create(mem_ctx, &state,
 			struct smbd_smb2_tdis_state);
@@ -522,35 +521,40 @@ static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx,
 	 */
 	smb2req->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
 
-	for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
-		if (preq == smb2req) {
-			/* Can't cancel current request. */
-			continue;
-		}
-		if (preq->tcon != smb2req->tcon) {
-			/* Request on different tcon. */
-			continue;
-		}
-
-		/*
-		 * Never cancel anything in a compound
-		 * request. Way too hard to deal with
-		 * the result.
-		 */
-		if (!preq->compound_related && preq->subreq != NULL) {
-			tevent_req_cancel(preq->subreq);
-		}
-
-		/*
-		 * Now wait until the request is finished.
-		 *
-		 * We don't set a callback, as we just want to block the
-		 * wait queue and the talloc_free() of the request will
-		 * remove the item from the wait queue.
-		 */
-		subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
-		if (tevent_req_nomem(subreq, req)) {
-			return tevent_req_post(req, ev);
+	xconn = smb2req->xconn->client->connections;
+	for (; xconn != NULL; xconn = xconn->next) {
+		struct smbd_smb2_request *preq;
+
+		for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
+			if (preq == smb2req) {
+				/* Can't cancel current request. */
+				continue;
+			}
+			if (preq->tcon != smb2req->tcon) {
+				/* Request on different tcon. */
+				continue;
+			}
+
+			/*
+			 * Never cancel anything in a compound
+			 * request. Way too hard to deal with
+			 * the result.
+			 */
+			if (!preq->compound_related && preq->subreq != NULL) {
+				tevent_req_cancel(preq->subreq);
+			}
+
+			/*
+			 * Now wait until the request is finished.
+			 *
+			 * We don't set a callback, as we just want to block the
+			 * wait queue and the talloc_free() of the request will
+			 * remove the item from the wait queue.
+			 */
+			subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
+			if (tevent_req_nomem(subreq, req)) {
+				return tevent_req_post(req, ev);
+			}
 		}
 	}
 
-- 
1.9.1


From 67c3692a5404f888b637328fdb32c6d4d2f748e3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 May 2015 20:26:41 +0200
Subject: [PATCH 17/17] s3:selftest: run smb2.notify with --signing=required

This reproduces a bug withe implicit canceled requests.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/selftest/tests.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 7436d26..dd06e07 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -383,6 +383,9 @@ for t in tests:
     elif t == "local.nss":
         for env in ["nt4_dc:local", "ad_member:local", "nt4_member:local", "ad_dc:local", "ad_dc_ntvfs:local"]:
             plansmbtorture4testsuite(t, env, '//$SERVER/tmp -U$USERNAME%$PASSWORD')
+    elif t == "smb2.notify":
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --signing=required')
+        plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD --signing=required')
     else:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
-- 
1.9.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20150506/361be703/attachment.pgp>


More information about the samba-technical mailing list