summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2018-06-13 13:30:33 +0200
committerStefan Metzmacher <metze@samba.org>2018-06-18 08:59:17 +0200
commitd1c8057997f97c6cd537496611dfae4e8b4af520 (patch)
tree95bdeddd9a478ac9609460fe284720abd42e1a7e /source3
parentb27d885478245d8bd56ab4f5459908b6c574d15d (diff)
downloadsamba-d1c8057997f97c6cd537496611dfae4e8b4af520.tar.gz
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 <metze@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
Diffstat (limited to 'source3')
-rw-r--r--source3/include/smb.h2
-rw-r--r--source3/smbd/globals.h2
-rw-r--r--source3/smbd/uid.c54
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,
+ };
}
/****************************************************************************