From 675dd77807063b0eec407cb51184dc74812657a6 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 14 Jun 2023 13:59:55 +0100 Subject: [PATCH] Parameterise the sockdir with the UID of the user The top level socket directory is now called XRDP_SOCKET_ROOT_PATH. Below that are user-specific directories referred to with the XRDP_SOCKET_PATH macro - this name is hard-coded into xorgxrdp and the audio modules as an environment variable. XRDP_SOCKET_PATH now looks like $XRDP_SOCKET_ROOT_PATH/ XRDP_SOCKET_PATH is only writeable by the user, and readable by the user and the xrdp process. --- common/xrdp_sockets.h | 29 +++++++++-- docs/man/sesman.ini.5.in | 5 ++ libipm/Makefile.am | 1 + libipm/scp.c | 25 +++++++--- libipm/scp.h | 11 ++++- sesman/Makefile.am | 2 +- sesman/chansrv/Makefile.am | 2 +- sesman/chansrv/chansrv.c | 8 +-- sesman/chansrv/sound.c | 8 +-- sesman/libsesman/sesman_config.c | 30 +++++++----- sesman/libsesman/sesman_config.h | 6 +++ sesman/scp_process.c | 83 ++++++++++++++++++++++++++++---- sesman/sesexec/Makefile.am | 2 +- sesman/sesexec/env.c | 5 +- sesman/sesexec/login_info.c | 3 +- sesman/sesexec/session.c | 25 +++++----- sesman/sesman.c | 4 +- sesman/sesman.ini.in | 6 +++ sesman/session_list.c | 35 -------------- sesman/tools/Makefile.am | 2 +- sesman/tools/dis.c | 3 +- sesman/tools/sesadmin.c | 2 +- sesman/tools/sesrun.c | 2 +- xrdp/Makefile.am | 2 +- xrdp/xrdp_mm.c | 29 +++++++---- xrdp/xrdp_types.h | 1 + xrdpapi/Makefile.am | 2 +- xrdpapi/xrdpapi.c | 2 +- 28 files changed, 219 insertions(+), 116 deletions(-) diff --git a/common/xrdp_sockets.h b/common/xrdp_sockets.h index 6402798c..ebf044ff 100644 --- a/common/xrdp_sockets.h +++ b/common/xrdp_sockets.h @@ -21,16 +21,39 @@ #if !defined(XRDP_SOCKETS_H) #define XRDP_SOCKETS_H -/* basename of socket files */ +/* XRDP_SOCKET_ROOT_PATH must be defined to include this file */ +#ifdef __cppcheck__ +/* avoid syntax errors */ +# define XRDP_SOCKET_ROOT_PATH "/dummy" +#elif !defined(XRDP_SOCKET_ROOT_PATH) +# error "XRDP_SOCKET_ROOT_PATH must be defined" +#endif + +/* Buffer size for code for fullpath declarations + * + * This needs to fit in the sun_path field of a sockaddr_un. POSIX + * does not define this size, so the value below is the lower of + * the FreeBSD/OpenBSD/NetBSD(104) and Linux(108) values */ +#define XRDP_SOCKETS_MAXPATH 104 + +/* The socketdir is rooted at XRDP_SOCKET_ROOT_PATH. User-specific + * sockets live in a user-specific sub-directory of this called + * XRDP_SOCKET_PATH. The sub-directory is the UID of the user */ +#define XRDP_SOCKET_PATH XRDP_SOCKET_ROOT_PATH "/%d" + +/* Sockets in XRDP_SOCKET_ROOT_PATH */ +#define SCP_LISTEN_PORT_BASE_STR "sesman.socket" + +/* names of socket files within XRDP_SOCKET_PATH, qualified by + * display number */ #define XRDP_CHANSRV_BASE_STR "xrdp_chansrv_socket_%d" #define CHANSRV_PORT_OUT_BASE_STR "xrdp_chansrv_audio_out_socket_%d" #define CHANSRV_PORT_IN_BASE_STR "xrdp_chansrv_audio_in_socket_%d" #define CHANSRV_API_BASE_STR "xrdpapi_%d" #define XRDP_X11RDP_BASE_STR "xrdp_display_%d" #define XRDP_DISCONNECT_BASE_STR "xrdp_disconnect_display_%d" -#define SCP_LISTEN_PORT_BASE_STR "sesman.socket" -/* fullpath of sockets */ +/* fullpath declarations */ #define XRDP_CHANSRV_STR XRDP_SOCKET_PATH "/" XRDP_CHANSRV_BASE_STR #define CHANSRV_PORT_OUT_STR XRDP_SOCKET_PATH "/" CHANSRV_PORT_OUT_BASE_STR #define CHANSRV_PORT_IN_STR XRDP_SOCKET_PATH "/" CHANSRV_PORT_IN_BASE_STR diff --git a/docs/man/sesman.ini.5.in b/docs/man/sesman.ini.5.in index 1933893a..0d4f5c90 100644 --- a/docs/man/sesman.ini.5.in +++ b/docs/man/sesman.ini.5.in @@ -312,6 +312,11 @@ to a setuid Xorg executable. However, if a kernel security module (such as AppArmor) is used to confine xrdp, \fIno_new_privs\fR may interfere with transitions between confinement domains. +.TP +\fBSessionSockdirGroup\fR=\fIgroup\fR +Sets the group owner of the directories containing session sockets. This +is normally the GID of the xrdp process so xrdp can connect to user sessions. + .SH "X11 SERVER" Following parameters can be used in the \fB[Xvnc]\fR and \fB[Xorg]\fR sections. diff --git a/libipm/Makefile.am b/libipm/Makefile.am index 84ea0948..4770f4dd 100644 --- a/libipm/Makefile.am +++ b/libipm/Makefile.am @@ -1,6 +1,7 @@ AM_CPPFLAGS = \ -DSESMAN_RUNTIME_PATH=\"${sesmanruntimedir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/common module_LTLIBRARIES = \ diff --git a/libipm/scp.c b/libipm/scp.c index de0028d7..eaeac344 100644 --- a/libipm/scp.c +++ b/libipm/scp.c @@ -332,14 +332,16 @@ scp_get_sys_login_request(struct trans *trans, int scp_send_login_response(struct trans *trans, enum scp_login_status login_result, - int server_closed) + int server_closed, + int uid) { return libipm_msg_out_simple_send( trans, (int)E_SCP_LOGIN_RESPONSE, - "ib", + "ibi", login_result, - (server_closed != 0)); /* Convert to 0/1 */ + (server_closed != 0), /* Convert to 0/1 */ + uid); } /*****************************************************************************/ @@ -347,22 +349,33 @@ scp_send_login_response(struct trans *trans, int scp_get_login_response(struct trans *trans, enum scp_login_status *login_result, - int *server_closed) + int *server_closed, + int *uid) { int32_t i_login_result = 0; + int32_t i_uid = 0; int dummy; + /* User can pass in NULL for server_closed if they're trying an - * login method like UDS for which all fails are fatal */ + * login method like UDS for which all fails are fatal. Likewise + * they may be uninterested in the uid */ if (server_closed == NULL) { server_closed = &dummy; } + if (uid == NULL) + { + uid = &dummy; + } - int rv = libipm_msg_in_parse(trans, "ib", &i_login_result, server_closed); + int rv = libipm_msg_in_parse(trans, "ibi", + &i_login_result, server_closed, &i_uid); if (rv == 0) { *login_result = (enum scp_login_status)i_login_result; + *uid = i_uid; } + return rv; } diff --git a/libipm/scp.h b/libipm/scp.h index eec86c4f..ff54fd6a 100644 --- a/libipm/scp.h +++ b/libipm/scp.h @@ -284,12 +284,14 @@ scp_get_sys_login_request(struct trans *trans, * @param login_result What happened to the login * @param server_closed If login fails, whether server has closed connection. * If not, a retry can be made. + * @param uid UID for a successful login * @return != 0 for error */ int scp_send_login_response(struct trans *trans, enum scp_login_status login_result, - int server_closed); + int server_closed, + int uid); /** * Parses an incoming E_SCP_LOGIN_RESPONSE (SCP client) @@ -298,12 +300,17 @@ scp_send_login_response(struct trans *trans, * @param[out] login_result 0 for success, PAM error code otherwise * @param[out] server_closed If login fails, whether server has closed * connection. If not a retry can be made. + * @param[out] uid UID for a successful login + * + * server_closed and uid can be passed NULL if the caller isn't interested. + * * @return != 0 for error */ int scp_get_login_response(struct trans *trans, enum scp_login_status *login_result, - int *server_closed); + int *server_closed, + int *uid); /** * Send an E_SCP_LOGOUT_REQUEST (SCP client) diff --git a/sesman/Makefile.am b/sesman/Makefile.am index 542186d8..638ca94e 100644 --- a/sesman/Makefile.am +++ b/sesman/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_LIBEXEC_PATH=\"${libexecdir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ - -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -DSESMAN_RUNTIME_PATH=\"${sesmanruntimedir}\" \ -I$(top_srcdir)/sesman/libsesman \ -I$(top_srcdir)/common \ diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 75eee8d7..959cdb52 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -8,7 +8,7 @@ AM_CPPFLAGS = \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ - -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/sesman/libsesman \ -I$(top_srcdir)/common diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index b83c1057..31daff4c 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -1238,7 +1238,7 @@ my_api_trans_conn_in(struct trans *trans, struct trans *new_trans) static int setup_listen(void) { - char port[256]; + char port[XRDP_SOCKETS_MAXPATH]; int error = 0; if (g_lis_trans != 0) @@ -1248,7 +1248,7 @@ setup_listen(void) g_lis_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); g_lis_trans->is_term = g_is_term; - g_snprintf(port, 255, XRDP_CHANSRV_STR, g_display_num); + g_snprintf(port, sizeof(port), XRDP_CHANSRV_STR, g_getuid(), g_display_num); g_lis_trans->trans_conn_in = my_trans_conn_in; error = trans_listen(g_lis_trans, port); @@ -1267,12 +1267,12 @@ setup_listen(void) static int setup_api_listen(void) { - char port[256]; + char port[XRDP_SOCKETS_MAXPATH]; int error = 0; g_api_lis_trans = trans_create(TRANS_MODE_UNIX, 8192 * 4, 8192 * 4); g_api_lis_trans->is_term = g_is_term; - g_snprintf(port, 255, CHANSRV_API_STR, g_display_num); + g_snprintf(port, sizeof(port), CHANSRV_API_STR, g_getuid(), g_display_num); g_api_lis_trans->trans_conn_in = my_api_trans_conn_in; error = trans_listen(g_api_lis_trans, port); diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index 7e03b598..2c862f99 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -1894,11 +1894,11 @@ sound_sndsrvr_source_data_in(struct trans *trans) static int sound_start_source_listener(void) { - char port[1024]; + char port[XRDP_SOCKETS_MAXPATH]; g_audio_l_trans_in = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192); g_audio_l_trans_in->is_term = g_is_term; - g_snprintf(port, 255, CHANSRV_PORT_IN_STR, g_display_num); + g_snprintf(port, sizeof(port), CHANSRV_PORT_IN_STR, g_getuid(), g_display_num); g_audio_l_trans_in->trans_conn_in = sound_sndsrvr_source_conn_in; if (trans_listen(g_audio_l_trans_in, port) != 0) { @@ -1913,11 +1913,11 @@ sound_start_source_listener(void) static int sound_start_sink_listener(void) { - char port[1024]; + char port[XRDP_SOCKETS_MAXPATH]; g_audio_l_trans_out = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192); g_audio_l_trans_out->is_term = g_is_term; - g_snprintf(port, 255, CHANSRV_PORT_OUT_STR, g_display_num); + g_snprintf(port, sizeof(port), CHANSRV_PORT_OUT_STR, g_getuid(), g_display_num); g_audio_l_trans_out->trans_conn_in = sound_sndsrvr_sink_conn_in; if (trans_listen(g_audio_l_trans_out, port) != 0) { diff --git a/sesman/libsesman/sesman_config.c b/sesman/libsesman/sesman_config.c index e47a8549..9e3d9e72 100644 --- a/sesman/libsesman/sesman_config.c +++ b/sesman/libsesman/sesman_config.c @@ -71,6 +71,7 @@ #define SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD "RestrictInboundClipboard" #define SESMAN_CFG_SEC_ALLOW_ALTERNATE_SHELL "AllowAlternateShell" #define SESMAN_CFG_SEC_XORG_NO_NEW_PRIVILEGES "XorgNoNewPrivileges" +#define SESMAN_CFG_SEC_SESSION_SOCKDIR_GROUP "SessionSockdirGroup" #define SESMAN_CFG_SESSIONS "Sessions" #define SESMAN_CFG_SESS_MAX "MaxSessions" @@ -312,6 +313,7 @@ config_read_security(int file, struct config_security *sc, sc->xorg_no_new_privileges = 1; sc->ts_users = g_strdup(""); sc->ts_admins = g_strdup(""); + sc->session_sockdir_group = g_strdup(""); file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v); @@ -324,29 +326,25 @@ config_read_security(int file, struct config_security *sc, { sc->allow_root = g_text2bool(value); } - - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) { sc->login_retry = g_atoi(value); } - - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_USR_GROUP)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_USR_GROUP)) { g_free(sc->ts_users); sc->ts_users = g_strdup(value); } - - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ADM_GROUP)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ADM_GROUP)) { g_free(sc->ts_admins); sc->ts_admins = g_strdup(value); } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALWAYSGROUPCHECK)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALWAYSGROUPCHECK)) { sc->ts_always_group_check = g_text2bool(value); } - - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD)) { char unrecognised[256]; sc->restrict_outbound_clipboard = @@ -360,7 +358,7 @@ config_read_security(int file, struct config_security *sc, unrecognised); } } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD)) { char unrecognised[256]; sc->restrict_inbound_clipboard = @@ -374,17 +372,21 @@ config_read_security(int file, struct config_security *sc, unrecognised); } } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ALTERNATE_SHELL)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ALTERNATE_SHELL)) { sc->allow_alternate_shell = g_text2bool(value); } - - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_XORG_NO_NEW_PRIVILEGES)) + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_XORG_NO_NEW_PRIVILEGES)) { sc->xorg_no_new_privileges = g_text2bool(value); } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_SESSION_SOCKDIR_GROUP)) + { + g_free(sc->session_sockdir_group); + sc->session_sockdir_group = g_strdup(value); + } } return 0; @@ -684,6 +686,7 @@ config_dump(struct config_sesman *config) g_writeln(" RestrictInboundClipboard: %s", restrict_s); g_writeln(" TSUsersGroup: %s", sc->ts_users); g_writeln(" TSAdminsGroup: %s", sc->ts_admins); + g_writeln(" SessionSockdirGroup: %s", sc->session_sockdir_group); /* Xorg */ @@ -741,6 +744,7 @@ config_free(struct config_sesman *cs) list_delete(cs->env_values); g_free(cs->sec.ts_users); g_free(cs->sec.ts_admins); + g_free(cs->sec.session_sockdir_group); g_free(cs); } } diff --git a/sesman/libsesman/sesman_config.h b/sesman/libsesman/sesman_config.h index 9dd6672b..5f403fa1 100644 --- a/sesman/libsesman/sesman_config.h +++ b/sesman/libsesman/sesman_config.h @@ -107,6 +107,12 @@ struct config_security * @brief if the Xorg X11 server should be started with no_new_privs (Linux only) */ int xorg_no_new_privileges; + + /* + * @var session_sockdir_group + * @brief Group to have read access to the session sockdirs + */ + char *session_sockdir_group; }; /** diff --git a/sesman/scp_process.c b/sesman/scp_process.c index 7fab3d46..3f0c3630 100644 --- a/sesman/scp_process.c +++ b/sesman/scp_process.c @@ -44,6 +44,7 @@ #include "session_list.h" #include "sesexec_control.h" #include "string_calls.h" +#include "xrdp_sockets.h" /******************************************************************************/ @@ -139,7 +140,7 @@ process_sys_login_request(struct pre_session_item *psi) { /* We only get here if something has gone * wrong with the handover to sesexec */ - rv = scp_send_login_response(psi->client_trans, errorcode, 1); + rv = scp_send_login_response(psi->client_trans, errorcode, 1, -1); psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION; } } @@ -219,15 +220,15 @@ process_uds_login_request(struct pre_session_item *psi) int uid; int pid; char *username = NULL; - int server_closed = 1; + int server_closed; rv = g_sck_get_peer_cred(psi->client_trans->sck, &pid, &uid, NULL); if (rv != 0) { + errorcode = E_SCP_LOGIN_GENERAL_ERROR; LOG(LOG_LEVEL_INFO, "Unable to get peer credentials for socket %d", (int)psi->client_trans->sck); - errorcode = E_SCP_LOGIN_GENERAL_ERROR; } else { @@ -252,21 +253,26 @@ process_uds_login_request(struct pre_session_item *psi) errorcode = authenticate_and_authorize_uds_connection( psi, uid, username); g_free(username); - - if (errorcode == E_SCP_LOGIN_OK) - { - server_closed = 0; - } } } - if (server_closed) + if (errorcode == E_SCP_LOGIN_OK) { + server_closed = 0; + } + else + { + server_closed = 1; + /* Close the connection after returning from this callback */ psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION; + + /* Never return the UID if the server is closing */ + uid = -1; } - return scp_send_login_response(psi->client_trans, errorcode, server_closed); + return scp_send_login_response(psi->client_trans, errorcode, + server_closed, uid); } /******************************************************************************/ @@ -302,6 +308,58 @@ process_logout_request(struct pre_session_item *psi) return 0; } +/******************************************************************************/ +/** + * Create xrdp socket path for the user + * + * We do this here rather than in sesexec as we're single-threaded here + * and so don't have to worry about race conditions + * + * Directory is owned by UID of session, but can be accessed by + * the group specified in the config. + * + * Errors are logged so the caller doesn't have to + */ +static int +create_xrdp_socket_path(uid_t uid) +{ + int rv = 1; + const char *sockdir_group = g_cfg->sec.session_sockdir_group; + int gid = 0; // Default if no group specified + + char sockdir[XRDP_SOCKETS_MAXPATH]; + g_snprintf(sockdir, sizeof(sockdir), XRDP_SOCKET_PATH, (int)uid); + + // Create directory permissions 0x750, if it doesn't exist already. + int old_umask = g_umask_hex(0x750 ^ 0x777); + if (!g_directory_exist(sockdir) && !g_create_dir(sockdir)) + { + LOG(LOG_LEVEL_ERROR, + "create_xrdp_socket_path: Can't create %s [%s]", + sockdir, g_get_strerror()); + } + else if (sockdir_group != NULL && sockdir_group[0] != '\0' && + g_getgroup_info(sockdir_group, &gid) != 0) + { + LOG(LOG_LEVEL_ERROR, + "create_xrdp_socket_path: Can't get GID of group %s [%s]", + sockdir_group, g_get_strerror()); + } + else if (g_chown(sockdir, uid, gid) != 0) + { + LOG(LOG_LEVEL_ERROR, + "create_xrdp_socket_path: Can't set owner of %s to %d:%d [%s]", + sockdir, uid, gid, g_get_strerror()); + } + else + { + rv = 0; + } + (void)g_umask_hex(old_umask); + + return rv; +} + /******************************************************************************/ static int @@ -385,6 +443,11 @@ process_create_session_request(struct pre_session_item *psi) { status = E_SCP_SCREATE_NO_MEMORY; } + // Create a socket dir for this user + else if (create_xrdp_socket_path(psi->uid) != 0) + { + status = E_SCP_SCREATE_GENERAL_ERROR; + } // Create a sesexec process if we don't have one (UDS login) else if (psi->sesexec_trans == NULL && sesexec_start(psi) != 0) { diff --git a/sesman/sesexec/Makefile.am b/sesman/sesexec/Makefile.am index f2bac24a..b7d5abb6 100644 --- a/sesman/sesexec/Makefile.am +++ b/sesman/sesexec/Makefile.am @@ -2,7 +2,7 @@ AM_CPPFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_LIBEXEC_PATH=\"${libexecdir}/xrdp\" \ - -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/sesman/libsesman \ -I$(top_srcdir)/libipm \ -I$(top_srcdir)/common diff --git a/sesman/sesexec/env.c b/sesman/sesexec/env.c index a7e55659..f56a93d4 100644 --- a/sesman/sesexec/env.c +++ b/sesman/sesexec/env.c @@ -152,9 +152,10 @@ env_set_user(int uid, char **passwd_file, int display, // Use our PID as the XRDP_SESSION value g_snprintf(text, sizeof(text), "%d", g_pid); g_setenv("XRDP_SESSION", text, 1); - /* XRDP_SOCKET_PATH should be set even here. It's used by + /* XRDP_SOCKET_PATH should be set here. It's used by * xorgxrdp and the pulseaudio plugin */ - g_setenv("XRDP_SOCKET_PATH", XRDP_SOCKET_PATH, 1); + g_snprintf(text, sizeof(text), XRDP_SOCKET_PATH, uid); + g_setenv("XRDP_SOCKET_PATH", text, 1); /* pulse sink socket */ g_snprintf(text, sizeof(text), CHANSRV_PORT_OUT_BASE_STR, display); g_setenv("XRDP_PULSE_SINK_SOCKET", text, 1); diff --git a/sesman/sesexec/login_info.c b/sesman/sesexec/login_info.c index a8ccda81..adb8ef1a 100644 --- a/sesman/sesexec/login_info.c +++ b/sesman/sesexec/login_info.c @@ -280,7 +280,8 @@ login_info_sys_login_user(struct trans *scp_trans, } } - if (scp_send_login_response(scp_trans, status, server_closed) != 0) + if (scp_send_login_response(scp_trans, status, + server_closed, result->uid) != 0) { status = E_SCP_LOGIN_GENERAL_ERROR; break; diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index 900b3943..a4950973 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -370,8 +370,6 @@ prepare_xorg_xserver_params(const struct session_parameters *s, g_snprintf(text, sizeof(text), "%d", g_cfg->sess.kill_disconnected); g_setenv("XRDP_SESMAN_KILL_DISCONNECTED", text, 1); - g_setenv("XRDP_SOCKET_PATH", XRDP_SOCKET_PATH, 1); - /* get path of Xorg from config */ xserver = (const char *)list_get_item(g_cfg->xorg_params, 0); @@ -716,15 +714,14 @@ session_start(struct login_info *login_info, /******************************************************************************/ static int -cleanup_sockets(int display) +cleanup_sockets(int uid, int display) { - LOG(LOG_LEVEL_INFO, "cleanup_sockets:"); - char file[256]; - int error; + LOG_DEVEL(LOG_LEVEL_INFO, "cleanup_sockets:"); - error = 0; + char file[XRDP_SOCKETS_MAXPATH]; + int error = 0; - g_snprintf(file, 255, CHANSRV_PORT_OUT_STR, display); + g_snprintf(file, sizeof(file), CHANSRV_PORT_OUT_STR, uid, display); if (g_file_exist(file)) { LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file); @@ -737,7 +734,7 @@ cleanup_sockets(int display) } } - g_snprintf(file, 255, CHANSRV_PORT_IN_STR, display); + g_snprintf(file, sizeof(file), CHANSRV_PORT_IN_STR, uid, display); if (g_file_exist(file)) { LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file); @@ -750,7 +747,7 @@ cleanup_sockets(int display) } } - g_snprintf(file, 255, XRDP_CHANSRV_STR, display); + g_snprintf(file, sizeof(file), XRDP_CHANSRV_STR, uid, display); if (g_file_exist(file)) { LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file); @@ -763,7 +760,7 @@ cleanup_sockets(int display) } } - g_snprintf(file, 255, CHANSRV_API_STR, display); + g_snprintf(file, sizeof(file), CHANSRV_API_STR, uid, display); if (g_file_exist(file)) { LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file); @@ -779,7 +776,7 @@ cleanup_sockets(int display) /* the following files should be deleted by xorgxrdp * but just in case the deletion failed */ - g_snprintf(file, 255, XRDP_X11RDP_STR, display); + g_snprintf(file, sizeof(file), XRDP_X11RDP_STR, uid, display); if (g_file_exist(file)) { LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file); @@ -792,7 +789,7 @@ cleanup_sockets(int display) } } - g_snprintf(file, 255, XRDP_DISCONNECT_STR, display); + g_snprintf(file, sizeof(file), XRDP_DISCONNECT_STR, uid, display); if (g_file_exist(file)) { LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file); @@ -908,7 +905,7 @@ session_process_child_exit(struct session_data *sd, if (!session_active(sd)) { - cleanup_sockets(sd->params.display); + cleanup_sockets(g_login_info->uid, sd->params.display); } } diff --git a/sesman/sesman.c b/sesman/sesman.c index f5d0b9cf..1c1cb619 100644 --- a/sesman/sesman.c +++ b/sesman/sesman.c @@ -50,6 +50,7 @@ #include "string_calls.h" #include "trans.h" #include "xrdp_configure_options.h" +#include "xrdp_sockets.h" /** * Maximum number of pre-session items @@ -688,9 +689,6 @@ read_pid_file(const char *pid_file, int *pid) static int create_xrdp_socket_root_path(void) { -#ifndef XRDP_SOCKET_PATH -# error "XRDP_SOCKET_PATH must be defined" -#endif int uid = g_getuid(); int gid = g_getgid(); diff --git a/sesman/sesman.ini.in b/sesman/sesman.ini.in index 01a1aa5b..685af28b 100644 --- a/sesman/sesman.ini.in +++ b/sesman/sesman.ini.in @@ -44,6 +44,12 @@ RestrictInboundClipboard=none ; however, interfere with the use of security modules such as AppArmor. ; Leave this unset unless you need to disable it. #XorgNoNewPrivileges=true +; Specify the group which is to have read access to the directory where +; local sockets for the session are created. This is normally the GID +; which the xrdp process runs as. +; Default is 'root' +#SessionSockdirGroup=root + [Sessions] ;; X11DisplayOffset - x11 display number offset diff --git a/sesman/session_list.c b/sesman/session_list.c index 497c6eb8..a3a333dd 100644 --- a/sesman/session_list.c +++ b/sesman/session_list.c @@ -198,41 +198,6 @@ x_server_running_check_ports(int display) } } - if (!x_running) - { - LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text); - g_sprintf(text, XRDP_CHANSRV_STR, display); - x_running = g_file_exist(text); - } - - if (!x_running) - { - LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text); - g_sprintf(text, CHANSRV_PORT_OUT_STR, display); - x_running = g_file_exist(text); - } - - if (!x_running) - { - LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text); - g_sprintf(text, CHANSRV_PORT_IN_STR, display); - x_running = g_file_exist(text); - } - - if (!x_running) - { - LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text); - g_sprintf(text, CHANSRV_API_STR, display); - x_running = g_file_exist(text); - } - - if (!x_running) - { - LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text); - g_sprintf(text, XRDP_X11RDP_STR, display); - x_running = g_file_exist(text); - } - if (x_running) { LOG(LOG_LEVEL_INFO, "Found X server running at %s", text); diff --git a/sesman/tools/Makefile.am b/sesman/tools/Makefile.am index a6803bb3..73f1a3b9 100644 --- a/sesman/tools/Makefile.am +++ b/sesman/tools/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ - -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/sesman/libsesman \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libipm diff --git a/sesman/tools/dis.c b/sesman/tools/dis.c index cc06e870..2e744ef7 100644 --- a/sesman/tools/dis.c +++ b/sesman/tools/dis.c @@ -29,6 +29,7 @@ #include #include "xrdp_sockets.h" +#include "os_calls.h" #include "string_calls.h" int main(int argc, char **argv) @@ -62,7 +63,7 @@ int main(int argc, char **argv) } memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; - sprintf(sa.sun_path, XRDP_DISCONNECT_STR, dis); + sprintf(sa.sun_path, XRDP_DISCONNECT_STR, g_getuid(), dis); if (access(sa.sun_path, F_OK) != 0) { diff --git a/sesman/tools/sesadmin.c b/sesman/tools/sesadmin.c index 8c9157ba..e41c8fed 100644 --- a/sesman/tools/sesadmin.c +++ b/sesman/tools/sesadmin.c @@ -95,7 +95,7 @@ int main(int argc, char **argv) if ((rv = scp_send_uds_login_request(t)) == 0 && (rv = wait_for_sesman_reply(t, E_SCP_LOGIN_RESPONSE)) == 0) { - rv = scp_get_login_response(t, &login_result, NULL); + rv = scp_get_login_response(t, &login_result, NULL, NULL); if (rv == 0) { if (login_result != E_SCP_LOGIN_OK) diff --git a/sesman/tools/sesrun.c b/sesman/tools/sesrun.c index e326b073..affc7835 100644 --- a/sesman/tools/sesrun.c +++ b/sesman/tools/sesrun.c @@ -460,7 +460,7 @@ handle_login_response(struct trans *t, int *server_closed) } else { - rv = scp_get_login_response(t, &login_result, server_closed); + rv = scp_get_login_response(t, &login_result, server_closed, NULL); if (rv == 0) { if (login_result != E_SCP_LOGIN_OK) diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index 432fdf2d..3e11f4ee 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -9,7 +9,7 @@ AM_CPPFLAGS = \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ -DXRDP_MODULE_PATH=\"${moduledir}\" \ - -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_builddir) \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libipm \ diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 04e646a8..3f1db0af 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -61,6 +61,8 @@ xrdp_mm_create(struct xrdp_wm *owner) self->resize_queue = list_create(); self->resize_queue->auto_free = 1; + self->uid = -1; /* Never good to default UIDs to 0 */ + pid = g_getpid(); /* setup wait objects for signalling */ g_snprintf(buf, sizeof(buf), "xrdp_%8.8x_resize_ready", pid); @@ -469,11 +471,12 @@ xrdp_mm_setup_mod2(struct xrdp_mm *self) { if (self->code == XVNC_SESSION_CODE) { - g_snprintf(text, 255, "%d", 5900 + self->display); + g_snprintf(text, sizeof(text), "%d", 5900 + self->display); } else if (self->code == XORG_SESSION_CODE) { - g_snprintf(text, 255, XRDP_X11RDP_STR, self->display); + g_snprintf(text, sizeof(text), XRDP_X11RDP_STR, + self->uid, self->display); } else { @@ -2178,7 +2181,8 @@ xrdp_mm_process_login_response(struct xrdp_mm *self) self->mmcs_expecting_msg = 0; - rv = scp_get_login_response(self->sesman_trans, &login_result, &server_closed); + rv = scp_get_login_response(self->sesman_trans, &login_result, + &server_closed, &self->uid); if (rv == 0) { if (login_result != E_SCP_LOGIN_OK) @@ -2346,11 +2350,16 @@ cleanup_states(struct xrdp_mm *self) * @param value assigned to chansrvport * @param dest Output buffer * @param dest_size Total size of output buffer, including terminator space + * @param uid of destination + * + * Pass in dest of NULL, dest_size of 0 and uid of -1 to simply see if + * the string parses OK. + * * @return 0 for success */ static int -parse_chansrvport(const char *value, char *dest, int dest_size) +parse_chansrvport(const char *value, char *dest, int dest_size, int uid) { int rv = 0; @@ -2373,7 +2382,7 @@ parse_chansrvport(const char *value, char *dest, int dest_size) } else { - g_snprintf(dest, dest_size, XRDP_CHANSRV_STR, g_atoi(p)); + g_snprintf(dest, dest_size, XRDP_CHANSRV_STR, uid, g_atoi(p)); } } else @@ -2561,7 +2570,7 @@ xrdp_mm_connect(struct xrdp_mm *self) { const char *csp = xrdp_mm_get_value(self, "chansrvport"); /* It's defined, but is it a valid string? */ - if (csp != NULL && parse_chansrvport(csp, NULL, 0) == 0) + if (csp != NULL && parse_chansrvport(csp, NULL, 0, -1) == 0) { self->use_chansrv = 1; } @@ -2652,6 +2661,7 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) "access control check was successful"); // No reply needed for this one status = scp_send_logout_request(self->sesman_trans); + self->uid = -1; } if (status == 0 && self->use_sesman) @@ -2723,20 +2733,21 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) { if (self->use_chansrv) { - char portbuff[256]; + char portbuff[XRDP_SOCKETS_MAXPATH]; xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "Connecting to chansrv"); if (self->use_sesman) { g_snprintf(portbuff, sizeof(portbuff), - XRDP_CHANSRV_STR, self->display); + XRDP_CHANSRV_STR, self->uid, self->display); } else { const char *cp = xrdp_mm_get_value(self, "chansrvport"); portbuff[0] = '\0'; - parse_chansrvport(cp, portbuff, sizeof(portbuff)); + parse_chansrvport(cp, portbuff, sizeof(portbuff), + self->uid); } xrdp_mm_update_allowed_channels(self); diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index e379ff50..58af848c 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -401,6 +401,7 @@ struct xrdp_mm int (*mod_exit)(struct xrdp_mod *); struct xrdp_mod *mod; /* module interface */ int display; /* 10 for :10.0, 11 for :11.0, etc */ + int uid; /* UID for a successful login, -1 otherwise */ struct guid guid; /* GUID for the session, or all zeros */ int code; /* 0=Xvnc session, 20=xorg driver mode */ struct xrdp_encoder *encoder; diff --git a/xrdpapi/Makefile.am b/xrdpapi/Makefile.am index 55014bc5..266b07a5 100644 --- a/xrdpapi/Makefile.am +++ b/xrdpapi/Makefile.am @@ -4,7 +4,7 @@ EXTRA_DIST = \ vrplayer.mk AM_CPPFLAGS = \ - -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/common module_LTLIBRARIES = \ diff --git a/xrdpapi/xrdpapi.c b/xrdpapi/xrdpapi.c index 1b72339e..4288b355 100644 --- a/xrdpapi/xrdpapi.c +++ b/xrdpapi/xrdpapi.c @@ -140,7 +140,7 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName, memset(&s, 0, sizeof(struct sockaddr_un)); s.sun_family = AF_UNIX; bytes = sizeof(s.sun_path); - snprintf(s.sun_path, bytes - 1, CHANSRV_API_STR, wts->display_num); + snprintf(s.sun_path, bytes - 1, CHANSRV_API_STR, getuid(), wts->display_num); s.sun_path[bytes - 1] = 0; bytes = sizeof(struct sockaddr_un);