summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2014-03-10 09:53:18 +0100
committerKarolin Seeger <kseeger@samba.org>2014-04-01 09:11:20 +0200
commite039346a004d39a377377602223877e5cc743ff2 (patch)
tree982a6ad918ac08d991eacbcd488a2a99f0670258 /source3/smbd
parent3f4af7f4937485573c31f19c988e9beb0040ddbf (diff)
downloadsamba-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.c83
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)