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

Stefan Metzmacher metze at samba.org
Wed Jul 11 22:41:36 UTC 2018


Hi,

here's an updated patchset for the impersonation in smbd,
which is required to implement path based async SMB_VFS functions.

This applies on top of the tevent related patches (for tevent-0.9.37).

As this is not really needed for 4.9.0 it can be pushed after 4.9.0rc1
is branched, on the other side it won't hurt to have it there
and have it tested in a release cycle before we really require it.

It also passed private autobuilds a few times.

Please review and push:-)

Thanks!
metze

Am 17.06.2018 um 22:59 schrieb Stefan Metzmacher via samba-technical:
> 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 301e39aec315427ea4a0d48de1bdcc0016b286c8 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 1/8] 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 9d5321cf4ccc..c6c4573f9c9b 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -598,6 +598,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 871bb6b30c4d65543b6baee1729dec6d26ae947c 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 2/8] 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 c6c4573f9c9b..98202b13de13 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 2a5f58b14eda70c9298d848929ee313fb365d666 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 3/8] 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 98202b13de13..18af3df2e630 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -957,3 +957,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 ed1045b650c3b6a1059c32fa14c3c34b214d1da4 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 4/8] 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 18af3df2e630..9799f8b59dd1 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 e61046eb9a71e44dcf4e3dd4dd4c382d1de51a11 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 5/8] 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.

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

diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 9799f8b59dd1..fcc4d51a698c 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -974,52 +974,961 @@ 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;
+
+	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 = become_user(state->conn, state->vuid);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		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;
+}
+
+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);
+	bool ok;
+
+	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));
+
+	ok = unbecome_user();
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_after_use() - failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_vuid_state);
+	bool ok;
+
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
+
+	ok = change_to_user(state->conn, state->vuid);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
+		  __func__, fde, handler_name, 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)
+{
+	struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_vuid_state);
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+	bool ok;
+
+	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 = change_to_user(state->conn, state->vuid);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
+		  __func__, te, handler_name, 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)
+{
+	struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_vuid_state);
+	bool ok;
+
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
+	ok = change_to_user(state->conn, state->vuid);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, 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)
+{
+	struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_vuid_state);
+	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 = change_to_user(state->conn, state->vuid);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
+		  __func__, se, handler_name, 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;
+
+	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 = become_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;
+}
+
+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);
+	bool ok;
+
+	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));
+
+	ok = unbecome_user();
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_after_use() - failed");
+		return;
+	}
+
+	DEBUG(11,("%s: deimpersonated 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));
+}
+
+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)
+{
+	struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_sess_state);
+	bool ok;
+
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
+
+	ok = change_to_user_by_session(state->conn, state->session_info);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_fd_handler failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
+		  __func__, fde, handler_name, 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)
+{
+	struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_sess_state);
+	struct timeval_buf requested_buf;
+	struct timeval_buf trigger_buf;
+	bool ok;
+
+	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 = change_to_user_by_session(state->conn, state->session_info);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_tm_handler failed");
+		return;
+	}
+
+	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));
 }
 
+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)
+{
+	DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
+		  __func__, te, handler_name, 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)
+{
+	struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_sess_state);
+	bool ok;
+
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, location));
+
+	ok = change_to_user_by_session(state->conn, state->session_info);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_im_handler failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
+		  __func__, im, handler_name, 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)
+{
+	struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
+		private_data, struct smbd_impersonate_conn_sess_state);
+	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 = change_to_user_by_session(state->conn, state->session_info);
+	if (!ok) {
+		smb_panic("smbd_impersonate_conn_sess_before_si_handler failed");
+		return;
+	}
+
+	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));
+}
+
+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)
+{
+	DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
+		  __func__, se, handler_name, 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;
+
+	return ev;
+}
 
-	wrap_ev = smbd_impersonate_debug_create(main_ev,
-						"conn_sess",
-						DBGLVL_DEBUG);
+struct smbd_impersonate_root_state {
+	uint8_t _dummy;
+};
 
-	return wrap_ev;
+static bool smbd_impersonate_root_before_use(struct tevent_context *wrap_ev,
+					     void *private_data,
+					     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;
+}
+
+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();
+
+	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,
+						void *private_data,
+						struct tevent_context *main_ev,
+						struct tevent_fd *fde,
+						uint16_t flags,
+						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);
+}
+
+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)
+{
+	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);
 }
 
+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)
+{
+	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);
+}
+
+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)
+{
+	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);
+}
+
+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)
+{
+	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);
+}
+
+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)
+{
+	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);
+}
+
+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)
+{
+	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);
+}
+
+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)
+{
+	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);
+}
+
+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)
+{
+	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();
 }
 
-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();
+
+	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,
+						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);
+	DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
+		  __func__, fde, (uintmax_t)flags, handler_name, location));
 
-	return wrap_ev;
+	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_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)
+{
+	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);
+}
+
+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;
+	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);
+	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)
+{
+	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);
+}
+
+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;
+
+	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) {
+		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)
+{
+	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);
+}
+
+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;
+
+	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) {
+		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)
+{
+	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);
+}
+
+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 3be0671ca9c6bed639122bccfadb2523a4f69297 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 Jun 2018 19:20:53 +0200
Subject: [PATCH 6/8] smbd: avoid explicit change_to_user() in
 defer_rename_done() already done by impersonation

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

diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
index 5a6a28a323e2..1f07b7e11900 100644
--- a/source3/smbd/smb2_setinfo.c
+++ b/source3/smbd/smb2_setinfo.c
@@ -281,7 +281,6 @@ static void defer_rename_done(struct tevent_req *subreq)
 	NTSTATUS status;
 	struct share_mode_lock *lck;
 	int ret_size = 0;
-	bool ok;
 
 	status = dbwrap_watched_watch_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
@@ -292,16 +291,6 @@ static void defer_rename_done(struct tevent_req *subreq)
 		return;
 	}
 
-	/*
-	 * Make sure we run as the user again
-	 */
-	ok = change_to_user(state->smb2req->tcon->compat,
-			    state->smb2req->session->compat->vuid);
-	if (!ok) {
-		tevent_req_nterror(state->req, NT_STATUS_ACCESS_DENIED);
-		return;
-	}
-
 	/* Do we still need to wait ? */
 	lck = get_existing_share_mode_lock(state->req, state->fsp->file_id);
 	if (lck == NULL) {
-- 
2.17.1


From 5d4e3e300cbef625209be19ce19aa4fe6a10ea19 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 7/8] 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 a2b81ecdcbdd5ac406e34fa3245deff11cf0ada4 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 8/8] 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/20180712/90b7e568/signature.sig>


More information about the samba-technical mailing list