*/
#include "includes.h"
-#include "system/filesys.h"
#include "system/passwd.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "auth.h"
#include "../auth/auth_util.h"
#include "lib/util/time_basic.h"
-#include "lib/pthreadpool/pthreadpool_tevent.h"
-
-static struct smb_vfs_ev_glue *smbd_impersonate_user_ev_glue_create(
- struct connection_struct *conn,
- uint64_t vuid,
- struct auth_session_info *session_info);
struct smbd_impersonate_debug_state {
int dbg_lvl;
}
}
/* Not used, safe to free. */
- conn->user_ev_ctx = NULL;
- TALLOC_FREE(conn->user_vfs_evg);
+ TALLOC_FREE(conn->user_ev_ctx);
TALLOC_FREE(conn->session_info);
}
}
free_conn_session_info_if_unused(conn);
conn->session_info = ent->session_info;
- conn->user_vfs_evg = ent->user_vfs_evg;
+ conn->user_ev_ctx = ent->user_ev_ctx;
conn->read_only = ent->read_only;
conn->share_access = ent->share_access;
conn->vuid = ent->vuid;
- conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(
- conn->user_vfs_evg);
- SMB_ASSERT(conn->user_ev_ctx != NULL);
return(True);
}
}
ent->session_info->unix_token->uid = sec_initial_uid();
}
- ent->user_vfs_evg = smbd_impersonate_user_ev_glue_create(conn,
- vuid, ent->session_info);
- if (ent->user_vfs_evg == NULL) {
- TALLOC_FREE(ent->session_info);
- ent->vuid = UID_FIELD_INVALID;
- return false;
+ 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;
+ }
}
/*
free_conn_session_info_if_unused(conn);
conn->session_info = ent->session_info;
conn->vuid = ent->vuid;
- conn->user_vfs_evg = ent->user_vfs_evg;
- conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(conn->user_vfs_evg);
- SMB_ASSERT(conn->user_ev_ctx != NULL);
-
+ conn->user_ev_ctx = ent->user_ev_ctx;
if (vuid == UID_FIELD_INVALID) {
/*
* Not strictly needed, just make it really
ent->read_only = false;
ent->share_access = 0;
ent->session_info = NULL;
- ent->user_vfs_evg = NULL;
+ ent->user_ev_ctx = NULL;
}
conn->read_only = readonly_share;
return ev;
}
-
-struct smbd_impersonate_tp_current_state {
- const void *conn_ptr;
- uint64_t vuid; /* SMB2 compat */
- struct security_unix_token partial_ut;
- bool chdir_safe;
- int saved_cwd_fd;
-};
-
-static int smbd_impersonate_tp_current_state_destructor(
- struct smbd_impersonate_tp_current_state *state)
-{
- if (state->saved_cwd_fd != -1) {
- smb_panic(__location__);
- }
-
- return 0;
-}
-
-static bool smbd_impersonate_tp_current_before_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- struct smbd_impersonate_tp_current_state *state =
- talloc_get_type_abort(private_data,
- struct smbd_impersonate_tp_current_state);
-
- if (state->conn_ptr != current_user.conn) {
- smb_panic(__location__);
- }
-
- if (state->vuid != current_user.vuid) {
- smb_panic(__location__);
- }
-
- if (state->partial_ut.uid != current_user.ut.uid) {
- smb_panic(__location__);
- }
-
- if (state->partial_ut.gid != current_user.ut.gid) {
- smb_panic(__location__);
- }
-
- if (state->partial_ut.ngroups != current_user.ut.ngroups) {
- smb_panic(__location__);
- }
-
- /*
- * We don't verify the group list, we should have hit
- * an assert before. We only want to catch programmer
- * errors here!
- *
- * We just have a sync pool and want to make sure
- * we're already in the correct state.
- *
- * So we don't do any active impersonation.
- */
-
- /*
- * we may need to remember the current working directory
- * and later restore it in the after_job hook.
- */
- if (state->chdir_safe) {
- int open_flags = O_RDONLY;
- bool ok;
-
-#ifdef O_DIRECTORY
- open_flags |= O_DIRECTORY;
-#endif
-#ifdef O_CLOEXEC
- open_flags |= O_CLOEXEC;
-#endif
-
- state->saved_cwd_fd = open(".", open_flags);
- if (state->saved_cwd_fd == -1) {
- DBG_ERR("unable to open '.' with open_flags[0x%x] - %s\n",
- open_flags, strerror(errno));
- smb_panic("smbd_impersonate_tp_current_before_job: "
- "unable to open cwd '.'");
- return false;
- }
- ok = smb_set_close_on_exec(state->saved_cwd_fd);
- SMB_ASSERT(ok);
- }
-
- return true;
-}
-
-static bool smbd_impersonate_tp_current_after_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- struct smbd_impersonate_tp_current_state *state =
- talloc_get_type_abort(private_data,
- struct smbd_impersonate_tp_current_state);
- int ret;
-
- /*
- * There's no impersonation to revert.
- *
- * But we may need to reset the current working directory.
- */
- if (state->saved_cwd_fd == -1) {
- return true;
- }
-
- ret = fchdir(state->saved_cwd_fd);
- if (ret != 0) {
- DBG_ERR("unable to fchdir to the original directory - %s\n",
- strerror(errno));
- smb_panic("smbd_impersonate_tp_current_after_job: "
- "unable restore cwd with fchdir.");
- return false;
- }
-
- close(state->saved_cwd_fd);
- state->saved_cwd_fd = -1;
-
- return true;
-}
-
-static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_current_ops = {
- .name = "smbd_impersonate_tp_current",
- .before_job = smbd_impersonate_tp_current_before_job,
- .after_job = smbd_impersonate_tp_current_after_job,
-};
-
-struct pthreadpool_tevent *smbd_impersonate_tp_current_create(
- TALLOC_CTX *mem_ctx,
- struct pthreadpool_tevent *sync_tp,
- struct connection_struct *conn,
- uint64_t vuid, bool chdir_safe,
- const struct security_unix_token *unix_token)
-{
- struct pthreadpool_tevent *wrap_tp = NULL;
- struct smbd_impersonate_tp_current_state *state = NULL;
- size_t max_threads;
-
- max_threads = pthreadpool_tevent_max_threads(sync_tp);
- SMB_ASSERT(max_threads == 0);
-
- /*
- * We have a fake threadpool without real threads.
- * So we just provide a a wrapper that asserts that
- * we are already in the required impersonation state.
- */
-
- wrap_tp = pthreadpool_tevent_wrapper_create(sync_tp,
- mem_ctx,
- &smbd_impersonate_tp_current_ops,
- &state,
- struct smbd_impersonate_tp_current_state);
- if (wrap_tp == NULL) {
- return NULL;
- }
-
- state->conn_ptr = conn;
- state->vuid = vuid;
- state->partial_ut = *unix_token;
- state->partial_ut.groups = NULL;
- state->chdir_safe = chdir_safe;
- state->saved_cwd_fd = -1;
-
- if (chdir_safe) {
- pthreadpool_tevent_force_per_thread_cwd(wrap_tp, state);
- }
-
- talloc_set_destructor(state, smbd_impersonate_tp_current_state_destructor);
-
- return wrap_tp;
-}
-
-struct smbd_impersonate_tp_sess_state {
- const struct security_unix_token *unix_token;
-};
-
-static bool smbd_impersonate_tp_sess_before_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- struct smbd_impersonate_tp_sess_state *state =
- talloc_get_type_abort(private_data,
- struct smbd_impersonate_tp_sess_state);
- int ret;
-
- /* Become the correct credential on this thread. */
- ret = set_thread_credentials(state->unix_token->uid,
- state->unix_token->gid,
- (size_t)state->unix_token->ngroups,
- state->unix_token->groups);
- if (ret != 0) {
- return false;
- }
-
- return true;
-}
-
-static bool smbd_impersonate_tp_sess_after_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- /*
- * We skip the 'unbecome' here, if the following
- * job cares, it already called set_thread_credentials() again.
- *
- * fd based jobs on the raw pool, don't really care...
- */
- return true;
-}
-
-static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_sess_ops = {
- .name = "smbd_impersonate_tp_sess",
- .before_job = smbd_impersonate_tp_sess_before_job,
- .after_job = smbd_impersonate_tp_sess_after_job,
-};
-
-static struct pthreadpool_tevent *smbd_impersonate_tp_sess_create(
- TALLOC_CTX *mem_ctx,
- struct pthreadpool_tevent *main_tp,
- struct auth_session_info *session_info)
-{
- struct pthreadpool_tevent *wrap_tp = NULL;
- struct smbd_impersonate_tp_sess_state *state = NULL;
- size_t max_threads;
-
- max_threads = pthreadpool_tevent_max_threads(main_tp);
- SMB_ASSERT(max_threads > 0);
-
- wrap_tp = pthreadpool_tevent_wrapper_create(main_tp,
- mem_ctx,
- &smbd_impersonate_tp_sess_ops,
- &state,
- struct smbd_impersonate_tp_sess_state);
- if (wrap_tp == NULL) {
- return NULL;
- }
-
- state->unix_token = copy_unix_token(state, session_info->unix_token);
- if (state->unix_token == NULL) {
- int saved_errno = errno;
- TALLOC_FREE(wrap_tp);
- errno = saved_errno;
- return NULL;
- }
-
- return wrap_tp;
-}
-
-struct smbd_impersonate_tp_become_state {
- void (*become_fn)(void);
- void (*unbecome_fn)(void);
- bool chdir_safe;
- int saved_cwd_fd;
-};
-
-static int smbd_impersonate_tp_become_state_destructor(
- struct smbd_impersonate_tp_become_state *state)
-{
- if (state->saved_cwd_fd != -1) {
- smb_panic(__location__);
- }
-
- return 0;
-}
-
-
-static bool smbd_impersonate_tp_become_before_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- struct smbd_impersonate_tp_become_state *state =
- talloc_get_type_abort(private_data,
- struct smbd_impersonate_tp_become_state);
-
- /*
- * we may need to remember the current working directory
- * and later restore it in the after_job hook.
- */
- if (state->chdir_safe) {
- int open_flags = O_RDONLY;
- bool ok;
-
-#ifdef O_DIRECTORY
- open_flags |= O_DIRECTORY;
-#endif
-#ifdef O_CLOEXEC
- open_flags |= O_CLOEXEC;
-#endif
-
- state->saved_cwd_fd = open(".", open_flags);
- if (state->saved_cwd_fd == -1) {
- DBG_ERR("unable to open '.' with open_flags[0x%x] - %s\n",
- open_flags, strerror(errno));
- smb_panic("smbd_impersonate_tp_current_before_job: "
- "unable to open cwd '.'");
- return false;
- }
- ok = smb_set_close_on_exec(state->saved_cwd_fd);
- SMB_ASSERT(ok);
- }
-
- /*
- * The function should abort on error...
- */
- state->become_fn();
-
- return true;
-}
-
-static bool smbd_impersonate_tp_become_after_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- struct smbd_impersonate_tp_become_state *state =
- talloc_get_type_abort(private_data,
- struct smbd_impersonate_tp_become_state);
- int ret;
-
- /*
- * The function should abort on error...
- */
- state->unbecome_fn();
-
- /*
- * There's no impersonation to revert.
- *
- * But we may need to reset the current working directory.
- */
- if (state->saved_cwd_fd == -1) {
- return true;
- }
-
- ret = fchdir(state->saved_cwd_fd);
- if (ret != 0) {
- DBG_ERR("unable to fchdir to the original directory - %s\n",
- strerror(errno));
- smb_panic("smbd_impersonate_tp_current_after_job: "
- "unable restore cwd with fchdir.");
- return false;
- }
-
- close(state->saved_cwd_fd);
- state->saved_cwd_fd = -1;
-
- return true;
-}
-
-static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_become_ops = {
- .name = "smbd_impersonate_tp_become",
- .before_job = smbd_impersonate_tp_become_before_job,
- .after_job = smbd_impersonate_tp_become_after_job,
-};
-
-struct pthreadpool_tevent *smbd_impersonate_tp_become_create(
- TALLOC_CTX *mem_ctx,
- struct pthreadpool_tevent *sync_tp,
- bool chdir_safe,
- void (*become_fn)(void),
- void (*unbecome_fn)(void))
-{
- struct pthreadpool_tevent *wrap_tp = NULL;
- struct smbd_impersonate_tp_become_state *state = NULL;
- size_t max_threads;
-
- max_threads = pthreadpool_tevent_max_threads(sync_tp);
- SMB_ASSERT(max_threads == 0);
-
- /*
- * We have a fake threadpool without real threads.
- * So we just provide a a wrapper that asserts that
- * we are already in the required impersonation state.
- */
-
- wrap_tp = pthreadpool_tevent_wrapper_create(sync_tp,
- mem_ctx,
- &smbd_impersonate_tp_become_ops,
- &state,
- struct smbd_impersonate_tp_become_state);
- if (wrap_tp == NULL) {
- return NULL;
- }
-
- state->become_fn = become_fn;
- state->unbecome_fn = unbecome_fn;
- state->chdir_safe = chdir_safe;
- state->saved_cwd_fd = -1;
-
- if (chdir_safe) {
- pthreadpool_tevent_force_per_thread_cwd(wrap_tp, state);
- }
-
- talloc_set_destructor(state, smbd_impersonate_tp_become_state_destructor);
-
- return wrap_tp;
-}
-
-struct smbd_impersonate_tp_root_state {
- const struct security_unix_token *fallback_token;
-};
-
-static bool smbd_impersonate_tp_root_before_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- int ret;
-
- /*
- * Become root in this thread.
- */
- ret = set_thread_credentials(0, 0, 0, NULL);
- if (ret != 0) {
- return false;
- }
-
- return true;
-}
-
-static bool smbd_impersonate_tp_root_after_job(struct pthreadpool_tevent *wrap,
- void *private_data,
- struct pthreadpool_tevent *main,
- const char *location)
-{
- struct smbd_impersonate_tp_root_state *state =
- talloc_get_type_abort(private_data,
- struct smbd_impersonate_tp_root_state);
- int ret;
-
- /*
- * Move to a non root token again.
- * We just use the one of the user_ev_ctx.
- *
- * The main goal is that we don't leave
- * a thread arround with a root token.
- */
- ret = set_thread_credentials(state->fallback_token->uid,
- state->fallback_token->gid,
- (size_t)state->fallback_token->ngroups,
- state->fallback_token->groups);
- if (ret != 0) {
- return false;
- }
-
- return true;
-}
-
-static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_root_ops = {
- .name = "smbd_impersonate_tp_root",
- .before_job = smbd_impersonate_tp_root_before_job,
- .after_job = smbd_impersonate_tp_root_after_job,
-};
-
-static struct pthreadpool_tevent *smbd_impersonate_tp_root_create(
- TALLOC_CTX *mem_ctx,
- struct pthreadpool_tevent *main_tp,
- int snum,
- const struct security_unix_token *fallback_token)
-{
- struct pthreadpool_tevent *wrap_tp = NULL;
- struct smbd_impersonate_tp_root_state *state = NULL;
- size_t max_threads;
-
- max_threads = pthreadpool_tevent_max_threads(main_tp);
- SMB_ASSERT(max_threads > 0);
-
- wrap_tp = pthreadpool_tevent_wrapper_create(main_tp,
- mem_ctx,
- &smbd_impersonate_tp_root_ops,
- &state,
- struct smbd_impersonate_tp_root_state);
- if (wrap_tp == NULL) {
- return NULL;
- }
-
- state->fallback_token = copy_unix_token(state, fallback_token);
- if (state->fallback_token == NULL) {
- int saved_errno = errno;
- TALLOC_FREE(wrap_tp);
- errno = saved_errno;
- return NULL;
- }
-
- return wrap_tp;
-}
-
-static struct smb_vfs_ev_glue *smbd_impersonate_user_ev_glue_create(
- struct connection_struct *conn,
- uint64_t vuid,
- struct auth_session_info *session_info)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- struct smb_vfs_ev_glue *user_vfs_evg = NULL;
- struct tevent_context *user_ev_ctx = NULL;
- struct pthreadpool_tevent *user_tp_fd_safe = NULL;
- struct pthreadpool_tevent *user_tp_path_safe = NULL;
- bool user_tp_path_sync = true;
- struct pthreadpool_tevent *user_tp_chdir_safe = NULL;
- bool user_tp_chdir_sync = true;
- struct pthreadpool_tevent *root_tp_fd_safe = NULL;
- struct pthreadpool_tevent *root_tp_path_safe = NULL;
- bool root_tp_path_sync = true;
- struct pthreadpool_tevent *root_tp_chdir_safe = NULL;
- bool root_tp_chdir_sync = true;
- size_t max_threads;
-
- if (vuid == UID_FIELD_INVALID) {
- user_ev_ctx = smbd_impersonate_conn_sess_create(
- conn->sconn->raw_ev_ctx, conn, session_info);
- if (user_ev_ctx == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- } else {
- user_ev_ctx = smbd_impersonate_conn_vuid_create(
- conn->sconn->raw_ev_ctx, conn, vuid);
- if (user_ev_ctx == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- }
- SMB_ASSERT(talloc_reparent(conn, frame, user_ev_ctx));
-
-#ifdef HAVE_LINUX_THREAD_CREDENTIALS
- user_tp_path_sync = lp_parm_bool(SNUM(conn),
- "smbd",
- "force sync user path safe threadpool",
- false);
- user_tp_chdir_sync = lp_parm_bool(SNUM(conn),
- "smbd",
- "force sync user chdir safe threadpool",
- false);
- root_tp_path_sync = lp_parm_bool(SNUM(conn),
- "smbd",
- "force sync root path safe threadpool",
- false);
- root_tp_chdir_sync = lp_parm_bool(SNUM(conn),
- "smbd",
- "force sync root chdir safe threadpool",
- false);
-#endif
-
- max_threads = pthreadpool_tevent_max_threads(conn->sconn->raw_thread_pool);
- if (max_threads == 0) {
- /*
- * We don't have real threads, so we need to force
- * the sync versions...
- */
- user_tp_path_sync = true;
- user_tp_chdir_sync = true;
- root_tp_path_sync = true;
- root_tp_chdir_sync = true;
- }
-
- /*
- * fd_safe is easy :-)
- */
- user_tp_fd_safe = conn->sconn->raw_thread_pool;
- root_tp_fd_safe = conn->sconn->raw_thread_pool;
-
- if (user_tp_path_sync) {
- /*
- * We don't have support for per thread credentials,
- * so we just provide a sync thread pool with a wrapper
- * that asserts that we are already in the required
- * impersonation state.
- */
- user_tp_path_safe = smbd_impersonate_tp_current_create(conn,
- conn->sconn->sync_thread_pool,
- conn,
- vuid,
- false, /* chdir_safe */
- session_info->unix_token);
- if (user_tp_path_safe == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- } else {
- user_tp_path_safe = smbd_impersonate_tp_sess_create(conn,
- conn->sconn->raw_thread_pool,
- session_info);
- if (user_tp_path_safe == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- }
- SMB_ASSERT(talloc_reparent(conn, frame, user_tp_path_safe));
-
- if (pthreadpool_tevent_per_thread_cwd(user_tp_path_safe)) {
- user_tp_chdir_safe = user_tp_path_safe;
- } else {
- user_tp_chdir_sync = true;
- }
-
- if (user_tp_chdir_sync) {
- /*
- * We don't have support for per thread credentials,
- * so we just provide a sync thread pool with a wrapper
- * that asserts that we are already in the required
- * impersonation state.
- *
- * And it needs to cleanup after [f]chdir() within
- * the job...
- */
- user_tp_chdir_safe = smbd_impersonate_tp_current_create(conn,
- conn->sconn->sync_thread_pool,
- conn,
- vuid,
- true, /* chdir_safe */
- session_info->unix_token);
- if (user_tp_chdir_safe == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- SMB_ASSERT(talloc_reparent(conn, frame, user_tp_chdir_safe));
- } else {
- SMB_ASSERT(user_tp_chdir_safe != NULL);
- }
-
- if (root_tp_path_sync) {
- /*
- * We don't have support for per thread credentials,
- * so we just provide a sync thread pool with a wrapper
- * that wrapps the job in become_root()/unbecome_root().
- */
- root_tp_path_safe = smbd_impersonate_tp_become_create(conn,
- conn->sconn->sync_thread_pool,
- false, /* chdir_safe */
- become_root,
- unbecome_root);
- if (root_tp_path_safe == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- } else {
- root_tp_path_safe = smbd_impersonate_tp_root_create(conn,
- conn->sconn->raw_thread_pool,
- SNUM(conn),
- session_info->unix_token);
- if (root_tp_path_safe == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- }
- SMB_ASSERT(talloc_reparent(conn, frame, root_tp_path_safe));
-
- if (pthreadpool_tevent_per_thread_cwd(root_tp_path_safe)) {
- root_tp_chdir_safe = root_tp_path_safe;
- } else {
- root_tp_chdir_sync = true;
- }
-
- if (root_tp_chdir_sync) {
- /*
- * We don't have support for per thread credentials,
- * so we just provide a sync thread pool with a wrapper
- * that wrapps the job in become_root()/unbecome_root().
- *
- * And it needs to cleanup after [f]chdir() within
- * the job...
- */
- root_tp_chdir_safe = smbd_impersonate_tp_become_create(conn,
- conn->sconn->sync_thread_pool,
- true, /* chdir_safe */
- become_root,
- unbecome_root);
- if (root_tp_chdir_safe == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
- SMB_ASSERT(talloc_reparent(conn, frame, root_tp_chdir_safe));
- } else {
- SMB_ASSERT(root_tp_chdir_safe != NULL);
- }
-
- user_vfs_evg = smb_vfs_ev_glue_create(conn,
- user_ev_ctx,
- user_tp_fd_safe,
- user_tp_path_safe,
- user_tp_chdir_safe,
- conn->sconn->root_ev_ctx,
- root_tp_fd_safe,
- root_tp_path_safe,
- root_tp_chdir_safe);
- if (user_vfs_evg == NULL) {
- TALLOC_FREE(frame);
- return NULL;
- }
-
- /*
- * Make sure everything is a talloc child of user_vfs_evg
- */
- SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_ev_ctx));
- SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_tp_path_safe));
- if (user_tp_path_safe != user_tp_chdir_safe) {
- SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_tp_chdir_safe));
- }
- SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, root_tp_path_safe));
- if (root_tp_path_safe != root_tp_chdir_safe) {
- SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, root_tp_chdir_safe));
- }
-
- TALLOC_FREE(frame);
- return user_vfs_evg;
-}