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

Stefan Metzmacher metze at samba.org
Sun Jun 17 20:59:04 UTC 2018


Am 14.06.2018 um 22:12 schrieb Jeremy Allison via samba-technical:
> On Thu, Jun 14, 2018 at 08:13:07PM +0200, Stefan Metzmacher wrote:
>> 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.
> 
> Wow, this is a dense patchset :-). I'll study carefully,
> and send feedback.

Here's the update on top of the current part2.

It also passed some autobuilds and is ready and reviewed code wise,
Just the debug messages in [PATCH 35/37] FIXUP: add debuggging to
impersonation will be improved and squashed.

metze

-------------- next part --------------
From d8ada3e398128f965f669354fde26f054b956419 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/37] 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 da8a26c3ee0611cfcedf7c356081b0286fed6cd2 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/37] 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 3485d98d39a1d964f571a6ecada7013c09c6760f 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/37] 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 f8c295f990cde74ae084cd174d84314480b912aa 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/37] 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 12c326138ad47ae56d370eee6958b619c3b086cb 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/37] 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 bc9f5ba0993fce79d517a52275fa027c860246be 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/37] 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 d2305981cba15b383c6321bbc88057d3002db18a 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/37] 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 75be13ece04eca64cdae03f724892ea4b560566d 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/37] 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 36c94f99efb57492a10221f73bf6c8de5445163d 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/37] 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 d55dbcde9cb78d00350e08bd6f6f4c5faef33950 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/37] 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 9cd581d1fb45c2416cf0daa1ab81c2e95ee567be 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/37] 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 c125b3d2fd08a34508afb91a2c2a3ee8a4e8735f 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/37] 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 8ef043b2d2f8b0abd0ff68f9c54aa0570702f565 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/37] 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 248f997b370408199c4e29ecfd1de7b7d67b837c 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/37] 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 c15eaea332b64f6ea7433ac6f900974af90632c7 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/37] 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 2bf0006dc6d03c21dc74dfc1ac5583c7db8e442c 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/37] 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 154521178eecafefa8a20d2161752891923461eb 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/37] 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 daa635bd1f60a92e338333183ca1d8970f1884ea 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/37] 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 c6cc0cbc10461cf43eaccfcf0120bdf8962a0822 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/37] 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 f5a35f3fdb0ff17ca6395bfc9207bceeaf65af69 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/37] 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 e204c5733fb7cfe8bb1043a42a2c29f382bca807 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 16 Jun 2018 14:12:01 +0200
Subject: [PATCH 21/37] tevent: add a simple wrapper test

This checks that for all supported event types the before and after
handlers are called.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/testsuite.c | 327 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 327 insertions(+)

diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index dba8f5895f76..ac274223d8bd 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -696,6 +696,329 @@ static bool test_event_fd2(struct torture_context *tctx,
 	return true;
 }
 
