From 786324d44fb8e797d53db7904d231f2012fcfd57 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 5 Mar 2014 14:07:11 -0800 Subject: [PATCH 01/26] s3: smbd: SMB2 server. Add a generic wait_queue mechanism. NTSTATUS smbd_smb2_wait_for_request_to_complete( struct smbd_smb2_request *smb2req_to_awaken, struct smbd_smb2_request *smb2req_to_wait_for, struct tevent_context *ev, void (*callback_fn)(struct tevent_req *), void *priv_ptr) Parameters are: struct smbd_smb2_request *smb2req_to_awaken - SMB2 request to be awoken. struct smbd_smb2_request *smb2req_to_wait_for - SMB2 request to wait for. struct tevent_context *ev - Event context. void (*callback_fn)(struct tevent_req *) - Callback Function to call once request has completed. void *priv_ptr - Private pointer passed to callback. Allows an SMB2 request to suspend itself via registering a wait request using tevent_wait_send() on another SMB2 request. The suspending request will be awoken only when the second SMB2 request completes and sends its reply back to the client. Signed-off-by: Jeremy Allison --- source3/smbd/globals.h | 38 ++++++++++++++++ source3/smbd/smb2_server.c | 105 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 3baa048..a352ad8 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -254,6 +254,27 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req); size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req); void remove_smb2_chained_fsp(files_struct *fsp); +/************************************************************* + Add a tevent request to the wait queue associated with an + SMB2 request. Will get notified once the SMB2 request completes. + + Parameters are: + + struct smbd_smb2_request *smb2req_to_awaken, - SMB2 request to be awoken. + struct smbd_smb2_request *smb2req_to_wait_for - SMB2 request to wait for. + struct tevent_context *ev, - Event context. + void (*callback_fn)(struct tevent_req *), - Callback Function to call + once request has completed. + void *priv_ptr - Private pointer passed to + callback. +*************************************************************/ + +NTSTATUS smbd_smb2_wait_for_request_to_complete( + struct smbd_smb2_request *smb2req_to_awaken, + struct smbd_smb2_request *smb2req_to_wait_for, + struct tevent_context *ev, + void (*callback_fn)(struct tevent_req *), + void *priv_ptr); NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req, uint32_t data_length); @@ -480,6 +501,16 @@ struct smbd_smb2_send_queue { TALLOC_CTX *mem_ctx; }; +struct smb2_request_wait_list { + struct smb2_request_wait_list *prev, *next; + /* + * Waiting event to trigger once the enclosing + * struct smbd_smb2_request has sent out a reply. + * This pointer is created by tevent_wait_send(). + */ + struct tevent_req *wait_req; +}; + struct smbd_smb2_request { struct smbd_smb2_request *prev, *next; @@ -487,6 +518,13 @@ struct smbd_smb2_request { struct smbd_smb2_send_queue queue_entry; + /* + * A list of wait events that represent + * other SMB2 requests waiting for this + * request to complete. + */ + struct smb2_request_wait_list *wait_list; + /* the session the request operates on, maybe NULL */ struct smbXsrv_session *session; uint64_t last_session_id; diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 3c46efd..3ef0964 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -29,6 +29,7 @@ #include "../lib/util/bitmap.h" #include "../librpc/gen_ndr/krb5pac.h" #include "auth.h" +#include "lib/tevent_wait.h" static void smbd_smb2_connection_handler(struct tevent_context *ev, struct tevent_fd *fde, @@ -1161,6 +1162,13 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re newreq->do_signing = req->do_signing; newreq->current_idx = req->current_idx; + /* + * Note we never duplicate the wait list of + * SMB2 requests to awaken. The wait list + * is associated with the SMB2 request left + * on the request queue. + */ + outvec = talloc_zero_array(newreq, struct iovec, count); if (!outvec) { TALLOC_FREE(newreq); @@ -1606,6 +1614,99 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, } } +/************************************************************* + Destructor for a wait list entry. + Ensures we are removed from any linked list + associated with an SMB2 request we may still be on. + Only matters if the request to be awoken finishes + before the request doing the wake-up. +*************************************************************/ + +static int smbd_smb2_cleanup_wait_list_entry(struct smb2_request_wait_list *pwe) +{ + if (pwe->prev) { + /* + * This is only the case when the SMB2 request to + * be awakened has finished and is being freed before + * the SMB2 request that should awaken us. This should + * be a very rare occurrence. + */ + struct smb2_request_wait_list *wl_head; + DLIST_HEAD(pwe, wl_head); + DLIST_REMOVE(wl_head, pwe); + } + return 0; +} + +/************************************************************* + Add a tevent request to the wait queue associated with an + SMB2 request. Will get notified once the SMB2 request completes. + + Parameters are: + + struct smbd_smb2_request *smb2req_to_awaken, - SMB2 request to be awoken. + struct smbd_smb2_request *smb2req_to_wait_for - SMB2 request to wait for. + struct tevent_context *ev, - Event context. + void (*callback_fn)(struct tevent_req *), - Callback Function to call + once request has completed. + void *priv_ptr - Private pointer passed to + callback. +*************************************************************/ + +NTSTATUS smbd_smb2_wait_for_request_to_complete( + struct smbd_smb2_request *smb2req_to_awaken, + struct smbd_smb2_request *smb2req_to_wait_for, + struct tevent_context *ev, + void (*callback_fn)(struct tevent_req *), + void *priv_ptr) +{ + struct smb2_request_wait_list *pwe = talloc_zero(smb2req_to_awaken, + struct smb2_request_wait_list); + if (pwe == NULL) { + return NT_STATUS_NO_MEMORY; + } + + pwe->wait_req = tevent_wait_send(pwe, ev); + if (pwe->wait_req == NULL) { + TALLOC_FREE(pwe); + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(pwe->wait_req, + callback_fn, + priv_ptr); + DLIST_ADD_END(smb2req_to_wait_for->wait_list, pwe, + struct smb2_request_wait_list *); + + /* + * The following is needed in case the SMB2 request + * to_awaken finishes and is deleted before the + * request we want to awaken us. + */ + talloc_set_destructor(pwe, smbd_smb2_cleanup_wait_list_entry); + return NT_STATUS_OK; +} + +/************************************************************* + Awaken all tevent requests that were waiting for this + SMB2 request to complete. +*************************************************************/ + +static void smbd_smb2_awaken_waiting_requests(struct smbd_smb2_request *req) +{ + struct smb2_request_wait_list *pwl_next; + struct smb2_request_wait_list *pwl; + + for (pwl = req->wait_list; pwl; pwl = pwl_next) { + pwl_next = pwl->next; + + tevent_wait_done(pwl->wait_req); + + DLIST_REMOVE(req->wait_list, pwl); + /* Esnure the destructor is safe. */ + pwl->next = pwl->prev = NULL; + } +} + static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req) { struct smbd_server_connection *sconn = req->sconn; @@ -1627,6 +1728,8 @@ static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req) * cancel requests never have a response */ DLIST_REMOVE(req->sconn->smb2.requests, req); + /* Wake all other requests waiting for completion. */ + smbd_smb2_awaken_waiting_requests(req); TALLOC_FREE(req); for (cur = sconn->smb2.requests; cur; cur = cur->next) { @@ -2483,6 +2586,8 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) * move it off the "being processed" queue. */ DLIST_REMOVE(req->sconn->smb2.requests, req); + /* Wake all other requests waiting for completion. */ + smbd_smb2_awaken_waiting_requests(req); req->queue_entry.mem_ctx = req; req->queue_entry.vector = req->out.vector; -- 1.9.0.279.gdc9e3eb From a84a4528047210b1780090ba186d6b4dfd17d2f6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 13 Jan 2014 14:12:18 -0800 Subject: [PATCH 02/26] s3: SMB2 logoff - factor code out into a function remove_outstanding_session_refs(). We will be reusing this. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 9d7193b..16cc5cd 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -455,10 +455,30 @@ static int pp_self_ref_destructor(struct smbd_smb2_session_setup_state **pp_stat return 0; } -static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) +static void remove_outstanding_session_refs(struct smbd_smb2_request *smb2req) { struct smbd_smb2_request *preq; + for (preq = smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { + if (preq == smb2req) { + /* Don't remove the session from the current + request in flight. */ + continue; + } + if (preq->session == 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; + } + } +} + +static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) +{ /* * If state->session is not NULL, * we move the session from the session table to the request on failure @@ -479,21 +499,7 @@ static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_set * to it. */ - for (preq = state->smb2req->sconn->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; - } - } - + remove_outstanding_session_refs(state->smb2req); return 0; } -- 1.9.0.279.gdc9e3eb From c19bcf46932a92511bc1638ed4eaecd50381f71a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 13 Jan 2014 14:31:31 -0800 Subject: [PATCH 03/26] s3: SMB2 logoff - add find_outstanding_session_request() Walk the outstanding SMB2 requests and return the first one (not including the current request being processed) on this session. Return NULL if there are no outstanding requests on this session. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 16cc5cd..91565f0 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -794,6 +794,49 @@ static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req, return status; } +/******************************************************** + Walk the outstanding SMB2 requests and return the + first one (not including the current request being processed) + on this session. Return NULL if there are no outstanding + requests on this session. +********************************************************/ + +static struct smbd_smb2_request *find_outstanding_session_request( + const struct smbd_smb2_request *smb2req) +{ + struct smbd_smb2_request *preq; + + if (smb2req->session == NULL) { + return NULL; + } + for (preq = smb2req->sconn->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; + } + + if (preq->compound_related) { + /* + * Never cancel anything in a compound + * request. Way too hard to deal with + * the result. + */ + continue; + } + + /* + * If we get here we've found a request + * request we're going to cancel. + */ + break; + } + return preq; +} + NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { NTSTATUS status; -- 1.9.0.279.gdc9e3eb From 9935124d0f047afe8bd6928bf20974d30f8d0a0a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 14:03:22 -0800 Subject: [PATCH 04/26] s3: smbd: SMB2 logoff - Add definition of struct smbd_smb2_logout_state. Not yet used - will be used in async logoff code. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 91565f0..93f6936 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -837,6 +837,11 @@ static struct smbd_smb2_request *find_outstanding_session_request( return preq; } +struct smbd_smb2_logout_state { + struct smbd_smb2_request *smb2req; + struct tevent_context *ev; +}; + NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { NTSTATUS status; -- 1.9.0.279.gdc9e3eb From 62e5ea1e98f94d0b843bc9ee850f58f4179f0cba Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 14:04:59 -0800 Subject: [PATCH 05/26] s3: smbd: SMB2 logoff - Add tevent_wait.h header to smb2_sesssetup.c Will be used in async logoff code. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 93f6936..a995224 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -28,6 +28,7 @@ #include "../lib/tsocket/tsocket.h" #include "../libcli/security/security.h" #include "../lib/util/tevent_ntstatus.h" +#include "lib/tevent_wait.h" static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- 1.9.0.279.gdc9e3eb From a0c95e5a232f7f269f7e9f07d14ea47c9f2819cd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Mar 2014 10:11:33 -0800 Subject: [PATCH 06/26] smbd: SMB2 logoff - Add utility function wait_for_outstanding_requests(). This looks for an outstanding request on this session, calls tevent_req_cancel() on it and then uses the new SMB2 request wait mechanism smbd_smb2_wait_for_request_to_complete() to add a tevent request to the wait queue associated with the SMB2 request we just cancelled. Returns NT_STATUS_RETRY if we are waiting. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index a995224..8684dba 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -843,6 +843,53 @@ struct smbd_smb2_logout_state { struct tevent_context *ev; }; +static void smbd_smb2_logoff_do(struct tevent_req *subreq); + +/*************************************************************** + Utility function to wait for outstanding SMB2 requests on + this session. + If we return NT_STATUS_RETRY we have set ourselves to wait + for another request to complete. +***************************************************************/ + +static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_logout_state *state, + struct tevent_req *req) +{ + struct smbd_smb2_request *smb2req = state->smb2req; + struct smbd_smb2_request *smb2_wait_req; + NTSTATUS status; + + /* + * Try and find a request to cancel. If we can, + * cancel it and tell ourselves to wait unti it's finished. + */ + smb2_wait_req = find_outstanding_session_request(smb2req); + if (smb2_wait_req != NULL) { + + tevent_req_cancel(smb2_wait_req->subreq); + + status = smbd_smb2_wait_for_request_to_complete( + smb2req, /* Request to wake up on completion. */ + smb2_wait_req, /* Request we're waiting on. */ + state->ev, /* Event context. */ + smbd_smb2_logoff_do, /* callback. */ + req); /* Private pointer. */ + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("logoff wait failed: %s\n", + nt_errstr(status))); + return status; + } + /* We're waiting on another SMB2 request. */ + return NT_STATUS_RETRY; + } + + return NT_STATUS_OK; +} + +static void smbd_smb2_logoff_do(struct tevent_req *subreq) +{ +} + NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { NTSTATUS status; -- 1.9.0.279.gdc9e3eb From 6eec70b595aebf8be83cf9c64a127f0f1ee08277 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Mar 2014 10:15:07 -0800 Subject: [PATCH 07/26] smbd: SMB2 logoff - Add utility function try_to_tear_down_session(). Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 8684dba..08862a0 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -886,6 +886,34 @@ static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_logout_state *sta return NT_STATUS_OK; } +/*************************************************************** + Utility function to do the work of tearing down a session. +***************************************************************/ + +static NTSTATUS try_to_tear_down_session(struct smbd_smb2_request *smb2req) +{ + NTSTATUS status = smbXsrv_session_logoff(smb2req->session); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * We may need to sign the response, so we need to keep + * the session until the response is sent to the wire. + */ + talloc_steal(smb2req, smb2req->session); + /* + * The return from smbXsrv_session_logoff() + * leaves all outstanding pointers to + * smb2req->session not on this request in an + * undefined state, ensure we don't try and + * access any req->session pointers once + * we return. + */ + remove_outstanding_session_refs(smb2req); + return NT_STATUS_OK; +} + static void smbd_smb2_logoff_do(struct tevent_req *subreq) { } -- 1.9.0.279.gdc9e3eb From 50a36a8c01e93eee75c4632ee5e4c5459c4544c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:33:00 -0800 Subject: [PATCH 08/26] s3: smbd: SMB2 logoff - Add wait completion function smbd_smb2_logoff_do(). Wait callback function called when we were woken up by an SMB2 request we were waiting on completing. Checks to see if we should still wait, and goes back to sleep if so, otherwise tears down the session and finishes the request. When re-awoken calls change_to_root_user() as SMB2_OP_LOGOFF has .as_root = true in smb2_server.c and we have processed other commands so may have swiched user whilst we were waiting. Thanks to Metze for pointing this out. This avoids any tevent reentrancy and is a clean, simple way of handling deferred notification. Many thanks to Volker for showing the way to do this inside smb2_close.c. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 63 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 08862a0..b5fd873 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -914,10 +914,6 @@ static NTSTATUS try_to_tear_down_session(struct smbd_smb2_request *smb2req) return NT_STATUS_OK; } -static void smbd_smb2_logoff_do(struct tevent_req *subreq) -{ -} - NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { NTSTATUS status; @@ -959,3 +955,62 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) return smbd_smb2_request_done(req, outbody, NULL); } + +/*************************************************************** + Wait callback function called when we were woken up by an + SMB2 request we were waiting on completing. Checks to see + if we should still wait, and goes back to sleep if so, + otherwise tears down the session and finishes the request. +***************************************************************/ + +static void smbd_smb2_logoff_do(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); + NTSTATUS status; + int ret; + + ret = tevent_wait_recv(subreq); + TALLOC_FREE(subreq); + if (ret != 0) { + DEBUG(10, ("tevent_wait_recv returned %s\n", + strerror(ret))); + /* + * Continue anyway, this should never happen + */ + } + + /* Should we still wait ? */ + status = wait_for_outstanding_requests(state, req); + + if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { + /* + * NT_STATUS_RETRY means we're waiting + * for another cancelled request to complete. + */ + return; + } + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("waiting for requetsts failed: %s\n", + nt_errstr(status))); + tevent_req_done(req); + return; + } + + /* + * As we've been awoken, we may have changed + * uid in the meantime. Ensure we're still + * root (SMB2_OP_LOGOFF has .as_root = true). + */ + change_to_root_user(); + + status = try_to_tear_down_session(state->smb2req); + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("tearing down session failed: %s\n", + nt_errstr(status))); + } + /* Either way we're done. */ + tevent_req_done(req); +} -- 1.9.0.279.gdc9e3eb From 0b3b65adf24712c2aaaeafa144b743dda67e8385 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 14:36:47 -0800 Subject: [PATCH 09/26] s3: smbd: SMB2 logoff - Add smbd_smb2_logoff_send(). Send function in making logoff async. Note the similarity to the smbd_smb2_logoff_do() function, as this function does the same thing when worken from the wait queue. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index b5fd873..c8cb926 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -956,6 +956,49 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) return smbd_smb2_request_done(req, outbody, NULL); } +static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req) +{ + NTSTATUS status; + struct tevent_req *req; + struct smbd_smb2_logout_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct smbd_smb2_logout_state); + if (req == NULL) { + return NULL; + } + state->smb2req = smb2req; + state->ev = ev; + + status = wait_for_outstanding_requests(state, req); + + /* + * NT_STATUS_RETRY means we're waiting + * for a cancelled request to complete. + */ + + if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { + return req; + } + + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("waiting for requests failed: %s\n", + nt_errstr(status))); + return tevent_req_post(req, ev); + } + + status = try_to_tear_down_session(state->smb2req); + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("tearing down session failed: %s\n", + nt_errstr(status))); + return tevent_req_post(req, ev); + } + tevent_req_done(req); + return tevent_req_post(req, ev); +} + /*************************************************************** Wait callback function called when we were woken up by an SMB2 request we were waiting on completing. Checks to see -- 1.9.0.279.gdc9e3eb From a7b45512d3743fba1aef9178d9839150fa3c78b6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Mar 2014 10:20:50 -0800 Subject: [PATCH 10/26] s3: smbd: SMB2 logoff - Add smbd_smb2_logoff_recv(). Boilerplate async receive function. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index c8cb926..e6552e7 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -1057,3 +1057,15 @@ static void smbd_smb2_logoff_do(struct tevent_req *subreq) /* Either way we're done. */ tevent_req_done(req); } + +static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + tevent_req_received(req); + return NT_STATUS_OK; +} -- 1.9.0.279.gdc9e3eb From c3c66c169869be647bab18a2b1957f89441c45e1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 14:40:25 -0800 Subject: [PATCH 11/26] s3: smbd: SMB2 logoff - Add smbd_smb2_request_logoff_done(). Reply function for aync logoff. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index e6552e7..164c1eb 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -956,6 +956,49 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) return smbd_smb2_request_done(req, outbody, NULL); } +static void smbd_smb2_request_logoff_done(struct tevent_req *subreq) +{ + struct smbd_smb2_request *smb2req = + tevent_req_callback_data(subreq, + struct smbd_smb2_request); + DATA_BLOB outbody; + NTSTATUS status; + NTSTATUS error; + + status = smbd_smb2_logoff_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + error = smbd_smb2_request_error(smb2req, status); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; + } + + outbody = smbd_smb2_generate_outbody(smb2req, 0x04); + if (outbody.data == NULL) { + error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; + } + + SSVAL(outbody.data, 0x00, 0x04); /* struct size */ + SSVAL(outbody.data, 0x02, 0); /* reserved */ + + error = smbd_smb2_request_done(smb2req, outbody, NULL); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } +} + static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req) -- 1.9.0.279.gdc9e3eb From 9433338b061ec1cb66c23a76bb10520eaf2baddd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 14:45:09 -0800 Subject: [PATCH 12/26] s3: smbd: SMB2 logoff - Add forward references for asnyc logoff functions. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 164c1eb..ae17b51 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -914,6 +914,12 @@ static NTSTATUS try_to_tear_down_session(struct smbd_smb2_request *smb2req) return NT_STATUS_OK; } +static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req); +static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req); +static void smbd_smb2_request_logoff_done(struct tevent_req *subreq); + NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { NTSTATUS status; -- 1.9.0.279.gdc9e3eb From b380a969750004f9c1a8f0e92ba615ca3e26ee2f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 14:46:11 -0800 Subject: [PATCH 13/26] s3: smbd: SMB2 logoff - Convert smbd_smb2_request_process_logoff() to asnyc. Use standard _send()/_recv() idiom. Plumbs in all the previous 'not yet used' functions. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_sesssetup.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index ae17b51..6d6a7e5 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -923,43 +923,24 @@ static void smbd_smb2_request_logoff_done(struct tevent_req *subreq); NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { NTSTATUS status; - DATA_BLOB outbody; + struct tevent_req *subreq = NULL; status = smbd_smb2_request_verify_sizes(req, 0x04); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } - /* - * TODO: cancel all outstanding requests on the session - */ - status = smbXsrv_session_logoff(req->session); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("smbd_smb2_request_process_logoff: " - "smbXsrv_session_logoff() failed: %s\n", - nt_errstr(status))); - /* - * If we hit this case, there is something completely - * wrong, so we better disconnect the transport connection. - */ - return status; + subreq = smbd_smb2_logoff_send(req, req->sconn->ev_ctx, req); + if (subreq == NULL) { + return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } + tevent_req_set_callback(subreq, smbd_smb2_request_logoff_done, req); /* - * we may need to sign the response, so we need to keep - * the session until the response is sent to the wire. + * Wait a long time before going async on this to allow + * requests we're waiting on to finish. Set timeout to 10 secs. */ - talloc_steal(req, req->session); - - outbody = smbd_smb2_generate_outbody(req, 0x04); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - return smbd_smb2_request_done(req, outbody, NULL); + return smbd_smb2_request_pending_queue(req, subreq, 10000000); } static void smbd_smb2_request_logoff_done(struct tevent_req *subreq) -- 1.9.0.279.gdc9e3eb From e4778165527a648d2c4bd5eac0a810f0ed15d261 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:10:19 -0800 Subject: [PATCH 14/26] s3: smbd: SMB2 tdis - add find_outstanding_tcon_request() Walk the outstanding SMB2 requests and return the first one (not including the current request being processed) on this session. Return NULL if there are no outstanding requests on this session. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index e1f0987..db295a1 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -411,6 +411,54 @@ static NTSTATUS smbd_smb2_tree_connect_recv(struct tevent_req *req, return NT_STATUS_OK; } +/******************************************************** + Walk the outstanding SMB2 requests and return the + first one (not including the current request being processed) + on this tcon. Return NULL if there are no outstanding + requests on this session. +********************************************************/ + +static struct smbd_smb2_request *find_outstanding_tcon_request( + const struct smbd_smb2_request *smb2req) +{ + struct smbd_smb2_request *preq; + + if (smb2req->tcon == NULL) { + return NULL; + } + for (preq = smb2req->sconn->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; + } + if (preq->compound_related) { + /* + * Never cancel anything in a compound + * request. Way too hard to deal with + * the result. + */ + continue; + } + if (preq->subreq == NULL) { + /* + * Can this happen (not really + * in progress) ? + */ + continue; + } + /* + * If we get here we've found a request + * we're going to cancel. + */ + break; + } + return preq; +} + NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) { NTSTATUS status; -- 1.9.0.279.gdc9e3eb From 8e00888cc58f2a10a70e0415169408d18b2a9992 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:17:26 -0800 Subject: [PATCH 15/26] s3: smbd: SMB2 tdis - Add definition of struct smbd_smb2_tdis_state. Not yet used - will be used in async tdis code. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index db295a1..aa18ea1 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -496,3 +496,8 @@ NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) return smbd_smb2_request_done(req, outbody, NULL); } + +struct smbd_smb2_tdis_state { + struct smbd_smb2_request *smb2req; + struct tevent_context *ev; +}; -- 1.9.0.279.gdc9e3eb From ded3df51daf7d081c1c73f42f49135d9c28171b2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:18:23 -0800 Subject: [PATCH 16/26] s3: smbd: SMB2 tdis - Add tevent_wait.h header to smb2_tcon.c Will be used in async tdis code. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index aa18ea1..bbf6ed6 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -26,6 +26,7 @@ #include "auth.h" #include "lib/param/loadparm.h" #include "../lib/util/tevent_ntstatus.h" +#include "lib/tevent_wait.h" static struct tevent_req *smbd_smb2_tree_connect_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- 1.9.0.279.gdc9e3eb From 81e37d45eaac502532f16be8f0b1696718a4c977 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Mar 2014 10:23:53 -0800 Subject: [PATCH 17/26] smbd: SMB2 tdis - Add utility function wait_for_outstanding_requests(). This looks for an outstanding request on this tcon, calls tevent_req_cancel() on it and then uses the new SMB2 request wait mechanism smbd_smb2_wait_for_request_to_complete() to add a tevent request to the wait queue associated with the SMB2 request we just cancelled. Returns NT_STATUS_RETRY if we are waiting. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index bbf6ed6..9783d9d 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -502,3 +502,49 @@ struct smbd_smb2_tdis_state { struct smbd_smb2_request *smb2req; struct tevent_context *ev; }; + +static void smbd_smb2_tdis_do(struct tevent_req *subreq); + +/*************************************************************** + Utility function to wait for outstanding SMB2 requests on + this tcon. + If we return NT_STATUS_RETRY we have set ourselves to wait + for another request to complete. +***************************************************************/ + +static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_tdis_state *state, + struct tevent_req *req) +{ + struct smbd_smb2_request *smb2req = state->smb2req; + struct smbd_smb2_request *smb2_wait_req; + NTSTATUS status; + + /* + * Try and find a request to cancel. If we can, + * cancel it and tell ourselves to wait unti it's finished. + */ + smb2_wait_req = find_outstanding_tcon_request(smb2req); + if (smb2_wait_req != NULL) { + + tevent_req_cancel(smb2_wait_req->subreq); + + status = smbd_smb2_wait_for_request_to_complete( + smb2req, /* Request to wake up on completion. */ + smb2_wait_req, /* Request we're waiting on. */ + state->ev, /* Event context. */ + smbd_smb2_tdis_do, /* callback. */ + req); /* Private pointer. */ + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("tdis wait failed: %s\n", + nt_errstr(status))); + return status; + } + /* We're waiting on another SMB2 request. */ + return NT_STATUS_RETRY; + } + return NT_STATUS_OK; +} + +static void smbd_smb2_tdis_do(struct tevent_req *subreq) +{ +} -- 1.9.0.279.gdc9e3eb From a2a19ffc9844828c3fecfb6282b9297b17f61eb6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Mar 2014 10:26:44 -0800 Subject: [PATCH 18/26] smbd: SMB2 tdis - Add utility function try_to_tear_down_tcon(). Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index 9783d9d..ef9dc77 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -545,6 +545,23 @@ static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_tdis_state *state return NT_STATUS_OK; } +/*************************************************************** + Utility function to do the work of tearing down a connection. +***************************************************************/ + +static NTSTATUS try_to_tear_down_tcon(struct smbd_smb2_request *smb2req) +{ + NTSTATUS status = smbXsrv_tcon_disconnect(smb2req->tcon, smb2req->tcon->compat->vuid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("smbXsrv_tcon_disconnect() failed: %s\n", + nt_errstr(status))); + return status; + } + + TALLOC_FREE(smb2req->tcon); + return NT_STATUS_OK; +} + static void smbd_smb2_tdis_do(struct tevent_req *subreq) { } -- 1.9.0.279.gdc9e3eb From b019b29b75e8f007302cbddf75fe9864af2c3ac5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Mar 2014 10:30:29 -0800 Subject: [PATCH 19/26] s3: smbd: SMB2 tdis - Add wait completion function smbd_smb2_tdis_do(). Wait callback function called when we were woken up by an SMB2 request we were waiting on completing. Checks to see if we should still wait, and goes back to sleep if so, otherwise tears down the tcon and finishes the request. When ready to tear down the tcon it calls change_to_root_user() as SMB2_OP_TDIS has .as_root = true in smb2_server.c and we may have processed other commands and so may have swiched user whilst we were waiting. Thanks to Metze for pointing this out. This avoids any tevent reentrancy and is a clean, simple way of handling deferred notification. Many thanks to Volker for showing the way to do this inside smb2_close.c. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index ef9dc77..b973b11 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -562,6 +562,61 @@ static NTSTATUS try_to_tear_down_tcon(struct smbd_smb2_request *smb2req) return NT_STATUS_OK; } +/*************************************************************** + Wait callback function called when we were woken up by an + SMB2 request we were waiting on completing. Checks to see + if we should still wait, and goes back to sleep if so, + otherwise tears down the tcon and finishes the request. +***************************************************************/ + static void smbd_smb2_tdis_do(struct tevent_req *subreq) { + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct smbd_smb2_tdis_state *state = tevent_req_data( + req, struct smbd_smb2_tdis_state); + NTSTATUS status; + int ret; + + ret = tevent_wait_recv(subreq); + TALLOC_FREE(subreq); + if (ret != 0) { + DEBUG(10, ("tevent_wait_recv returned %s\n", + strerror(ret))); + /* + * Continue anyway, this should never happen + */ + } + + status = wait_for_outstanding_requests(state, req); + + if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { + /* + * NT_STATUS_RETRY means we're waiting + * for another cancelled request to complete. + */ + return; + } + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("waiting for requests failed: %s\n", + nt_errstr(status))); + tevent_req_done(req); + return; + } + + /* + * As we've been awoken, we may have changed + * uid in the meantime. Ensure we're still + * root (SMB2_OP_TDIS has .as_root = true). + */ + change_to_root_user(); + + status = try_to_tear_down_tcon(state->smb2req); + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("tearing down the tcon failed: %s\n", + nt_errstr(status))); + return; + } + /* Either way we're done. */ + tevent_req_done(req); } -- 1.9.0.279.gdc9e3eb From d31496092c8245ecad5240dca6966df4fbf4dca6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:40:35 -0800 Subject: [PATCH 20/26] s3: smbd: SMB2 tdis - Add smbd_smb2_tdis_send(). Send function in making tdis async. Note the similarity to the smbd_smb2_tdis_do() function, as this function does the same thing when worken from the wait queue. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index b973b11..86fa7f6 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -562,6 +562,50 @@ static NTSTATUS try_to_tear_down_tcon(struct smbd_smb2_request *smb2req) return NT_STATUS_OK; } +static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req) +{ + NTSTATUS status; + struct tevent_req *req; + struct smbd_smb2_tdis_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct smbd_smb2_tdis_state); + if (req == NULL) { + return NULL; + } + state->smb2req = smb2req; + state->ev = ev; + + status = wait_for_outstanding_requests(state, req); + + /* + * NT_STATUS_RETRY means we're waiting + * for a cancelled request to complete. + */ + + if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { + return req; + } + + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("waiting for requests failed: %s\n", + nt_errstr(status))); + return tevent_req_post(req, ev); + } + + status = try_to_tear_down_tcon(state->smb2req); + if (tevent_req_nterror(req, status)) { + DEBUG(0, ("tearing down the tcon failed: %s\n", + nt_errstr(status))); + return tevent_req_post(req, ev); + } + /* Either way, we're done. */ + tevent_req_done(req); + return tevent_req_post(req, ev); +} + /*************************************************************** Wait callback function called when we were woken up by an SMB2 request we were waiting on completing. Checks to see -- 1.9.0.279.gdc9e3eb From b2593b3f573c1db00ee36f1848ab306a56b37e42 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:42:02 -0800 Subject: [PATCH 21/26] s3: smbd: SMB2 tdis - Add smbd_smb2_tdis_recv(). Boilerplate async receive function. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index 86fa7f6..ec4e444 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -664,3 +664,15 @@ static void smbd_smb2_tdis_do(struct tevent_req *subreq) /* Either way we're done. */ tevent_req_done(req); } + +static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + tevent_req_received(req); + return NT_STATUS_OK; +} -- 1.9.0.279.gdc9e3eb From a9ded2e2baa23b5fcab8b7f87db1d6e7672551ac Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:44:12 -0800 Subject: [PATCH 22/26] s3: smbd: SMB2 tdis - Add smbd_smb2_request_tdis_done(). Reply function for aync tdis. Not yet used. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index ec4e444..5826073 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -498,6 +498,49 @@ NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) return smbd_smb2_request_done(req, outbody, NULL); } +static void smbd_smb2_request_tdis_done(struct tevent_req *subreq) +{ + struct smbd_smb2_request *smb2req = + tevent_req_callback_data(subreq, + struct smbd_smb2_request); + DATA_BLOB outbody; + NTSTATUS status; + NTSTATUS error; + + status = smbd_smb2_tdis_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + error = smbd_smb2_request_error(smb2req, status); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; + } + + outbody = smbd_smb2_generate_outbody(smb2req, 0x04); + if (outbody.data == NULL) { + error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; + } + + SSVAL(outbody.data, 0x00, 0x04); /* struct size */ + SSVAL(outbody.data, 0x02, 0); /* reserved */ + + error = smbd_smb2_request_done(smb2req, outbody, NULL); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } +} + struct smbd_smb2_tdis_state { struct smbd_smb2_request *smb2req; struct tevent_context *ev; -- 1.9.0.279.gdc9e3eb From 54efc50cf38bb0d97c269ca04efe49251b6adaa7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:45:47 -0800 Subject: [PATCH 23/26] s3: smbd: SMB2 tdis - Add forward references for asnyc tdis functions. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index 5826073..3c338c4 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -460,6 +460,12 @@ static struct smbd_smb2_request *find_outstanding_tcon_request( return preq; } +static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req); +static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req); +static void smbd_smb2_request_tdis_done(struct tevent_req *subreq); + NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) { NTSTATUS status; -- 1.9.0.279.gdc9e3eb From 53ae24a2dbc0900d85429585e26efdde900e1bca Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 6 Mar 2014 15:49:13 -0800 Subject: [PATCH 24/26] s3: smbd: SMB2 tdis - Convert smbd_smb2_request_process_tdis() to asnyc. Use standard _send()/_recv() idiom. Plumbs in all the previous 'not yet used' functions. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_tcon.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index 3c338c4..44d1bdc 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -469,39 +469,24 @@ static void smbd_smb2_request_tdis_done(struct tevent_req *subreq); NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) { NTSTATUS status; - DATA_BLOB outbody; + struct tevent_req *subreq = NULL; status = smbd_smb2_request_verify_sizes(req, 0x04); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } - /* - * TODO: cancel all outstanding requests on the tcon - */ - status = smbXsrv_tcon_disconnect(req->tcon, req->tcon->compat->vuid); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("smbd_smb2_request_process_tdis: " - "smbXsrv_tcon_disconnect() failed: %s\n", - nt_errstr(status))); - /* - * If we hit this case, there is something completely - * wrong, so we better disconnect the transport connection. - */ - return status; - } - - TALLOC_FREE(req->tcon); - - outbody = smbd_smb2_generate_outbody(req, 0x04); - if (outbody.data == NULL) { + subreq = smbd_smb2_tdis_send(req, req->sconn->ev_ctx, req); + if (subreq == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } + tevent_req_set_callback(subreq, smbd_smb2_request_tdis_done, req); - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - return smbd_smb2_request_done(req, outbody, NULL); + /* + * Wait a long time before going async on this to allow + * requests we're waiting on to finish. Set timeout to 10 secs. + */ + return smbd_smb2_request_pending_queue(req, subreq, 10000000); } static void smbd_smb2_request_tdis_done(struct tevent_req *subreq) -- 1.9.0.279.gdc9e3eb From cbdbf574169db74f67f937ad1e1858467a795aad Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 28 Jan 2014 14:07:26 -0800 Subject: [PATCH 25/26] s4: smbtorture: Update the torture_smb2_notify_ulogoff test to demonstrate the problem. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source4/torture/smb2/notify.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c index e83b099..e9664d3 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -69,6 +69,13 @@ goto done; \ }} while (0) +#define WAIT_FOR_ASYNC_RESPONSE(req) \ + while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \ + if (tevent_loop_once(torture->ev) != 0) { \ + break; \ + } \ + } + #define BASEDIR "test_notify" #define FNAME "smb2-notify01.dat" @@ -1280,7 +1287,7 @@ static bool torture_smb2_notify_ulogoff(struct torture_context *torture, CHECK_STATUS(status, NT_STATUS_OK); io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; - status = smb2_create(tree2, torture, &(io.smb2)); + status = smb2_create(tree1, torture, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); h1 = io.smb2.out.file.handle; @@ -1295,7 +1302,9 @@ static bool torture_smb2_notify_ulogoff(struct torture_context *torture, req = smb2_notify_send(tree1, &(notify.smb2)); - status = smb2_logoff(tree2->session); + WAIT_FOR_ASYNC_RESPONSE(req); + + status = smb2_logoff(tree1->session); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_notify_recv(req, torture, &(notify.smb2)); -- 1.9.0.279.gdc9e3eb From 144021bfd56f5f9fe3fb628e0cf207c7630890e9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 24 Feb 2014 10:44:59 -0800 Subject: [PATCH 26/26] s4: smbtorture: Add a proper change_notify going async followed by tdis test. [Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. https://bugzilla.samba.org/show_bug.cgi?id=10344 Signed-off-by: Jeremy Allison --- source4/torture/smb2/notify.c | 68 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c index e9664d3..650337e 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -1195,7 +1195,7 @@ static bool torture_smb2_notify_tree_disconnect( smb2_deltree(tree, BASEDIR); smb2_util_rmdir(tree, BASEDIR); - torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY " + torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY " "TREE-DISCONNECT\n"); /* @@ -1247,6 +1247,71 @@ done: } /* + testing of change notifies followed by a tdis - no cancel +*/ + +static bool torture_smb2_notify_tree_disconnect_1( + struct torture_context *torture, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + union smb_notify notify; + union smb_open io; + struct smb2_handle h1; + struct smb2_request *req; + + smb2_deltree(tree, BASEDIR); + smb2_util_rmdir(tree, BASEDIR); + + torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY " + "TREE-DISCONNECT\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(tree, 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(tree, &(notify.smb2)); + WAIT_FOR_ASYNC_RESPONSE(req); + + status = smb2_tdis(tree); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_notify_recv(req, torture, &(notify.smb2)); + CHECK_VAL(notify.smb2.out.num_changes, 0); + +done: + smb2_deltree(tree, BASEDIR); + return ret; +} + +/* basic testing of change notifies followed by a ulogoff */ @@ -2000,6 +2065,7 @@ struct torture_suite *torture_smb2_notify_init(void) torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir); torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask); 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_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff); torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree); -- 1.9.0.279.gdc9e3eb