smbd: implement smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create() wrappers
authorStefan Metzmacher <metze@samba.org>
Fri, 11 May 2012 13:51:42 +0000 (15:51 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 12 Jul 2018 12:25:18 +0000 (14:25 +0200)
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@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/smbd/uid.c

index 9799f8b59dd1477f9b26dcf0981b2dfc32ac4279..fcc4d51a698c544365b5f2b9f01098372ee72345 100644 (file)
@@ -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;
 }