+struct test_wrapper_state {
+	struct torture_context *tctx;
+	int num_events;
+	int num_wrap_handlers;
+};
+
+static bool test_wrapper_before_use(struct tevent_context *wrap_ev,
+				    void *private_data,
+				    struct tevent_context *main_ev,
+				    const char *location)
+{
+	struct test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+	return true;
+}
+
+static void test_wrapper_after_use(struct tevent_context *wrap_ev,
+				   void *private_data,
+				   struct tevent_context *main_ev,
+				   const char *location)
+{
+	struct test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static void test_wrapper_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 test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_wrap_handlers++;
+}
+
+static const struct tevent_wrapper_ops test_wrapper_ops = {
+	.name				= "test_wrapper",
+	.before_use			= test_wrapper_before_use,
+	.after_use			= test_wrapper_after_use,
+	.before_fd_handler		= test_wrapper_before_fd_handler,
+	.after_fd_handler		= test_wrapper_after_fd_handler,
+	.before_timer_handler		= test_wrapper_before_timer_handler,
+	.after_timer_handler		= test_wrapper_after_timer_handler,
+	.before_immediate_handler	= test_wrapper_before_immediate_handler,
+	.after_immediate_handler	= test_wrapper_after_immediate_handler,
+	.before_signal_handler		= test_wrapper_before_signal_handler,
+	.after_signal_handler		= test_wrapper_after_signal_handler,
+};
+
+static void test_wrapper_timer_handler(struct tevent_context *ev,
+				       struct tevent_timer *te,
+				       struct timeval tv,
+				       void *private_data)
+{
+	struct test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+
+	torture_comment(state->tctx, "timer handler\n");
+
+	state->num_events++;
+	talloc_free(te);
+	return;
+}
+
+static void test_wrapper_fd_handler(struct tevent_context *ev,
+				    struct tevent_fd *fde,
+				    unsigned short fd_flags,
+				    void *private_data)
+{
+	struct test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	torture_comment(state->tctx, "fd handler\n");
+
+	state->num_events++;
+	talloc_free(fde);
+	return;
+}
+
+static void test_wrapper_immediate_handler(struct tevent_context *ev,
+					   struct tevent_immediate *im,
+					   void *private_data)
+{
+	struct test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	state->num_events++;
+	talloc_free(im);
+
+	torture_comment(state->tctx, "immediate handler\n");
+
+	tevent_context_before_use(ev);
+	tevent_context_after_use(ev);
+	return;
+}
+
+static void test_wrapper_signal_handler(struct tevent_context *ev,
+					struct tevent_signal *se,
+					int signum,
+					int count,
+					void *siginfo,
+					void *private_data)
+{
+	struct test_wrapper_state *state =
+		(struct test_wrapper_state *)private_data;
+
+	torture_comment(state->tctx, "signal handler\n");
+
+	state->num_events++;
+	talloc_free(se);
+	return;
+}
+
+static bool test_wrapper(struct torture_context *tctx,
+			 const void *test_data)
+{
+	struct test_wrapper_state *state = NULL;
+	int sock[2] = { -1, -1};
+	uint8_t c = 0;
+	const int num_events = 4;
+	const char *backend = (const char *)test_data;
+	struct tevent_context *ev = NULL;
+	struct tevent_context *wrap_ev = NULL;
+	struct tevent_fd *fde = NULL;
+	struct tevent_timer *te = NULL;
+	struct tevent_signal *se = NULL;
+	struct tevent_immediate *im = NULL;
+	int ret;
+	bool ok = false;
+
+	ev = tevent_context_init_byname(tctx, backend);
+	if (ev == NULL) {
+		torture_skip(tctx, talloc_asprintf(tctx,
+			     "event backend '%s' not supported\n",
+			     backend));
+		return true;
+	}
+
+	tevent_set_debug_stderr(ev);
+	torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+	wrap_ev = tevent_context_wrapper_create(
+		ev, ev,	&test_wrapper_ops, &state, struct test_wrapper_state);
+	torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+				     "tevent_context_wrapper_create failed\n");
+	*state = (struct test_wrapper_state) {
+		.tctx = tctx,
+	};
+
+	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+	torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+	te = tevent_add_timer(wrap_ev, wrap_ev,
+			      timeval_current_ofs(0, 0),
+			      test_wrapper_timer_handler, state);
+	torture_assert_not_null_goto(tctx, te, ok, done,
+				     "tevent_add_timer failed\n");
+
+	fde = tevent_add_fd(wrap_ev, wrap_ev,
+			    sock[1],
+			    TEVENT_FD_READ,
+			    test_wrapper_fd_handler,
+			    state);
+	torture_assert_not_null_goto(tctx, fde, ok, done,
+				     "tevent_add_fd failed\n");
+
+	im = tevent_create_immediate(wrap_ev);
+	torture_assert_not_null_goto(tctx, im, ok, done,
+				     "tevent_create_immediate failed\n");
+
+	se = tevent_add_signal(wrap_ev, wrap_ev,
+			       SIGUSR1,
+			       0,
+			       test_wrapper_signal_handler,
+			       state);
+	torture_assert_not_null_goto(tctx, se, ok, done,
+				     "tevent_add_signal failed\n");
+
+	do_write(sock[0], &c, 1);
+	kill(getpid(), SIGUSR1);
+	tevent_schedule_immediate(im,
+				  wrap_ev,
+				  test_wrapper_immediate_handler,
+				  state);
+
+	ret = tevent_loop_wait(ev);
+	torture_assert_goto(tctx, ret == 0, ok, done, "tevent_loop_wait failed\n");
+
+	torture_comment(tctx, "Num events: %d\n", state->num_events);
+	torture_comment(tctx, "Num wrap handlers: %d\n",
+			state->num_wrap_handlers);
+
+	torture_assert_goto(tctx, state->num_events == num_events, ok, done,
+			    "Wrong event count\n");
+	torture_assert_goto(tctx, state->num_wrap_handlers == num_events*2+2,
+			    ok, done, "Wrong wrapper count\n");
+
+	ok = true;
+
+done:
+	TALLOC_FREE(wrap_ev);
+	TALLOC_FREE(ev);
+
+	if (sock[0] != -1) {
+		close(sock[0]);
+	}
+	if (sock[1] != -1) {
+		close(sock[1]);
+	}
+	return ok;
+}
+
 #ifdef HAVE_PTHREAD
 
 static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1280,6 +1603,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
 					       "fd2",
 					       test_event_fd2,
 					       (const void *)list[i]);
