impersonation part 3 (Re: [Patches] Preparation for tevent impersonation (part1))

Stefan Metzmacher metze at samba.org
Thu Jun 14 18:13:07 UTC 2018


Hi Jeremy,

here's the almost finished patchset, that actually implements the
impersonation for tevent. (The pthreadpool_tevent impersonation will
follow later as part4).

This is (as part2) already reviewed by Ralph, but we want to
add some tests in tevent for the new wrapper infrastructure
and add useful debug message to the
smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create() wrappers.
We'll do that once everything is otherwise complete, working and reviewed.

metze

-------------- next part --------------
From 5cdf02fd7322b99f294e0c65b86921c5f7bdd397 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 23 Sep 2015 04:27:53 +0200
Subject: [PATCH 01/56] tevent.h: improve tevent_req documentation

Document tevent_req naming conventions.

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent.h | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 3ccac6a3600c..0e2e806ee5c4 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -697,6 +697,22 @@ void tevent_get_trace_callback(struct tevent_context *ev,
  * the tevent_req structure can be talloc_free'ed. After it has
  * finished, it should talloc_free'ed by the API user.
  *
+ * tevent_req variable naming conventions:
+ *
+ * The name of the variable pointing to the tevent_req structure
+ * returned by a _send() function SHOULD be named differently between
+ * implementation and caller.
+ *
+ * From the point of view of the implementation (of the _send() and
+ * _recv() functions) the variable returned by tevent_req_create() is
+ * always called @em req.
+ *
+ * While the caller of the _send() function should use @em subreq to
+ * hold the result.
+ *
+ * @see tevent_req_create()
+ * @see tevent_req_fn()
+ *
  * @{
  */
 
@@ -748,9 +764,9 @@ struct tevent_req;
 /**
  * @brief A tevent request callback function.
  *
- * @param[in]  req      The tevent async request which executed this callback.
+ * @param[in]  subreq      The tevent async request which executed this callback.
  */
-typedef void (*tevent_req_fn)(struct tevent_req *req);
+typedef void (*tevent_req_fn)(struct tevent_req *subreq);
 
 /**
  * @brief Set an async request callback.
@@ -799,8 +815,6 @@ void *_tevent_req_callback_data(struct tevent_req *req);
  *
  * @param[in]  req      The structure to get the callback data from.
  *
- * @param[in]  req      The structure to get the data from.
- *
  * @return              The private data or NULL if not set.
  */
 void *tevent_req_callback_data_void(struct tevent_req *req);
-- 
2.17.1


From 1c35a960a52c8687209da0db8fda55a46cf55a18 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 06:54:10 +0200
Subject: [PATCH 02/56] tevent/testsuite: return after torture_fail()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/testsuite.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 63abbf2dc1a6..08aa7588acee 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -191,8 +191,9 @@ static bool test_event_context(struct torture_context *test,
 	while (!finished) {
 		errno = 0;
 		if (tevent_loop_once(ev_ctx) == -1) {
-			talloc_free(ev_ctx);
+			TALLOC_FREE(ev_ctx);
 			torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
+			return false;
 		}
 	}
 
-- 
2.17.1


From 8ebfc6687c89f24de0f61e19aadc557062aa6406 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 16:51:01 +0100
Subject: [PATCH 03/56] tevent: allow tevent_abort() to cope with ev == NULL

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index a2d2003cbf43..3d32fd7e12de 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -577,8 +577,10 @@ void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
 
 static void tevent_abort(struct tevent_context *ev, const char *reason)
 {
-	tevent_debug(ev, TEVENT_DEBUG_FATAL,
-		     "abort: %s\n", reason);
+	if (ev != NULL) {
+		tevent_debug(ev, TEVENT_DEBUG_FATAL,
+			     "abort: %s\n", reason);
+	}
 
 	if (!tevent_abort_fn) {
 		abort();
-- 
2.17.1


From 872aa7002a4a39de2bace13b690603b25424b737 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 15:10:00 +0200
Subject: [PATCH 04/56] tevent: make tevent_abort() available for backends

We'll remove the _PRIVATE_ with the next release.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent.c          | 5 ++---
 lib/tevent/tevent_internal.h | 2 ++
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 3d32fd7e12de..501d548a9f09 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -70,8 +70,6 @@
 #include <sys/eventfd.h>
 #endif
 
-static void tevent_abort(struct tevent_context *ev, const char *reason);
-
 struct tevent_ops_list {
 	struct tevent_ops_list *next, *prev;
 	const char *name;
@@ -575,7 +573,8 @@ void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
 	tevent_abort_fn = abort_fn;
 }
 
-static void tevent_abort(struct tevent_context *ev, const char *reason)
+_PRIVATE_
+void tevent_abort(struct tevent_context *ev, const char *reason)
 {
 	if (ev != NULL) {
 		tevent_debug(ev, TEVENT_DEBUG_FATAL,
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index ec3955e70a49..cbe2e69548dc 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -246,6 +246,8 @@ struct tevent_debug_ops {
 void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
 		  const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
 
+void tevent_abort(struct tevent_context *ev, const char *reason);
+
 struct tevent_context {
 	/* the specific events implementation */
 	const struct tevent_ops *ops;
-- 
2.17.1


From 2880382fa60d9d34f5249f18d82de7fe2a09b3b1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 05/56] tevent: use struct initializers for tevent_fd

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_fd.c   | 19 +++++++++----------
 lib/tevent/tevent_poll.c | 21 +++++++++++----------
 2 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index 455961b67c84..f33ae841b396 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -60,16 +60,15 @@ struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev, TALLOC_CTX *me
 	fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
 	if (!fde) return NULL;
 
-	fde->event_ctx		= ev;
-	fde->fd			= fd;
-	fde->flags		= flags;
-	fde->handler		= handler;
-	fde->close_fn		= NULL;
-	fde->private_data	= private_data;
-	fde->handler_name	= handler_name;
-	fde->location		= location;
-	fde->additional_flags	= 0;
-	fde->additional_data	= NULL;
+	*fde = (struct tevent_fd) {
+		.event_ctx	= ev,
+		.fd		= fd,
+		.flags		= flags,
+		.handler	= handler,
+		.private_data	= private_data,
+		.handler_name	= handler_name,
+		.location	= location,
+	};
 
 	DLIST_ADD(ev->fd_events, fde);
 
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 09d85fa322ad..f1d52533f5de 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -307,16 +307,17 @@ static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
 	if (fde == NULL) {
 		return NULL;
 	}
-	fde->event_ctx		= ev;
-	fde->fd			= fd;
-	fde->flags		= flags;
-	fde->handler		= handler;
-	fde->close_fn		= NULL;
-	fde->private_data	= private_data;
-	fde->handler_name	= handler_name;
-	fde->location		= location;
-	fde->additional_flags	= UINT64_MAX;
-	fde->additional_data	= NULL;
+
+	*fde = (struct tevent_fd) {
+		.event_ctx		= ev,
+		.fd			= fd,
+		.flags			= flags,
+		.handler		= handler,
+		.private_data		= private_data,
+		.handler_name		= handler_name,
+		.location		= location,
+		.additional_flags	= UINT64_MAX,
+	};
 
 	tevent_poll_event_add_fd_internal(ev, fde);
 	poll_event_wake_pollthread(poll_ev);
-- 
2.17.1


From cc087b1745fff1d54c77b8a2d38a3abd484af79a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 06/56] tevent: use struct initializers for tevent_timer

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_timed.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index 92f3ed17b26e..ae1eb98d8b2a 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -224,13 +224,14 @@ static struct tevent_timer *tevent_common_add_timer_internal(
 	te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
 	if (te == NULL) return NULL;
 
-	te->event_ctx		= ev;
-	te->next_event		= next_event;
-	te->handler		= handler;
-	te->private_data	= private_data;
-	te->handler_name	= handler_name;
-	te->location		= location;
-	te->additional_data	= NULL;
+	*te = (struct tevent_timer) {
+		.event_ctx	= ev,
+		.next_event	= next_event,
+		.handler	= handler,
+		.private_data	= private_data,
+		.handler_name	= handler_name,
+		.location	= location,
+	};
 
 	if (ev->timer_events == NULL) {
 		ev->last_zero_timer = NULL;
-- 
2.17.1


From 45df9f2c143efa1f1d643aac5115bbf2ef7b7cca Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 07/56] tevent: use struct initializers for tevent_signal

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_signal.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index c85e1c528c4e..1283aab48211 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -257,22 +257,23 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 	se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
 	if (se == NULL) return NULL;
 
-	se->event_ctx		= ev;
-	se->signum              = signum;
-	se->sa_flags            = sa_flags;
-	se->handler		= handler;
-	se->private_data	= private_data;
-	se->handler_name	= handler_name;
-	se->location		= location;
-	se->additional_data	= NULL;
-
 	sl = talloc(se, struct tevent_common_signal_list);
 	if (!sl) {
 		talloc_free(se);
 		return NULL;
 	}
 	sl->se = se;
-	se->additional_data	= sl;
+
+	*se = (struct tevent_signal) {
+		.event_ctx	= ev,
+		.signum		= signum,
+		.sa_flags	= sa_flags,
+		.handler	= handler,
+		.private_data	= private_data,
+		.handler_name	= handler_name,
+		.location	= location,
+		.additional_data= sl,
+	};
 
 	/* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
 	if (!talloc_reference(se, sig_state)) {
-- 
2.17.1


From 4037f02a23e7e7a558af37954c6548eb2d5986a4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 08/56] tevent: use struct initializers for tevent_immediate

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_immediate.c | 30 ++++++++++++++++--------------
 lib/tevent/tevent_threads.c   | 16 +++++++++-------
 2 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 9ff532234306..7b4c3e843ded 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -30,6 +30,8 @@
 
 static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 {
+	const char *create_location = im->create_location;
+
 	if (!im->event_ctx) {
 		return;
 	}
@@ -44,13 +46,10 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 	}
 
 	DLIST_REMOVE(im->event_ctx->immediate_events, im);
-	im->event_ctx		= NULL;
-	im->handler		= NULL;
-	im->private_data	= NULL;
-	im->handler_name	= NULL;
-	im->schedule_location	= NULL;
-	im->cancel_fn		= NULL;
-	im->additional_data	= NULL;
+
+	*im = (struct tevent_immediate) {
+		.create_location	= create_location,
+	};
 
 	talloc_set_destructor(im, NULL);
 }
@@ -74,19 +73,22 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 				      const char *handler_name,
 				      const char *location)
 {
+	const char *create_location = im->create_location;
+
 	tevent_common_immediate_cancel(im);
 
 	if (!handler) {
 		return;
 	}
 
-	im->event_ctx		= ev;
-	im->handler		= handler;
-	im->private_data	= private_data;
-	im->handler_name	= handler_name;
-	im->schedule_location	= location;
-	im->cancel_fn		= NULL;
-	im->additional_data	= NULL;
+	*im = (struct tevent_immediate) {
+		.event_ctx		= ev,
+		.handler		= handler,
+		.private_data		= private_data,
+		.handler_name		= handler_name,
+		.create_location	= create_location,
+		.schedule_location	= location,
+	};
 
 	DLIST_ADD_END(ev->immediate_events, im);
 	talloc_set_destructor(im, tevent_common_immediate_destructor);
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 2c6e66b09049..728f8416d452 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -449,6 +449,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 					 const char *location)
 {
 #ifdef HAVE_PTHREAD
+	const char *create_location = im->create_location;
 	struct tevent_context *ev;
 	int ret, wakeup_fd;
 
@@ -474,13 +475,14 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 		abort();
 	}
 
-	im->event_ctx		= ev;
-	im->handler		= handler;
-	im->private_data	= private_data;
-	im->handler_name	= handler_name;
-	im->schedule_location	= location;
-	im->cancel_fn		= NULL;
-	im->additional_data	= NULL;
+	*im = (struct tevent_immediate) {
+		.event_ctx		= ev,
+		.handler		= handler,
+		.private_data		= private_data,
+		.handler_name		= handler_name,
+		.create_location	= create_location,
+		.schedule_location	= location,
+	};
 
 	ret = pthread_mutex_lock(&ev->scheduled_mutex);
 	if (ret != 0) {
-- 
2.17.1


From 1fb9cd9bedfd0e7c783d719b9a55a66ad70e2417 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 10:25:27 +0100
Subject: [PATCH 09/56] tevent: use _tevent_schedule_immediate() to move events
 from a thread to the main_ev

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_immediate.c |  8 +++++---
 lib/tevent/tevent_threads.c   | 14 +++++++++++++-
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 7b4c3e843ded..c640a565b082 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -36,9 +36,11 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 		return;
 	}
 
-	tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
-		     "Cancel immediate event %p \"%s\"\n",
-		     im, im->handler_name);
+	if (im->handler_name != NULL) {
+		tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
+			     "Cancel immediate event %p \"%s\"\n",
+			     im, im->handler_name);
+	}
 
 	/* let the backend free im->additional_data */
 	if (im->cancel_fn) {
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 728f8416d452..3f91ab8bc2ab 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -532,8 +532,20 @@ void tevent_common_threaded_activate_immediate(struct tevent_context *ev)
 
 	while (ev->scheduled_immediates != NULL) {
 		struct tevent_immediate *im = ev->scheduled_immediates;
+		struct tevent_immediate copy = *im;
+
 		DLIST_REMOVE(ev->scheduled_immediates, im);
-		DLIST_ADD_END(ev->immediate_events, im);
+
+		tevent_debug(ev, TEVENT_DEBUG_TRACE,
+			     "Schedule immediate event \"%s\": %p from thread into main\n",
+			     im->handler_name, im);
+		im->handler_name = NULL;
+		_tevent_schedule_immediate(im,
+					   ev,
+					   copy.handler,
+					   copy.private_data,
+					   copy.handler_name,
+					   copy.schedule_location);
 	}
 
 	ret = pthread_mutex_unlock(&ev->scheduled_mutex);
-- 
2.17.1


From 0fe15ae9b2d011f0c70a5b305dd91e71701caa83 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 10:32:15 +0100
Subject: [PATCH 10/56] tevent: add
 tevent_threaded_schedule_immediate_destructor that just aborts

This will be active while the event is part of the ev->scheduled_immediates
list.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_threads.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 3f91ab8bc2ab..efdac9856dd1 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -441,6 +441,14 @@ struct tevent_threaded_context *tevent_threaded_context_create(
 #endif
 }
 
+static int tevent_threaded_schedule_immediate_destructor(struct tevent_immediate *im)
+{
+	if (im->event_ctx != NULL) {
+		abort();
+	}
+	return 0;
+}
+
 void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 					 struct tevent_immediate *im,
 					 tevent_immediate_handler_t handler,
@@ -484,6 +492,14 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 		.schedule_location	= location,
 	};
 
+	/*
+	 * Make sure the event won't be destroyed while
+	 * it's part of the ev->scheduled_immediates list.
+	 * _tevent_schedule_immediate() will reset the destructor
+	 * in tevent_common_threaded_activate_immediate().
+	 */
+	talloc_set_destructor(im, tevent_threaded_schedule_immediate_destructor);
+
 	ret = pthread_mutex_lock(&ev->scheduled_mutex);
 	if (ret != 0) {
 		abort();
-- 
2.17.1


From e51e96e9a42c8a7660ae0d534c9be8dc4f5bd12c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 17 Apr 2018 16:33:47 +0200
Subject: [PATCH 11/56] tevent: add tevent_common_check_double_free() helper
 function

This will be used to generically support TALLOC_FREE() on
event which are currently running.

It aborts on every explicit talloc_free(), but ignores implicit
cleanup when the talloc parent is about to go.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent.c          | 20 ++++++++++++++++++++
 lib/tevent/tevent_internal.h |  2 ++
 2 files changed, 22 insertions(+)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 501d548a9f09..d12ec10720e9 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -429,6 +429,26 @@ static int tevent_common_context_constructor(struct tevent_context *ev)
 	return 0;
 }
 
+_PRIVATE_
+void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason)
+{
+	void *parent_ptr = talloc_parent(ptr);
+	size_t parent_blocks = talloc_total_blocks(parent_ptr);
+
+	if (parent_ptr != NULL && parent_blocks == 0) {
+		/*
+		 * This is an implicit talloc free, as we still have a parent
+		 * but it's already being destroyed. Note that
+		 * talloc_total_blocks(ptr) also just returns 0 if a
+		 * talloc_free(ptr) is still in progress of freeing all
+		 * children.
+		 */
+		return;
+	}
+
+	tevent_abort(NULL, reason);
+}
+
 /*
   create a event_context structure for a specific implemementation.
   This must be the first events call, and all subsequent calls pass
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index cbe2e69548dc..4fd49f58ffb0 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -248,6 +248,8 @@ void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
 
 void tevent_abort(struct tevent_context *ev, const char *reason);
 
+void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason);
+
 struct tevent_context {
 	/* the specific events implementation */
 	const struct tevent_ops *ops;
-- 
2.17.1


From b1eb3acc0988acd9ab8b84bd5ca3fe69c9189480 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 12:02:45 +0200
Subject: [PATCH 12/56] tevent: simplify
 tevent_cleanup_pending_signal_handlers()

Calling tevent_signal_destructor() does the same as se->event_ctx is already
NULL.

This also makes sure we correctly cleanup the SA_SIGINFO array.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_signal.c | 16 +++-------------
 1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 1283aab48211..6bb69d77d7a5 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -194,6 +194,7 @@ static int tevent_signal_destructor(struct tevent_signal *se)
 		DLIST_REMOVE(ev->signal_events, se);
 	}
 
+	se->additional_data = NULL;
 	talloc_free(sl);
 
 	if (sig_state->sig_handlers[se->signum] == NULL) {
@@ -464,18 +465,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
 
 void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
 {
-	struct tevent_common_signal_list *sl =
-		talloc_get_type_abort(se->additional_data,
-		struct tevent_common_signal_list);
-
-	tevent_common_signal_list_destructor(sl);
-
-	if (sig_state->sig_handlers[se->signum] == NULL) {
-		if (sig_state->oldact[se->signum]) {
-			sigaction(se->signum, sig_state->oldact[se->signum], NULL);
-			talloc_free(sig_state->oldact[se->signum]);
-			sig_state->oldact[se->signum] = NULL;
-		}
-	}
+	tevent_signal_destructor(se);
+	talloc_set_destructor(se, NULL);
 	return;
 }
-- 
2.17.1


From 114c3e77bd54d05c39de561c00b6a70c7c4fd7a5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 27 Mar 2018 14:30:20 +0200
Subject: [PATCH 13/56] tevent: use talloc_zero() in tevent_signal.c

This might not be strictly required, but it might
avoid problems in future...

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_signal.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 6bb69d77d7a5..73b8de798f69 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -255,10 +255,10 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 		}
 	}
 
-	se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
+	se = talloc_zero(mem_ctx?mem_ctx:ev, struct tevent_signal);
 	if (se == NULL) return NULL;
 
-	sl = talloc(se, struct tevent_common_signal_list);
+	sl = talloc_zero(se, struct tevent_common_signal_list);
 	if (!sl) {
 		talloc_free(se);
 		return NULL;
@@ -303,7 +303,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 			}
 		}
 #endif
-		sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
+		sig_state->oldact[signum] = talloc_zero(sig_state, struct sigaction);
 		if (sig_state->oldact[signum] == NULL) {
 			talloc_free(se);
 			return NULL;
-- 
2.17.1


From 1ffbea8125e9b900e0d789d93aebe769f3b88b69 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 17 Apr 2018 16:43:54 +0200
Subject: [PATCH 14/56] tevent: simplify tevent_signal_destructor()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_signal.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 73b8de798f69..ef2302433168 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -184,31 +184,22 @@ static int tevent_common_signal_list_destructor(struct tevent_common_signal_list
 */
 static int tevent_signal_destructor(struct tevent_signal *se)
 {
-	struct tevent_common_signal_list *sl =
-		talloc_get_type_abort(se->additional_data,
-		struct tevent_common_signal_list);
+	TALLOC_FREE(se->additional_data);
 
-	if (se->event_ctx) {
-		struct tevent_context *ev = se->event_ctx;
-
-		DLIST_REMOVE(ev->signal_events, se);
+	if (se->event_ctx != NULL) {
+		DLIST_REMOVE(se->event_ctx->signal_events, se);
 	}
 
-	se->additional_data = NULL;
-	talloc_free(sl);
-
 	if (sig_state->sig_handlers[se->signum] == NULL) {
 		/* restore old handler, if any */
 		if (sig_state->oldact[se->signum]) {
 			sigaction(se->signum, sig_state->oldact[se->signum], NULL);
-			talloc_free(sig_state->oldact[se->signum]);
-			sig_state->oldact[se->signum] = NULL;
+			TALLOC_FREE(sig_state->oldact[se->signum]);
 		}
 #ifdef SA_SIGINFO
 		if (se->sa_flags & SA_SIGINFO) {
 			if (sig_state->sig_info[se->signum]) {
-				talloc_free(sig_state->sig_info[se->signum]);
-				sig_state->sig_info[se->signum] = NULL;
+				TALLOC_FREE(sig_state->sig_info[se->signum]);
 			}
 		}
 #endif
-- 
2.17.1


From 2363d77fe0d8aa6ecd495aefb046a10f420c0482 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 13:01:01 +0200
Subject: [PATCH 15/56] tevent: split out tevent_common_invoke_signal_handler()

As side effect this avoids tricks with tevent_se_exists_destructor() to
figure out if the event handler removed itself.

We'll remove _PRIVATE_ with the next release.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_internal.h |   5 ++
 lib/tevent/tevent_signal.c   | 101 ++++++++++++++++++++++-------------
 2 files changed, 68 insertions(+), 38 deletions(-)

diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 4fd49f58ffb0..48212949e161 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -216,6 +216,8 @@ struct tevent_immediate {
 struct tevent_signal {
 	struct tevent_signal *prev, *next;
 	struct tevent_context *event_ctx;
+	bool busy;
+	bool destroyed;
 	int signum;
 	int sa_flags;
 	tevent_signal_handler_t handler;
@@ -378,6 +380,9 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 					       const char *location);
 int tevent_common_check_signal(struct tevent_context *ev);
 void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+					int signum, int count, void *siginfo,
+					bool *removed);
 
 bool tevent_standard_init(void);
 bool tevent_poll_init(void);
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index ef2302433168..3ca03334c92f 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -184,6 +184,12 @@ static int tevent_common_signal_list_destructor(struct tevent_common_signal_list
 */
 static int tevent_signal_destructor(struct tevent_signal *se)
 {
+	if (se->destroyed) {
+		tevent_common_check_double_free(se, "tevent_signal double free");
+		goto done;
+	}
+	se->destroyed = true;
+
 	TALLOC_FREE(se->additional_data);
 
 	if (se->event_ctx != NULL) {
@@ -205,6 +211,11 @@ static int tevent_signal_destructor(struct tevent_signal *se)
 #endif
 	}
 
+done:
+	if (se->busy) {
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -322,13 +333,43 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 	return se;
 }
 
-struct tevent_se_exists {
-	struct tevent_se_exists **myself;
-};
-
-static int tevent_se_exists_destructor(struct tevent_se_exists *s)
+_PRIVATE_
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+					int signum, int count, void *siginfo,
+					bool *removed)
 {
-	*s->myself = NULL;
+	bool remove = false;
+
+	if (removed != NULL) {
+		*removed = false;
+	}
+
+	if (se->event_ctx == NULL) {
+		return 0;
+	}
+
+	se->busy = true;
+	se->handler(se->event_ctx, se, signum, count, siginfo, se->private_data);
+	se->busy = false;
+
+#ifdef SA_RESETHAND
+	if (se->sa_flags & SA_RESETHAND) {
+		remove = true;
+	}
+#endif
+
+	if (se->destroyed) {
+		talloc_set_destructor(se, NULL);
+		remove = true;
+	}
+
+	if (remove) {
+		TALLOC_FREE(se);
+		if (removed != NULL) {
+			*removed = true;
+		}
+	}
+
 	return 0;
 }
 
@@ -348,6 +389,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
 		struct tevent_common_signal_list *sl, *next;
 		struct tevent_sigcounter counter = sig_state->signal_count[i];
 		uint32_t count = tevent_sig_count(counter);
+		int ret;
 #ifdef SA_SIGINFO
 		/* Ensure we null out any stored siginfo_t entries
 		 * after processing for debugging purposes. */
@@ -359,25 +401,9 @@ int tevent_common_check_signal(struct tevent_context *ev)
 		}
 		for (sl=sig_state->sig_handlers[i];sl;sl=next) {
 			struct tevent_signal *se = sl->se;
-			struct tevent_se_exists *exists;
 
 			next = sl->next;
 
-			/*
-			 * We have to be careful to not touch "se"
-			 * after it was deleted in its handler. Thus
-			 * we allocate a child whose destructor will
-			 * tell by nulling out itself that its parent
-			 * is gone.
-			 */
-			exists = talloc(se, struct tevent_se_exists);
-			if (exists == NULL) {
-				continue;
-			}
-			exists->myself = &exists;
-			talloc_set_destructor(
-				exists, tevent_se_exists_destructor);
-
 #ifdef SA_SIGINFO
 			if (se->sa_flags & SA_SIGINFO) {
 				uint32_t j;
@@ -391,29 +417,28 @@ int tevent_common_check_signal(struct tevent_context *ev)
 					 * signals in the ringbuffer. */
 					uint32_t ofs = (counter.seen + j)
 						% TEVENT_SA_INFO_QUEUE_COUNT;
-					se->handler(ev, se, i, 1,
-						    (void*)&sig_state->sig_info[i][ofs],
-						    se->private_data);
-					if (!exists) {
+					bool removed = false;
+
+					ret = tevent_common_invoke_signal_handler(
+						se, i, 1,
+						(void*)&sig_state->sig_info[i][ofs],
+						&removed);
+					if (ret != 0) {
+						tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
+					}
+					if (removed) {
 						break;
 					}
 				}
-#ifdef SA_RESETHAND
-				if (exists && (se->sa_flags & SA_RESETHAND)) {
-					talloc_free(se);
-				}
-#endif
-				talloc_free(exists);
 				continue;
 			}
 #endif
-			se->handler(ev, se, i, count, NULL, se->private_data);
-#ifdef SA_RESETHAND
-			if (exists && (se->sa_flags & SA_RESETHAND)) {
-				talloc_free(se);
+
+			ret = tevent_common_invoke_signal_handler(se, i, count,
+								  NULL, NULL);
+			if (ret != 0) {
+				tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
 			}
-#endif
-			talloc_free(exists);
 		}
 
 #ifdef SA_SIGINFO
-- 
2.17.1


From e5bfb3b97fe728ce59b064de5cadac9be2a304a6 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 13:08:42 +0200
Subject: [PATCH 16/56] tevent: split out tevent_common_invoke_timer_handler()

As side effect this avoids tricks with an extra
tevent_common_timed_deny_destructor().

We'll remove the _PRIVATE_ with the next release.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_internal.h |   5 ++
 lib/tevent/tevent_timed.c    | 112 +++++++++++++++++++++++------------
 2 files changed, 79 insertions(+), 38 deletions(-)

diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 48212949e161..bd1c2a0370a3 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -187,6 +187,8 @@ struct tevent_fd {
 struct tevent_timer {
 	struct tevent_timer *prev, *next;
 	struct tevent_context *event_ctx;
+	bool busy;
+	bool destroyed;
 	struct timeval next_event;
 	tevent_timer_handler_t handler;
 	/* this is private for the specific handler */
@@ -355,6 +357,9 @@ struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
 					        const char *handler_name,
 					        const char *location);
 struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
+int tevent_common_invoke_timer_handler(struct tevent_timer *te,
+				       struct timeval current_time,
+				       bool *removed);
 
 void tevent_common_schedule_immediate(struct tevent_immediate *im,
 				      struct tevent_context *ev,
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index ae1eb98d8b2a..d460e7001dca 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -133,6 +133,12 @@ struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
 */
 static int tevent_common_timed_destructor(struct tevent_timer *te)
 {
+	if (te->destroyed) {
+		tevent_common_check_double_free(te, "tevent_timer double free");
+		goto done;
+	}
+	te->destroyed = true;
+
 	if (te->event_ctx == NULL) {
 		return 0;
 	}
@@ -146,12 +152,14 @@ static int tevent_common_timed_destructor(struct tevent_timer *te)
 	}
 	DLIST_REMOVE(te->event_ctx->timer_events, te);
 
-	return 0;
-}
+	te->event_ctx = NULL;
 
-static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
-{
-	return -1;
+done:
+	if (te->busy) {
+		return -1;
+	}
+
+	return 0;
 }
 
 static void tevent_common_insert_timer(struct tevent_context *ev,
@@ -160,6 +168,11 @@ static void tevent_common_insert_timer(struct tevent_context *ev,
 {
 	struct tevent_timer *prev_te = NULL;
 
+	if (te->destroyed) {
+		tevent_abort(ev, "tevent_timer use after free");
+		return;
+	}
+
 	/* keep the list ordered */
 	if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) {
 		/*
@@ -303,6 +316,58 @@ void tevent_update_timer(struct tevent_timer *te, struct timeval next_event)
 	tevent_common_insert_timer(ev, te, false);
 }
 
+_PRIVATE_
+int tevent_common_invoke_timer_handler(struct tevent_timer *te,
+				       struct timeval current_time,
+				       bool *removed)
+{
+	if (removed != NULL) {
+		*removed = false;
+	}
+
+	if (te->event_ctx == NULL) {
+		return 0;
+	}
+
+	/*
+	 * We need to remove the timer from the list before calling the
+	 * handler because in a semi-async inner event loop called from the
+	 * handler we don't want to come across this event again -- vl
+	 */
+	if (te->event_ctx->last_zero_timer == te) {
+		te->event_ctx->last_zero_timer = DLIST_PREV(te);
+	}
+	DLIST_REMOVE(te->event_ctx->timer_events, te);
+
+	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+		     "Running timer event %p \"%s\"\n",
+		     te, te->handler_name);
+
+	/*
+	 * If the timed event was registered for a zero current_time,
+	 * then we pass a zero timeval here too! To avoid the
+	 * overhead of gettimeofday() calls.
+	 *
+	 * otherwise we pass the current time
+	 */
+	te->busy = true;
+	te->handler(te->event_ctx, te, current_time, te->private_data);
+	te->busy = false;
+
+	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+		     "Ending timer event %p \"%s\"\n",
+		     te, te->handler_name);
+
+	te->event_ctx = NULL;
+	talloc_set_destructor(te, NULL);
+	TALLOC_FREE(te);
+
+	if (removed != NULL) {
+		*removed = true;
+	}
+
+	return 0;
+}
 /*
   do a single event loop using the events defined in ev
 
@@ -313,6 +378,7 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
 {
 	struct timeval current_time = tevent_timeval_zero();
 	struct tevent_timer *te = ev->timer_events;
+	int ret;
 
 	if (!te) {
 		/* have a default tick time of 30 seconds. This guarantees
@@ -344,40 +410,10 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
 	/*
 	 * ok, we have a timed event that we'll process ...
 	 */
-
-	/* deny the handler to free the event */
-	talloc_set_destructor(te, tevent_common_timed_deny_destructor);
-
-	/* We need to remove the timer from the list before calling the
-	 * handler because in a semi-async inner event loop called from the
-	 * handler we don't want to come across this event again -- vl */
-	if (ev->last_zero_timer == te) {
-		ev->last_zero_timer = DLIST_PREV(te);
+	ret = tevent_common_invoke_timer_handler(te, current_time, NULL);
+	if (ret != 0) {
+		tevent_abort(ev, "tevent_common_invoke_timer_handler() failed");
 	}
-	DLIST_REMOVE(ev->timer_events, te);
-
-	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
-		     "Running timer event %p \"%s\"\n",
-		     te, te->handler_name);
-
-	/*
-	 * If the timed event was registered for a zero current_time,
-	 * then we pass a zero timeval here too! To avoid the
-	 * overhead of gettimeofday() calls.
-	 *
-	 * otherwise we pass the current time
-	 */
-	te->handler(ev, te, current_time, te->private_data);
-
-	/* The destructor isn't necessary anymore, we've already removed the
-	 * event from the list. */
-	talloc_set_destructor(te, NULL);
-
-	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
-		     "Ending timer event %p \"%s\"\n",
-		     te, te->handler_name);
-
-	talloc_free(te);
 
 	return tevent_timeval_zero();
 }
-- 
2.17.1


From 070b4a9a18efc191bb2b71dc69c61259a6c2ad5a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 13:08:42 +0200
Subject: [PATCH 17/56] tevent: split out
 tevent_common_invoke_immediate_handler()

We'll remove _PRIVATE_ with the next release.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_immediate.c | 88 ++++++++++++++++++++++++++---------
 lib/tevent/tevent_internal.h  |  4 ++
 lib/tevent/tevent_threads.c   |  6 +++
 3 files changed, 75 insertions(+), 23 deletions(-)

diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index c640a565b082..abcaca41fb80 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -31,6 +31,12 @@
 static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 {
 	const char *create_location = im->create_location;
+	bool busy = im->busy;
+
+	if (im->destroyed) {
+		tevent_abort(im->event_ctx, "tevent_immediate use after free");
+		return;
+	}
 
 	if (!im->event_ctx) {
 		return;
@@ -51,9 +57,12 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 
 	*im = (struct tevent_immediate) {
 		.create_location	= create_location,
+		.busy			= busy,
 	};
 
-	talloc_set_destructor(im, NULL);
+	if (!busy) {
+		talloc_set_destructor(im, NULL);
+	}
 }
 
 /*
@@ -61,7 +70,21 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 */
 static int tevent_common_immediate_destructor(struct tevent_immediate *im)
 {
+	if (im->destroyed) {
+		tevent_common_check_double_free(im,
+						"tevent_immediate double free");
+		goto done;
+	}
+
 	tevent_common_immediate_cancel(im);
+
+	im->destroyed = true;
+
+done:
+	if (im->busy) {
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -76,6 +99,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 				      const char *location)
 {
 	const char *create_location = im->create_location;
+	bool busy = im->busy;
 
 	tevent_common_immediate_cancel(im);
 
@@ -90,6 +114,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 		.handler_name		= handler_name,
 		.create_location	= create_location,
 		.schedule_location	= location,
+		.busy			= busy,
 	};
 
 	DLIST_ADD_END(ev->immediate_events, im);
@@ -100,18 +125,15 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 		     handler_name, im);
 }
 
-/*
-  trigger the first immediate event and return true
-  if no event was triggered return false
-*/
-bool tevent_common_loop_immediate(struct tevent_context *ev)
+_PRIVATE_
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+					   bool *removed)
 {
-	struct tevent_immediate *im = ev->immediate_events;
-	tevent_immediate_handler_t handler;
-	void *private_data;
+	struct tevent_context *ev = im->event_ctx;
+	struct tevent_immediate cur = *im;
 
-	if (!im) {
-		return false;
+	if (removed != NULL) {
+		*removed = false;
 	}
 
 	tevent_debug(ev, TEVENT_DEBUG_TRACE,
@@ -122,21 +144,41 @@ bool tevent_common_loop_immediate(struct tevent_context *ev)
 	 * remember the handler and then clear the event
 	 * the handler might reschedule the event
 	 */
-	handler = im->handler;
-	private_data = im->private_data;
 
-	DLIST_REMOVE(im->event_ctx->immediate_events, im);
-	im->event_ctx		= NULL;
-	im->handler		= NULL;
-	im->private_data	= NULL;
-	im->handler_name	= NULL;
-	im->schedule_location	= NULL;
-	im->cancel_fn		= NULL;
-	im->additional_data	= NULL;
+	im->busy = true;
+	im->handler_name = NULL;
+	tevent_common_immediate_cancel(im);
+	cur.handler(ev, im, cur.private_data);
+	im->busy = false;
+
+	if (im->destroyed) {
+		talloc_set_destructor(im, NULL);
+		TALLOC_FREE(im);
+		if (removed != NULL) {
+			*removed = true;
+		}
+	}
+
+	return 0;
+}
+
+/*
+  trigger the first immediate event and return true
+  if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+	struct tevent_immediate *im = ev->immediate_events;
+	int ret;
 
-	talloc_set_destructor(im, NULL);
+	if (!im) {
+		return false;
+	}
 
-	handler(ev, im, private_data);
+	ret = tevent_common_invoke_immediate_handler(im, NULL);
+	if (ret != 0) {
+		tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
+	}
 
 	return true;
 }
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index bd1c2a0370a3..a590a5bb3b75 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -203,6 +203,8 @@ struct tevent_timer {
 struct tevent_immediate {
 	struct tevent_immediate *prev, *next;
 	struct tevent_context *event_ctx;
+	bool busy;
+	bool destroyed;
 	tevent_immediate_handler_t handler;
 	/* this is private for the specific handler */
 	void *private_data;
@@ -367,6 +369,8 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 				      void *private_data,
 				      const char *handler_name,
 				      const char *location);
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+					   bool *removed);
 bool tevent_common_loop_immediate(struct tevent_context *ev);
 void tevent_common_threaded_activate_immediate(struct tevent_context *ev);
 
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index efdac9856dd1..9410765266e4 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -482,6 +482,12 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 	if ((im->event_ctx != NULL) || (handler == NULL)) {
 		abort();
 	}
+	if (im->destroyed) {
+		abort();
+	}
+	if (im->busy) {
+		abort();
+	}
 
 	*im = (struct tevent_immediate) {
 		.event_ctx		= ev,
-- 
2.17.1


From 4f5cec723fb36aef58bf61f22fd5b14b9f5228b5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 14:45:33 +0200
Subject: [PATCH 18/56] tevent: split out tevent_common_invoke_fd_handler()

We'll remove _PRIVATE_ with the next release.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent_epoll.c    |  3 +--
 lib/tevent/tevent_fd.c       | 40 ++++++++++++++++++++++++++++++++++++
 lib/tevent/tevent_internal.h |  4 ++++
 lib/tevent/tevent_poll.c     |  3 +--
 4 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 4147c67af2a0..5f7ef5d83d17 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -725,8 +725,7 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
 		 */
 		flags &= fde->flags;
 		if (flags) {
-			fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
-			break;
+			return tevent_common_invoke_fd_handler(fde, flags, NULL);
 		}
 	}
 
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index f33ae841b396..f8234641ad3d 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -30,6 +30,12 @@
 
 int tevent_common_fd_destructor(struct tevent_fd *fde)
 {
+	if (fde->destroyed) {
+		tevent_common_check_double_free(fde, "tevent_fd double free");
+		goto done;
+	}
+	fde->destroyed = true;
+
 	if (fde->event_ctx) {
 		DLIST_REMOVE(fde->event_ctx->fd_events, fde);
 	}
@@ -37,6 +43,13 @@ int tevent_common_fd_destructor(struct tevent_fd *fde)
 	if (fde->close_fn) {
 		fde->close_fn(fde->event_ctx, fde, fde->fd, fde->private_data);
 		fde->fd = -1;
+		fde->close_fn = NULL;
+	}
+
+	fde->event_ctx = NULL;
+done:
+	if (fde->busy) {
+		return -1;
 	}
 
 	return 0;
@@ -92,3 +105,30 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
 {
 	fde->close_fn = close_fn;
 }
+
+_PRIVATE_
+int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
+				    bool *removed)
+{
+	if (removed != NULL) {
+		*removed = false;
+	}
+
+	if (fde->event_ctx == NULL) {
+		return 0;
+	}
+
+	fde->busy = true;
+	fde->handler(fde->event_ctx, fde, flags, fde->private_data);
+	fde->busy = false;
+
+	if (fde->destroyed) {
+		talloc_set_destructor(fde, NULL);
+		TALLOC_FREE(fde);
+		if (removed != NULL) {
+			*removed = true;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index a590a5bb3b75..ed39aa2bebe4 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -170,6 +170,8 @@ struct tevent_req {
 struct tevent_fd {
 	struct tevent_fd *prev, *next;
 	struct tevent_context *event_ctx;
+	bool busy;
+	bool destroyed;
 	int fd;
 	uint16_t flags; /* see TEVENT_FD_* flags */
 	tevent_fd_handler_t handler;
@@ -343,6 +345,8 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
 				   tevent_fd_close_fn_t close_fn);
 uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde);
 void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
+				    bool *removed);
 
 struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
 					     TALLOC_CTX *mem_ctx,
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index f1d52533f5de..a1f7ef22206d 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -603,8 +603,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
 		flags &= fde->flags;
 		if (flags != 0) {
 			DLIST_DEMOTE(ev->fd_events, fde);
-			fde->handler(ev, fde, flags, fde->private_data);
-			return 0;
+			return tevent_common_invoke_fd_handler(fde, flags, NULL);
 		}
 	}
 
-- 
2.17.1


From d55767a3ad48fc2426cdca196cb9e4e0900fdc50 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 May 2018 15:43:12 +0200
Subject: [PATCH 19/56] tevent: make use of #include "system/threads.h"

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/testsuite.c      | 2 +-
 lib/tevent/tevent_threads.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 08aa7588acee..dba8f5895f76 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -32,7 +32,7 @@
 #include "torture/torture.h"
 #include "torture/local/proto.h"
 #ifdef HAVE_PTHREAD
-#include <pthread.h>
+#include "system/threads.h"
 #include <assert.h>
 #endif
 
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 9410765266e4..5d4e0c426769 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -28,8 +28,8 @@
 #include "tevent_internal.h"
 #include "tevent_util.h"
 
-#if defined(HAVE_PTHREAD)
-#include <pthread.h>
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
 
 struct tevent_immediate_list {
 	struct tevent_immediate_list *next, *prev;
-- 
2.17.1


From 5e4d509acdb776a5ff816abeebf54e5b39e6c2a7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 16:51:38 +0200
Subject: [PATCH 20/56] TESTS... tevent: add tevent_context_wrapper_create()
 infrastructure

This allows to specify wrapper tevent_contexts, which adds the ability
to run functions before and after the event handler functions.

This can be used to implement impersonation hooks
or advanced debugging/profiling hooks.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/tevent.c           |  18 ++
 lib/tevent/tevent.h           | 213 +++++++++++++++++
 lib/tevent/tevent_debug.c     |  16 ++
 lib/tevent/tevent_fd.c        |  25 +-
 lib/tevent/tevent_immediate.c |  22 +-
 lib/tevent/tevent_internal.h  |  28 +++
 lib/tevent/tevent_signal.c    |  28 ++-
 lib/tevent/tevent_threads.c   |  40 ++--
 lib/tevent/tevent_timed.c     |  27 ++-
 lib/tevent/tevent_wrapper.c   | 418 ++++++++++++++++++++++++++++++++++
 lib/tevent/wscript            |   2 +-
 11 files changed, 819 insertions(+), 18 deletions(-)
 create mode 100644 lib/tevent/tevent_wrapper.c

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index d12ec10720e9..802dce43552b 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -298,6 +298,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
 	struct tevent_timer *te, *tn;
 	struct tevent_immediate *ie, *in;
 	struct tevent_signal *se, *sn;
+	struct tevent_wrapper_glue *gl, *gn;
 
 #ifdef HAVE_PTHREAD
 	int ret;
@@ -345,6 +346,13 @@ int tevent_common_context_destructor(struct tevent_context *ev)
 	}
 #endif
 
+	for (gl = ev->wrapper.list; gl; gl = gn) {
+		gn = gl->next;
+
+		gl->main_ev = NULL;
+		DLIST_REMOVE(ev->wrapper.list, gl);
+	}
+
 	tevent_common_wakeup_fini(ev);
 
 	for (fd = ev->fd_events; fd; fd = fn) {
@@ -677,6 +685,16 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
 
 void tevent_loop_allow_nesting(struct tevent_context *ev)
 {
+	if (ev->wrapper.glue != NULL) {
+		tevent_abort(ev, "tevent_loop_allow_nesting() on wrapper");
+		return;
+	}
+
+	if (ev->wrapper.list != NULL) {
+		tevent_abort(ev, "tevent_loop_allow_nesting() with wrapper");
+		return;
+	}
+
 	ev->nesting.allowed = true;
 }
 
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 0e2e806ee5c4..2fa7221c4a4a 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -1967,6 +1967,219 @@ bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
 
 /* @} */
 
+/**
+ * @defgroup tevent_wrapper_ops The tevent wrapper operation functions
+ * @ingroup tevent
+ *
+ * The following structure and registration functions are exclusively
+ * needed for people writing wrapper functions for event handlers
+ * e.g. wrappers can be used for debugging/profiling or impersonation.
+ *
+ * There is nothing useful for normal tevent user in here.
+ * @{
+ */
+
+struct tevent_wrapper_ops {
+	const char *name;
+
+	bool (*before_use)(struct tevent_context *wrap_ev,
+			   void *private_state,
+			   struct tevent_context *main_ev,
+			   const char *location);
+	void (*after_use)(struct tevent_context *wrap_ev,
+			  void *private_state,
+			  struct tevent_context *main_ev,
+			  const char *location);
+
+	void (*before_fd_handler)(struct tevent_context *wrap_ev,
+				  void *private_state,
+				  struct tevent_context *main_ev,
+				  struct tevent_fd *fde,
+				  uint16_t flags,
+				  const char *handler_name,
+				  const char *location);
+	void (*after_fd_handler)(struct tevent_context *wrap_ev,
+				 void *private_state,
+				 struct tevent_context *main_ev,
+				 struct tevent_fd *fde,
+				 uint16_t flags,
+				 const char *handler_name,
+				 const char *location);
+
+	void (*before_timer_handler)(struct tevent_context *wrap_ev,
+				     void *private_state,
+				     struct tevent_context *main_ev,
+				     struct tevent_timer *te,
+				     struct timeval requested_time,
+				     struct timeval trigger_time,
+				     const char *handler_name,
+				     const char *location);
+	void (*after_timer_handler)(struct tevent_context *wrap_ev,
+				    void *private_state,
+				    struct tevent_context *main_ev,
+				    struct tevent_timer *te,
+				    struct timeval requested_time,
+				    struct timeval trigger_time,
+				    const char *handler_name,
+				    const char *location);
+
+	void (*before_immediate_handler)(struct tevent_context *wrap_ev,
+					 void *private_state,
+					 struct tevent_context *main_ev,
+					 struct tevent_immediate *im,
+					 const char *handler_name,
+					 const char *location);
+	void (*after_immediate_handler)(struct tevent_context *wrap_ev,
+					void *private_state,
+					struct tevent_context *main_ev,
+					struct tevent_immediate *im,
+					const char *handler_name,
+					const char *location);
+
+	void (*before_signal_handler)(struct tevent_context *wrap_ev,
+				      void *private_state,
+				      struct tevent_context *main_ev,
+				      struct tevent_signal *se,
+				      int signum,
+				      int count,
+				      void *siginfo,
+				      const char *handler_name,
+				      const char *location);
+	void (*after_signal_handler)(struct tevent_context *wrap_ev,
+				     void *private_state,
+				     struct tevent_context *main_ev,
+				     struct tevent_signal *se,
+				     int signum,
+				     int count,
+				     void *siginfo,
+				     const char *handler_name,
+				     const char *location);
+};
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a wrapper tevent_context.
+ *
+ * @param[in]  main_ev        The main event context to work on.
+ *
+ * @param[in]  mem_ctx        The talloc memory context to use.
+ *
+ * @param[in]  ops            The tevent_wrapper_ops function table.
+ *
+ * @param[out] private_state  The private state use by the wrapper functions.
+ *
+ * @param[in]  private_type   The talloc type of the private_state.
+ *
+ * @return                    The wrapper event context, NULL on error.
+ *
+ * @note Available as of tevent 0.9.37
+ */
+struct tevent_context *tevent_context_wrapper_create(struct tevent_context *main_ev,
+						TALLOC_CTX *mem_ctx,
+						const struct tevent_wrapper_ops *ops,
+						void **private_state,
+						const char *private_type);
+#else
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+						TALLOC_CTX *mem_ctx,
+						const struct tevent_wrapper_ops *ops,
+						void *pstate,
+						size_t psize,
+						const char *type,
+						const char *location);
+#define tevent_context_wrapper_create(main_ev, mem_ctx, ops, state, type) \
+	_tevent_context_wrapper_create(main_ev, mem_ctx, ops, \
+				       state, sizeof(type), #type, __location__)
+#endif
+
+/**
+ * @brief Check if the event context is a wrapper event context.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @return              Is a wrapper (true), otherwise (false).
+ *
+ * @see tevent_context_wrapper_create()
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_is_wrapper(struct tevent_context *ev);
+
+#ifdef DOXYGEN
+/**
+ * @brief Prepare the environment of a (wrapper) event context.
+ *
+ * A caller might call this before passing a wrapper event context
+ * to a tevent_req based *_send() function.
+ *
+ * The wrapper event context might do something like impersonation.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @return              Success (true) or failure (false).
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_after_use
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_before_use(struct tevent_context *ev);
+#else
+bool _tevent_context_before_use(struct tevent_context *ev,
+				const char *location);
+#define tevent_context_before_use(ev) \
+	_tevent_context_before_use(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Release the environment of a (wrapper) event context.
+ *
+ * A caller might call this after receiving the result from
+ * a *_recv function of a tevent_req based function pair.
+ *
+ * The wrapper event context might undo something like impersonation.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_before_use
+ *
+ * @note Available as of tevent 0.9.37
+ */
+void tevent_context_after_use(struct tevent_context *ev);
+#else
+void _tevent_context_after_use(struct tevent_context *ev,
+			       const char *location);
+#define tevent_context_after_use(ev) \
+	_tevent_context_after_use(ev, __location__)
+#endif
+
+/**
+ * @brief Check is the two context pointers belong to the same low level loop
+ *
+ * With the introduction of wrapper contexts it's not trivial
+ * to check if two context pointers belong to the same low level
+ * event loop. Some code may need to know this in order
+ * to make some caching decisions.
+ *
+ * @param[in]  ev1       The first event context.
+ * @param[in]  ev2       The second event context.
+ *
+ * @return true if both contexts belong to the same (still existing) context
+ * loop, false otherwise.
+ *
+ * @see tevent_context_wrapper_create
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_same_loop(struct tevent_context *ev1,
+			      struct tevent_context *ev2);
+
+/* @} */
+
 /**
  * @defgroup tevent_compat The tevent compatibility functions
  * @ingroup tevent
diff --git a/lib/tevent/tevent_debug.c b/lib/tevent/tevent_debug.c
index 31da7b968366..0a57639076e2 100644
--- a/lib/tevent/tevent_debug.c
+++ b/lib/tevent/tevent_debug.c
@@ -41,6 +41,13 @@ int tevent_set_debug(struct tevent_context *ev,
 				   va_list ap) PRINTF_ATTRIBUTE(3,0),
 		     void *context)
 {
+	if (ev->wrapper.glue != NULL) {
+		ev = tevent_wrapper_main_ev(ev);
+		tevent_abort(ev, "tevent_set_debug() on wrapper");
+		errno = EINVAL;
+		return -1;
+	}
+
 	ev->debug_ops.debug = debug;
 	ev->debug_ops.context = context;
 	return 0;
@@ -86,6 +93,9 @@ void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
 	if (!ev) {
 		return;
 	}
+	if (ev->wrapper.glue != NULL) {
+		ev = tevent_wrapper_main_ev(ev);
+	}
 	if (ev->debug_ops.debug == NULL) {
 		return;
 	}
@@ -98,6 +108,12 @@ void tevent_set_trace_callback(struct tevent_context *ev,
 			       tevent_trace_callback_t cb,
 			       void *private_data)
 {
+	if (ev->wrapper.glue != NULL) {
+		ev = tevent_wrapper_main_ev(ev);
+		tevent_abort(ev, "tevent_set_trace_callback() on wrapper");
+		return;
+	}
+
 	ev->tracing.callback = cb;
 	ev->tracing.private_data = private_data;
 }
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index f8234641ad3d..38d0eaeba73a 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -110,6 +110,8 @@ _PRIVATE_
 int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
 				    bool *removed)
 {
+	struct tevent_context *handler_ev = fde->event_ctx;
+
 	if (removed != NULL) {
 		*removed = false;
 	}
@@ -119,7 +121,28 @@ int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
 	}
 
 	fde->busy = true;
-	fde->handler(fde->event_ctx, fde, flags, fde->private_data);
+	if (fde->wrapper != NULL) {
+		fde->wrapper->ops->before_fd_handler(
+					fde->wrapper->wrap_ev,
+					fde->wrapper->private_state,
+					fde->wrapper->main_ev,
+					fde,
+					flags,
+					fde->handler_name,
+					fde->location);
+		handler_ev = fde->wrapper->wrap_ev;
+	}
+	fde->handler(handler_ev, fde, flags, fde->private_data);
+	if (fde->wrapper != NULL) {
+		fde->wrapper->ops->after_fd_handler(
+					fde->wrapper->wrap_ev,
+					fde->wrapper->private_state,
+					fde->wrapper->main_ev,
+					fde,
+					flags,
+					fde->handler_name,
+					fde->location);
+	}
 	fde->busy = false;
 
 	if (fde->destroyed) {
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index abcaca41fb80..ee4d8fa6e2a6 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -129,6 +129,7 @@ _PRIVATE_
 int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
 					   bool *removed)
 {
+	struct tevent_context *handler_ev = im->event_ctx;
 	struct tevent_context *ev = im->event_ctx;
 	struct tevent_immediate cur = *im;
 
@@ -148,7 +149,26 @@ int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
 	im->busy = true;
 	im->handler_name = NULL;
 	tevent_common_immediate_cancel(im);
-	cur.handler(ev, im, cur.private_data);
+	if (cur.wrapper != NULL) {
+		cur.wrapper->ops->before_immediate_handler(
+					cur.wrapper->wrap_ev,
+					cur.wrapper->private_state,
+					cur.wrapper->main_ev,
+					im,
+					cur.handler_name,
+					cur.schedule_location);
+		handler_ev = cur.wrapper->wrap_ev;
+	}
+	cur.handler(handler_ev, im, cur.private_data);
+	if (cur.wrapper != NULL) {
+		cur.wrapper->ops->after_immediate_handler(
+					cur.wrapper->wrap_ev,
+					cur.wrapper->private_state,
+					cur.wrapper->main_ev,
+					im,
+					cur.handler_name,
+					cur.schedule_location);
+	}
 	im->busy = false;
 
 	if (im->destroyed) {
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index ed39aa2bebe4..e90dd5ef8268 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -170,6 +170,7 @@ struct tevent_req {
 struct tevent_fd {
 	struct tevent_fd *prev, *next;
 	struct tevent_context *event_ctx;
+	struct tevent_wrapper_glue *wrapper;
 	bool busy;
 	bool destroyed;
 	int fd;
@@ -189,6 +190,7 @@ struct tevent_fd {
 struct tevent_timer {
 	struct tevent_timer *prev, *next;
 	struct tevent_context *event_ctx;
+	struct tevent_wrapper_glue *wrapper;
 	bool busy;
 	bool destroyed;
 	struct timeval next_event;
@@ -205,6 +207,7 @@ struct tevent_timer {
 struct tevent_immediate {
 	struct tevent_immediate *prev, *next;
 	struct tevent_context *event_ctx;
+	struct tevent_wrapper_glue *wrapper;
 	bool busy;
 	bool destroyed;
 	tevent_immediate_handler_t handler;
@@ -222,6 +225,7 @@ struct tevent_immediate {
 struct tevent_signal {
 	struct tevent_signal *prev, *next;
 	struct tevent_context *event_ctx;
+	struct tevent_wrapper_glue *wrapper;
 	bool busy;
 	bool destroyed;
 	int signum;
@@ -314,6 +318,18 @@ struct tevent_context {
 		void *private_data;
 	} tracing;
 
+	struct {
+		/*
+		 * This is used on the main event context
+		 */
+		struct tevent_wrapper_glue *list;
+
+		/*
+		 * This is used on the wrapper event context
+		 */
+		struct tevent_wrapper_glue *glue;
+	} wrapper;
+
 	/*
 	 * an optimization pointer into timer_events
 	 * used by used by common code via
@@ -397,6 +413,18 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
 					int signum, int count, void *siginfo,
 					bool *removed);
 
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev);
+
+struct tevent_wrapper_ops;
+
+struct tevent_wrapper_glue {
+	struct tevent_wrapper_glue *prev, *next;
+	struct tevent_context *wrap_ev;
+	struct tevent_context *main_ev;
+	const struct tevent_wrapper_ops *ops;
+	void *private_state;
+};
+
 bool tevent_standard_init(void);
 bool tevent_poll_init(void);
 void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 3ca03334c92f..e0665cbafee6 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -338,6 +338,7 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
 					int signum, int count, void *siginfo,
 					bool *removed)
 {
+	struct tevent_context *handler_ev = se->event_ctx;
 	bool remove = false;
 
 	if (removed != NULL) {
@@ -349,7 +350,32 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
 	}
 
 	se->busy = true;
-	se->handler(se->event_ctx, se, signum, count, siginfo, se->private_data);
+	if (se->wrapper != NULL) {
+		se->wrapper->ops->before_signal_handler(
+						se->wrapper->wrap_ev,
+						se->wrapper->private_state,
+						se->wrapper->main_ev,
+						se,
+						signum,
+						count,
+						siginfo,
+						se->handler_name,
+						se->location);
+		handler_ev = se->wrapper->wrap_ev;
+	}
+	se->handler(handler_ev, se, signum, count, siginfo, se->private_data);
+	if (se->wrapper != NULL) {
+		se->wrapper->ops->after_signal_handler(
+						se->wrapper->wrap_ev,
+						se->wrapper->private_state,
+						se->wrapper->main_ev,
+						se,
+						signum,
+						count,
+						siginfo,
+						se->handler_name,
+						se->location);
+	}
 	se->busy = false;
 
 #ifdef SA_RESETHAND
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 5d4e0c426769..85a6cbf55e33 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -217,6 +217,18 @@ struct tevent_thread_proxy *tevent_thread_proxy_create(
 	int pipefds[2];
 	struct tevent_thread_proxy *tp;
 
+	if (dest_ev_ctx->wrapper.glue != NULL) {
+		/*
+		 * stacking of wrappers is not supported
+		 */
+		tevent_debug(dest_ev_ctx->wrapper.glue->main_ev,
+			     TEVENT_DEBUG_FATAL,
+			     "%s() not allowed on a wrapper context\n",
+			     __func__);
+		errno = EINVAL;
+		return NULL;
+	}
+
 	tp = talloc_zero(dest_ev_ctx, struct tevent_thread_proxy);
 	if (tp == NULL) {
 		return NULL;
@@ -375,10 +387,11 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
 static int tevent_threaded_context_destructor(
 	struct tevent_threaded_context *tctx)
 {
+	struct tevent_context *main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
 	int ret;
 
-	if (tctx->event_ctx != NULL) {
-		DLIST_REMOVE(tctx->event_ctx->threaded_contexts, tctx);
+	if (main_ev != NULL) {
+		DLIST_REMOVE(main_ev->threaded_contexts, tctx);
 	}
 
 	/*
@@ -410,10 +423,11 @@ struct tevent_threaded_context *tevent_threaded_context_create(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
 {
 #ifdef HAVE_PTHREAD
+	struct tevent_context *main_ev = tevent_wrapper_main_ev(ev);
 	struct tevent_threaded_context *tctx;
 	int ret;
 
-	ret = tevent_common_wakeup_init(ev);
+	ret = tevent_common_wakeup_init(main_ev);
 	if (ret != 0) {
 		errno = ret;
 		return NULL;
@@ -431,7 +445,7 @@ struct tevent_threaded_context *tevent_threaded_context_create(
 		return NULL;
 	}
 
-	DLIST_ADD(ev->threaded_contexts, tctx);
+	DLIST_ADD(main_ev->threaded_contexts, tctx);
 	talloc_set_destructor(tctx, tevent_threaded_context_destructor);
 
 	return tctx;
@@ -458,7 +472,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 {
 #ifdef HAVE_PTHREAD
 	const char *create_location = im->create_location;
-	struct tevent_context *ev;
+	struct tevent_context *main_ev = NULL;
 	int ret, wakeup_fd;
 
 	ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
@@ -466,9 +480,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 		abort();
 	}
 
-	ev = tctx->event_ctx;
-
-	if (ev == NULL) {
+	if (tctx->event_ctx == NULL) {
 		/*
 		 * Our event context is already gone.
 		 */
@@ -489,8 +501,10 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 		abort();
 	}
 
+	main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
+
 	*im = (struct tevent_immediate) {
-		.event_ctx		= ev,
+		.event_ctx		= tctx->event_ctx,
 		.handler		= handler,
 		.private_data		= private_data,
 		.handler_name		= handler_name,
@@ -506,15 +520,15 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 	 */
 	talloc_set_destructor(im, tevent_threaded_schedule_immediate_destructor);
 
-	ret = pthread_mutex_lock(&ev->scheduled_mutex);
+	ret = pthread_mutex_lock(&main_ev->scheduled_mutex);
 	if (ret != 0) {
 		abort();
 	}
 
-	DLIST_ADD_END(ev->scheduled_immediates, im);
-	wakeup_fd = ev->wakeup_fd;
+	DLIST_ADD_END(main_ev->scheduled_immediates, im);
+	wakeup_fd = main_ev->wakeup_fd;
 
-	ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+	ret = pthread_mutex_unlock(&main_ev->scheduled_mutex);
 	if (ret != 0) {
 		abort();
 	}
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index d460e7001dca..5ede71696af4 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -321,6 +321,8 @@ int tevent_common_invoke_timer_handler(struct tevent_timer *te,
 				       struct timeval current_time,
 				       bool *removed)
 {
+	struct tevent_context *handler_ev = te->event_ctx;
+
 	if (removed != NULL) {
 		*removed = false;
 	}
@@ -351,7 +353,30 @@ int tevent_common_invoke_timer_handler(struct tevent_timer *te,
 	 * otherwise we pass the current time
 	 */
 	te->busy = true;
-	te->handler(te->event_ctx, te, current_time, te->private_data);
+	if (te->wrapper != NULL) {
+		te->wrapper->ops->before_timer_handler(
+					te->wrapper->wrap_ev,
+					te->wrapper->private_state,
+					te->wrapper->main_ev,
+					te,
+					te->next_event,
+					current_time,
+					te->handler_name,
+					te->location);
+		handler_ev = te->wrapper->wrap_ev;
+	}
+	te->handler(handler_ev, te, current_time, te->private_data);
+	if (te->wrapper != NULL) {
+		te->wrapper->ops->after_timer_handler(
+					te->wrapper->wrap_ev,
+					te->wrapper->private_state,
+					te->wrapper->main_ev,
+					te,
+					te->next_event,
+					current_time,
+					te->handler_name,
+					te->location);
+	}
 	te->busy = false;
 
 	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
diff --git a/lib/tevent/tevent_wrapper.c b/lib/tevent/tevent_wrapper.c
new file mode 100644
index 000000000000..8305a50dfca5
--- /dev/null
+++ b/lib/tevent/tevent_wrapper.c
@@ -0,0 +1,418 @@
+/*
+   Infrastructure for event context wrappers
+
+   Copyright (C) Stefan Metzmacher 2014
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#endif
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
+{
+	return 0;
+}
+
+static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
+						    TALLOC_CTX *mem_ctx,
+						    int fd, uint16_t flags,
+						    tevent_fd_handler_t handler,
+						    void *private_data,
+						    const char *handler_name,
+						    const char *location)
+{
+	struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+	struct tevent_fd *fde = NULL;
+
+	if (glue->main_ev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
+			     handler, private_data,
+			     handler_name, location);
+	if (fde == NULL) {
+		return NULL;
+	}
+
+	fde->wrapper = glue;
+
+	return fde;
+}
+
+static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
+							  TALLOC_CTX *mem_ctx,
+							  struct timeval next_event,
+							  tevent_timer_handler_t handler,
+							  void *private_data,
+							  const char *handler_name,
+							  const char *location)
+{
+	struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+	struct tevent_timer *te = NULL;
+
+	if (glue->main_ev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
+			       handler, private_data,
+			       handler_name, location);
+	if (te == NULL) {
+		return NULL;
+	}
+
+	te->wrapper = glue;
+
+	return te;
+}
+
+static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
+						   struct tevent_context *ev,
+						   tevent_immediate_handler_t handler,
+						   void *private_data,
+						   const char *handler_name,
+						   const char *location)
+{
+	struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+
+	if (glue->main_ev == NULL) {
+		tevent_abort(ev, location);
+		errno = EINVAL;
+		return;
+	}
+
+	_tevent_schedule_immediate(im, glue->main_ev,
+				   handler, private_data,
+				   handler_name, location);
+
+	im->wrapper = glue;
+
+	return;
+}
+
+static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
+							    TALLOC_CTX *mem_ctx,
+							    int signum, int sa_flags,
+							    tevent_signal_handler_t handler,
+							    void *private_data,
+							    const char *handler_name,
+							    const char *location)
+{
+	struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+	struct tevent_signal *se = NULL;
+
+	if (glue->main_ev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	se = _tevent_add_signal(glue->main_ev, mem_ctx,
+				signum, sa_flags,
+				handler, private_data,
+				handler_name, location);
+	if (se == NULL) {
+		return NULL;
+	}
+
+	se->wrapper = glue;
+
+	return se;
+}
+
+static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
+{
+	tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
+	errno = ENOSYS;
+	return -1;
+}
+
+static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
+{
+	tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
+	errno = ENOSYS;
+	return -1;
+}
+
+static const struct tevent_ops tevent_wrapper_glue_ops = {
+	.context_init		= tevent_wrapper_glue_context_init,
+	.add_fd			= tevent_wrapper_glue_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= tevent_common_fd_set_flags,
+	.add_timer		= tevent_wrapper_glue_add_timer,
+	.schedule_immediate	= tevent_wrapper_glue_schedule_immediate,
+	.add_signal		= tevent_wrapper_glue_add_signal,
+	.loop_once		= tevent_wrapper_glue_loop_once,
+	.loop_wait		= tevent_wrapper_glue_loop_wait,
+};
+
+static int tevent_wrapper_glue_destructor(struct tevent_wrapper_glue *glue)
+{
+	struct tevent_context *main_ev = glue->main_ev;
+	struct tevent_fd *fd = NULL, *fn = NULL;
+	struct tevent_timer *te = NULL, *tn = NULL;
+	struct tevent_immediate *ie = NULL, *in = NULL;
+	struct tevent_signal *se = NULL, *sn = NULL;
+#ifdef HAVE_PTHREAD
+	struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
+#endif
+
+	if (main_ev == NULL) {
+		return 0;
+	}
+
+	glue->main_ev = NULL;
+	DLIST_REMOVE(main_ev->wrapper.list, glue);
+
+#ifdef HAVE_PTHREAD
+	for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
+		int ret;
+
+		tctxn = tctx->next;
+
+		if (tctx->event_ctx != glue->wrap_ev) {
+			continue;
+		}
+
+		ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+		if (ret != 0) {
+			abort();
+		}
+
+		/*
+		 * Indicate to the thread that the tevent_context is
+		 * gone. The counterpart of this is in
+		 * _tevent_threaded_schedule_immediate, there we read
+		 * this under the threaded_context's mutex.
+		 */
+
+		tctx->event_ctx = NULL;
+
+		ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+		if (ret != 0) {
+			abort();
+		}
+
+		DLIST_REMOVE(main_ev->threaded_contexts, tctx);
+	}
+#endif
+
+	for (fd = main_ev->fd_events; fd; fd = fn) {
+		fn = fd->next;
+
+		if (fd->wrapper != glue) {
+			continue;
+		}
+
+		tevent_fd_set_flags(fd, 0);
+
+		fd->event_ctx = NULL;
+		DLIST_REMOVE(main_ev->fd_events, fd);
+	}
+
+	for (te = main_ev->timer_events; te; te = tn) {
+		tn = te->next;
+
+		if (te->wrapper != glue) {
+			continue;
+		}
+
+		te->event_ctx = NULL;
+
+		if (main_ev->last_zero_timer == te) {
+			main_ev->last_zero_timer = DLIST_PREV(te);
+		}
+		DLIST_REMOVE(main_ev->timer_events, te);
+	}
+
+	for (ie = main_ev->immediate_events; ie; ie = in) {
+		in = ie->next;
+
+		if (ie->wrapper != glue) {
+			continue;
+		}
+
+		ie->event_ctx = NULL;
+		ie->cancel_fn = NULL;
+		DLIST_REMOVE(main_ev->immediate_events, ie);
+	}
+
+	for (se = main_ev->signal_events; se; se = sn) {
+		sn = se->next;
+
+		if (se->wrapper != glue) {
+			continue;
+		}
+
+		tevent_cleanup_pending_signal_handlers(se);
+	}
+
+	return 0;
+}
+
+_PRIVATE_
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+						TALLOC_CTX *mem_ctx,
+						const struct tevent_wrapper_ops *ops,
+						void *pstate,
+						size_t psize,
+						const char *type,
+						const char *location)
+{
+	void **ppstate = (void **)pstate;
+	struct tevent_context *ev = NULL;
+
+	if (main_ev->wrapper.glue != NULL) {
+		/*
+		 * stacking of wrappers is not supported
+		 */
+		tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+			     "%s: %s() stacking not allowed\n",
+			     __func__, location);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (main_ev->nesting.allowed) {
+		/*
+		 * wrappers conflict with nesting
+		 */
+		tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+			     "%s: %s() conflicts with nesting\n",
+			     __func__, location);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	ev = tevent_context_init_ops(mem_ctx,
+				     &tevent_wrapper_glue_ops,
+				     NULL);
+	if (ev == NULL) {
+		return NULL;
+	}
+
+	ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
+	if (ev->wrapper.glue == NULL) {
+		talloc_free(ev);
+		return NULL;
+	}
+
+	ev->wrapper.glue->wrap_ev = ev;
+	ev->wrapper.glue->main_ev = main_ev;
+	ev->wrapper.glue->ops = ops;
+	ev->wrapper.glue->private_state = talloc_size(ev->wrapper.glue, psize);
+	if (ev->wrapper.glue->private_state == NULL) {
+		talloc_free(ev);
+		return NULL;
+	}
+	talloc_set_name_const(ev->wrapper.glue->private_state, type);
+
+	DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
+
+	talloc_set_destructor(ev->wrapper.glue, tevent_wrapper_glue_destructor);
+
+	*ppstate = ev->wrapper.glue->private_state;
+	return ev;
+}
+
+_PRIVATE_
+bool tevent_context_is_wrapper(struct tevent_context *ev)
+{
+	if (ev->wrapper.glue != NULL) {
+		return true;
+	}
+
+	return false;
+}
+
+_PRIVATE_
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
+{
+	if (ev == NULL) {
+		return NULL;
+	}
+
+	if (ev->wrapper.glue == NULL) {
+		return ev;
+	}
+
+	return ev->wrapper.glue->main_ev;
+}
+
+_PRIVATE_
+bool _tevent_context_before_use(struct tevent_context *ev,
+				const char *location)
+{
+	if (ev->wrapper.glue == NULL) {
+		return true;
+	}
+
+	if (ev->wrapper.glue->main_ev == NULL) {
+		return false;
+	}
+
+	return ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
+						 ev->wrapper.glue->private_state,
+						 ev->wrapper.glue->main_ev,
+						 location);
+}
+
+_PRIVATE_
+void _tevent_context_after_use(struct tevent_context *ev,
+			       const char *location)
+{
+	if (ev->wrapper.glue == NULL) {
+		return;
+	}
+
+	if (ev->wrapper.glue->main_ev == NULL) {
+		return;
+	}
+
+	ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
+					 ev->wrapper.glue->private_state,
+					 ev->wrapper.glue->main_ev,
+					 location);
+}
+
+_PRIVATE_
+bool tevent_context_same_loop(struct tevent_context *ev1,
+			      struct tevent_context *ev2)
+{
+	struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
+	struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
+
+	if (main_ev1 == NULL) {
+		return false;
+	}
+
+	if (main_ev1 == main_ev2) {
+		return true;
+	}
+
+	return false;
+}
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 94d190f3b605..2395ead9aa93 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -77,7 +77,7 @@ def build(bld):
     bld.RECURSE('lib/talloc')
 
     SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
-             tevent_queue.c tevent_req.c
+             tevent_queue.c tevent_req.c tevent_wrapper.c
              tevent_poll.c tevent_threads.c
              tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
 
-- 
2.17.1


From 8e22217444b0090ad17c3ebc9d9810790d13e12e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Aug 2014 21:51:09 +0200
Subject: [PATCH 21/56] TODO: tevent: version 0.9.37

* make tevent_abort() reachable for backends
* add tevent_common_invoke_*_handler() functions
* add tevent_context_same_loop() function
* add tevent_context_wrapper_create() infrastructure
---
 lib/tevent/ABI/tevent-0.9.37.sigs | 111 ++++++++++++++++++++++++++++++
 lib/tevent/tevent.c               |   2 -
 lib/tevent/tevent_fd.c            |   1 -
 lib/tevent/tevent_immediate.c     |   1 -
 lib/tevent/tevent_signal.c        |   1 -
 lib/tevent/tevent_timed.c         |   1 -
 lib/tevent/tevent_wrapper.c       |   5 --
 lib/tevent/wscript                |   2 +-
 8 files changed, 112 insertions(+), 12 deletions(-)
 create mode 100644 lib/tevent/ABI/tevent-0.9.37.sigs

diff --git a/lib/tevent/ABI/tevent-0.9.37.sigs b/lib/tevent/ABI/tevent-0.9.37.sigs
new file mode 100644
index 000000000000..85bf4a89ae2e
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.37.sigs
@@ -0,0 +1,111 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_after_use: void (struct tevent_context *, const char *)
+_tevent_context_before_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 802dce43552b..548aa6db33e0 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -437,7 +437,6 @@ static int tevent_common_context_constructor(struct tevent_context *ev)
 	return 0;
 }
 
-_PRIVATE_
 void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason)
 {
 	void *parent_ptr = talloc_parent(ptr);
@@ -601,7 +600,6 @@ void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
 	tevent_abort_fn = abort_fn;
 }
 
-_PRIVATE_
 void tevent_abort(struct tevent_context *ev, const char *reason)
 {
 	if (ev != NULL) {
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index 38d0eaeba73a..47c842c3ac72 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -106,7 +106,6 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
 	fde->close_fn = close_fn;
 }
 
-_PRIVATE_
 int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
 				    bool *removed)
 {
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index ee4d8fa6e2a6..22e6a3e7f13f 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -125,7 +125,6 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 		     handler_name, im);
 }
 
-_PRIVATE_
 int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
 					   bool *removed)
 {
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index e0665cbafee6..3f3fdcec1c29 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -333,7 +333,6 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 	return se;
 }
 
-_PRIVATE_
 int tevent_common_invoke_signal_handler(struct tevent_signal *se,
 					int signum, int count, void *siginfo,
 					bool *removed)
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index 5ede71696af4..1f5ec0953fff 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -316,7 +316,6 @@ void tevent_update_timer(struct tevent_timer *te, struct timeval next_event)
 	tevent_common_insert_timer(ev, te, false);
 }
 
-_PRIVATE_
 int tevent_common_invoke_timer_handler(struct tevent_timer *te,
 				       struct timeval current_time,
 				       bool *removed)
diff --git a/lib/tevent/tevent_wrapper.c b/lib/tevent/tevent_wrapper.c
index 8305a50dfca5..2bc2b82d34a6 100644
--- a/lib/tevent/tevent_wrapper.c
+++ b/lib/tevent/tevent_wrapper.c
@@ -274,7 +274,6 @@ static int tevent_wrapper_glue_destructor(struct tevent_wrapper_glue *glue)
 	return 0;
 }
 
-_PRIVATE_
 struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
 						TALLOC_CTX *mem_ctx,
 						const struct tevent_wrapper_ops *ops,
@@ -339,7 +338,6 @@ struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *mai
 	return ev;
 }
 
-_PRIVATE_
 bool tevent_context_is_wrapper(struct tevent_context *ev)
 {
 	if (ev->wrapper.glue != NULL) {
@@ -363,7 +361,6 @@ struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
 	return ev->wrapper.glue->main_ev;
 }
 
-_PRIVATE_
 bool _tevent_context_before_use(struct tevent_context *ev,
 				const char *location)
 {
@@ -381,7 +378,6 @@ bool _tevent_context_before_use(struct tevent_context *ev,
 						 location);
 }
 
-_PRIVATE_
 void _tevent_context_after_use(struct tevent_context *ev,
 			       const char *location)
 {
@@ -399,7 +395,6 @@ void _tevent_context_after_use(struct tevent_context *ev,
 					 location);
 }
 
-_PRIVATE_
 bool tevent_context_same_loop(struct tevent_context *ev1,
 			      struct tevent_context *ev2)
 {
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 2395ead9aa93..54330d27cadb 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'tevent'
-VERSION = '0.9.36'
+VERSION = '0.9.37'
 
 blddir = 'bin'
 
-- 
2.17.1


From a5f59ad02375b0515ba7eb552a3ff3f1808360ad Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 18 May 2018 16:28:47 +0200
Subject: [PATCH 22/56] s3:messages: protect against usage of wrapper
 tevent_context objects for messaging

This makes a lot of assumtion easier to understand and the introduction
of wrapper tevent contexts will not change the existing behaviour.

We'll relax this a bit in the next commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/lib/messages.c          | 23 +++++++++++++++++++++++
 source3/lib/messages_ctdb.c     |  8 ++++++++
 source3/lib/messages_ctdb_ref.c | 12 ++++++++++++
 source3/lib/messages_dgm.c      | 14 ++++++++++++++
 source3/lib/messages_dgm_ref.c  | 12 ++++++++++++
 5 files changed, 69 insertions(+)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 82a177856f60..1a5ea4659aa4 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -365,6 +365,11 @@ static bool messaging_alert_event_contexts(struct messaging_context *ctx)
 		 * alternatively would be to track whether the
 		 * immediate has already been scheduled. For
 		 * now, avoid that complexity here.
+		 *
+		 * reg->ev and ctx->event_ctx can't
+		 * be wrapper tevent_context pointers
+		 * so we don't need to use
+		 * tevent_context_same_loop().
 		 */
 
 		if (reg->ev == ctx->event_ctx) {
@@ -493,6 +498,12 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
 
 	sec_init();
 
+	if (tevent_context_is_wrapper(ev)) {
+		/* This is really a programmer error! */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
 	lck_path = lock_path("msg.lock");
 	if (lck_path == NULL) {
 		return NT_STATUS_NO_MEMORY;
@@ -1023,6 +1034,13 @@ struct tevent_req *messaging_filtered_read_send(
 	state->filter = filter;
 	state->private_data = private_data;
 
+	if (tevent_context_is_wrapper(ev)) {
+		/* This is really a programmer error! */
+		DBG_ERR("Wrapper tevent context doesn't use main context.\n");
+		tevent_req_error(req, EINVAL);
+		return tevent_req_post(req, ev);
+	}
+
 	/*
 	 * We have to defer the callback here, as we might be called from
 	 * within a different tevent_context than state->ev
@@ -1343,6 +1361,11 @@ static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
 	bool consumed;
 	size_t i;
 
+	/*
+	 * ev and msg_ctx->event_ctx can't be wrapper tevent_context pointers
+	 * so we don't need to use tevent_context_same_loop().
+	 */
+
 	if (ev == msg_ctx->event_ctx) {
 		consumed = messaging_dispatch_classic(msg_ctx, rec);
 		if (consumed) {
diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
index d3e2e3f85893..a1aeb37af198 100644
--- a/source3/lib/messages_ctdb.c
+++ b/source3/lib/messages_ctdb.c
@@ -209,6 +209,14 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 		return NULL;
 	}
 
+	if (tevent_context_is_wrapper(ev)) {
+		/*
+		 * This is really a programmer error!
+		 */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		return NULL;
+	}
+
 	fde = talloc(mem_ctx, struct messaging_ctdb_fde);
 	if (fde == NULL) {
 		return NULL;
diff --git a/source3/lib/messages_ctdb_ref.c b/source3/lib/messages_ctdb_ref.c
index 3570ed8ae4c8..47b4b758dac5 100644
--- a/source3/lib/messages_ctdb_ref.c
+++ b/source3/lib/messages_ctdb_ref.c
@@ -52,6 +52,18 @@ void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 {
 	struct msg_ctdb_ref *result, *tmp_refs;
 
+	if (tevent_context_is_wrapper(ev)) {
+		/*
+		 * This is really a programmer error!
+		 *
+		 * The main/raw tevent context should
+		 * have been registered first!
+		 */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		*err = EINVAL;
+		return NULL;
+	}
+
 	result = talloc(mem_ctx, struct msg_ctdb_ref);
 	if (result == NULL) {
 		*err = ENOMEM;
diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c
index b8878b68b996..1c76615093c0 100644
--- a/source3/lib/messages_dgm.c
+++ b/source3/lib/messages_dgm.c
@@ -993,6 +993,12 @@ int messaging_dgm_init(struct tevent_context *ev,
 		return EEXIST;
 	}
 
+	if (tevent_context_is_wrapper(ev)) {
+		/* This is really a programmer error! */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		return EINVAL;
+	}
+
 	ctx = talloc_zero(NULL, struct messaging_dgm_context);
 	if (ctx == NULL) {
 		goto fail_nomem;
@@ -1673,6 +1679,14 @@ struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
 		return NULL;
 	}
 
+	if (tevent_context_is_wrapper(ev)) {
+		/*
+		 * This is really a programmer error!
+		 */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		return NULL;
+	}
+
 	fde = talloc(mem_ctx, struct messaging_dgm_fde);
 	if (fde == NULL) {
 		return NULL;
diff --git a/source3/lib/messages_dgm_ref.c b/source3/lib/messages_dgm_ref.c
index 39d22700740c..a22077043651 100644
--- a/source3/lib/messages_dgm_ref.c
+++ b/source3/lib/messages_dgm_ref.c
@@ -54,6 +54,18 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 {
 	struct msg_dgm_ref *result, *tmp_refs;
 
+	if (tevent_context_is_wrapper(ev)) {
+		/*
+		 * This is really a programmer error!
+		 *
+		 * The main/raw tevent context should
+		 * have been registered first!
+		 */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		*err = EINVAL;
+		return NULL;
+	}
+
 	result = talloc(mem_ctx, struct msg_dgm_ref);
 	if (result == NULL) {
 		*err = ENOMEM;
-- 
2.17.1


From 642ef7babf4d5a309368318a992747e25c39640d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 14:48:46 +0100
Subject: [PATCH 23/56] s3:messages: allow
 messaging_{dgm,ctdb}_register_tevent_context() to use wrapper tevent_context

This is only allowed if the raw tevent context is already registered.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/lib/messages_ctdb.c | 38 ++++++++++++++++++++++++++++---------
 source3/lib/messages_dgm.c  | 38 ++++++++++++++++++++++++++++---------
 2 files changed, 58 insertions(+), 18 deletions(-)

diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
index a1aeb37af198..11fe72661cc3 100644
--- a/source3/lib/messages_ctdb.c
+++ b/source3/lib/messages_ctdb.c
@@ -209,14 +209,6 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 		return NULL;
 	}
 
-	if (tevent_context_is_wrapper(ev)) {
-		/*
-		 * This is really a programmer error!
-		 */
-		DBG_ERR("Should not be used with a wrapper tevent context\n");
-		return NULL;
-	}
-
 	fde = talloc(mem_ctx, struct messaging_ctdb_fde);
 	if (fde == NULL) {
 		return NULL;
@@ -234,7 +226,24 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 			 */
 			continue;
 		}
-		if (fde_ev->ev == ev) {
+
+		/*
+		 * We can only have one tevent_fd
+		 * per low level tevent_context.
+		 *
+		 * This means any wrapper tevent_context
+		 * needs to share the structure with
+		 * the main tevent_context and/or
+		 * any sibling wrapper tevent_context.
+		 *
+		 * This means we need to use tevent_context_same_loop()
+		 * instead of just (fde_ev->ev == ev).
+		 *
+		 * Note: the tevent_context_is_wrapper() check below
+		 * makes sure that fde_ev->ev is always a raw
+		 * tevent context.
+		 */
+		if (tevent_context_same_loop(fde_ev->ev, ev)) {
 			break;
 		}
 	}
@@ -242,6 +251,17 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 	if (fde_ev == NULL) {
 		int sock = ctdbd_conn_get_fd(ctx->conn);
 
+		if (tevent_context_is_wrapper(ev)) {
+			/*
+			 * This is really a programmer error!
+			 *
+			 * The main/raw tevent context should
+			 * have been registered first!
+			 */
+			DBG_ERR("Should not be used with a wrapper tevent context\n");
+			return NULL;
+		}
+
 		fde_ev = talloc(fde, struct messaging_ctdb_fde_ev);
 		if (fde_ev == NULL) {
 			return NULL;
diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c
index 1c76615093c0..0ad8f46e09f1 100644
--- a/source3/lib/messages_dgm.c
+++ b/source3/lib/messages_dgm.c
@@ -1679,14 +1679,6 @@ struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
 		return NULL;
 	}
 
-	if (tevent_context_is_wrapper(ev)) {
-		/*
-		 * This is really a programmer error!
-		 */
-		DBG_ERR("Should not be used with a wrapper tevent context\n");
-		return NULL;
-	}
-
 	fde = talloc(mem_ctx, struct messaging_dgm_fde);
 	if (fde == NULL) {
 		return NULL;
@@ -1704,12 +1696,40 @@ struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
 			 */
 			continue;
 		}
-		if (fde_ev->ev == ev) {
+
+		/*
+		 * We can only have one tevent_fd
+		 * per low level tevent_context.
+		 *
+		 * This means any wrapper tevent_context
+		 * needs to share the structure with
+		 * the main tevent_context and/or
+		 * any sibling wrapper tevent_context.
+		 *
+		 * This means we need to use tevent_context_same_loop()
+		 * instead of just (fde_ev->ev == ev).
+		 *
+		 * Note: the tevent_context_is_wrapper() check below
+		 * makes sure that fde_ev->ev is always a raw
+		 * tevent context.
+		 */
+		if (tevent_context_same_loop(fde_ev->ev, ev)) {
 			break;
 		}
 	}
 
 	if (fde_ev == NULL) {
+		if (tevent_context_is_wrapper(ev)) {
+			/*
+			 * This is really a programmer error!
+			 *
+			 * The main/raw tevent context should
+			 * have been registered first!
+			 */
+			DBG_ERR("Should not be used with a wrapper tevent context\n");
+			return NULL;
+		}
+
 		fde_ev = talloc(fde, struct messaging_dgm_fde_ev);
 		if (fde_ev == NULL) {
 			return NULL;
-- 
2.17.1


From f0ceafb0bf04ea859d09460a03789ad56279d912 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 14:48:46 +0100
Subject: [PATCH 24/56] s3:messages: allow messaging_dgm_ref() to use wrapper
 tevent_context

This is only allowed if the raw tevent context is already registered.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/lib/messages_dgm_ref.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/source3/lib/messages_dgm_ref.c b/source3/lib/messages_dgm_ref.c
index a22077043651..8fb3bd612086 100644
--- a/source3/lib/messages_dgm_ref.c
+++ b/source3/lib/messages_dgm_ref.c
@@ -54,18 +54,6 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 {
 	struct msg_dgm_ref *result, *tmp_refs;
 
-	if (tevent_context_is_wrapper(ev)) {
-		/*
-		 * This is really a programmer error!
-		 *
-		 * The main/raw tevent context should
-		 * have been registered first!
-		 */
-		DBG_ERR("Should not be used with a wrapper tevent context\n");
-		*err = EINVAL;
-		return NULL;
-	}
-
 	result = talloc(mem_ctx, struct msg_dgm_ref);
 	if (result == NULL) {
 		*err = ENOMEM;
@@ -86,6 +74,18 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	if (refs == NULL) {
 		int ret;
 
+		if (tevent_context_is_wrapper(ev)) {
+			/*
+			 * This is really a programmer error!
+			 *
+			 * The main/raw tevent context should
+			 * have been registered first!
+			 */
+			DBG_ERR("Should not be used with a wrapper tevent context\n");
+			*err = EINVAL;
+			return NULL;
+		}
+
 		ret = messaging_dgm_init(ev, unique, socket_dir, lockfile_dir,
 					 msg_dgm_ref_recv, NULL);
 		DBG_DEBUG("messaging_dgm_init returned %s\n", strerror(ret));
-- 
2.17.1


From ac6d53fb8d6802b843b968a34e9c5dc765889d41 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 14:48:46 +0100
Subject: [PATCH 25/56] s3:messages: allow messaging_filtered_read_send() to
 use wrapper tevent_context

As it gets 'messaging_context' as argument, we're sure a messaging context
with a raw tevent context already exist.

It means we can allow a wrapper tevent context that wrapps the main tevent
context of the messaging context.

The use of tevent_req_defer_callback() makes sure that the callers
callback function calls messaging_filtered_read_recv() from the
correct "wrapped" environment.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/lib/messages.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 1a5ea4659aa4..dab53f1c48e3 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -206,7 +206,7 @@ static bool messaging_register_event_context(struct messaging_context *ctx,
 			continue;
 		}
 
-		if (reg->ev == ev) {
+		if (tevent_context_same_loop(reg->ev, ev)) {
 			reg->refcount += 1;
 			return true;
 		}
@@ -255,7 +255,7 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
 			continue;
 		}
 
-		if (reg->ev == ev) {
+		if (tevent_context_same_loop(reg->ev, ev)) {
 			reg->refcount -= 1;
 
 			if (reg->refcount == 0) {
@@ -1034,7 +1034,9 @@ struct tevent_req *messaging_filtered_read_send(
 	state->filter = filter;
 	state->private_data = private_data;
 
-	if (tevent_context_is_wrapper(ev)) {
+	if (tevent_context_is_wrapper(ev) &&
+	    !tevent_context_same_loop(ev, msg_ctx->event_ctx))
+	{
 		/* This is really a programmer error! */
 		DBG_ERR("Wrapper tevent context doesn't use main context.\n");
 		tevent_req_error(req, EINVAL);
@@ -1043,7 +1045,11 @@ struct tevent_req *messaging_filtered_read_send(
 
 	/*
 	 * We have to defer the callback here, as we might be called from
-	 * within a different tevent_context than state->ev
+	 * within a different tevent_context than state->ev.
+	 *
+	 * This is important for two cases:
+	 * 1. nested event contexts, used by blocking ctdb calls
+	 * 2. possible impersonation using wrapper tevent contexts.
 	 */
 	tevent_req_defer_callback(req, state->ev);
 
@@ -1339,7 +1345,7 @@ static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
 
 		state = tevent_req_data(
 			req, struct messaging_filtered_read_state);
-		if ((ev == state->ev) &&
+		if (tevent_context_same_loop(ev, state->ev) &&
 		    state->filter(rec, state->private_data)) {
 			messaging_filtered_read_done(req, rec);
 			return true;
-- 
2.17.1


From 5170cacfc8951dc69e8f788b4dd4912fc571fbb1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 19 May 2018 10:14:25 +0200
Subject: [PATCH 26/56] s4:messaging: allow imessaging_post_handler() to free
 the messaging context from a handler

In usecases like using messaging_client_init() with irpc processing we may
free the imessaging_context during the messaging handler.
imessaging_post_handler() is not yet really used, but it will change in
the next commits. imessaging_post_state is a child of imessaging_context
and might be implicitly free'ed before the explicit TALLOC_FREE(state).

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source4/lib/messaging/messaging.c | 33 +++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index b8d4e50f12c7..8903322bdc7f 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -433,18 +433,48 @@ fail:
 
 struct imessaging_post_state {
 	struct imessaging_context *msg_ctx;
+	struct imessaging_post_state **busy_ref;
 	size_t buf_len;
 	uint8_t buf[];
 };
 
+static int imessaging_post_state_destructor(struct imessaging_post_state *state)
+{
+	if (state->busy_ref != NULL) {
+		*state->busy_ref = NULL;
+		state->busy_ref = NULL;
+	}
+	return 0;
+}
+
 static void imessaging_post_handler(struct tevent_context *ev,
 				    struct tevent_immediate *ti,
 				    void *private_data)
 {
 	struct imessaging_post_state *state = talloc_get_type_abort(
 		private_data, struct imessaging_post_state);
+
+	/*
+	 * In usecases like using messaging_client_init() with irpc processing
+	 * we may free the imessaging_context during the messaging handler.
+	 * imessaging_post_state is a child of imessaging_context and
+	 * might be implicitly free'ed before the explicit TALLOC_FREE(state).
+	 *
+	 * The busy_ref pointer makes sure the destructor clears
+	 * the local 'state' variable.
+	 */
+
+	SMB_ASSERT(state->busy_ref == NULL);
+	state->busy_ref = &state;
+
 	imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
 			    state->msg_ctx);
+
+	if (state == NULL) {
+		return;
+	}
+
+	state->busy_ref = NULL;
 	TALLOC_FREE(state);
 }
 
@@ -461,6 +491,8 @@ static int imessaging_post_self(struct imessaging_context *msg,
 	}
 	talloc_set_name_const(state, "struct imessaging_post_state");
 
+	talloc_set_destructor(state, imessaging_post_state_destructor);
+
 	ti = tevent_create_immediate(state);
 	if (ti == NULL) {
 		TALLOC_FREE(state);
@@ -468,6 +500,7 @@ static int imessaging_post_self(struct imessaging_context *msg,
 	}
 
 	state->msg_ctx = msg;
+	state->busy_ref = NULL;
 	state->buf_len = buf_len;
 	memcpy(state->buf, buf, buf_len);
 
-- 
2.17.1


From 4dd21b64629a24509228378f00b7735252743a97 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 18 May 2018 16:28:47 +0200
Subject: [PATCH 27/56] s4:messaging: make sure only imessaging_client_init()
 can be used with a wrapper tevent_context wrapper

imessaging_client_init() can be used with a wrapper tevent_context,
but only if a global messaging_dgm_ref() already exist.

All other uses of imessaging_init() and imessaging_client_init()
require a raw tevent_context.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source4/lib/messaging/messaging.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index 8903322bdc7f..935951f3fbae 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -319,7 +319,7 @@ NTSTATUS imessaging_reinit_all(void)
 /*
   create the listening socket and setup the dispatcher
 */
-struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
+static struct imessaging_context *imessaging_init_internal(TALLOC_CTX *mem_ctx,
 					   struct loadparm_context *lp_ctx,
 					   struct server_id server_id,
 					   struct tevent_context *ev)
@@ -573,6 +573,30 @@ static void imessaging_dgm_recv(struct tevent_context *ev,
 	}
 }
 
+struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
+					   struct loadparm_context *lp_ctx,
+					   struct server_id server_id,
+					   struct tevent_context *ev)
+{
+	if (ev == NULL) {
+		return NULL;
+	}
+
+	if (tevent_context_is_wrapper(ev)) {
+		/*
+		 * This is really a programmer error!
+		 *
+		 * The main/raw tevent context should
+		 * have been registered first!
+		 */
+		DBG_ERR("Should not be used with a wrapper tevent context\n");
+		errno = EINVAL;
+		return NULL;
+	}
+
+	return imessaging_init_internal(mem_ctx, lp_ctx, server_id, ev);
+}
+
 /*
    A hack, for the short term until we get 'client only' messaging in place
 */
@@ -589,7 +613,7 @@ struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
 	/* This is because we are not in the s3 serverid database */
 	id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
 
-	return imessaging_init(mem_ctx, lp_ctx, id, ev);
+	return imessaging_init_internal(mem_ctx, lp_ctx, id, ev);
 }
 /*
   a list of registered irpc server functions
-- 
2.17.1


From 1f41588a2b4fd0a0f99671fb710261bb7d78216e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 28/56] vfs_default: maintain
 vfswrap_offload_write_state->{src_ev,dst_ev}

These get filled with impersonation wrappers in the following commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_default.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index baeb285eeb34..ede11ad34ed9 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1584,13 +1584,14 @@ static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
 }
 
 struct vfswrap_offload_write_state {
-	struct tevent_context *ev;
 	uint8_t *buf;
 	bool read_lck_locked;
 	bool write_lck_locked;
 	DATA_BLOB *token;
+	struct tevent_context *src_ev;
 	struct files_struct *src_fsp;
 	off_t src_off;
+	struct tevent_context *dst_ev;
 	struct files_struct *dst_fsp;
 	off_t dst_off;
 	off_t to_copy;
@@ -1641,9 +1642,9 @@ static struct tevent_req *vfswrap_offload_write_send(
 	}
 
 	*state = (struct vfswrap_offload_write_state) {
-		.ev = ev,
 		.token = token,
 		.src_off = transfer_offset,
+		.dst_ev = ev,
 		.dst_fsp = dest_fsp,
 		.dst_off = dest_off,
 		.to_copy = to_copy,
@@ -1685,7 +1686,6 @@ static struct tevent_req *vfswrap_offload_write_send(
 	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
 	}
-	state->src_fsp = src_fsp;
 
 	DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
 
@@ -1701,6 +1701,9 @@ static struct tevent_req *vfswrap_offload_write_send(
 		return tevent_req_post(req, ev);
 	}
 
+	state->src_ev = state->src_fsp->conn->sconn->ev_ctx;
+	state->src_fsp = src_fsp;
+
 	state->buf = talloc_array(state, uint8_t, num);
 	if (tevent_req_nomem(state->buf, req)) {
 		return tevent_req_post(req, ev);
@@ -1765,7 +1768,7 @@ static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
 	}
 
 	subreq = SMB_VFS_PREAD_SEND(state,
-				    state->src_fsp->conn->sconn->ev_ctx,
+				    state->src_ev,
 				    state->src_fsp,
 				    state->buf,
 				    state->next_io_size,
@@ -1829,7 +1832,7 @@ static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
 	}
 
 	subreq = SMB_VFS_PWRITE_SEND(state,
-				     state->ev,
+				     state->dst_ev,
 				     state->dst_fsp,
 				     state->buf,
 				     state->next_io_size,
-- 
2.17.1


From c055b6c300723f46fce6a57b43d58c66cd3dc0f0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 29/56] smbd: rename smbXsrv_client->ev_ctx into
 smbXsrv_client->raw_ev_ctx

That makes it clearer that no tevent_context wrapper is used here
and the related code should really run without any (active) impersonation
as before.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/librpc/idl/smbXsrv.idl |  2 +-
 source3/smbd/process.c         |  4 ++--
 source3/smbd/smbXsrv_client.c  | 18 +++++++++++-------
 source3/smbd/smbXsrv_session.c | 10 +++++++---
 4 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl
index 26758113af47..935c40842523 100644
--- a/source3/librpc/idl/smbXsrv.idl
+++ b/source3/librpc/idl/smbXsrv.idl
@@ -107,7 +107,7 @@ interface smbXsrv
 
 	typedef [public] struct {
 		[ignore] smbXsrv_client_table		*table;
-		[ignore] struct tevent_context		*ev_ctx;
+		[ignore] struct tevent_context		*raw_ev_ctx;
 		[ignore] struct messaging_context	*msg_ctx;
 
 		[ref] smbXsrv_client_global0		*global;
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 3041474ff62b..67105a18724f 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3695,7 +3695,7 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 	}
 	talloc_steal(frame, xconn);
 
-	xconn->ev_ctx = client->ev_ctx;
+	xconn->ev_ctx = client->raw_ev_ctx;
 	xconn->msg_ctx = client->msg_ctx;
 	xconn->transport.sock = sock_fd;
 	smbd_echo_init(xconn);
@@ -3846,7 +3846,7 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 	xconn->smb1.sessions.done_sesssetup = false;
 	xconn->smb1.sessions.max_send = SMB_BUFFER_SIZE_MAX;
 
-	xconn->transport.fde = tevent_add_fd(client->ev_ctx,
+	xconn->transport.fde = tevent_add_fd(client->raw_ev_ctx,
 					     xconn,
 					     sock_fd,
 					     TEVENT_FD_READ,
diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c
index 30cf25276bed..3e0a1d51e5ae 100644
--- a/source3/smbd/smbXsrv_client.c
+++ b/source3/smbd/smbXsrv_client.c
@@ -507,7 +507,7 @@ NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx,
 		TALLOC_FREE(table);
 		return NT_STATUS_NO_MEMORY;
 	}
-	client->ev_ctx = ev_ctx;
+	client->raw_ev_ctx = ev_ctx;
 	client->msg_ctx = msg_ctx;
 
 	client->server_multi_channel_enabled = lp_server_multi_channel_support();
@@ -543,9 +543,11 @@ NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx,
 		NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
 	}
 
-	subreq = messaging_filtered_read_send(client, client->ev_ctx, client->msg_ctx,
-					      smbXsrv_client_connection_pass_filter,
-					      client);
+	subreq = messaging_filtered_read_send(client,
+					client->raw_ev_ctx,
+					client->msg_ctx,
+					smbXsrv_client_connection_pass_filter,
+					client);
 	if (subreq == NULL) {
 		TALLOC_FREE(client);
 		return NT_STATUS_NO_MEMORY;
@@ -678,9 +680,11 @@ static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq)
 next:
 	TALLOC_FREE(rec);
 
-	subreq = messaging_filtered_read_send(client, client->ev_ctx, client->msg_ctx,
-					      smbXsrv_client_connection_pass_filter,
-					      client);
+	subreq = messaging_filtered_read_send(client,
+					client->raw_ev_ctx,
+					client->msg_ctx,
+					smbXsrv_client_connection_pass_filter,
+					client);
 	if (subreq == NULL) {
 		const char *r;
 		r = "messaging_read_send(MSG_SMBXSRV_CONNECTION_PASS failed";
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 121ff264a9cc..2c5b2ffe2fcd 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -258,7 +258,9 @@ static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
 
 	table->global.db_ctx = smbXsrv_session_global_db_ctx;
 
-	subreq = messaging_read_send(table, client->ev_ctx, client->msg_ctx,
+	subreq = messaging_read_send(table,
+				     client->raw_ev_ctx,
+				     client->msg_ctx,
 				     MSG_SMBXSRV_SESSION_CLOSE);
 	if (subreq == NULL) {
 		TALLOC_FREE(table);
@@ -376,7 +378,7 @@ static void smbXsrv_session_close_loop(struct tevent_req *subreq)
 		goto next;
 	}
 
-	subreq = smb2srv_session_shutdown_send(session, client->ev_ctx,
+	subreq = smb2srv_session_shutdown_send(session, client->raw_ev_ctx,
 					       session, NULL);
 	if (subreq == NULL) {
 		status = NT_STATUS_NO_MEMORY;
@@ -396,7 +398,9 @@ static void smbXsrv_session_close_loop(struct tevent_req *subreq)
 next:
 	TALLOC_FREE(rec);
 
-	subreq = messaging_read_send(table, client->ev_ctx, client->msg_ctx,
+	subreq = messaging_read_send(table,
+				     client->raw_ev_ctx,
+				     client->msg_ctx,
 				     MSG_SMBXSRV_SESSION_CLOSE);
 	if (subreq == NULL) {
 		const char *r;
-- 
2.17.1


From 831dd50baa88c45c967ed95f661826dd4f9afce9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 30/56] smbd: replace xconn->ev_ctx with
 xconn->client->raw_ev_ctx

This is the same pointer and we don't have a lot of callers,
so we can just use one pointer.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/globals.h     |  2 --
 source3/smbd/oplock.c      |  3 ++-
 source3/smbd/process.c     | 18 +++++++++++-------
 source3/smbd/smb2_server.c |  3 ++-
 4 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 09f87f90b1b1..6b6ee864ab8c 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -363,12 +363,10 @@ struct smbXsrv_connection {
 
 	struct smbXsrv_client *client;
 
-
 	const struct tsocket_address *local_address;
 	const struct tsocket_address *remote_address;
 	const char *remote_hostname;
 
-	struct tevent_context *ev_ctx;
 	struct messaging_context *msg_ctx;
 
 	enum protocol_types protocol;
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 0f95bb013984..6d37f35babe7 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -576,7 +576,8 @@ NTSTATUS downgrade_lease(struct smbXsrv_connection *xconn,
 			lck->data->modified = true;
 		}
 
-		tevent_schedule_immediate(state->im, xconn->ev_ctx,
+		tevent_schedule_immediate(state->im,
+					  xconn->client->raw_ev_ctx,
 					  downgrade_lease_additional_trigger,
 					  state);
 	}
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 67105a18724f..6c5ecb055572 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -2736,8 +2736,10 @@ static int release_ip(struct tevent_context *ev,
 		 * as we might be called from within ctdbd_migrate(),
 		 * we need to defer our action to the next event loop
 		 */
-		tevent_schedule_immediate(state->im, xconn->ev_ctx,
-					  smbd_release_ip_immediate, state);
+		tevent_schedule_immediate(state->im,
+					  xconn->client->raw_ev_ctx,
+					  smbd_release_ip_immediate,
+					  state);
 
 		/*
 		 * Make sure we don't get any io on the connection.
@@ -3386,14 +3388,16 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn)
 		close(listener_pipe[0]);
 		set_blocking(listener_pipe[1], false);
 
-		status = smbd_reinit_after_fork(xconn->msg_ctx, xconn->ev_ctx,
-						true, "smbd-echo");
+		status = smbd_reinit_after_fork(xconn->msg_ctx,
+						xconn->client->raw_ev_ctx,
+						true,
+						"smbd-echo");
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(1, ("reinit_after_fork failed: %s\n",
 				  nt_errstr(status)));
 			exit(1);
 		}
-		initialize_password_db(true, xconn->ev_ctx);
+		initialize_password_db(true, xconn->client->raw_ev_ctx);
 		smbd_echo_loop(xconn, listener_pipe[1]);
 		exit(0);
 	}
@@ -3407,7 +3411,8 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn)
 	 * Without smb signing this is the same as the normal smbd
 	 * listener. This needs to change once signing comes in.
 	 */
-	xconn->smb1.echo_handler.trusted_fde = tevent_add_fd(xconn->ev_ctx,
+	xconn->smb1.echo_handler.trusted_fde = tevent_add_fd(
+					xconn->client->raw_ev_ctx,
 					xconn,
 					xconn->smb1.echo_handler.trusted_fd,
 					TEVENT_FD_READ,
@@ -3695,7 +3700,6 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 	}
 	talloc_steal(frame, xconn);
 
-	xconn->ev_ctx = client->raw_ev_ctx;
 	xconn->msg_ctx = client->msg_ctx;
 	xconn->transport.sock = sock_fd;
 	smbd_echo_init(xconn);
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 3250bc438562..58cd6354028a 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -227,7 +227,8 @@ static NTSTATUS smbd_initialize_smb2(struct smbXsrv_connection *xconn,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	xconn->transport.fde = tevent_add_fd(xconn->ev_ctx,
+	xconn->transport.fde = tevent_add_fd(
+					xconn->client->raw_ev_ctx,
 					xconn,
 					xconn->transport.sock,
 					TEVENT_FD_READ,
-- 
2.17.1


From e6af4f780e9abdd2c323e27c170c1e2cffabe075 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 31/56] smbd: replace xconn->msg_ctx with
 xconn->client->msg_ctx

This is the same pointer and we don't have a lot of callers,
so we can just use one pointer.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/globals.h         | 2 --
 source3/smbd/process.c         | 3 +--
 source3/smbd/smbXsrv_client.c  | 2 +-
 source3/smbd/smbXsrv_open.c    | 4 ++--
 source3/smbd/smbXsrv_session.c | 4 ++--
 source3/smbd/smbXsrv_tcon.c    | 2 +-
 6 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 6b6ee864ab8c..54c931dce2d0 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -367,8 +367,6 @@ struct smbXsrv_connection {
 	const struct tsocket_address *remote_address;
 	const char *remote_hostname;
 
-	struct messaging_context *msg_ctx;
-
 	enum protocol_types protocol;
 
 	struct {
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 6c5ecb055572..ba8b7e43fb5e 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3388,7 +3388,7 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn)
 		close(listener_pipe[0]);
 		set_blocking(listener_pipe[1], false);
 
-		status = smbd_reinit_after_fork(xconn->msg_ctx,
+		status = smbd_reinit_after_fork(xconn->client->msg_ctx,
 						xconn->client->raw_ev_ctx,
 						true,
 						"smbd-echo");
@@ -3700,7 +3700,6 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 	}
 	talloc_steal(frame, xconn);
 
-	xconn->msg_ctx = client->msg_ctx;
 	xconn->transport.sock = sock_fd;
 	smbd_echo_init(xconn);
 	xconn->protocol = PROTOCOL_NONE;
diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c
index 3e0a1d51e5ae..4cae8c5287e2 100644
--- a/source3/smbd/smbXsrv_client.c
+++ b/source3/smbd/smbXsrv_client.c
@@ -345,7 +345,7 @@ NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req,
 	iov.iov_base = blob.data;
 	iov.iov_len = blob.length;
 
-	status = messaging_send_iov(smb2req->xconn->msg_ctx,
+	status = messaging_send_iov(smb2req->xconn->client->msg_ctx,
 				    global->server_id,
 				    MSG_SMBXSRV_CONNECTION_PASS,
 				    &iov, 1,
diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c
index 4ad0021cdf4f..2a2cf6973e7d 100644
--- a/source3/smbd/smbXsrv_open.c
+++ b/source3/smbd/smbXsrv_open.c
@@ -871,7 +871,7 @@ NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
 	global->open_persistent_id = global->open_global_id;
 	global->open_volatile_id = op->local_id;
 
-	global->server_id = messaging_server_id(conn->msg_ctx);
+	global->server_id = messaging_server_id(conn->client->msg_ctx);
 	global->open_time = now;
 	global->open_owner = *current_sid;
 	if (conn->protocol >= PROTOCOL_SMB2_10) {
@@ -1416,7 +1416,7 @@ NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
 	op->status = NT_STATUS_FILE_CLOSED;
 
 	op->global->open_volatile_id = op->local_id;
-	op->global->server_id = messaging_server_id(conn->msg_ctx);
+	op->global->server_id = messaging_server_id(conn->client->msg_ctx);
 
 	ptr = op;
 	val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 2c5b2ffe2fcd..3d8f0be06efa 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -1110,7 +1110,7 @@ static void smb2srv_session_close_previous_check(struct tevent_req *req)
 		return;
 	}
 
-	status = messaging_send(conn->msg_ctx,
+	status = messaging_send(conn->client->msg_ctx,
 				global->channels[0].server_id,
 				MSG_SMBXSRV_SESSION_CLOSE, &blob);
 	TALLOC_FREE(state->db_rec);
@@ -1362,7 +1362,7 @@ NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session,
 	c = &global->channels[global->num_channels];
 	ZERO_STRUCTP(c);
 
-	c->server_id = messaging_server_id(conn->msg_ctx);
+	c->server_id = messaging_server_id(conn->client->msg_ctx);
 	c->local_address = tsocket_address_string(conn->local_address,
 						  global->channels);
 	if (c->local_address == NULL) {
diff --git a/source3/smbd/smbXsrv_tcon.c b/source3/smbd/smbXsrv_tcon.c
index 5ad557e1f5e6..627eeb166d9a 100644
--- a/source3/smbd/smbXsrv_tcon.c
+++ b/source3/smbd/smbXsrv_tcon.c
@@ -1095,7 +1095,7 @@ NTSTATUS smb1srv_tcon_create(struct smbXsrv_connection *conn,
 			     NTTIME now,
 			     struct smbXsrv_tcon **_tcon)
 {
-	struct server_id id = messaging_server_id(conn->msg_ctx);
+	struct server_id id = messaging_server_id(conn->client->msg_ctx);
 
 	return smbXsrv_tcon_create(conn->client->tcon_table,
 				   conn->protocol,
-- 
2.17.1


From 8d25509b4b07951c7659e2a6607d71c5fe64504b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 24 May 2018 07:18:10 +0200
Subject: [PATCH 32/56] smbd: remove unused tevent_context argument from
 notify_init

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/notify.c     | 2 +-
 source3/smbd/notify_msg.c | 1 -
 source3/smbd/proto.h      | 1 -
 source3/smbd/service.c    | 2 +-
 source3/utils/status.c    | 1 -
 5 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index add59089187e..44c0b09432e7 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -539,7 +539,7 @@ void smbd_notifyd_restarted(struct messaging_context *msg,
 
 	TALLOC_FREE(sconn->notify_ctx);
 
-	sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx, sconn->ev_ctx,
+	sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx,
 					sconn, notify_callback);
 	if (sconn->notify_ctx == NULL) {
 		DBG_DEBUG("notify_init failed\n");
diff --git a/source3/smbd/notify_msg.c b/source3/smbd/notify_msg.c
index 3787df74bfd0..ff38b964914f 100644
--- a/source3/smbd/notify_msg.c
+++ b/source3/smbd/notify_msg.c
@@ -48,7 +48,6 @@ static int notify_context_destructor(struct notify_context *ctx);
 
 struct notify_context *notify_init(
 	TALLOC_CTX *mem_ctx, struct messaging_context *msg,
-	struct tevent_context *ev,
 	struct smbd_server_connection *sconn,
 	void (*callback)(struct smbd_server_connection *sconn,
 			 void *, struct timespec,
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index f9f29230162c..ab4a8d68d3f1 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -586,7 +586,6 @@ int fam_watch(TALLOC_CTX *mem_ctx,
 
 struct notify_context *notify_init(
 	TALLOC_CTX *mem_ctx, struct messaging_context *msg,
-	struct tevent_context *ev,
 	struct smbd_server_connection *sconn,
 	void (*callback)(struct smbd_server_connection *sconn,
 			 void *, struct timespec,
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index a22a0270cd79..a928de6c78f0 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -458,7 +458,7 @@ static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
 		return NT_STATUS_OK;
 	}
 
-	sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx, sconn->ev_ctx,
+	sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx,
 					sconn, notify_callback);
 	if (sconn->notify_ctx == NULL) {
 		return NT_STATUS_NO_MEMORY;
diff --git a/source3/utils/status.c b/source3/utils/status.c
index 6370f7002e8b..d04efedee3f6 100644
--- a/source3/utils/status.c
+++ b/source3/utils/status.c
@@ -735,7 +735,6 @@ int main(int argc, const char *argv[])
 		struct notify_context *n;
 
 		n = notify_init(talloc_tos(), msg_ctx,
-				messaging_tevent_context(msg_ctx),
 				NULL, NULL);
 		if (n == NULL) {
 			goto done;
-- 
2.17.1


From 8325877c8ebdc8565a44cf5d9eeb7becab6f9497 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 33/56] s3:smb2_server: use req->xconn->client->raw_ev_ctx for
 smbd_smb2_request_pending_timer()

There's no need to use req->ev_ctx here just to do some network io.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_server.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 58cd6354028a..99668980ad5e 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -1482,8 +1482,14 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 		data_blob_clear_free(&req->last_key);
 	}
 
+	/*
+	 * smbd_smb2_request_pending_timer() just send a packet
+	 * to the client and doesn't need any impersonation.
+	 * So we use req->xconn->client->raw_ev_ctx instead
+	 * of req->ev_ctx here.
+	 */
 	defer_endtime = timeval_current_ofs_usec(defer_time);
-	req->async_te = tevent_add_timer(req->sconn->ev_ctx,
+	req->async_te = tevent_add_timer(req->xconn->client->raw_ev_ctx,
 					 req, defer_endtime,
 					 smbd_smb2_request_pending_timer,
 					 req);
-- 
2.17.1


From dd872a77ae9801061c73d4c1952a32d23c60abc1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 34/56] s3:smb2_server: use req->xconn->client->raw_ev_ctx for
 smbd_smb2_request_dispatch_immediate()

smbd_smb2_request_dispatch() will redo the impersonation anyway,
so we don't use req->ev_ctx.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_server.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 99668980ad5e..697e3ac9562c 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2922,8 +2922,13 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
 			}
 		}
 
+		/*
+		 * smbd_smb2_request_dispatch() will redo the impersonation.
+		 * So we use req->xconn->client->raw_ev_ctx instead
+		 * of req->ev_ctx here.
+		 */
 		tevent_schedule_immediate(im,
-					req->sconn->ev_ctx,
+					req->xconn->client->raw_ev_ctx,
 					smbd_smb2_request_dispatch_immediate,
 					req);
 		return NT_STATUS_OK;
-- 
2.17.1


From 7b76001a660782aa3322c6eb97bbb5967bed892c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 35/56] smbd: use req->xconn->client->raw_ev_ctx for
 schedule_deferred_open_message_smb()

process_smb() will redo the impersonation anyway.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/process.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index ba8b7e43fb5e..8cc44c33983f 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -822,7 +822,14 @@ bool schedule_deferred_open_message_smb(struct smbXsrv_connection *xconn,
 				"scheduling mid %llu\n",
 				(unsigned long long)mid ));
 
-			te = tevent_add_timer(pml->sconn->ev_ctx,
+			/*
+			 * smbd_deferred_open_timer() calls
+			 * process_smb() to redispatch the request
+			 * including the required impersonation.
+			 *
+			 * So we can just use the raw tevent_context.
+			 */
+			te = tevent_add_timer(xconn->client->raw_ev_ctx,
 					      pml,
 					      timeval_zero(),
 					      smbd_deferred_open_timer,
-- 
2.17.1


From f6cf280d69011250aa55adba477e9e609415008b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 36/56] smbd: add smbd_server_connection->raw_ev_ctx pointer

This will replace smbd_server_connection->ev_ctx in the next commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/globals.h | 1 +
 source3/smbd/msdfs.c   | 5 +++--
 source3/smbd/process.c | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 54c931dce2d0..13e36702d0f5 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -872,6 +872,7 @@ struct smbd_server_connection {
 	const struct tsocket_address *remote_address;
 	const char *remote_hostname;
 	struct tevent_context *ev_ctx;
+	struct tevent_context *raw_ev_ctx;
 	struct messaging_context *msg_ctx;
 	struct notify_context *notify_ctx;
 	bool using_smb2;
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index a143e6d23cac..07a871ae3399 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -257,12 +257,13 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	sconn->ev_ctx = samba_tevent_context_init(sconn);
-	if (sconn->ev_ctx == NULL) {
+	sconn->raw_ev_ctx = samba_tevent_context_init(sconn);
+	if (sconn->raw_ev_ctx == NULL) {
 		TALLOC_FREE(sconn);
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	sconn->ev_ctx = sconn->raw_ev_ctx;
 	sconn->msg_ctx = msg;
 
 	conn = conn_new(sconn);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 8cc44c33983f..332b607e93f7 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3922,6 +3922,7 @@ void smbd_process(struct tevent_context *ev_ctx,
 	sconn->client = client;
 
 	sconn->ev_ctx = ev_ctx;
+	sconn->raw_ev_ctx = ev_ctx;
 	sconn->msg_ctx = msg_ctx;
 
 	ret = pthreadpool_tevent_init(sconn, lp_aio_max_threads(),
-- 
2.17.1


From b1e95aa68aa6cb66f9120c794749293d04c96f20 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 37/56] vfs_glusterfs: explain that/why we use the raw
 tevent_context in init_gluster_aio()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_glusterfs.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
index c2af793016f2..02289a64e505 100644
--- a/source3/modules/vfs_glusterfs.c
+++ b/source3/modules/vfs_glusterfs.c
@@ -729,7 +729,16 @@ static bool init_gluster_aio(struct vfs_handle_struct *handle)
 	read_fd = fds[0];
 	write_fd = fds[1];
 
-	aio_read_event = tevent_add_fd(handle->conn->sconn->ev_ctx,
+	/*
+	 * We use the raw tevent context here,
+	 * as this is a global event handler.
+	 *
+	 * The tevent_req_defer_callback()
+	 * calls will make sure the results
+	 * of async calls are propagated
+	 * to the correct tevent_context.
+	 */
+	aio_read_event = tevent_add_fd(handle->conn->sconn->raw_ev_ctx,
 					NULL,
 					read_fd,
 					TEVENT_FD_READ,
-- 
2.17.1


From ec4c263bd7daeab0f481c25ef8d0bc80d60bef93 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 38/56] smbd: explain that/why we use the raw tevent_context
 for update_write_time_handler()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/fileio.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index cde6a057ccda..1fe806e058d2 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -232,9 +232,17 @@ void trigger_write_time_update(struct files_struct *fsp)
 	DEBUG(5, ("Update write time %d usec later on %s\n",
 		  delay, fsp_str_dbg(fsp)));
 
-	/* trigger the update 2 seconds later */
+	/*
+	 * trigger the update 2 seconds later
+	 *
+	 * Note that update_write_time_handler()
+	 * => fsp_flush_write_time_update()
+	 * won't do any SMB_VFS calls and don't
+	 * need impersonation. So we use the
+	 * raw event context for this.
+	 */
 	fsp->update_write_time_event =
-		tevent_add_timer(fsp->conn->sconn->ev_ctx, NULL,
+		tevent_add_timer(fsp->conn->sconn->raw_ev_ctx, NULL,
 				 timeval_current_ofs_usec(delay),
 				 update_write_time_handler, fsp);
 }
-- 
2.17.1


From 1bfe46fce70fd5a42dd83d6f6dbf64f2dad20958 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 39/56] smbd: explain that/why we use the raw tevent_context
 for lease_timeout_handler()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/oplock.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 6d37f35babe7..b13aae888202 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -338,6 +338,11 @@ static void lease_timeout_handler(struct tevent_context *ctx,
 	struct share_mode_lock *lck;
 	uint16_t old_epoch = lease->lease.lease_epoch;
 
+	/*
+	 * This function runs without any specific impersonation
+	 * and must not call any SMB_VFS operations!
+	 */
+
 	fsp = file_find_one_fsp_from_lease_key(lease->sconn,
 					       &lease->lease.lease_key);
 	if (fsp == NULL) {
@@ -429,7 +434,12 @@ bool fsp_lease_update(struct share_mode_lock *lck,
 
 			DEBUG(10,("%s: setup timeout handler\n", __func__));
 
-			lease->timeout = tevent_add_timer(lease->sconn->ev_ctx,
+			/*
+			 * lease_timeout_handler() only accesses locking.tdb
+			 * so we don't use any impersonation and use
+			 * the raw tevent context.
+			 */
+			lease->timeout = tevent_add_timer(lease->sconn->raw_ev_ctx,
 							  lease, t,
 							  lease_timeout_handler,
 							  lease);
-- 
2.17.1


From a4f225e8d2c4916c434eb72b1e31cbda2bc99700 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 40/56] smbd: explain that/why we use the raw tevent_context
 for oplock_timeout_handler()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/oplock.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index b13aae888202..f7654176a880 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -727,6 +727,11 @@ static void oplock_timeout_handler(struct tevent_context *ctx,
 {
 	files_struct *fsp = (files_struct *)private_data;
 
+	/*
+	 * Note this function doesn't run under any specific impersonation and
+	 * is not expected to call any SMB_VFS operation!
+	 */
+
 	SMB_ASSERT(fsp->sent_oplock_break != NO_BREAK_SENT);
 
 	/* Remove the timed event handler. */
@@ -761,8 +766,15 @@ static void add_oplock_timeout_handler(files_struct *fsp)
 			  "around\n"));
 	}
 
+	/*
+	 * For now we keep the logic and use the
+	 * raw event context. We're called from
+	 * the messaging system from a raw event context.
+	 * Also oplock_timeout_handler doesn't invoke
+	 * SMB_VFS calls.
+	 */
 	fsp->oplock_timeout =
-		tevent_add_timer(fsp->conn->sconn->ev_ctx, fsp,
+		tevent_add_timer(fsp->conn->sconn->raw_ev_ctx, fsp,
 				 timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
 				 oplock_timeout_handler, fsp);
 
-- 
2.17.1


From d06e5e53a4725a464284594b47e3aa2b5cb26975 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 41/56] smbd: explain that/why we use the raw tevent_context
 for do_break_to_none()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/oplock.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index f7654176a880..34bebc61f7a7 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -1150,7 +1150,15 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 		TALLOC_FREE(state);
 		return;
 	}
-	tevent_schedule_immediate(im, sconn->ev_ctx, do_break_to_none, state);
+
+	/*
+	 * do_break_to_none() only operates on the
+	 * locking.tdb and send network packets to
+	 * the client. That doesn't require any
+	 * impersonation, so we just use the
+	 * raw tevent context here.
+	 */
+	tevent_schedule_immediate(im, sconn->raw_ev_ctx, do_break_to_none, state);
 }
 
 static void send_break_to_none(struct messaging_context *msg_ctx,
@@ -1177,6 +1185,11 @@ static void do_break_to_none(struct tevent_context *ctx,
 	struct share_mode_lock *lck;
 	struct share_mode_data *d;
 
+	/*
+	 * Note this function doesn't run under any specific impersonation and
+	 * is not expected to call any SMB_VFS operation!
+	 */
+
 	lck = get_existing_share_mode_lock(talloc_tos(), state->id);
 	if (lck == NULL) {
 		DEBUG(1, ("%s: failed to lock share mode entry for file %s.\n",
-- 
2.17.1


From 530ba4f27db4ff77962b06ec54ac08ca1cbd05f7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 42/56] smbd: explain that/why we use the raw tevent_context
 for linux_oplock_signal_handler()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/oplock_linux.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index dd772bf6cb5b..7d1f0404512b 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -125,6 +125,12 @@ static void linux_oplock_signal_handler(struct tevent_context *ev_ctx,
 	int fd = info->si_fd;
 	files_struct *fsp;
 
+	/*
+	 * This function doesn't expect any specific impersonation, as it only
+	 * sends messages to other smbd processes. And messaging_send_iov_from()
+	 * already handles EACCES.
+	 */
+
 	fsp = file_find_fd(sconn, fd);
 	if (fsp == NULL) {
 		DEBUG(0,("linux_oplock_signal_handler: failed to find fsp for file fd=%d (file was closed ?)\n", fd ));
@@ -237,7 +243,13 @@ struct kernel_oplocks *linux_init_kernel_oplocks(struct smbd_server_connection *
 	ctx->ops = &linux_koplocks;
 	ctx->private_data = sconn;
 
-	se = tevent_add_signal(sconn->ev_ctx,
+	/*
+	 * linux_oplock_signal_handler() only
+	 * sends messages to other smbd processes
+	 * and doesn't require any impersonation.
+	 * So we can just use the raw tevent_context.
+	 */
+	se = tevent_add_signal(sconn->raw_ev_ctx,
 			       ctx,
 			       RT_SIGNAL_LEASE, SA_SIGINFO,
 			       linux_oplock_signal_handler,
-- 
2.17.1


From 50fa0005c485e5b1db9ec80f6a0c751c42c057db Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 43/56] smbd: use raw_ev_ctx to clear the MSG_SMB_CONF_UPDATED
 registration

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

diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 332b607e93f7..515c0299f0ec 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -4061,7 +4061,7 @@ void smbd_process(struct tevent_context *ev_ctx,
 			   ID_CACHE_KILL, smbd_id_cache_kill);
 
 	messaging_deregister(sconn->msg_ctx,
-			     MSG_SMB_CONF_UPDATED, sconn->ev_ctx);
+			     MSG_SMB_CONF_UPDATED, sconn->raw_ev_ctx);
 	messaging_register(sconn->msg_ctx, sconn,
 			   MSG_SMB_CONF_UPDATED, smbd_conf_updated);
 
-- 
2.17.1


From b08d2e051b5a62c694b09358446823abd72c058d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 44/56] smbd: add smbd_server_connection->{root,guest}_ev_ctx
 pointer

For now these are just the same as smbd_server_connection->ev_ctx,
but this will change in future and we'll use impersonation wrappers.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/globals.h | 2 ++
 source3/smbd/msdfs.c   | 2 ++
 source3/smbd/process.c | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 13e36702d0f5..c6195ed82e6e 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -873,6 +873,8 @@ struct smbd_server_connection {
 	const char *remote_hostname;
 	struct tevent_context *ev_ctx;
 	struct tevent_context *raw_ev_ctx;
+	struct tevent_context *root_ev_ctx;
+	struct tevent_context *guest_ev_ctx;
 	struct messaging_context *msg_ctx;
 	struct notify_context *notify_ctx;
 	bool using_smb2;
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index 07a871ae3399..c2d73160cf83 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -264,6 +264,8 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
 	}
 
 	sconn->ev_ctx = sconn->raw_ev_ctx;
+	sconn->root_ev_ctx = sconn->raw_ev_ctx;
+	sconn->guest_ev_ctx = sconn->raw_ev_ctx;
 	sconn->msg_ctx = msg;
 
 	conn = conn_new(sconn);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 515c0299f0ec..97fa29534dcd 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3923,6 +3923,8 @@ void smbd_process(struct tevent_context *ev_ctx,
 
 	sconn->ev_ctx = ev_ctx;
 	sconn->raw_ev_ctx = ev_ctx;
+	sconn->root_ev_ctx = ev_ctx;
+	sconn->guest_ev_ctx = ev_ctx;
 	sconn->msg_ctx = msg_ctx;
 
 	ret = pthreadpool_tevent_init(sconn, lp_aio_max_threads(),
-- 
2.17.1


From 5b30c569a6eb854901a74229d6afd91210bd5ed7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 45/56] smbd: use sconn->root_ev_ctx for brl_timeout_fn()

This already calls change_to_root_user(), which can be removed
later.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/blocking.c  | 6 +++++-
 source3/smbd/smb2_lock.c | 6 +++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 6cbf5c03e932..c281aae619de 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -135,7 +135,11 @@ static bool recalc_brl_timeout(struct smbd_server_connection *sconn)
 		    (int)from_now.tv_sec, (int)from_now.tv_usec));
 	}
 
-	sconn->smb1.locks.brl_timeout = tevent_add_timer(sconn->ev_ctx,
+	/*
+	 * brl_timeout_fn() calls change_to_root_user()
+	 * so we can use sconn->root_ev_ctx.
+	 */
+	sconn->smb1.locks.brl_timeout = tevent_add_timer(sconn->root_ev_ctx,
 							 NULL, next_timeout,
 							 brl_timeout_fn, sconn);
 	if (sconn->smb1.locks.brl_timeout == NULL) {
diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c
index a05470e52e4a..3cc591089a42 100644
--- a/source3/smbd/smb2_lock.c
+++ b/source3/smbd/smb2_lock.c
@@ -568,8 +568,12 @@ static bool recalc_smb2_brl_timeout(struct smbd_server_connection *sconn)
 			(int)from_now.tv_sec, (int)from_now.tv_usec));
 	}
 
+	/*
+	 * brl_timeout_fn() calls change_to_root_user()
+	 * so we can use sconn->root_ev_ctx.
+	 */
 	sconn->smb2.locks.brl_timeout = tevent_add_timer(
-				sconn->ev_ctx,
+				sconn->root_ev_ctx,
 				NULL,
 				next_timeout,
 				brl_timeout_fn,
-- 
2.17.1


From 6047d28b1ccb2c0089df8fbbe159447e1fbddf61 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 46/56] smbd: use sconn->root_ev_ctx for
 smbd_sig_{term,hup}_handler()

They already call change_to_root_user(), which can be removed
later.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 97fa29534dcd..1559d1f7270b 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -977,7 +977,7 @@ static void smbd_setup_sig_term_handler(struct smbd_server_connection *sconn)
 {
 	struct tevent_signal *se;
 
-	se = tevent_add_signal(sconn->ev_ctx,
+	se = tevent_add_signal(sconn->root_ev_ctx,
 			       sconn,
 			       SIGTERM, 0,
 			       smbd_sig_term_handler,
@@ -1007,7 +1007,7 @@ static void smbd_setup_sig_hup_handler(struct smbd_server_connection *sconn)
 {
 	struct tevent_signal *se;
 
-	se = tevent_add_signal(sconn->ev_ctx,
+	se = tevent_add_signal(sconn->root_ev_ctx,
 			       sconn,
 			       SIGHUP, 0,
 			       smbd_sig_hup_handler,
-- 
2.17.1


From 7ee8240f8d342d57a2fefe872a172011693159b2 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 47/56] smbd: add an effective connection_struct->user_ev_ctx
 that holds the event context used for the current user

This will be filled with an impersonation wrapper in the next commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/include/vfs.h             | 2 ++
 source3/modules/vfs_aio_pthread.c | 2 +-
 source3/modules/vfs_default.c     | 2 +-
 source3/modules/vfs_readonly.c    | 1 +
 source3/smbd/conn.c               | 7 +++++++
 source3/smbd/msdfs.c              | 2 ++
 source3/smbd/uid.c                | 6 ++++++
 7 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 54ab1604b799..249cf0697792 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -398,6 +398,7 @@ typedef struct files_struct {
 
 struct vuid_cache_entry {
 	struct auth_session_info *session_info;
+	struct tevent_context *user_ev_ctx;
 	uint64_t vuid; /* SMB2 compat */
 	bool read_only;
 	uint32_t share_access;
@@ -445,6 +446,7 @@ typedef struct connection_struct {
 	 * on the vuid using this tid, this might change per SMB request.
 	 */
 	struct auth_session_info *session_info;
+	struct tevent_context *user_ev_ctx;
 
 	/*
 	 * If the "force group" parameter is set, this is the primary gid that
diff --git a/source3/modules/vfs_aio_pthread.c b/source3/modules/vfs_aio_pthread.c
index 88794bb7acc7..a9e2b09827bd 100644
--- a/source3/modules/vfs_aio_pthread.c
+++ b/source3/modules/vfs_aio_pthread.c
@@ -276,7 +276,7 @@ static int open_async(const files_struct *fsp,
 	}
 
 	subreq = pthreadpool_tevent_job_send(opd,
-					     fsp->conn->sconn->ev_ctx,
+					     fsp->conn->user_ev_ctx,
 					     fsp->conn->sconn->pool,
 					     aio_open_worker, opd);
 	if (subreq == NULL) {
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index ede11ad34ed9..082b70f5a98e 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1701,7 +1701,7 @@ static struct tevent_req *vfswrap_offload_write_send(
 		return tevent_req_post(req, ev);
 	}
 
-	state->src_ev = state->src_fsp->conn->sconn->ev_ctx;
+	state->src_ev = src_fsp->conn->user_ev_ctx;
 	state->src_fsp = src_fsp;
 
 	state->buf = talloc_array(state, uint8_t, num);
diff --git a/source3/modules/vfs_readonly.c b/source3/modules/vfs_readonly.c
index cde8ef973ca1..570eb7c4d15a 100644
--- a/source3/modules/vfs_readonly.c
+++ b/source3/modules/vfs_readonly.c
@@ -84,6 +84,7 @@ static int readonly_connect(vfs_handle_struct *handle,
       for (i=0; i< VUID_CACHE_SIZE; i++) {
         struct vuid_cache_entry *ent = &conn->vuid_cache->array[i];
         ent->vuid = UID_FIELD_INVALID;
+        ent->user_ev_ctx = NULL;
         TALLOC_FREE(ent->session_info);
         ent->read_only = false;
         ent->share_access = 0;
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index 8f472c0d2458..3b9aaac7834b 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -94,6 +94,12 @@ static void conn_clear_vuid_cache(connection_struct *conn, uint64_t vuid)
 
 		if (ent->vuid == vuid) {
 			ent->vuid = UID_FIELD_INVALID;
+
+			if (conn->user_ev_ctx == ent->user_ev_ctx) {
+				conn->user_ev_ctx = NULL;
+			}
+			ent->user_ev_ctx = NULL;
+
 			/*
 			 * We need to keep conn->session_info around
 			 * if it's equal to ent->session_info as a SMBulogoff
@@ -117,6 +123,7 @@ static void conn_clear_vuid_cache(connection_struct *conn, uint64_t vuid)
 			} else {
 				TALLOC_FREE(ent->session_info);
 			}
+
 			ent->read_only = False;
 			ent->share_access = 0;
 		}
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index c2d73160cf83..eaecf13e23d8 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -314,6 +314,8 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
 		vfs_user = get_current_username();
 	}
 
+	conn->user_ev_ctx = sconn->raw_ev_ctx;
+
 	set_conn_connectpath(conn, connpath);
 
 	/*
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index aa6994ac53d0..69a2bb0f2e32 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -76,6 +76,7 @@ static void free_conn_session_info_if_unused(connection_struct *conn)
 		}
 	}
 	/* Not used, safe to free. */
+	conn->user_ev_ctx = NULL;
 	TALLOC_FREE(conn->session_info);
 }
 
@@ -201,6 +202,7 @@ static bool check_user_ok(connection_struct *conn,
 			}
 			free_conn_session_info_if_unused(conn);
 			conn->session_info = ent->session_info;
+			conn->user_ev_ctx = ent->user_ev_ctx;
 			conn->read_only = ent->read_only;
 			conn->share_access = ent->share_access;
 			conn->vuid = ent->vuid;
@@ -249,6 +251,8 @@ static bool check_user_ok(connection_struct *conn,
 		ent->session_info->unix_token->uid = sec_initial_uid();
 	}
 
+	ent->user_ev_ctx = conn->sconn->raw_ev_ctx;
+
 	/*
 	 * It's actually OK to call check_user_ok() with
 	 * vuid == UID_FIELD_INVALID as called from change_to_user_by_session().
@@ -261,6 +265,7 @@ static bool check_user_ok(connection_struct *conn,
 	free_conn_session_info_if_unused(conn);
 	conn->session_info = ent->session_info;
 	conn->vuid = ent->vuid;
+	conn->user_ev_ctx = ent->user_ev_ctx;
 	if (vuid == UID_FIELD_INVALID) {
 		/*
 		 * Not strictly needed, just make it really
@@ -269,6 +274,7 @@ static bool check_user_ok(connection_struct *conn,
 		ent->read_only = false;
 		ent->share_access = 0;
 		ent->session_info = NULL;
+		ent->user_ev_ctx = NULL;
 	}
 
 	conn->read_only = readonly_share;
-- 
2.17.1


From d5069794035f65256907d97644b7499a11cb7230 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 48/56] smbd: add an effective {smb,smbd_smb2}_request->ev_ctx
 that holds the event context used for the request processing

In future this will an impersonation wrapper tevent_context based on the
user session.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/include/vfs.h                | 2 ++
 source3/smbd/aio.c                   | 8 ++++----
 source3/smbd/globals.h               | 3 +++
 source3/smbd/ipc.c                   | 4 ++--
 source3/smbd/open.c                  | 8 ++++----
 source3/smbd/pipes.c                 | 8 ++++----
 source3/smbd/process.c               | 8 ++++++++
 source3/smbd/reply.c                 | 2 +-
 source3/smbd/smb2_break.c            | 4 ++--
 source3/smbd/smb2_close.c            | 2 +-
 source3/smbd/smb2_create.c           | 6 +++---
 source3/smbd/smb2_flush.c            | 2 +-
 source3/smbd/smb2_getinfo.c          | 2 +-
 source3/smbd/smb2_glue.c             | 1 +
 source3/smbd/smb2_ioctl.c            | 2 +-
 source3/smbd/smb2_ioctl_named_pipe.c | 2 +-
 source3/smbd/smb2_lock.c             | 4 ++--
 source3/smbd/smb2_notify.c           | 4 ++--
 source3/smbd/smb2_query_directory.c  | 2 +-
 source3/smbd/smb2_read.c             | 2 +-
 source3/smbd/smb2_server.c           | 2 ++
 source3/smbd/smb2_sesssetup.c        | 4 ++--
 source3/smbd/smb2_setinfo.c          | 2 +-
 source3/smbd/smb2_tcon.c             | 4 ++--
 source3/smbd/smb2_write.c            | 2 +-
 25 files changed, 53 insertions(+), 37 deletions(-)

diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 249cf0697792..4e5b78709034 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -514,6 +514,8 @@ struct smb_request {
 
 	size_t unread_bytes;
 	bool encrypted;
+	/* the tevent_context (wrapper) the request operates on */
+	struct tevent_context *ev_ctx;
 	connection_struct *conn;
 	struct smbd_server_connection *sconn;
 	struct smbXsrv_connection *xconn;
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index b984036e9f8e..c066ea1a9788 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -206,7 +206,7 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
 	aio_ex->nbyte = smb_maxcnt;
 	aio_ex->offset = startpos;
 
-	req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx,
+	req = SMB_VFS_PREAD_SEND(aio_ex, smbreq->ev_ctx,
 				 fsp,
 				 smb_buf(aio_ex->outbuf.data) + 1 /* pad */,
 				 smb_maxcnt, startpos);
@@ -459,7 +459,7 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
 	aio_ex->nbyte = numtowrite;
 	aio_ex->offset = startpos;
 
-	req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
+	req = pwrite_fsync_send(aio_ex, smbreq->ev_ctx, fsp,
 				data, numtowrite, startpos,
 				aio_ex->write_through);
 	if (req == NULL) {
@@ -701,7 +701,7 @@ NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
 	aio_ex->nbyte = smb_maxcnt;
 	aio_ex->offset = startpos;
 
-	req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
+	req = SMB_VFS_PREAD_SEND(aio_ex, smbreq->ev_ctx, fsp,
 				 preadbuf->data, smb_maxcnt, startpos);
 	if (req == NULL) {
 		DEBUG(0, ("smb2: SMB_VFS_PREAD_SEND failed. "
@@ -850,7 +850,7 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
 	aio_ex->nbyte = in_data.length;
 	aio_ex->offset = in_offset;
 
-	req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
+	req = pwrite_fsync_send(aio_ex, smbreq->ev_ctx, fsp,
 				in_data.data, in_data.length, in_offset,
 				write_through);
 	if (req == NULL) {
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index c6195ed82e6e..d43e5bdfdcb0 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -700,6 +700,9 @@ struct smbd_smb2_request {
 	struct smbXsrv_tcon *tcon;
 	uint32_t last_tid;
 
+	/* the tevent_context (wrapper) the request operates on */
+	struct tevent_context *ev_ctx;
+
 	int current_idx;
 	bool do_signing;
 	/* Was the request encrypted? */
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index f1c8ea0c2ed4..85236e0102f2 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -281,7 +281,7 @@ static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
 	state->num_data = length;
 	state->max_read = max_read;
 
-	subreq = np_write_send(state, req->sconn->ev_ctx, state->handle,
+	subreq = np_write_send(state, req->ev_ctx, state->handle,
 			       state->data, length);
 	if (subreq == NULL) {
 		TALLOC_FREE(state);
@@ -330,7 +330,7 @@ static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
 		goto send;
 	}
 
-	subreq = np_read_send(state, req->sconn->ev_ctx,
+	subreq = np_read_send(state, req->ev_ctx,
 			      state->handle, state->data, state->max_read);
 	if (subreq == NULL) {
 		reply_nterror(req, NT_STATUS_NO_MEMORY);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 4b28e7ff9a26..db5eb4e459b6 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -2408,7 +2408,7 @@ static void defer_open(struct share_mode_lock *lck,
 	DBG_DEBUG("defering mid %" PRIu64 "\n", req->mid);
 
 	watch_req = dbwrap_watched_watch_send(watch_state,
-					      req->sconn->ev_ctx,
+					      req->ev_ctx,
 					      lck->data->record,
 					      (struct server_id){0});
 	if (watch_req == NULL) {
@@ -2416,7 +2416,7 @@ static void defer_open(struct share_mode_lock *lck,
 	}
 	tevent_req_set_callback(watch_req, defer_open_done, watch_state);
 
-	ok = tevent_req_set_endtime(watch_req, req->sconn->ev_ctx, abs_timeout);
+	ok = tevent_req_set_endtime(watch_req, req->ev_ctx, abs_timeout);
 	if (!ok) {
 		exit_server("tevent_req_set_endtime failed");
 	}
@@ -2508,7 +2508,7 @@ static void setup_kernel_oplock_poll_open(struct timeval request_time,
 	 * As this timer event is owned by req, it will
 	 * disappear if req it talloc_freed.
 	 */
-	open_rec->te = tevent_add_timer(req->sconn->ev_ctx,
+	open_rec->te = tevent_add_timer(req->ev_ctx,
 					req,
 					timeval_current_ofs(1, 0),
 					kernel_oplock_poll_open_timer,
@@ -2695,7 +2695,7 @@ static void schedule_async_open(struct timeval request_time,
 		exit_server("push_deferred_open_message_smb failed");
 	}
 
-	open_rec->te = tevent_add_timer(req->sconn->ev_ctx,
+	open_rec->te = tevent_add_timer(req->ev_ctx,
 					req,
 					timeval_current_ofs(20, 0),
 					schedule_async_open_timer,
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index 4be57bc2a5f0..c945f0f61776 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -67,7 +67,7 @@ NTSTATUS open_np_file(struct smb_request *smb_req, const char *name,
 			 conn->sconn->remote_address,
 			 conn->sconn->local_address,
 			 conn->session_info,
-			 conn->sconn->ev_ctx,
+			 smb_req->ev_ctx,
 			 conn->sconn->msg_ctx,
 			 &fsp->fake_file_handle);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -206,7 +206,7 @@ void reply_pipe_write(struct smb_request *req)
 	DEBUG(6, ("reply_pipe_write: %s, name: %s len: %d\n", fsp_fnum_dbg(fsp),
 		  fsp_str_dbg(fsp), (int)state->numtowrite));
 
-	subreq = np_write_send(state, req->sconn->ev_ctx,
+	subreq = np_write_send(state, req->ev_ctx,
 			       fsp->fake_file_handle, data, state->numtowrite);
 	if (subreq == NULL) {
 		TALLOC_FREE(state);
@@ -322,7 +322,7 @@ void reply_pipe_write_and_X(struct smb_request *req)
 		state->numtowrite -= 2;
 	}
 
-	subreq = np_write_send(state, req->sconn->ev_ctx,
+	subreq = np_write_send(state, req->ev_ctx,
 			       fsp->fake_file_handle, data, state->numtowrite);
 	if (subreq == NULL) {
 		TALLOC_FREE(state);
@@ -435,7 +435,7 @@ void reply_pipe_read_and_X(struct smb_request *req)
 	state->outbuf = req->outbuf;
 	req->outbuf = NULL;
 
-	subreq = np_read_send(state, req->sconn->ev_ctx,
+	subreq = np_read_send(state, req->ev_ctx,
 			      fsp->fake_file_handle, data,
 			      state->smb_maxcnt);
 	if (subreq == NULL) {
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 1559d1f7270b..2ce433d57634 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -1508,6 +1508,8 @@ static connection_struct *switch_message(uint8_t type, struct smb_request *req)
 
 	errno = 0;
 
+	req->ev_ctx = NULL;
+
 	if (!xconn->smb1.negprot.done) {
 		switch (type) {
 			/*
@@ -1626,6 +1628,8 @@ static connection_struct *switch_message(uint8_t type, struct smb_request *req)
 			return conn;
 		}
 
+		req->ev_ctx = conn->user_ev_ctx;
+
 		if (flags & FORCE_AS_ROOT) {
 			as_root = true;
 		}
@@ -1638,6 +1642,8 @@ static connection_struct *switch_message(uint8_t type, struct smb_request *req)
 			reply_nterror(req, NT_STATUS_ACCESS_DENIED);
 			return conn;
 		}
+
+		req->ev_ctx = req->sconn->guest_ev_ctx;
 	} else {
 		/*
 		 * everything else needs to run as root
@@ -1659,6 +1665,8 @@ static connection_struct *switch_message(uint8_t type, struct smb_request *req)
 	if (as_root) {
 		/* This call needs to be run as root */
 		change_to_root_user();
+
+		req->ev_ctx = req->sconn->root_ev_ctx;
 	}
 
 	/* load service specific parameters */
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 1b99664cbd8b..5afe57d11cb7 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -5392,7 +5392,7 @@ void reply_close(struct smb_request *req)
 		 */
 
 		fsp->deferred_close = tevent_wait_send(
-			fsp, fsp->conn->sconn->ev_ctx);
+			fsp, req->ev_ctx);
 		if (fsp->deferred_close == NULL) {
 			status = NT_STATUS_NO_MEMORY;
 			goto done;
diff --git a/source3/smbd/smb2_break.c b/source3/smbd/smb2_break.c
index 86529ed2e1f8..21fbef42dced 100644
--- a/source3/smbd/smb2_break.c
+++ b/source3/smbd/smb2_break.c
@@ -86,7 +86,7 @@ NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
 	}
 
-	subreq = smbd_smb2_oplock_break_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_oplock_break_send(req, req->ev_ctx,
 					     req, in_fsp, in_oplock_level);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
@@ -265,7 +265,7 @@ static NTSTATUS smbd_smb2_request_process_lease_break(
 	in_lease_key.data[1] = BVAL(inbody, 16);
 	in_lease_state = IVAL(inbody, 24);
 
-	subreq = smbd_smb2_lease_break_send(req, req->sconn->ev_ctx, req,
+	subreq = smbd_smb2_lease_break_send(req, req->ev_ctx, req,
 					    in_lease_key, in_lease_state);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
diff --git a/source3/smbd/smb2_close.c b/source3/smbd/smb2_close.c
index 992b52929ec4..33863d32f5f2 100644
--- a/source3/smbd/smb2_close.c
+++ b/source3/smbd/smb2_close.c
@@ -70,7 +70,7 @@ NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_close_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_close_send(req, req->ev_ctx,
 				      req, in_fsp, in_flags);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 3f38af5dde27..8fbea238698c 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -228,7 +228,7 @@ NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
 	}
 
 	tsubreq = smbd_smb2_create_send(smb2req,
-				       smb2req->sconn->ev_ctx,
+				       smb2req->ev_ctx,
 				       smb2req,
 				       in_oplock_level,
 				       in_impersonation_level,
@@ -1763,7 +1763,7 @@ bool schedule_deferred_open_message_smb2(
 		(unsigned long long)mid ));
 
 	tevent_schedule_immediate(state->im,
-			smb2req->sconn->ev_ctx,
+			smb2req->ev_ctx,
 			smbd_smb2_create_request_dispatch_immediate,
 			smb2req);
 
@@ -1795,7 +1795,7 @@ static bool smbd_smb2_create_cancel(struct tevent_req *req)
 
 	remove_deferred_open_message_smb2_internal(smb2req, mid);
 
-	tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
+	tevent_req_defer_callback(req, smb2req->ev_ctx);
 	tevent_req_nterror(req, NT_STATUS_CANCELLED);
 	return true;
 }
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
index 470a8df49442..4f815a6f5b0c 100644
--- a/source3/smbd/smb2_flush.c
+++ b/source3/smbd/smb2_flush.c
@@ -58,7 +58,7 @@ NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_flush_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_flush_send(req, req->ev_ctx,
 				      req, in_fsp);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 694e9f83b754..da82bf523787 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -120,7 +120,7 @@ NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_getinfo_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_getinfo_send(req, req->ev_ctx,
 					req, in_fsp,
 					in_info_type,
 					in_file_info_class,
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 6a73ec050e24..cccc763c3425 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -46,6 +46,7 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
 	smbreq->conn = req->tcon->compat;
 	smbreq->sconn = req->sconn;
 	smbreq->xconn = req->xconn;
+	smbreq->ev_ctx = req->ev_ctx;
 	smbreq->smbpid = (uint16_t)IVAL(inhdr, SMB2_HDR_PID);
 	smbreq->flags2 = FLAGS2_UNICODE_STRINGS |
 			 FLAGS2_32_BIT_ERROR_CODES |
diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c
index be70e3a09128..451733c1a659 100644
--- a/source3/smbd/smb2_ioctl.c
+++ b/source3/smbd/smb2_ioctl.c
@@ -217,7 +217,7 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
 		break;
 	}
 
-	subreq = smbd_smb2_ioctl_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_ioctl_send(req, req->ev_ctx,
 				      req, in_fsp,
 				      in_ctl_code,
 				      in_input_buffer,
diff --git a/source3/smbd/smb2_ioctl_named_pipe.c b/source3/smbd/smb2_ioctl_named_pipe.c
index f9e3dec049c0..f8012ae19203 100644
--- a/source3/smbd/smb2_ioctl_named_pipe.c
+++ b/source3/smbd/smb2_ioctl_named_pipe.c
@@ -143,7 +143,7 @@ static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq)
 		(unsigned int)state->out_output.length ));
 
 	subreq = np_read_send(state->smbreq->conn,
-			      state->smb2req->sconn->ev_ctx,
+			      state->smb2req->ev_ctx,
 			      state->fsp->fake_file_handle,
 			      state->out_output.data,
 			      state->out_output.length);
diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c
index 3cc591089a42..da5a54df6233 100644
--- a/source3/smbd/smb2_lock.c
+++ b/source3/smbd/smb2_lock.c
@@ -134,7 +134,7 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_lock_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_lock_send(req, req->ev_ctx,
 				     req, in_fsp,
 				     in_lock_count,
 				     in_locks);
@@ -368,7 +368,7 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
 	}
 
 	if (async) {
-		tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
+		tevent_req_defer_callback(req, smb2req->ev_ctx);
 		SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
 		return req;
 	}
diff --git a/source3/smbd/smb2_notify.c b/source3/smbd/smb2_notify.c
index 242415625567..e49e76d96413 100644
--- a/source3/smbd/smb2_notify.c
+++ b/source3/smbd/smb2_notify.c
@@ -94,7 +94,7 @@ NTSTATUS smbd_smb2_request_process_notify(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_notify_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_notify_send(req, req->ev_ctx,
 				       req, in_fsp,
 				       in_flags,
 				       in_output_buffer_length,
@@ -355,7 +355,7 @@ static void smbd_smb2_notify_reply(struct smb_request *smbreq,
 		}
 	}
 
-	tevent_req_defer_callback(req, state->smb2req->sconn->ev_ctx);
+	tevent_req_defer_callback(req, state->smb2req->ev_ctx);
 
 	if (!NT_STATUS_IS_OK(state->status)) {
 		tevent_req_nterror(req, state->status);
diff --git a/source3/smbd/smb2_query_directory.c b/source3/smbd/smb2_query_directory.c
index 700f43e31262..50a5bca5d7b2 100644
--- a/source3/smbd/smb2_query_directory.c
+++ b/source3/smbd/smb2_query_directory.c
@@ -124,7 +124,7 @@ NTSTATUS smbd_smb2_request_process_query_directory(struct smbd_smb2_request *req
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_query_directory_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_query_directory_send(req, req->ev_ctx,
 				     req, in_fsp,
 				     in_file_info_class,
 				     in_flags,
diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c
index a7d2496bc6f3..065a5cd5fc69 100644
--- a/source3/smbd/smb2_read.c
+++ b/source3/smbd/smb2_read.c
@@ -97,7 +97,7 @@ NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_read_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_read_send(req, req->ev_ctx,
 				     req, in_fsp,
 				     in_flags,
 				     in_length,
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 697e3ac9562c..1b61963ee899 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2614,8 +2614,10 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 		SMB_ASSERT(call->fileid_ofs == 0);
 		/* This call needs to be run as root */
 		change_to_root_user();
+		req->ev_ctx = req->sconn->root_ev_ctx;
 	} else {
 		SMB_ASSERT(call->need_tcon);
+		req->ev_ctx = req->tcon->compat->user_ev_ctx;
 	}
 
 #define _INBYTES(_r) \
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 5e1e8b4ec579..fe5835b83f34 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -95,7 +95,7 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
 	in_security_buffer.length = in_security_length;
 
 	subreq = smbd_smb2_session_setup_wrap_send(smb2req,
-						   smb2req->sconn->ev_ctx,
+						   smb2req->ev_ctx,
 						   smb2req,
 						   in_session_id,
 						   in_flags,
@@ -1218,7 +1218,7 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, status);
 	}
 
-	subreq = smbd_smb2_logoff_send(req, req->sconn->ev_ctx, req);
+	subreq = smbd_smb2_logoff_send(req, req->ev_ctx, req);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
index 4958bb8f16e7..5a6a28a323e2 100644
--- a/source3/smbd/smb2_setinfo.c
+++ b/source3/smbd/smb2_setinfo.c
@@ -107,7 +107,7 @@ NTSTATUS smbd_smb2_request_process_setinfo(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_setinfo_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_setinfo_send(req, req->ev_ctx,
 					req, in_fsp,
 					in_info_type,
 					in_file_info_class,
diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c
index ebd31602efcd..3a4a15d3059e 100644
--- a/source3/smbd/smb2_tcon.c
+++ b/source3/smbd/smb2_tcon.c
@@ -94,7 +94,7 @@ NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req)
 	}
 
 	subreq = smbd_smb2_tree_connect_send(req,
-					     req->sconn->ev_ctx,
+					     req->ev_ctx,
 					     req,
 					     in_path_string);
 	if (subreq == NULL) {
@@ -491,7 +491,7 @@ NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, status);
 	}
 
-	subreq = smbd_smb2_tdis_send(req, req->sconn->ev_ctx, req);
+	subreq = smbd_smb2_tdis_send(req, req->ev_ctx, req);
 	if (subreq == NULL) {
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c
index ee95bd317aef..d5ab12ecc21a 100644
--- a/source3/smbd/smb2_write.c
+++ b/source3/smbd/smb2_write.c
@@ -109,7 +109,7 @@ NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
 	}
 
-	subreq = smbd_smb2_write_send(req, req->sconn->ev_ctx,
+	subreq = smbd_smb2_write_send(req, req->ev_ctx,
 				      req, in_fsp,
 				      in_data_buffer,
 				      in_offset,
-- 
2.17.1


From bc6dff07fc2a5128bbcc9bfe285a44ffe23fb81c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 49/56] smbd: remove unused smbd_server_connection->ev_ctx

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/globals.h | 1 -
 source3/smbd/msdfs.c   | 1 -
 source3/smbd/process.c | 1 -
 3 files changed, 3 deletions(-)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index d43e5bdfdcb0..132ebabebf4e 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -874,7 +874,6 @@ struct smbd_server_connection {
 	const struct tsocket_address *local_address;
 	const struct tsocket_address *remote_address;
 	const char *remote_hostname;
-	struct tevent_context *ev_ctx;
 	struct tevent_context *raw_ev_ctx;
 	struct tevent_context *root_ev_ctx;
 	struct tevent_context *guest_ev_ctx;
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index eaecf13e23d8..a83a1ab1e318 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -263,7 +263,6 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	sconn->ev_ctx = sconn->raw_ev_ctx;
 	sconn->root_ev_ctx = sconn->raw_ev_ctx;
 	sconn->guest_ev_ctx = sconn->raw_ev_ctx;
 	sconn->msg_ctx = msg;
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 2ce433d57634..a8067fb0cd14 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3929,7 +3929,6 @@ void smbd_process(struct tevent_context *ev_ctx,
 	client->sconn = sconn;
 	sconn->client = client;
 
-	sconn->ev_ctx = ev_ctx;
 	sconn->raw_ev_ctx = ev_ctx;
 	sconn->root_ev_ctx = ev_ctx;
 	sconn->guest_ev_ctx = ev_ctx;
-- 
2.17.1


From a6b016438e73d2b4276378b18e67c1d71116985d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 25 May 2018 16:22:33 +0200
Subject: [PATCH 50/56] smbd: add [un]become_guest() helper functions

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/proto.h |  2 ++
 source3/smbd/uid.c   | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index ab4a8d68d3f1..cbb43829fe08 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1203,6 +1203,8 @@ void become_root(void);
 void unbecome_root(void);
 void smbd_become_root(void);
 void smbd_unbecome_root(void);
+bool become_guest(void);
+void unbecome_guest(void);
 bool become_user(connection_struct *conn, uint64_t vuid);
 bool become_user_by_fsp(struct files_struct *fsp);
 bool become_user_by_session(connection_struct *conn,
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 69a2bb0f2e32..2ea1888c0527 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -582,6 +582,34 @@ void smbd_unbecome_root(void)
 	pop_conn_ctx();
 }
 
+bool become_guest(void)
+{
+	bool ok;
+
+	ok = push_sec_ctx();
+	if (!ok) {
+		return false;
+	}
+
+	push_conn_ctx();
+
+	ok = change_to_guest();
+	if (!ok) {
+		pop_sec_ctx();
+		pop_conn_ctx();
+		return false;
+	}
+
+	return true;
+}
+
+void unbecome_guest(void)
+{
+	pop_sec_ctx();
+	pop_conn_ctx();
+	return true;
+}
+
 /****************************************************************************
  Push the current security context then force a change via change_to_user().
  Saves and restores the connection context.
-- 
2.17.1


From efea121530c4df1a0a55c1299e3b350445ac49a1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 07:47:38 +0100
Subject: [PATCH 51/56] smbd: add smbd_impersonate_debug_create() helper

This will be used to implement no-op impersonation
for the create_conn_struct_as_root() case were we
don't really have other unrelated events in the loop
and only need a valid tevent wrapper context to avoid
double free on the raw event context on teardown.

This also adds useful debugging instead of being
a full no-op wrapper.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/proto.h |   6 ++
 source3/smbd/uid.c   | 229 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 235 insertions(+)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index cbb43829fe08..f31ef98624c7 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1189,6 +1189,12 @@ void reply_transs2(struct smb_request *req);
 
 /* The following definitions come from smbd/uid.c  */
 
+#define smbd_impersonate_debug_create(main_ev, name, dbg_lvl) \
+	_smbd_impersonate_debug_create(main_ev, name, dbg_lvl, __location__)
+struct tevent_context *_smbd_impersonate_debug_create(struct tevent_context *main_ev,
+						      const char *name,
+						      int dbg_lvl,
+						      const char *location);
 bool change_to_guest(void);
 NTSTATUS check_user_share_access(connection_struct *conn,
 				const struct auth_session_info *session_info,
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 2ea1888c0527..cb8eedf63283 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -25,6 +25,235 @@
 #include "libcli/security/security.h"
 #include "passdb/lookup_sid.h"
 #include "auth.h"
+#include "lib/util/time_basic.h"
+
+struct smbd_impersonate_debug_state {
+	int dbg_lvl;
+	const char *name;
+};
+
+static bool smbd_impersonate_debug_before_use(struct tevent_context *wrap_ev,
+					      void *private_data,
+					      struct tevent_context *main_ev,
+					      const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev, location));
+
+	return true;
+}
+
+static void smbd_impersonate_debug_after_use(struct tevent_context *wrap_ev,
+					     void *private_data,
+					     struct tevent_context *main_ev,
+					     const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev, location));
+}
+
+static void smbd_impersonate_debug_before_fd_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev,
+	      fde, flags, handler_name, location));
+}
+
+static void smbd_impersonate_debug_after_fd_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev,
+	      fde, flags, handler_name, location));
+}
+
+static void smbd_impersonate_debug_before_timer_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_timer *te,
+						struct timeval requested_time,
+						struct timeval trigger_time,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev, te,
+	      timeval_str_buf(&requested_time, true, true, &requested_buf),
+	      timeval_str_buf(&trigger_time, true, true, &trigger_buf),
+	      handler_name, location));
+}
+
+static void smbd_impersonate_debug_after_timer_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_timer *te,
+						struct timeval requested_time,
+						struct timeval trigger_time,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev, te,
+	      timeval_str_buf(&requested_time, true, true, &requested_buf),
+	      timeval_str_buf(&trigger_time, true, true, &trigger_buf),
+	      handler_name, location));
+}
+
+static void smbd_impersonate_debug_before_immediate_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_immediate *im,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "im[%p] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev,
+	      im, handler_name, location));
+}
+
+static void smbd_impersonate_debug_after_immediate_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_immediate *im,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "im[%p] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev,
+	      im, handler_name, location));
+}
+
+static void smbd_impersonate_debug_before_signal_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_signal *se,
+						int signum,
+						int count,
+						void *siginfo,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev,
+	      se, signum, count, siginfo, handler_name, location));
+}
+
+static void smbd_impersonate_debug_after_signal_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_signal *se,
+						int signum,
+						int count,
+						void *siginfo,
+						const char *handler_name,
+						const char *location)
+{
+	struct smbd_impersonate_debug_state *state =
+		(struct smbd_impersonate_debug_state *)private_data;
+
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
+	      "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev,
+	      se, signum, count, siginfo, handler_name, location));
+}
+
+static const struct tevent_wrapper_ops smbd_impersonate_debug_ops = {
+	.name				= "smbd_impersonate_debug",
+	.before_use			= smbd_impersonate_debug_before_use,
+	.after_use			= smbd_impersonate_debug_after_use,
+	.before_fd_handler		= smbd_impersonate_debug_before_fd_handler,
+	.after_fd_handler		= smbd_impersonate_debug_after_fd_handler,
+	.before_timer_handler		= smbd_impersonate_debug_before_timer_handler,
+	.after_timer_handler		= smbd_impersonate_debug_after_timer_handler,
+	.before_immediate_handler	= smbd_impersonate_debug_before_immediate_handler,
+	.after_immediate_handler	= smbd_impersonate_debug_after_immediate_handler,
+	.before_signal_handler		= smbd_impersonate_debug_before_signal_handler,
+	.after_signal_handler		= smbd_impersonate_debug_after_signal_handler,
+};
+
+struct tevent_context *_smbd_impersonate_debug_create(struct tevent_context *main_ev,
+						      const char *name,
+						      int dbg_lvl,
+						      const char *location)
+{
+	struct tevent_context *wrap_ev = NULL;
+	struct smbd_impersonate_debug_state *state = NULL;
+
+	wrap_ev = tevent_context_wrapper_create(main_ev,
+					main_ev,
+					&smbd_impersonate_debug_ops,
+					&state,
+					struct smbd_impersonate_debug_state);
+	if (wrap_ev == NULL) {
+		return NULL;
+	}
+	state->name = name;
+	state->dbg_lvl = dbg_lvl;
+	DEBUG(state->dbg_lvl, (
+	      "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
+	      __func__, state->name, wrap_ev, state, main_ev, location));
+
+	return wrap_ev;
+}
 
 /* what user is current? */
 extern struct current_user current_user;
-- 
2.17.1


From 422a5374a717e6968d50e3863ccb4400223bab06 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 52/56] smbd: add simple noop
 smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create() wrappers

As a start these are just wrappers arround
smbd_impersonate_debug_create(), without any real impersonation.
But this will change shortly.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/proto.h | 11 ++++++++++
 source3/smbd/uid.c   | 50 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index f31ef98624c7..29121d5c4961 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1222,6 +1222,17 @@ const struct security_unix_token *get_current_utok(connection_struct *conn);
 const struct security_token *get_current_nttok(connection_struct *conn);
 uint64_t get_current_vuid(connection_struct *conn);
 
+struct tevent_context *smbd_impersonate_conn_vuid_create(
+				struct tevent_context *main_ev,
+				struct connection_struct *conn,
+				uint64_t vuid);
+struct tevent_context *smbd_impersonate_conn_sess_create(
+				struct tevent_context *main_ev,
+				struct connection_struct *conn,
+				struct auth_session_info *session_info);
+struct tevent_context *smbd_impersonate_root_create(struct tevent_context *main_ev);
+struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev);
+
 /* The following definitions come from smbd/utmp.c  */
 
 void sys_utmp_claim(const char *username, const char *hostname,
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index cb8eedf63283..314dbfd1d0c8 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -941,3 +941,53 @@ uint64_t get_current_vuid(connection_struct *conn)
 {
 	return current_user.vuid;
 }
+
+struct tevent_context *smbd_impersonate_conn_vuid_create(
+				struct tevent_context *main_ev,
+				struct connection_struct *conn,
+				uint64_t vuid)
+{
+	struct tevent_context *wrap_ev = NULL;
+
+	wrap_ev = smbd_impersonate_debug_create(main_ev,
+						"conn_vuid",
+						DBGLVL_DEBUG);
+
+	return wrap_ev;
+}
+
+struct tevent_context *smbd_impersonate_conn_sess_create(
+				struct tevent_context *main_ev,
+				struct connection_struct *conn,
+				struct auth_session_info *session_info)
+{
+	struct tevent_context *wrap_ev = NULL;
+
+	wrap_ev = smbd_impersonate_debug_create(main_ev,
+						"conn_sess",
+						DBGLVL_DEBUG);
+
+	return wrap_ev;
+}
+
+struct tevent_context *smbd_impersonate_root_create(struct tevent_context *main_ev)
+{
+	struct tevent_context *wrap_ev = NULL;
+
+	wrap_ev = smbd_impersonate_debug_create(main_ev,
+						"root",
+						DBGLVL_DEBUG);
+
+	return wrap_ev;
+}
+
+struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev)
+{
+	struct tevent_context *wrap_ev = NULL;
+
+	wrap_ev = smbd_impersonate_debug_create(main_ev,
+						"guest",
+						DBGLVL_DEBUG);
+
+	return wrap_ev;
+}
-- 
2.17.1


From 0270bfefc8acfae47f42de05e8a8a28eee3b0371 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 10:54:41 +0100
Subject: [PATCH 53/56] smbd: make use of
 smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create() wrappers

For now they just add debugging, but that will change shortly.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_readonly.c |  2 +-
 source3/smbd/conn.c            |  2 +-
 source3/smbd/msdfs.c           | 34 +++++++++++++++++++++++++++++++---
 source3/smbd/process.c         | 18 ++++++++++++++++--
 source3/smbd/uid.c             | 20 ++++++++++++++++++--
 5 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/source3/modules/vfs_readonly.c b/source3/modules/vfs_readonly.c
index 570eb7c4d15a..e7e12747a222 100644
--- a/source3/modules/vfs_readonly.c
+++ b/source3/modules/vfs_readonly.c
@@ -84,7 +84,7 @@ static int readonly_connect(vfs_handle_struct *handle,
       for (i=0; i< VUID_CACHE_SIZE; i++) {
         struct vuid_cache_entry *ent = &conn->vuid_cache->array[i];
         ent->vuid = UID_FIELD_INVALID;
-        ent->user_ev_ctx = NULL;
+        TALLOC_FREE(ent->user_ev_ctx);
         TALLOC_FREE(ent->session_info);
         ent->read_only = false;
         ent->share_access = 0;
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index 3b9aaac7834b..cfff6404608f 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -98,7 +98,7 @@ static void conn_clear_vuid_cache(connection_struct *conn, uint64_t vuid)
 			if (conn->user_ev_ctx == ent->user_ev_ctx) {
 				conn->user_ev_ctx = NULL;
 			}
-			ent->user_ev_ctx = NULL;
+			TALLOC_FREE(ent->user_ev_ctx);
 
 			/*
 			 * We need to keep conn->session_info around
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index a83a1ab1e318..ef3b02b7d56e 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -263,8 +263,17 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	sconn->root_ev_ctx = sconn->raw_ev_ctx;
-	sconn->guest_ev_ctx = sconn->raw_ev_ctx;
+	sconn->root_ev_ctx = smbd_impersonate_root_create(sconn->raw_ev_ctx);
+	if (sconn->root_ev_ctx == NULL) {
+		TALLOC_FREE(sconn);
+		return NT_STATUS_NO_MEMORY;
+	}
+	sconn->guest_ev_ctx = smbd_impersonate_guest_create(sconn->raw_ev_ctx);
+	if (sconn->guest_ev_ctx == NULL) {
+		TALLOC_FREE(sconn);
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	sconn->msg_ctx = msg;
 
 	conn = conn_new(sconn);
@@ -313,7 +322,26 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
 		vfs_user = get_current_username();
 	}
 
-	conn->user_ev_ctx = sconn->raw_ev_ctx;
+	/*
+	 * The impersonation has to be done by the caller
+	 * of create_conn_struct_tos[_cwd]().
+	 *
+	 * Note: the context can't be changed anyway
+	 * as we're using our own tevent_context
+	 * and not a global one were other requests
+	 * could change the current unix token.
+	 *
+	 * We just use a wrapper tevent_context in order
+	 * to avoid crashes because TALLOC_FREE(conn->user_ev_ctx)
+	 * would also remove sconn->raw_ev_ctx.
+	 */
+	conn->user_ev_ctx = smbd_impersonate_debug_create(sconn->raw_ev_ctx,
+							  "FAKE impersonation",
+							  DBGLVL_DEBUG);
+	if (conn->user_ev_ctx == NULL) {
+		TALLOC_FREE(conn);
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	set_conn_connectpath(conn, connpath);
 
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index a8067fb0cd14..37efe46b237e 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3898,6 +3898,8 @@ void smbd_process(struct tevent_context *ev_ctx,
 		.ev = ev_ctx,
 		.frame = talloc_stackframe(),
 	};
+	struct tevent_context *root_ev_ctx = NULL;
+	struct tevent_context *guest_ev_ctx = NULL;
 	struct smbXsrv_client *client = NULL;
 	struct smbd_server_connection *sconn = NULL;
 	struct smbXsrv_connection *xconn = NULL;
@@ -3910,6 +3912,18 @@ void smbd_process(struct tevent_context *ev_ctx,
 	char *chroot_dir = NULL;
 	int rc;
 
+	root_ev_ctx = smbd_impersonate_root_create(ev_ctx);
+	if (root_ev_ctx == NULL) {
+		DEBUG(0,("smbd_impersonate_root_create() failed\n"));
+		exit_server_cleanly("smbd_impersonate_root_create().\n");
+	}
+
+	guest_ev_ctx = smbd_impersonate_guest_create(ev_ctx);
+	if (guest_ev_ctx == NULL) {
+		DEBUG(0,("smbd_impersonate_guest_create() failed\n"));
+		exit_server_cleanly("smbd_impersonate_guest_create().\n");
+	}
+
 	status = smbXsrv_client_create(ev_ctx, ev_ctx, msg_ctx, now, &client);
 	if (!NT_STATUS_IS_OK(status)) {
 		DBG_ERR("smbXsrv_client_create(): %s\n", nt_errstr(status));
@@ -3930,8 +3944,8 @@ void smbd_process(struct tevent_context *ev_ctx,
 	sconn->client = client;
 
 	sconn->raw_ev_ctx = ev_ctx;
-	sconn->root_ev_ctx = ev_ctx;
-	sconn->guest_ev_ctx = ev_ctx;
+	sconn->root_ev_ctx = root_ev_ctx;
+	sconn->guest_ev_ctx = guest_ev_ctx;
 	sconn->msg_ctx = msg_ctx;
 
 	ret = pthreadpool_tevent_init(sconn, lp_aio_max_threads(),
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 314dbfd1d0c8..88ea98cba47c 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -305,7 +305,7 @@ static void free_conn_session_info_if_unused(connection_struct *conn)
 		}
 	}
 	/* Not used, safe to free. */
-	conn->user_ev_ctx = NULL;
+	TALLOC_FREE(conn->user_ev_ctx);
 	TALLOC_FREE(conn->session_info);
 }
 
@@ -480,7 +480,23 @@ static bool check_user_ok(connection_struct *conn,
 		ent->session_info->unix_token->uid = sec_initial_uid();
 	}
 
-	ent->user_ev_ctx = conn->sconn->raw_ev_ctx;
+	if (vuid == UID_FIELD_INVALID) {
+		ent->user_ev_ctx = smbd_impersonate_conn_sess_create(
+			conn->sconn->raw_ev_ctx, conn, ent->session_info);
+		if (ent->user_ev_ctx == NULL) {
+			TALLOC_FREE(ent->session_info);
+			ent->vuid = UID_FIELD_INVALID;
+			return false;
+		}
+	} else {
+		ent->user_ev_ctx = smbd_impersonate_conn_vuid_create(
+			conn->sconn->raw_ev_ctx, conn, vuid);
+		if (ent->user_ev_ctx == NULL) {
+			TALLOC_FREE(ent->session_info);
+			ent->vuid = UID_FIELD_INVALID;
+			return false;
+		}
+	}
 
 	/*
 	 * It's actually OK to call check_user_ok() with
-- 
2.17.1


From 102355c8f269e765acaee212518af03dd1443a18 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 11 May 2012 15:51:42 +0200
Subject: [PATCH 54/56] TODO debug at level 11? smbd: implement
 smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create() wrappers

This makes sure we're doing the correct impersonation for async
requests, which is a requirement to start adding path based
async SMB_VFS calls.
---
 source3/smbd/uid.c | 697 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 676 insertions(+), 21 deletions(-)

diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 88ea98cba47c..12e2c8579b8d 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -958,52 +958,707 @@ uint64_t get_current_vuid(connection_struct *conn)
 	return current_user.vuid;
 }
 
+struct smbd_impersonate_conn_vuid_state {
+	struct connection_struct *conn;
+	uint64_t vuid;
+};
+
+static bool smbd_impersonate_conn_vuid_before_use(struct tevent_context *wrap_ev,
+						  void *private_data,
+						  struct tevent_context *main_ev,
+						  const char *location)
+{
+	struct smbd_impersonate_conn_vuid_state *state =
+		talloc_get_type_abort(private_data,
+		struct smbd_impersonate_conn_vuid_state);
+	bool ok;
+
+	ok = change_to_user(state->conn, state->vuid);
+	if (!ok) {
+		return false;
+	}
+
+	return true;
+}
+
+static void smbd_impersonate_conn_vuid_after_use(struct tevent_context *wrap_ev,
+						 void *private_data,
+						 struct tevent_context *main_ev,
+						 const char *location)
+{
+	struct smbd_impersonate_conn_vuid_state *state =
+		talloc_get_type_abort(private_data,
+		struct smbd_impersonate_conn_vuid_state);
+	const struct smb_filename root_fname = {
+		.base_name = discard_const_p(char, "/"),
+	};
+
+	vfs_ChDir(state->conn, &root_fname);
+	change_to_root_user();
+}
+
+static void smbd_impersonate_conn_vuid_before_fd_handler(struct tevent_context *wrap_ev,
+							 void *private_data,
+							 struct tevent_context *main_ev,
+							 struct tevent_fd *fde,
+							 uint16_t flags,
+							 const char *handler_name,
+							 const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_vuid_after_fd_handler(struct tevent_context *wrap_ev,
+							void *private_data,
+							struct tevent_context *main_ev,
+							struct tevent_fd *fde,
+							uint16_t flags,
+							const char *handler_name,
+							const char *location)
+{
+	/* be lazy and defer change_to_root_user() */
+}
+
+static void smbd_impersonate_conn_vuid_before_timer_handler(struct tevent_context *wrap_ev,
+							    void *private_data,
+							    struct tevent_context *main_ev,
+							    struct tevent_timer *te,
+							    struct timeval requested_time,
+							    struct timeval trigger_time,
+							    const char *handler_name,
+							    const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_vuid_after_timer_handler(struct tevent_context *wrap_ev,
+							   void *private_data,
+							   struct tevent_context *main_ev,
+							   struct tevent_timer *te,
+							   struct timeval requested_time,
+							   struct timeval trigger_time,
+							   const char *handler_name,
+							   const char *location)
+{
+	/* be lazy and defer change_to_root_user() */
+}
+
+static void smbd_impersonate_conn_vuid_before_immediate_handler(struct tevent_context *wrap_ev,
+								void *private_data,
+								struct tevent_context *main_ev,
+								struct tevent_immediate *im,
+								const char *handler_name,
+								const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_vuid_after_immediate_handler(struct tevent_context *wrap_ev,
+							       void *private_data,
+							       struct tevent_context *main_ev,
+							       struct tevent_immediate *im,
+							       const char *handler_name,
+							       const char *location)
+{
+	/* be lazy and defer unbecome_user() */
+}
+
+static void smbd_impersonate_conn_vuid_before_signal_handler(struct tevent_context *wrap_ev,
+							     void *private_data,
+							     struct tevent_context *main_ev,
+							     struct tevent_signal *se,
+							     int signum,
+							     int count,
+							     void *siginfo,
+							     const char *handler_name,
+							     const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_vuid_after_signal_handler(struct tevent_context *wrap_ev,
+							    void *private_data,
+							    struct tevent_context *main_ev,
+							    struct tevent_signal *se,
+							    int signum,
+							    int count,
+							    void *siginfo,
+							    const char *handler_name,
+							    const char *location)
+{
+	/* be lazy and defer change_to_root_user() */
+}
+
+static const struct tevent_wrapper_ops smbd_impersonate_conn_vuid_ops = {
+	.name				= "smbd_impersonate_conn_vuid",
+	.before_use			= smbd_impersonate_conn_vuid_before_use,
+	.after_use			= smbd_impersonate_conn_vuid_after_use,
+	.before_fd_handler		= smbd_impersonate_conn_vuid_before_fd_handler,
+	.after_fd_handler		= smbd_impersonate_conn_vuid_after_fd_handler,
+	.before_timer_handler		= smbd_impersonate_conn_vuid_before_timer_handler,
+	.after_timer_handler		= smbd_impersonate_conn_vuid_after_timer_handler,
+	.before_immediate_handler	= smbd_impersonate_conn_vuid_before_immediate_handler,
+	.after_immediate_handler	= smbd_impersonate_conn_vuid_after_immediate_handler,
+	.before_signal_handler		= smbd_impersonate_conn_vuid_before_signal_handler,
+	.after_signal_handler		= smbd_impersonate_conn_vuid_after_signal_handler,
+};
+
 struct tevent_context *smbd_impersonate_conn_vuid_create(
 				struct tevent_context *main_ev,
 				struct connection_struct *conn,
 				uint64_t vuid)
 {
-	struct tevent_context *wrap_ev = NULL;
+	struct tevent_context *ev = NULL;
+	struct smbd_impersonate_conn_vuid_state *state = NULL;
+
+	ev = tevent_context_wrapper_create(main_ev,
+					   conn,
+					   &smbd_impersonate_conn_vuid_ops,
+					   &state,
+					   struct smbd_impersonate_conn_vuid_state);
+	if (ev == NULL) {
+		return NULL;
+	}
+	state->conn = conn;
+	state->vuid = vuid;
 
-	wrap_ev = smbd_impersonate_debug_create(main_ev,
-						"conn_vuid",
-						DBGLVL_DEBUG);
+	return ev;
+}
 
-	return wrap_ev;
+struct smbd_impersonate_conn_sess_state {
+	struct connection_struct *conn;
+	struct auth_session_info *session_info;
+};
+
+static bool smbd_impersonate_conn_sess_before_use(struct tevent_context *wrap_ev,
+						  void *private_data,
+						  struct tevent_context *main_ev,
+						  const char *location)
+{
+	struct smbd_impersonate_conn_sess_state *state =
+		talloc_get_type_abort(private_data,
+				      struct smbd_impersonate_conn_sess_state);
+	bool ok;
+
+	ok = change_to_user_by_session(state->conn, state->session_info);
+	if (!ok) {
+		return false;
+	}
+
+	return true;
+}
+
+static void smbd_impersonate_conn_sess_after_use(struct tevent_context *wrap_ev,
+						 void *private_data,
+						 struct tevent_context *main_ev,
+						 const char *location)
+{
+	struct smbd_impersonate_conn_sess_state *state =
+		talloc_get_type_abort(private_data,
+				      struct smbd_impersonate_conn_sess_state);
+	const struct smb_filename root_fname = {
+		.base_name = discard_const_p(char, "/"),
+	};
+
+	vfs_ChDir(state->conn, &root_fname);
+	change_to_root_user();
 }
 
+static void smbd_impersonate_conn_sess_before_fd_handler(struct tevent_context *wrap_ev,
+							 void *private_data,
+							 struct tevent_context *main_ev,
+							 struct tevent_fd *fde,
+							 uint16_t flags,
+							 const char *handler_name,
+							 const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_sess_after_fd_handler(struct tevent_context *wrap_ev,
+							void *private_data,
+							struct tevent_context *main_ev,
+							struct tevent_fd *fde,
+							uint16_t flags,
+							const char *handler_name,
+							const char *location)
+{
+	/* be lazy and defer change_to_root_user() */
+}
+
+static void smbd_impersonate_conn_sess_before_timer_handler(struct tevent_context *wrap_ev,
+							    void *private_data,
+							    struct tevent_context *main_ev,
+							    struct tevent_timer *te,
+							    struct timeval requested_time,
+							    struct timeval trigger_time,
+							    const char *handler_name,
+							    const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_sess_after_timer_handler(struct tevent_context *wrap_ev,
+							   void *private_data,
+							   struct tevent_context *main_ev,
+							   struct tevent_timer *te,
+							   struct timeval requested_time,
+							   struct timeval trigger_time,
+							   const char *handler_name,
+							   const char *location)
+{
+	/* be lazy and defer change_to_root_user() */
+}
+
+static void smbd_impersonate_conn_sess_before_immediate_handler(struct tevent_context *wrap_ev,
+								void *private_data,
+								struct tevent_context *main_ev,
+								struct tevent_immediate *im,
+								const char *handler_name,
+								const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_sess_after_immediate_handler(struct tevent_context *wrap_ev,
+							       void *private_data,
+							       struct tevent_context *main_ev,
+							       struct tevent_immediate *im,
+							       const char *handler_name,
+							       const char *location)
+{
+	/* be lazy and defer unbecome_user() */
+}
+
+static void smbd_impersonate_conn_sess_before_signal_handler(struct tevent_context *wrap_ev,
+							     void *private_data,
+							     struct tevent_context *main_ev,
+							     struct tevent_signal *se,
+							     int signum,
+							     int count,
+							     void *siginfo,
+							     const char *handler_name,
+							     const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
+						   main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_conn_sess_after_signal_handler(struct tevent_context *wrap_ev,
+							    void *private_data,
+							    struct tevent_context *main_ev,
+							    struct tevent_signal *se,
+							    int signum,
+							    int count,
+							    void *siginfo,
+							    const char *handler_name,
+							    const char *location)
+{
+	/* be lazy and defer change_to_root_user() */
+}
+
+static const struct tevent_wrapper_ops smbd_impersonate_conn_sess_ops = {
+	.name				= "smbd_impersonate_conn_sess",
+	.before_use			= smbd_impersonate_conn_sess_before_use,
+	.after_use			= smbd_impersonate_conn_sess_after_use,
+	.before_fd_handler		= smbd_impersonate_conn_sess_before_fd_handler,
+	.after_fd_handler		= smbd_impersonate_conn_sess_after_fd_handler,
+	.before_timer_handler		= smbd_impersonate_conn_sess_before_timer_handler,
+	.after_timer_handler		= smbd_impersonate_conn_sess_after_timer_handler,
+	.before_immediate_handler	= smbd_impersonate_conn_sess_before_immediate_handler,
+	.after_immediate_handler	= smbd_impersonate_conn_sess_after_immediate_handler,
+	.before_signal_handler		= smbd_impersonate_conn_sess_before_signal_handler,
+	.after_signal_handler		= smbd_impersonate_conn_sess_after_signal_handler,
+};
+
 struct tevent_context *smbd_impersonate_conn_sess_create(
 				struct tevent_context *main_ev,
 				struct connection_struct *conn,
 				struct auth_session_info *session_info)
 {
-	struct tevent_context *wrap_ev = NULL;
+	struct tevent_context *ev = NULL;
+	struct smbd_impersonate_conn_sess_state *state = NULL;
+
+	ev = tevent_context_wrapper_create(main_ev,
+					   conn,
+					   &smbd_impersonate_conn_sess_ops,
+					   &state,
+					   struct smbd_impersonate_conn_sess_state);
+	if (ev == NULL) {
+		return NULL;
+	}
+	state->conn = conn;
+	state->session_info = session_info;
 
-	wrap_ev = smbd_impersonate_debug_create(main_ev,
-						"conn_sess",
-						DBGLVL_DEBUG);
+	return ev;
+}
 
-	return wrap_ev;
+struct smbd_impersonate_root_state {
+	uint8_t _dummy;
+};
+
+static bool smbd_impersonate_root_before_use(struct tevent_context *wrap_ev,
+					     void *private_data,
+					     struct tevent_context *main_ev,
+					     const char *location)
+{
+	become_root();
+	return true;
+}
+
+static void smbd_impersonate_root_after_use(struct tevent_context *wrap_ev,
+					    void *private_data,
+					    struct tevent_context *main_ev,
+					    const char *location)
+{
+	unbecome_root();
+}
+
+static void smbd_impersonate_root_before_fd_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_root_after_fd_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_root_before_timer_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_timer *te,
+						struct timeval requested_time,
+						struct timeval trigger_time,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_root_after_timer_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_timer *te,
+						struct timeval requested_time,
+						struct timeval trigger_time,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_root_before_immediate_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_immediate *im,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_root_after_immediate_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_immediate *im,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
 }
 
+static void smbd_impersonate_root_before_signal_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_signal *se,
+						int signum,
+						int count,
+						void *siginfo,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_root_after_signal_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_signal *se,
+						int signum,
+						int count,
+						void *siginfo,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static const struct tevent_wrapper_ops smbd_impersonate_root_ops = {
+	.name				= "smbd_impersonate_root",
+	.before_use			= smbd_impersonate_root_before_use,
+	.after_use			= smbd_impersonate_root_after_use,
+	.before_fd_handler		= smbd_impersonate_root_before_fd_handler,
+	.after_fd_handler		= smbd_impersonate_root_after_fd_handler,
+	.before_timer_handler		= smbd_impersonate_root_before_timer_handler,
+	.after_timer_handler		= smbd_impersonate_root_after_timer_handler,
+	.before_immediate_handler	= smbd_impersonate_root_before_immediate_handler,
+	.after_immediate_handler	= smbd_impersonate_root_after_immediate_handler,
+	.before_signal_handler		= smbd_impersonate_root_before_signal_handler,
+	.after_signal_handler		= smbd_impersonate_root_after_signal_handler,
+};
+
 struct tevent_context *smbd_impersonate_root_create(struct tevent_context *main_ev)
 {
-	struct tevent_context *wrap_ev = NULL;
+	struct tevent_context *ev = NULL;
+	struct smbd_impersonate_root_state *state = NULL;
+
+	ev = tevent_context_wrapper_create(main_ev,
+					   main_ev,
+					   &smbd_impersonate_root_ops,
+					   &state,
+					   struct smbd_impersonate_root_state);
+	if (ev == NULL) {
+		return NULL;
+	}
 
-	wrap_ev = smbd_impersonate_debug_create(main_ev,
-						"root",
-						DBGLVL_DEBUG);
+	return ev;
+}
 
-	return wrap_ev;
+struct smbd_impersonate_guest_state {
+	uint8_t _dummy;
+};
+
+static bool smbd_impersonate_guest_before_use(struct tevent_context *wrap_ev,
+					      void *private_data,
+					      struct tevent_context *main_ev,
+					      const char *location)
+{
+	return become_guest();
 }
 
-struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev)
+static void smbd_impersonate_guest_after_use(struct tevent_context *wrap_ev,
+					     void *private_data,
+					     struct tevent_context *main_ev,
+					     const char *location)
 {
-	struct tevent_context *wrap_ev = NULL;
+	unbecome_guest();
+}
+
+static void smbd_impersonate_guest_before_fd_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						const char *handler_name,
+						const char *location)
+{
+	bool ok;
 
-	wrap_ev = smbd_impersonate_debug_create(main_ev,
-						"guest",
-						DBGLVL_DEBUG);
+	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
+					        main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_guest_before_use() - failed");
+		return;
+	}
+}
 
-	return wrap_ev;
+static void smbd_impersonate_guest_after_fd_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_guest_before_timer_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_timer *te,
+						struct timeval requested_time,
+						struct timeval trigger_time,
+						const char *handler_name,
+						const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
+					       main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_guest_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_guest_after_timer_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_timer *te,
+						struct timeval requested_time,
+						struct timeval trigger_time,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_guest_before_immediate_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_immediate *im,
+						const char *handler_name,
+						const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
+					       main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_guest_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_guest_after_immediate_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_immediate *im,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static void smbd_impersonate_guest_before_signal_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_signal *se,
+						int signum,
+						int count,
+						void *siginfo,
+						const char *handler_name,
+						const char *location)
+{
+	bool ok;
+
+	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
+					       main_ev, location);
+	if (!ok) {
+		smb_panic("smbd_impersonate_guest_before_use() - failed");
+		return;
+	}
+}
+
+static void smbd_impersonate_guest_after_signal_handler(struct tevent_context *wrap_ev,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_signal *se,
+						int signum,
+						int count,
+						void *siginfo,
+						const char *handler_name,
+						const char *location)
+{
+	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
+}
+
+static const struct tevent_wrapper_ops smbd_impersonate_guest_ops = {
+	.name				= "smbd_impersonate_guest",
+	.before_use			= smbd_impersonate_guest_before_use,
+	.after_use			= smbd_impersonate_guest_after_use,
+	.before_fd_handler		= smbd_impersonate_guest_before_fd_handler,
+	.after_fd_handler		= smbd_impersonate_guest_after_fd_handler,
+	.before_timer_handler		= smbd_impersonate_guest_before_timer_handler,
+	.after_timer_handler		= smbd_impersonate_guest_after_timer_handler,
+	.before_immediate_handler	= smbd_impersonate_guest_before_immediate_handler,
+	.after_immediate_handler	= smbd_impersonate_guest_after_immediate_handler,
+	.before_signal_handler		= smbd_impersonate_guest_before_signal_handler,
+	.after_signal_handler		= smbd_impersonate_guest_after_signal_handler,
+};
+
+struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev)
+{
+	struct tevent_context *ev = NULL;
+	struct smbd_impersonate_guest_state *state = NULL;
+
+	ev = tevent_context_wrapper_create(main_ev,
+					   main_ev,
+					   &smbd_impersonate_guest_ops,
+					   &state,
+					   struct smbd_impersonate_guest_state);
+	if (ev == NULL) {
+		return NULL;
+	}
+
+	return ev;
 }
-- 
2.17.1


From 2c3d24f06e446fc11ef517444d305cee79e08b8c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Apr 2018 14:29:52 +0200
Subject: [PATCH 55/56] smbd: remove unused change_to_root_user() from
 smbd_sig_hup_handler()

This is handled by using the root_ev_ctx in order to register
the signal event.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/process.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 37efe46b237e..c09f40e3d8df 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -998,7 +998,6 @@ static void smbd_sig_hup_handler(struct tevent_context *ev,
 		talloc_get_type_abort(private_data,
 		struct smbd_server_connection);
 
-	change_to_root_user();
 	DEBUG(1,("Reloading services after SIGHUP\n"));
 	reload_services(sconn, conn_snum_used, false);
 }
-- 
2.17.1


From 0ba7a096ad9e16284bb53a35796255f617f1463f Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 23 May 2018 16:28:48 +0200
Subject: [PATCH 56/56] smbd: remove unused change_to_root_user() from
 brl_timeout_fn()

This is handled by using the root_ev_ctx in order to register
the timer event.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/blocking.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index c281aae619de..095c9edeacc0 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -47,9 +47,6 @@ void brl_timeout_fn(struct tevent_context *event_ctx,
 		TALLOC_FREE(sconn->smb1.locks.brl_timeout);
 	}
 
-	change_to_root_user();	/* TODO: Possibly run all timed events as
-				 * root */
-
 	process_blocking_lock_queue(sconn);
 }
 
-- 
2.17.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20180614/60851a3d/signature-0001.sig>


More information about the samba-technical mailing list