From d1c8057997f97c6cd537496611dfae4e8b4af520 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 13 Jun 2018 13:30:33 +0200 Subject: [PATCH] smbd: call chdir_current_service() in change_to_user_internal() and pop_conn_ctx() change_to_user() should be the one and only function for the whole impersonation processing. So we also need to stack the chdir_current_service() behaviour for become_user/unbecome_user, so we may need to call vfs_ChDir(ctx_p->conn, ctx_p->conn->cwd_fname); in pop_conn_ctx(). Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme --- source3/include/smb.h | 2 ++ source3/smbd/globals.h | 2 ++ source3/smbd/uid.c | 54 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index 5e83ee90afe..9ec65430852 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -156,6 +156,8 @@ struct sys_notify_context { struct current_user { struct connection_struct *conn; uint64_t vuid; /* SMB2 compat */ + bool need_chdir; + bool done_chdir; struct security_unix_token ut; struct security_token *nt_user_token; }; diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 384599be1df..057645bedee 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -89,6 +89,8 @@ extern uint16_t fnf_handle; struct conn_ctx { connection_struct *conn; uint64_t vuid; + bool need_chdir; + bool done_chdir; userdom_struct user_info; }; /* A stack of current_user connection contexts. */ diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 913d4f3aa0a..289727d9574 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -52,6 +52,8 @@ bool change_to_guest(void) current_user.conn = NULL; current_user.vuid = UID_FIELD_INVALID; + current_user.need_chdir = false; + current_user.done_chdir = false; TALLOC_FREE(pass); @@ -295,6 +297,7 @@ static bool change_to_user_internal(connection_struct *conn, if ((current_user.conn == conn) && (current_user.vuid == vuid) && + (current_user.need_chdir == conn->tcon_done) && (current_user.ut.uid == session_info->unix_token->uid)) { DBG_INFO("Skipping user change - already user\n"); @@ -369,12 +372,26 @@ static bool change_to_user_internal(connection_struct *conn, current_user.conn = conn; current_user.vuid = vuid; + current_user.need_chdir = conn->tcon_done; - DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n", - (int)getuid(), - (int)geteuid(), - (int)getgid(), - (int)getegid())); + if (current_user.need_chdir) { + ok = chdir_current_service(conn); + if (!ok) { + DBG_ERR("chdir_current_service() failed!\n"); + return false; + } + current_user.done_chdir = true; + } + + if (CHECK_DEBUGLVL(DBGLVL_INFO)) { + char cwdbuf[PATH_MAX+1] = { 0, }; + DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n", + (int)getuid(), + (int)geteuid(), + (int)getgid(), + (int)getegid(), + getcwd(cwdbuf, sizeof(cwdbuf))); + } return true; } @@ -424,6 +441,8 @@ bool smbd_change_to_root_user(void) current_user.conn = NULL; current_user.vuid = UID_FIELD_INVALID; + current_user.need_chdir = false; + current_user.done_chdir = false; return(True); } @@ -485,6 +504,8 @@ static void push_conn_ctx(void) ctx_p->conn = current_user.conn; ctx_p->vuid = current_user.vuid; + ctx_p->need_chdir = current_user.need_chdir; + ctx_p->done_chdir = current_user.done_chdir; ctx_p->user_info = current_user_info; DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n", @@ -510,11 +531,30 @@ static void pop_conn_ctx(void) set_current_user_info(ctx_p->user_info.smb_name, ctx_p->user_info.unix_name, ctx_p->user_info.domain); + + /* + * Check if the current context did a chdir_current_service() + * and restore the cwd_fname of the previous context + * if needed. + */ + if (current_user.done_chdir && ctx_p->need_chdir) { + int ret; + + ret = vfs_ChDir(ctx_p->conn, ctx_p->conn->cwd_fname); + if (ret != 0) { + DBG_ERR("vfs_ChDir() failed!\n"); + smb_panic("vfs_ChDir() failed!\n"); + } + } + current_user.conn = ctx_p->conn; current_user.vuid = ctx_p->vuid; + current_user.need_chdir = ctx_p->need_chdir; + current_user.done_chdir = ctx_p->done_chdir; - ctx_p->conn = NULL; - ctx_p->vuid = UID_FIELD_INVALID; + *ctx_p = (struct conn_ctx) { + .vuid = UID_FIELD_INVALID, + }; } /**************************************************************************** -- 2.34.1