+		torture_suite_add_simple_tcase_const(backend_suite,
+					       "wrapper",
+					       test_wrapper,
+					       (const void *)list[i]);
 
 		torture_suite_add_suite(suite, backend_suite);
 	}
-- 
2.17.1


From bda6854a2e4d426900401f6fec6d8292e3f11c43 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 16 Jun 2018 16:55:44 +0200
Subject: [PATCH 22/37] tevent: add a test that frees wrapper_ev with pending
 events

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 lib/tevent/testsuite.c | 165 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index ac274223d8bd..a76df44dc880 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -1019,6 +1019,167 @@ done:
 	return ok;
 }
 
+struct test_free_wrapper_state {
+	struct torture_context *tctx;
+	int num_wrap_handlers;
+};
+
+static void test_free_wrapper_signal_handler(struct tevent_context *ev,
+					struct tevent_signal *se,
+					int signum,
+					int count,
+					void *siginfo,
+					void *private_data)
+{
+	struct test_free_wrapper_state *state =
+		(struct test_free_wrapper_state *)private_data;
+
+	torture_comment(state->tctx, "signal handler\n");
+
+	talloc_free(se);
+
+	/*
+	 * signal handlers have highest priority in tevent, so this signal
+	 * handler will always be started before the other handlers
+	 * below. Freeing the (wrapper) event context here tests that the
+	 * wrapper implementation correclty handles the wrapper ev going away
+	 * with pending events.
+	 */
+	talloc_free(ev);
+	return;
+}
+
+static void test_free_wrapper_fd_handler(struct tevent_context *ev,
+					 struct tevent_fd *fde,
+					 unsigned short fd_flags,
+					 void *private_data)
+{
+	struct test_free_wrapper_state *state =
+		(struct test_free_wrapper_state *)private_data;
+
+	torture_comment(state->tctx, "fd handler\n");
+
+	talloc_free(fde);
+	return;
+}
+
+static void test_free_wrapper_immediate_handler(struct tevent_context *ev,
+					   struct tevent_immediate *im,
+					   void *private_data)
+{
+	struct test_free_wrapper_state *state =
+		(struct test_free_wrapper_state *)private_data;
+
+	torture_comment(state->tctx, "immediate handler\n");
+
+	talloc_free(im);
+	return;
+}
+
+static void test_free_wrapper_timer_handler(struct tevent_context *ev,
+				       struct tevent_timer *te,
+				       struct timeval tv,
+				       void *private_data)
+{
+	struct test_free_wrapper_state *state =
+		(struct test_free_wrapper_state *)private_data;
+
+
+	torture_comment(state->tctx, "timer handler\n");
+
+	talloc_free(te);
+	return;
+}
+
+static bool test_free_wrapper(struct torture_context *tctx,
+			      const void *test_data)
+{
+	struct test_free_wrapper_state *state = NULL;
+	int sock[2] = { -1, -1};
+	uint8_t c = 0;
+	const char *backend = (const char *)test_data;
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev = NULL;
+	struct tevent_context *wrap_ev = NULL;
+	struct tevent_fd *fde = NULL;
+	struct tevent_timer *te = NULL;
+	struct tevent_signal *se = NULL;
+	struct tevent_immediate *im = NULL;
+	int ret;
+	bool ok = false;
+
+	ev = tevent_context_init_byname(frame, backend);
+	if (ev == NULL) {
+		torture_skip(tctx, talloc_asprintf(tctx,
+			     "event backend '%s' not supported\n",
+			     backend));
+		return true;
+	}
+
+	tevent_set_debug_stderr(ev);
+	torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+	wrap_ev = tevent_context_wrapper_create(
+		ev, ev,	&test_wrapper_ops, &state, struct test_free_wrapper_state);
+	torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+				     "tevent_context_wrapper_create failed\n");
+	*state = (struct test_free_wrapper_state) {
+		.tctx = tctx,
+	};
+
+	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+	torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+	fde = tevent_add_fd(wrap_ev, frame,
+			    sock[1],
+			    TEVENT_FD_READ,
+			    test_free_wrapper_fd_handler,
+			    state);
+	torture_assert_not_null_goto(tctx, fde, ok, done,
+				     "tevent_add_fd failed\n");
+
+	te = tevent_add_timer(wrap_ev, frame,
+			      timeval_current_ofs(0, 0),
+			      test_free_wrapper_timer_handler, state);
+	torture_assert_not_null_goto(tctx, te, ok, done,
+				     "tevent_add_timer failed\n");
+
+	im = tevent_create_immediate(frame);
+	torture_assert_not_null_goto(tctx, im, ok, done,
+				     "tevent_create_immediate failed\n");
+
+	se = tevent_add_signal(wrap_ev, frame,
+			       SIGUSR1,
+			       0,
+			       test_free_wrapper_signal_handler,
+			       state);
+	torture_assert_not_null_goto(tctx, se, ok, done,
+				     "tevent_add_signal failed\n");
+
+	do_write(sock[0], &c, 1);
+	kill(getpid(), SIGUSR1);
+	tevent_schedule_immediate(im,
+				  wrap_ev,
+				  test_free_wrapper_immediate_handler,
+				  state);
+
+	ret = tevent_loop_wait(ev);
+	torture_assert_goto(tctx, ret == 0, ok, done, "tevent_loop_wait failed\n");
+
+	ok = true;
+
+done:
+	TALLOC_FREE(frame);
+
+	if (sock[0] != -1) {
+		close(sock[0]);
+	}
+	if (sock[1] != -1) {
+		close(sock[1]);
+	}
+	return ok;
+}
+
 #ifdef HAVE_PTHREAD
 
 static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1607,6 +1768,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
 					       "wrapper",
 					       test_wrapper,
 					       (const void *)list[i]);
