From 29dd6f3e59055a17fa3d6a63619773f940e63374 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 23 Dec 2018 09:25:32 +0100 Subject: [PATCH] Revert "s3: vfs: add user_vfs_evg to connection_struct" This reverts commit 2dd95c1c38b9e1ce32d3d1081b6ec177910087a4. See the discussion in https://lists.samba.org/archive/samba-technical/2018-December/131731.html for the reasoning behind this revert. Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke Reviewed-by: Stefan Metzmacher --- source3/include/vfs.h | 3 +- source3/modules/vfs_readonly.c | 2 +- source3/smbd/conn.c | 8 +- source3/smbd/msdfs.c | 68 +-- source3/smbd/proto.h | 13 - source3/smbd/uid.c | 754 +-------------------------------- 6 files changed, 29 insertions(+), 819 deletions(-) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 619c1a8eb94..6516869b24e 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -407,7 +407,7 @@ typedef struct files_struct { struct vuid_cache_entry { struct auth_session_info *session_info; - struct smb_vfs_ev_glue *user_vfs_evg; + struct tevent_context *user_ev_ctx; uint64_t vuid; /* SMB2 compat */ bool read_only; uint32_t share_access; @@ -456,7 +456,6 @@ typedef struct connection_struct { */ struct auth_session_info *session_info; struct tevent_context *user_ev_ctx; - struct smb_vfs_ev_glue *user_vfs_evg; /* * If the "force group" parameter is set, this is the primary gid that diff --git a/source3/modules/vfs_readonly.c b/source3/modules/vfs_readonly.c index 37a9e806a15..e7e12747a22 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; - TALLOC_FREE(ent->user_vfs_evg); + 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 d8dc1c27d42..cfff6404608 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -95,12 +95,10 @@ static void conn_clear_vuid_cache(connection_struct *conn, uint64_t vuid) if (ent->vuid == vuid) { ent->vuid = UID_FIELD_INVALID; - conn->user_ev_ctx = NULL; - - if (conn->user_vfs_evg == ent->user_vfs_evg) { - conn->user_vfs_evg = NULL; + if (conn->user_ev_ctx == ent->user_ev_ctx) { + conn->user_ev_ctx = NULL; } - TALLOC_FREE(ent->user_vfs_evg); + 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 880a02b0320..9b0b2de27ca 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -253,10 +253,6 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx, const char *vfs_user; struct smbd_server_connection *sconn; const char *servicename = lp_const_servicename(snum); - const struct security_unix_token *unix_token = NULL; - struct tevent_context *user_ev_ctx = NULL; - struct pthreadpool_tevent *user_tp_chdir_safe = NULL; - struct pthreadpool_tevent *root_tp_chdir_safe = NULL; int ret; sconn = talloc_zero(ctx, struct smbd_server_connection); @@ -333,7 +329,6 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx, TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } - unix_token = conn->session_info->unix_token; /* unix_info could be NULL in session_info */ if (conn->session_info->unix_info != NULL) { vfs_user = conn->session_info->unix_info->unix_name; @@ -345,10 +340,6 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx, vfs_user = get_current_username(); } - if (unix_token == NULL) { - unix_token = get_current_utok(conn); - } - /* * The impersonation has to be done by the caller * of create_conn_struct_tos[_cwd](). @@ -362,63 +353,12 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx, * to avoid crashes because TALLOC_FREE(conn->user_ev_ctx) * would also remove sconn->raw_ev_ctx. */ - user_ev_ctx = smbd_impersonate_debug_create(sconn->raw_ev_ctx, - "FAKE impersonation", - DBGLVL_DEBUG); - if (user_ev_ctx == NULL) { - TALLOC_FREE(conn); - return NT_STATUS_NO_MEMORY; - } - SMB_ASSERT(talloc_reparent(sconn->raw_ev_ctx, conn, user_ev_ctx)); - - user_tp_chdir_safe = smbd_impersonate_tp_current_create(conn, - sconn->sync_thread_pool, - conn, - conn->vuid, - true, /* chdir_safe */ - unix_token); - if (user_tp_chdir_safe == NULL) { - TALLOC_FREE(conn); - return NT_STATUS_NO_MEMORY; - } - - root_tp_chdir_safe = smbd_impersonate_tp_become_create(conn, - sconn->sync_thread_pool, - true, /* chdir_safe */ - become_root, - unbecome_root); - if (root_tp_chdir_safe == NULL) { - TALLOC_FREE(conn); - return NT_STATUS_NO_MEMORY; - } - - /* - * We only use the chdir_safe wrappers - * for everything in order to keep - * it simple. - */ - conn->user_vfs_evg = smb_vfs_ev_glue_create(conn, - user_ev_ctx, - user_tp_chdir_safe, - user_tp_chdir_safe, - user_tp_chdir_safe, - sconn->root_ev_ctx, - root_tp_chdir_safe, - root_tp_chdir_safe, - root_tp_chdir_safe); - if (conn->user_vfs_evg == NULL) { - TALLOC_FREE(conn); - return NT_STATUS_NO_MEMORY; - } - - SMB_ASSERT(talloc_reparent(conn, conn->user_vfs_evg, user_ev_ctx)); - SMB_ASSERT(talloc_reparent(conn, conn->user_vfs_evg, user_tp_chdir_safe)); - SMB_ASSERT(talloc_reparent(conn, conn->user_vfs_evg, root_tp_chdir_safe)); - - conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(conn->user_vfs_evg); + 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_INTERNAL_ERROR; + return NT_STATUS_NO_MEMORY; } set_conn_connectpath(conn, connpath); diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 2a56c1e4346..eb35a94862a 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1255,19 +1255,6 @@ struct tevent_context *smbd_impersonate_conn_sess_create( struct tevent_context *smbd_impersonate_root_create(struct tevent_context *main_ev); struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev); -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 *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)); - /* 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 77e5f8c83b7..0518e5254a8 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -18,7 +18,6 @@ */ #include "includes.h" -#include "system/filesys.h" #include "system/passwd.h" #include "smbd/smbd.h" #include "smbd/globals.h" @@ -28,12 +27,6 @@ #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; @@ -314,8 +307,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_vfs_evg); + TALLOC_FREE(conn->user_ev_ctx); TALLOC_FREE(conn->session_info); } @@ -441,13 +433,10 @@ static bool check_user_ok(connection_struct *conn, } 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); } } @@ -493,12 +482,22 @@ static bool check_user_ok(connection_struct *conn, 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; + } } /* @@ -513,10 +512,7 @@ static bool check_user_ok(connection_struct *conn, free_conn_session_info_if_unused(conn); conn->session_info = ent->session_info; conn->vuid = ent->vuid; - conn->user_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 @@ -525,7 +521,7 @@ static bool check_user_ok(connection_struct *conn, 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; @@ -1937,713 +1933,3 @@ struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main 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; -} -- 2.25.1