From bc53009bf52f669c288c1962ac6e1635646e14db Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:04:55 +0200 Subject: [PATCH 01/18] s3:smbd: add a smbd_notify_cancel_by_map() helper function Signed-off-by: Stefan Metzmacher --- 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 ac1a55c..0a0ae83 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -374,6 +374,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. *****************************************************************************/ @@ -393,9 +404,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) @@ -413,9 +422,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); } /**************************************************************************** -- 1.9.1 From bbe28ff6f24e08cae19a38d3cb4e14b6f2338461 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:02:38 +0200 Subject: [PATCH 02/18] s3:smbd: use STATUS_NOTIFY_CLEANUP when closing a smb2 directory handle Signed-off-by: Stefan Metzmacher --- selftest/knownfail | 1 - source3/smbd/close.c | 15 +++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index af7e7fd..8b26630 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -187,7 +187,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 4fbd442f..fc1d380 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 07afb8aedd4cdb7da3d7c15e773b8f3478c91a3e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:02:38 +0200 Subject: [PATCH 03/18] s3:smbd: use STATUS_NOTIFY_CLEANUP on smb2 logoff (explicit and implicit) and tdis Signed-off-by: Stefan Metzmacher --- source3/smbd/notify.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 0a0ae83..0e4969d 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -378,8 +378,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 21b885f9d9a5644151047fb622ea1cbdde095ec3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:19:42 +0200 Subject: [PATCH 04/18] s4:torture/smb2: verify STATUS_NOTIFY_CLEANUP return value Signed-off-by: Stefan Metzmacher --- 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 c721d5f..827f5d5 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -1304,6 +1304,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: @@ -1372,6 +1373,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 4e5b42e9495b9c4e7565c5df58c17e8756f124b6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:20:50 +0200 Subject: [PATCH 05/18] s4:torture/smb2: add smb2.notify.close test Signed-off-by: Stefan Metzmacher --- 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 827f5d5..e9cfeda 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -1313,6 +1313,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 */ @@ -2026,6 +2095,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 f78b497c5788cba9a7cc6187233088891d44b0c5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:20:50 +0200 Subject: [PATCH 06/18] s4:torture/smb2: add smb2.notify.invalid-reauth test An invalid reauth closes the session. Signed-off-by: Stefan Metzmacher --- 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 e9cfeda..fe496c8 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -1450,6 +1450,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; @@ -2097,6 +2178,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 7c28c7bf879d8de55116acc4c51f4ecec4526c4e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:26:41 +0200 Subject: [PATCH 07/18] HACK try to reproduce https://bugzilla.samba.org/show_bug.cgi?id=11182 require signing --- selftest/target/Samba3.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index d8eb58c..66d0bd6 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -203,6 +203,7 @@ sub setup_s3dc($$) domain master = yes domain logons = yes lanman auth = yes + server signing = required rpc_server:epmapper = external rpc_server:spoolss = external -- 1.9.1 From 14ba2e3b24ca1d677dc59dc2c7e80b59c7270d12 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 1 May 2015 20:26:41 +0200 Subject: [PATCH 08/18] HACK try to reproduce https://bugzilla.samba.org/show_bug.cgi?id=11182 invalid pointer --- source3/smbd/smb2_sesssetup.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 57f623a..7f0e845 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -497,13 +497,13 @@ static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_set 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; + preq->session += 537; + // /* + // * If we no longer have a session we can't + // * sign or encrypt replies. + // */ + // preq->do_signing = false; + // preq->do_encryption = false; } } -- 1.9.1 From 567903de4afcaeaff69bc17cc744777a33b382e4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 09:05:32 +0200 Subject: [PATCH 09/18] Revert "HACK try to reproduce https://bugzilla.samba.org/show_bug.cgi?id=11182 invalid pointer" This reverts commit 14ba2e3b24ca1d677dc59dc2c7e80b59c7270d12. --- source3/smbd/smb2_sesssetup.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 7f0e845..57f623a 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -497,13 +497,13 @@ static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_set continue; } if (preq->session == state->smb2req->session) { - preq->session += 537; - // /* - // * If we no longer have a session we can't - // * sign or encrypt replies. - // */ - // preq->do_signing = false; - // preq->do_encryption = false; + 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; } } -- 1.9.1 From bb21cbcda5adb70717155e00a1930d37779da58e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 09:57:03 +0200 Subject: [PATCH 10/18] s3:smbXsrv_session: add smbXsrv_session_shutdown_send/recv helper functions Signed-off-by: Stefan Metzmacher --- source3/smbd/globals.h | 5 ++ source3/smbd/smbXsrv_session.c | 103 +++++++++++++++++++++++++++++++++++++++++ source4/torture/smb2/notify.c | 81 ++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index eacc5b3..b8c2a82 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -535,6 +535,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 *smbXsrv_session_shutdown_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbXsrv_session *session, + struct smbd_smb2_request *current_req); +NTSTATUS smbXsrv_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 7eca968..431abad 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -1298,6 +1298,109 @@ NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session, return NT_STATUS_USER_SESSION_DELETED; } +struct smbXsrv_session_shutdown_state { + struct tevent_queue *wait_queue; +}; + +static void smbXsrv_session_shutdown_wait_done(struct tevent_req *subreq); + +struct tevent_req *smbXsrv_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 smbXsrv_session_shutdown_state *state; + struct tevent_req *subreq; + struct smbXsrv_connection *xconn; + + req = tevent_req_create(mem_ctx, &state, + struct smbXsrv_session_shutdown_state); + if (req == NULL) { + return NULL; + } + + state->wait_queue = tevent_queue_create(state, "smbXsrv_session_shutdown_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. + */ + session->status = NT_STATUS_USER_SESSION_DELETED; + + 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; + } + + /* + * 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); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, smbXsrv_session_shutdown_wait_done, req); + + return req; +} + +static void smbXsrv_session_shutdown_wait_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smbXsrv_session_shutdown_state *state = + tevent_req_data(req, + struct smbXsrv_session_shutdown_state); + NTSTATUS status; + + tevent_queue_wait_recv(subreq); + TALLOC_FREE(subreq); + + tevent_req_done(req); +} + +NTSTATUS smbXsrv_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; diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c index fe496c8..5589559 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -1451,6 +1451,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 */ @@ -2178,6 +2258,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 ab48440b2787633d2055763673682579adb4f154 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:09:40 +0200 Subject: [PATCH 11/18] 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. Signed-off-by: Stefan Metzmacher --- 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 431abad..3bc132b 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -1060,6 +1060,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 d77aca493145cbc69a161fc101d0938584dd64ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:12:15 +0200 Subject: [PATCH 12/18] isq add smbXsrv_session_shutdown_ --- source3/smbd/smbXsrv_session.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c index 3bc132b..b72ae6a 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -1335,10 +1335,16 @@ struct tevent_req *smbXsrv_session_shutdown_send(TALLOC_CTX *mem_ctx, struct tevent_req *req; struct smbXsrv_session_shutdown_state *state; struct tevent_req *subreq; - struct smbXsrv_connection *xconn; + 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 smbXsrv_session_shutdown_state); + struct smbXsrv_session_shutdown_state); if (req == NULL) { return NULL; } @@ -1348,11 +1354,6 @@ struct tevent_req *smbXsrv_session_shutdown_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - /* - * Make sure that no new request will be able to use this session. - */ - session->status = NT_STATUS_USER_SESSION_DELETED; - for (xconn = session->client->connections; xconn != NULL; xconn = xconn->next) { struct smbd_smb2_request *preq; @@ -1366,6 +1367,21 @@ struct tevent_req *smbXsrv_session_shutdown_send(TALLOC_CTX *mem_ctx, 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 @@ -1389,6 +1405,12 @@ struct tevent_req *smbXsrv_session_shutdown_send(TALLOC_CTX *mem_ctx, } } + 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 @@ -1408,10 +1430,6 @@ static void smbXsrv_session_shutdown_wait_done(struct tevent_req *subreq) struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); - struct smbXsrv_session_shutdown_state *state = - tevent_req_data(req, - struct smbXsrv_session_shutdown_state); - NTSTATUS status; tevent_queue_wait_recv(subreq); TALLOC_FREE(subreq); -- 1.9.1 From 968202f14fb42d6b4a5e11aee8990c920b834532 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:13:27 +0200 Subject: [PATCH 13/18] TODO 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 TODO: simple fix before in order to make backports easier maybe the destructor fix already helps --- 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 b72ae6a..4b4355e 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -222,6 +222,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 = @@ -326,20 +328,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 = smbXsrv_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", + "smbXsrv_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); @@ -355,6 +359,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 = smbXsrv_session_shutdown_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("smbXsrv_session_close_loop: " + "smbXsrv_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 99ed051b51ea14092a3e8be464ecb84acdf6b92d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:17:34 +0200 Subject: [PATCH 14/18] NEEDED? smbXsrv_session_logoff_all_callback() destructor cleans up --- source3/smbd/smbXsrv_session.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c index 4b4355e..38e0af3 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -1649,6 +1649,8 @@ static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec, TDB_DATA val; void *ptr = NULL; struct smbXsrv_session *session = NULL; + struct tevent_context *ev = NULL; + struct tevent_req *subreq = NULL; NTSTATUS status; val = dbwrap_record_get_value(local_rec); @@ -1665,6 +1667,50 @@ 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; + + ev = samba_tevent_context_init(session); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + return 0; + } + + subreq = smbXsrv_session_shutdown_send(ev, ev, session, NULL); + if (subreq == NULL) { + TALLOC_FREE(ev); + status = NT_STATUS_NO_MEMORY; + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + return 0; + } + if (tevent_req_is_in_progress(subreq)) { + /* + * The last transport connection is gone + * we don't expect to wait. + */ + TALLOC_FREE(ev); + status = NT_STATUS_INTERNAL_ERROR; + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + return 0; + } + status = smbXsrv_session_shutdown_recv(subreq); + TALLOC_FREE(ev); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + return 0; + } + status = smbXsrv_session_logoff(session); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_IS_OK(state->first_status)) { -- 1.9.1 From 52989d4b9cf68ded05a45680d9c2ece9c2a03bd6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:20:06 +0200 Subject: [PATCH 15/18] s3:smb2_sesssetup: let smbd_smb2_logoff_* use smbXsrv_session_shutdown_* Signed-off-by: Stefan Metzmacher --- 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 57f623a..27bcfa4 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -855,95 +855,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 = smbXsrv_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 = smbXsrv_session_shutdown_recv(subreq); + if (tevent_req_nterror(req, status)) { + return; + } TALLOC_FREE(subreq); /* -- 1.9.1 From d8e42d079f0c41954685050719e723870e5ad3e8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:21:25 +0200 Subject: [PATCH 16/18] 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. Signed-off-by: Stefan Metzmacher --- 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 27bcfa4..e1d4db3 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)) { @@ -783,6 +783,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 = smbXsrv_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 = smbXsrv_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 eaf662da58ce03b124d290ce4bd6b95692f751c6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:27:26 +0200 Subject: [PATCH 17/18] s3:smb2_sesssetup: always assign smb2req->session when a session was created. Signed-off-by: Stefan Metzmacher --- 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 e1d4db3..4b5ece7b 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -363,7 +363,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; } @@ -582,6 +581,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 ecbdd2da9bf09b8b6e9b8ba5f793d10a7d4ff650 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 2 May 2015 16:29:03 +0200 Subject: [PATCH 18/18] 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_*(). Signed-off-by: Stefan Metzmacher --- 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 4b5ece7b..86515c1 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -443,94 +443,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, @@ -572,8 +490,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, @@ -604,11 +520,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, @@ -663,9 +574,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; } @@ -730,9 +638,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; } @@ -747,9 +652,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