+		torture_suite_add_simple_tcase_const(backend_suite,
+					       "free_wrapper",
+					       test_free_wrapper,
+					       (const void *)list[i]);
 
 		torture_suite_add_suite(suite, backend_suite);
 	}
-- 
2.17.1


From 73a0922a976f2ad48de2fd56b0ea22cad1ac9263 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 23/37] 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 541f38b8345745858a376ccd165d91f4cce27b65 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 24/37] 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 9451a7f71a9c954d04626e16c21b97c281918be3 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/37] 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 3082e5147c2fcdb6d4f6a2dce421412959e305ad 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 26/37] 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 1a4c554b30ce532347759ea74c9c9c838e392502 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 27/37] 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 f4bae1e1e906cf7842db80603a23215cffe24374 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 28/37] 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 30e323d7c8ee44c1d96e5839f26fed4a511d5dad 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 29/37] 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 86353ffe29515654854ed643e0e83a1f8b7c9e98 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 30/37] 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 e021031a8b75..0732a88d5295 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -594,6 +594,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;
+}
+
 /****************************************************************************
  Push the current security context then force a change via change_to_user().
  Saves and restores the connection context.
-- 
2.17.1


From 08091cb84d8049223f00def9b3b39dbf7212eefa 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 31/37] 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 0732a88d5295..2ac0d885ee3c 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 1bffff6b97f0232a2ae8f16d472aba87cfc7661f 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 32/37] 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 2ac0d885ee3c..f23a6b680d05 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -953,3 +953,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 648e614d3db12e14c39529f39c7c6a0321d4c4ac 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/37] 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 bac9d8f6bf66..dae1707429a0 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 a3571ee811ab..dc95af17393b 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -3900,6 +3900,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;
@@ -3912,6 +3914,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));
@@ -3932,8 +3946,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 f23a6b680d05..6f586e03a5aa 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -306,7 +306,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);
 }
 
@@ -481,7 +481,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 c2473b7b40ecf8bebb172f2add7f982a02534dbf 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 34/37] 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 6f586e03a5aa..3872d3866db2 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -970,52 +970,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 848da8502547ac86897007e94d7c7957b3819753 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 17 Jun 2018 11:50:08 +0200
Subject: [PATCH 35/37] FIXUP: add debuggging to impersonation

---
 source3/smbd/uid.c | 178 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 178 insertions(+)

diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 3872d3866db2..477da82fd25b 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -985,11 +985,22 @@ static bool smbd_impersonate_conn_vuid_before_use(struct tevent_context *wrap_ev
 		struct smbd_impersonate_conn_vuid_state);
 	bool ok;
 
+	DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
+		  "old uid[%ju] old gid[%ju] vuid[%ju] cwd[%s]\n",
+		  __func__, wrap_ev, main_ev, location,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  (uintmax_t)state->vuid, state->conn->cwd_fname->base_name));
+
 	ok = change_to_user(state->conn, state->vuid);
 	if (!ok) {
 		return false;
 	}
 
+	DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
+		  __func__, state->conn->session_info->unix_info->unix_name,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  state->conn->cwd_fname->base_name));
+
 	return true;
 }
 
@@ -1005,6 +1016,12 @@ static void smbd_impersonate_conn_vuid_after_use(struct tevent_context *wrap_ev,
 		.base_name = discard_const_p(char, "/"),
 	};
 
+	DEBUG(11,("%s: deimpersonating[%s] uid[%ju] gid[%ju] cwd[%s] "
+		  "location[%s]\n",
+		  __func__, state->conn->session_info->unix_info->unix_name,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  state->conn->cwd_fname->base_name, location));
+
 	vfs_ChDir(state->conn, &root_fname);
 	change_to_root_user();
 }
@@ -1019,6 +1036,9 @@ static void smbd_impersonate_conn_vuid_before_fd_handler(struct tevent_context *
 {
 	bool ok;
 
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
+
 	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
 						   main_ev, location);
 	if (!ok) {
@@ -1035,6 +1055,9 @@ static void smbd_impersonate_conn_vuid_after_fd_handler(struct tevent_context *w
 							const char *handler_name,
 							const char *location)
 {
+	DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
+		  __func__, fde, handler_name, location));
+
 	/* be lazy and defer change_to_root_user() */
 }
 
