diff options
author | Stefan Metzmacher <metze@samba.org> | 2014-03-10 09:53:18 +0100 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2014-04-01 09:11:20 +0200 |
commit | e039346a004d39a377377602223877e5cc743ff2 (patch) | |
tree | 982a6ad918ac08d991eacbcd488a2a99f0670258 /source3/smbd | |
parent | 3f4af7f4937485573c31f19c988e9beb0040ddbf (diff) | |
download | samba-e039346a004d39a377377602223877e5cc743ff2.tar.gz |
s3:smb2_sesssetup: cancel and wait for pending requests on logoff
Bug: https://bugzilla.samba.org/show_bug.cgi?id=10344
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit 7c26475d58a003888b7ba6f17f649cca6d93f6f3)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/smb2_sesssetup.c | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index f1e10edd96..e911945fb6 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/smbd_tevent_queue.h" static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -825,15 +826,19 @@ static void smbd_smb2_request_logoff_done(struct tevent_req *subreq) struct smbd_smb2_logout_state { struct smbd_smb2_request *smb2req; + struct tevent_queue *wait_queue; }; +static void smbd_smb2_logoff_wait_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; - NTSTATUS status; + struct tevent_req *subreq; + struct smbd_smb2_request *preq; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_logout_state); @@ -842,12 +847,83 @@ static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, } 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 = 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; + } + + /* + * 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 = smbd_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 = smbd_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, smbd_smb2_logoff_wait_done, req); + + return req; +} + +static void smbd_smb2_logoff_wait_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); + NTSTATUS status; + + smbd_tevent_queue_wait_recv(subreq); + TALLOC_FREE(subreq); + /* - * TODO: cancel all outstanding requests on the session + * 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 = smbXsrv_session_logoff(state->smb2req->session); if (tevent_req_nterror(req, status)) { - return tevent_req_post(req, ev); + return; } /* @@ -857,7 +933,6 @@ static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, talloc_steal(state->smb2req, state->smb2req->session); tevent_req_done(req); - return tevent_req_post(req, ev); } static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req) |