@@ -1048,6 +1071,15 @@ static void smbd_impersonate_conn_vuid_before_timer_handler(struct tevent_contex
 							    const char *location)
 {
 	bool ok;
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+
+	DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, te,
+		  timeval_str_buf(&requested_time, true, true, &requested_buf),
+		  timeval_str_buf(&trigger_time, true, true, &trigger_buf),
+		  handler_name, location));
 
 	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
 						   main_ev, location);
@@ -1066,6 +1098,9 @@ static void smbd_impersonate_conn_vuid_after_timer_handler(struct tevent_context
 							   const char *handler_name,
 							   const char *location)
 {
+	DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
+		  __func__, te, handler_name, location));
+
 	/* be lazy and defer change_to_root_user() */
 }
 
@@ -1078,6 +1113,9 @@ static void smbd_impersonate_conn_vuid_before_immediate_handler(struct tevent_co
 {
 	bool ok;
 
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
 						   main_ev, location);
 	if (!ok) {
@@ -1093,6 +1131,9 @@ static void smbd_impersonate_conn_vuid_after_immediate_handler(struct tevent_con
 							       const char *handler_name,
 							       const char *location)
 {
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	/* be lazy and defer unbecome_user() */
 }
 
@@ -1108,6 +1149,10 @@ static void smbd_impersonate_conn_vuid_before_signal_handler(struct tevent_conte
 {
 	bool ok;
 
+	DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, se, signum, count, siginfo, handler_name, location));
+
 	ok = smbd_impersonate_conn_vuid_before_use(wrap_ev, private_data,
 						   main_ev, location);
 	if (!ok) {
@@ -1126,6 +1171,9 @@ static void smbd_impersonate_conn_vuid_after_signal_handler(struct tevent_contex
 							    const char *handler_name,
 							    const char *location)
 {
+	DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
+		  __func__, se, handler_name, location));
+
 	/* be lazy and defer change_to_root_user() */
 }
 
@@ -1180,11 +1228,23 @@ static bool smbd_impersonate_conn_sess_before_use(struct tevent_context *wrap_ev
 				      struct smbd_impersonate_conn_sess_state);
 	bool ok;
 
+	DEBUG(11,("%s: impersonating user[%s] wrap_ev[%p] main_ev[%p] location[%s] "
+		  "old uid[%ju] old gid[%ju] cwd[%s]\n",
+		  __func__, state->session_info->unix_info->unix_name,
+		  wrap_ev, main_ev, location,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  state->conn->cwd_fname->base_name));
+
 	ok = change_to_user_by_session(state->conn, state->session_info);
 	if (!ok) {
 		return false;
 	}
 
+	DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
+		  __func__, state->conn->session_info->unix_info->unix_name,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  state->conn->cwd_fname->base_name));
+
 	return true;
 }
 
@@ -1200,6 +1260,12 @@ static void smbd_impersonate_conn_sess_after_use(struct tevent_context *wrap_ev,
 		.base_name = discard_const_p(char, "/"),
 	};
 
+	DEBUG(11,("%s: deimpersonating[%s] uid[%ju] gid[%ju] cwd[%s] "
+		  "location[%s]\n",
+		  __func__, state->session_info->unix_info->unix_name,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  state->conn->cwd_fname->base_name, location));
+
 	vfs_ChDir(state->conn, &root_fname);
 	change_to_root_user();
 }
@@ -1214,6 +1280,9 @@ static void smbd_impersonate_conn_sess_before_fd_handler(struct tevent_context *
 {
 	bool ok;
 
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
+
 	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
 						   main_ev, location);
 	if (!ok) {
@@ -1230,6 +1299,9 @@ static void smbd_impersonate_conn_sess_after_fd_handler(struct tevent_context *w
 							const char *handler_name,
 							const char *location)
 {
+	DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
+		  __func__, fde, handler_name, location));
+
 	/* be lazy and defer change_to_root_user() */
 }
 
@@ -1243,6 +1315,15 @@ static void smbd_impersonate_conn_sess_before_timer_handler(struct tevent_contex
 							    const char *location)
 {
 	bool ok;
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+
+	DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, te,
+		  timeval_str_buf(&requested_time, true, true, &requested_buf),
+		  timeval_str_buf(&trigger_time, true, true, &trigger_buf),
+		  handler_name, location));
 
 	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
 						   main_ev, location);
@@ -1261,6 +1342,9 @@ static void smbd_impersonate_conn_sess_after_timer_handler(struct tevent_context
 							   const char *handler_name,
 							   const char *location)
 {
+	DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
+		  __func__, te, handler_name, location));
+
 	/* be lazy and defer change_to_root_user() */
 }
 
@@ -1273,6 +1357,9 @@ static void smbd_impersonate_conn_sess_before_immediate_handler(struct tevent_co
 {
 	bool ok;
 
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
 						   main_ev, location);
 	if (!ok) {
@@ -1288,6 +1375,9 @@ static void smbd_impersonate_conn_sess_after_immediate_handler(struct tevent_con
 							       const char *handler_name,
 							       const char *location)
 {
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	/* be lazy and defer unbecome_user() */
 }
 
@@ -1303,6 +1393,10 @@ static void smbd_impersonate_conn_sess_before_signal_handler(struct tevent_conte
 {
 	bool ok;
 
+	DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, se, signum, count, siginfo, handler_name, location));
+
 	ok = smbd_impersonate_conn_sess_before_use(wrap_ev, private_data,
 						   main_ev, location);
 	if (!ok) {
@@ -1321,6 +1415,9 @@ static void smbd_impersonate_conn_sess_after_signal_handler(struct tevent_contex
 							    const char *handler_name,
 							    const char *location)
 {
+	DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
+		  __func__, se, handler_name, location));
+
 	/* be lazy and defer change_to_root_user() */
 }
 
@@ -1369,6 +1466,11 @@ static bool smbd_impersonate_root_before_use(struct tevent_context *wrap_ev,
 					     struct tevent_context *main_ev,
 					     const char *location)
 {
+	DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
+		  "uid[%ju] gid[%ju]\n",
+		  __func__, wrap_ev, main_ev, location,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid()));
+
 	become_root();
 	return true;
 }
@@ -1379,6 +1481,10 @@ static void smbd_impersonate_root_after_use(struct tevent_context *wrap_ev,
 					    const char *location)
 {
 	unbecome_root();
+
+	DEBUG(11,("%s: uid[%ju] gid[%ju] location[%s]\n",
+		  __func__, (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  location));
 }
 
 static void smbd_impersonate_root_before_fd_handler(struct tevent_context *wrap_ev,
@@ -1389,6 +1495,9 @@ static void smbd_impersonate_root_before_fd_handler(struct tevent_context *wrap_
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
+
 	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1400,6 +1509,9 @@ static void smbd_impersonate_root_after_fd_handler(struct tevent_context *wrap_e
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
+		  __func__, fde, handler_name, location));
+
 	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1412,6 +1524,16 @@ static void smbd_impersonate_root_before_timer_handler(struct tevent_context *wr
 						const char *handler_name,
 						const char *location)
 {
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+
+	DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, te,
+		  timeval_str_buf(&requested_time, true, true, &requested_buf),
+		  timeval_str_buf(&trigger_time, true, true, &trigger_buf),
+		  handler_name, location));
+
 	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1424,6 +1546,9 @@ static void smbd_impersonate_root_after_timer_handler(struct tevent_context *wra
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
+		  __func__, te, handler_name, location));
+
 	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1434,6 +1559,9 @@ static void smbd_impersonate_root_before_immediate_handler(struct tevent_context
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1444,6 +1572,9 @@ static void smbd_impersonate_root_after_immediate_handler(struct tevent_context
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1457,6 +1588,10 @@ static void smbd_impersonate_root_before_signal_handler(struct tevent_context *w
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, se, signum, count, siginfo, handler_name, location));
+
 	smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1470,6 +1605,9 @@ static void smbd_impersonate_root_after_signal_handler(struct tevent_context *wr
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
+		  __func__, se, handler_name, location));
+
 	smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1513,6 +1651,11 @@ static bool smbd_impersonate_guest_before_use(struct tevent_context *wrap_ev,
 					      struct tevent_context *main_ev,
 					      const char *location)
 {
+	DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
+		  "uid[%ju] gid[%ju]\n",
+		  __func__, wrap_ev, main_ev, location,
+		  (uintmax_t)geteuid(), (uintmax_t)getegid()));
+
 	return become_guest();
 }
 
@@ -1522,6 +1665,10 @@ static void smbd_impersonate_guest_after_use(struct tevent_context *wrap_ev,
 					     const char *location)
 {
 	unbecome_guest();
+
+	DEBUG(11,("%s: uid[%ju] gid[%ju] location[%s]\n",
+		  __func__, (uintmax_t)geteuid(), (uintmax_t)getegid(),
+		  location));
 }
 
 static void smbd_impersonate_guest_before_fd_handler(struct tevent_context *wrap_ev,
@@ -1534,6 +1681,9 @@ static void smbd_impersonate_guest_before_fd_handler(struct tevent_context *wrap
 {
 	bool ok;
 
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
+
 	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
 					        main_ev, location);
 	if (!ok) {
@@ -1550,6 +1700,9 @@ static void smbd_impersonate_guest_after_fd_handler(struct tevent_context *wrap_
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
+		  __func__, fde, handler_name, location));
+
 	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1563,6 +1716,15 @@ static void smbd_impersonate_guest_before_timer_handler(struct tevent_context *w
 						const char *location)
 {
 	bool ok;
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+
+	DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, te,
+		  timeval_str_buf(&requested_time, true, true, &requested_buf),
+		  timeval_str_buf(&trigger_time, true, true, &trigger_buf),
+		  handler_name, location));
 
 	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
 					       main_ev, location);
@@ -1581,6 +1743,9 @@ static void smbd_impersonate_guest_after_timer_handler(struct tevent_context *wr
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
+		  __func__, te, handler_name, location));
+
 	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1593,6 +1758,9 @@ static void smbd_impersonate_guest_before_immediate_handler(struct tevent_contex
 {
 	bool ok;
 
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
 					       main_ev, location);
 	if (!ok) {
@@ -1608,6 +1776,9 @@ static void smbd_impersonate_guest_after_immediate_handler(struct tevent_context
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
 	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
 }
 
@@ -1623,6 +1794,10 @@ static void smbd_impersonate_guest_before_signal_handler(struct tevent_context *
 {
 	bool ok;
 
+	DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
+		  "handler_name[%s] location[%s]\n",
+		  __func__, se, signum, count, siginfo, handler_name, location));
+
 	ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
 					       main_ev, location);
 	if (!ok) {
@@ -1641,6 +1816,9 @@ static void smbd_impersonate_guest_after_signal_handler(struct tevent_context *w
 						const char *handler_name,
 						const char *location)
 {
+	DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
+		  __func__, se, handler_name, location));
+
 	smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
 }
 
-- 
2.17.1


From 44c3d12ec7ea76bbca99a632b27a2723bcd46b53 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 36/37] 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 dc95af17393b..0a4106257f58 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 f0a1a64ee1769f7c59369624ff33242fd39830ed 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 37/37] 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/20180617/717ddd6c/signature-0001.sig>


More information about the samba-technical mailing list