From 0db849fc5c3f02ee24f10acd9f54a91a96fa2eaa Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:29:28 +0000 Subject: [PATCH] Move SCP to a Unix Domain Socket The TCP socket implementation of sesman has a number of limitations, namely that it is affected by firewalls, and also that determining the user on the other end requires a full authentication process. The advantage of the TCP socket is that sesman and xrdp can be run on separate machines. This is however not supported by the xorgxrdp backend (shared memory), and is insecure, in that passwords are sent in-the-clear, and the connection is susceptible to MitM attacks. This architecture has been deprecated in release notes since xrdp v0.9.17, and although it will continue to be supported in any further releases in the x0.9.x series, it will not be supported in the next major version. --- common/xrdp_sockets.h | 1 + configure.ac | 14 +++- docs/man/Makefile.am | 1 + docs/man/sesman.ini.5.in | 20 +++-- docs/man/xrdp-sesadmin.8.in | 10 +-- docs/man/xrdp-sesman.8.in | 2 + docs/man/xrdp-sesrun.8.in | 5 -- libipm/Makefile.am | 1 + libipm/scp.c | 98 ++++++++++++++++++---- libipm/scp.h | 33 +++++++- sesman/Makefile.am | 1 + sesman/config.c | 88 ++++++++++---------- sesman/config.h | 7 +- sesman/sesman.c | 125 ++++++++++++++++++++-------- sesman/sesman.ini.in | 4 +- sesman/sig.c | 13 +-- sesman/tools/sesadmin.c | 13 +-- sesman/tools/sesrun.c | 20 +---- xrdp/xrdp.ini.in | 4 - xrdp/xrdp_mm.c | 159 ++++++++++-------------------------- xrdp/xrdp_types.h | 2 - 21 files changed, 335 insertions(+), 286 deletions(-) diff --git a/common/xrdp_sockets.h b/common/xrdp_sockets.h index 1a625ef7..6402798c 100644 --- a/common/xrdp_sockets.h +++ b/common/xrdp_sockets.h @@ -28,6 +28,7 @@ #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 */ #define XRDP_CHANSRV_STR XRDP_SOCKET_PATH "/" XRDP_CHANSRV_BASE_STR diff --git a/configure.ac b/configure.ac index 83663c85..c6d4ced2 100644 --- a/configure.ac +++ b/configure.ac @@ -52,10 +52,16 @@ AC_CHECK_SIZEOF([void *]) AC_ARG_WITH([socketdir], [AS_HELP_STRING([--with-socketdir=DIR], - [Use directory for UNIX sockets (default: /tmp/.xrdp)])], - [], [with_socketdir="/tmp/.xrdp"]) + [Use directory for UNIX sockets for XRDP sessions (default: RUNSTATEDIR/xrdp)])], + [], [with_socketdir="$runstatedir/xrdp"]) AC_SUBST([socketdir], [$with_socketdir]) +AC_ARG_WITH([sesmanruntimedir], + [AS_HELP_STRING([--with-sesmanruntimedir=DIR], + [Use directory for sesman runtime data (default: RUNSTATEDIR/xrdp-sesman))])], + [], [with_sesmanruntimedir="$runstatedir/xrdp-sesman"]) +AC_SUBST([sesmanruntimedir], [$with_sesmanruntimedir]) + AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files, no to disable]), [], [ @@ -547,6 +553,10 @@ echo " exec_prefix $exec_prefix" echo " libdir $libdir" echo " bindir $bindir" echo " sysconfdir $sysconfdir" +echo " localstatedir $localstatedir" +echo " runstatedir $runstatedir" +echo " socketdir $socketdir" +echo " sesmanruntimedir $sesmanruntimedir" echo "" echo " unit tests performable $perform_unit_tests" echo "" diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am index 18574346..b55919fe 100644 --- a/docs/man/Makefile.am +++ b/docs/man/Makefile.am @@ -19,6 +19,7 @@ SUBST_VARS = sed \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@socketdir[@]|$(socketdir)|g' \ + -e 's|@sesmanruntimedir[@]|$(sesmanruntimedir)|g' \ -e 's|@xrdpconfdir[@]|$(sysconfdir)/xrdp|g' \ -e 's|@xrdphomeurl[@]|http://www.xrdp.org/|g' diff --git a/docs/man/sesman.ini.5.in b/docs/man/sesman.ini.5.in index 7291038f..af3be2a7 100644 --- a/docs/man/sesman.ini.5.in +++ b/docs/man/sesman.ini.5.in @@ -50,13 +50,19 @@ outside their proper section will be \fIignored\fR. Following parameters can be used in the \fB[Globals]\fR section. .TP -\fBListenAddress\fR=\fIip address\fR -xrdp-sesman listening address. If not specified, defaults to \fI0.0.0.0\fR -(all interfaces). - -.TP -\fBListenPort\fR=\fIport number\fR -xrdp-sesman listening port. If not specified, defaults to \fI3350\fR. +\fBListenPort\fR=\fIpath-to-socket\fR +UNIX domain socket for xrdp-sesman(8) to listen on. +.PP +.RS +The default value of this setting is 'sesman.socket'. +.PP +An absoute path can be specified by starting this parameter with a '/'. +In this instance, the system administrator is responsible for ensuring +the socket can only be created by a suitably privileged process. +.PP +If the parameter does not start with a '/', a name within +@sesmanruntimedir@ is used. +.RE .TP \fBEnableUserWindowManager\fR=\fI[true|false]\fR diff --git a/docs/man/xrdp-sesadmin.8.in b/docs/man/xrdp-sesadmin.8.in index ab540fca..6727772b 100644 --- a/docs/man/xrdp-sesadmin.8.in +++ b/docs/man/xrdp-sesadmin.8.in @@ -26,15 +26,11 @@ Defaults to \fBroot\fP. The \fIpassword\fP to authenticate with. The default is to ask for the password interactively. -.TP -.BI \-s= server -The host address of the \fIserver\fP to connect to. -Defaults to \fBlocalhost\fP. - .TP .BI \-i= port -The TCP \fIport\fP number to connect to. -Defaults to \fB3350\fP. +The sesman \fIUNIX domain socket\fP to connect to. +Defaults to \fBsesman.socket\fP. +If no path is specified for the socket, a default of @sesmanruntimedir@ is used. .TP .BI \-c= command diff --git a/docs/man/xrdp-sesman.8.in b/docs/man/xrdp-sesman.8.in index 03ebd47d..08e30ecb 100644 --- a/docs/man/xrdp-sesman.8.in +++ b/docs/man/xrdp-sesman.8.in @@ -58,6 +58,8 @@ to read it. @localstatedir@/log/xrdp\-sesman.log .br @localstatedir@/run/xrdp\-sesman.pid +.br +@sesmanruntimedir@/sesman.socket .SH "AUTHORS" Jay Sorg diff --git a/docs/man/xrdp-sesrun.8.in b/docs/man/xrdp-sesrun.8.in index 1cbd88dd..256c4f7a 100644 --- a/docs/man/xrdp-sesrun.8.in +++ b/docs/man/xrdp-sesrun.8.in @@ -29,11 +29,6 @@ option may not do what you expect. Set session bits-per-pixel (colour depth). Some session types (i.e. Xorg) will ignore this setting. .TP -.B -s -Server on which sesman is running (probably 'localhost'). -.br -Use of this option is discouraged as it will be removed in the future. -.TP .B -t Session type - one of Xorg, Xvnc or X11rdp. Alternatively, for testing only, use the numeric session code. diff --git a/libipm/Makefile.am b/libipm/Makefile.am index f0592442..2957182b 100644 --- a/libipm/Makefile.am +++ b/libipm/Makefile.am @@ -1,5 +1,6 @@ AM_CPPFLAGS = \ + -DSESMAN_RUNTIME_PATH=\"${sesmanruntimedir}\" \ -I$(top_srcdir)/common module_LTLIBRARIES = \ diff --git a/libipm/scp.c b/libipm/scp.c index b3f4fbf6..a6cfd827 100644 --- a/libipm/scp.c +++ b/libipm/scp.c @@ -33,6 +33,7 @@ #include "trans.h" #include "os_calls.h" #include "string_calls.h" +#include "xrdp_sockets.h" /*****************************************************************************/ static const char * @@ -66,28 +67,97 @@ scp_msgno_to_str(enum scp_msg_code n, char *buff, unsigned int buff_size) return buff; } +/*****************************************************************************/ +int +scp_port_to_unix_domain_path(const char *port, char *buff, + unsigned int bufflen) +{ + /* GOTCHA: Changes to this logic should be mirrored in + * scp_port_to_display_string() */ + + int result; + + /* Make sure we can safely de-reference 'port' */ + if (port == NULL) + { + port = ""; + } + + if (port[0] == '/') + { + result = g_snprintf(buff, bufflen, "%s", port); + } + else + { + const char *sep; + if ((sep = g_strrchr(port, '/')) != NULL && sep != port) + { + /* We allow the user to specify an absolute path, but not + * a relative one with embedded '/' characters */ + LOG(LOG_LEVEL_WARNING, "Ignoring path elements of '%s'", port); + port = sep + 1; + } + + if (port[0] == '\0') + { + port = SCP_LISTEN_PORT_BASE_STR; + } + else if (g_strcmp(port, "3350") == 0) + { + /* Version v0.9.x and earlier of xrdp used a TCP port + * number. If we come across this, we'll ignore it for + * compatibility with old config files */ + LOG(LOG_LEVEL_WARNING, + "Ignoring obsolete SCP port value '%s'", port); + port = SCP_LISTEN_PORT_BASE_STR; + } + + result = g_snprintf(buff, bufflen, SESMAN_RUNTIME_PATH "/%s", port); + } + + return result; +} + +/*****************************************************************************/ +int +scp_port_to_display_string(const char *port, char *buff, unsigned int bufflen) +{ + /* Make sure we can safely de-reference 'port' */ + if (port == NULL) + { + port = ""; + } + + /* Ignore any directories for the display */ + const char *sep; + if ((sep = g_strrchr(port, '/')) != NULL) + { + port = sep + 1; + } + + /* Check for a default */ + if (port[0] == '\0' || g_strcmp(port, "3350") == 0) + { + port = SCP_LISTEN_PORT_BASE_STR; + } + + return g_snprintf(buff, bufflen, "%s", port); +} + /*****************************************************************************/ struct trans * -scp_connect(const char *host, const char *port, +scp_connect(const char *port, int (*term_func)(void)) { + char sock_path[256]; struct trans *t; - if ((t = trans_create(TRANS_MODE_TCP, 128, 128)) != NULL) + + (void)scp_port_to_unix_domain_path(port, sock_path, sizeof(sock_path)); + if ((t = trans_create(TRANS_MODE_UNIX, 128, 128)) != NULL) { - if (host == NULL) - { - host = "localhost"; - } - - if (port == NULL) - { - port = "3350"; - } - t->is_term = term_func; - trans_connect(t, host, port, 3000); - if (t->status != TRANS_STATUS_UP) + if (trans_connect(t, NULL, sock_path, 3000) != 0) { trans_delete(t); t = NULL; diff --git a/libipm/scp.h b/libipm/scp.h index 7984a7b6..e2d87c3f 100644 --- a/libipm/scp.h +++ b/libipm/scp.h @@ -65,11 +65,38 @@ scp_msgno_to_str(enum scp_msg_code n, char *buff, unsigned int buff_size); /* Connection management facilities */ +/** + * Maps a port definition to a UNIX domain socket path + * @param port Port definition (e.g. from sesman.ini). Can be "" or NULL + * @param buff Buffer for result + * @param bufflen Length of buff + * + * @return Number of chars needed for result, excluding the '\0' + */ +int +scp_port_to_unix_domain_path(const char *port, char *buff, + unsigned int bufflen); + +/** + * Maps a port definition to a displayable string + * @param port Port definition (e.g. from sesman.ini). Can be "" or NULL + * @param buff Buffer for result + * @param bufflen Length of buff + * + * @return Number of chars needed for result, excluding the '\0' + * + * This differs from scp_port_to_unix_domain_path() in that the result is + * for displaying to the user (i.e. in a status message), rather than for + * connecting to. For log messages, use the result of + * scp_port_to_unix_domain_path() + */ +int +scp_port_to_display_string(const char *port, char *buff, unsigned int bufflen); + /** * Connect to an SCP server * - * @param host Host providing SCP service - * @param port TCP port for SCP service + * @param port Port definition (e.g. from sesman.ini) * @param term_func Function to poll during connection for program * termination, or NULL for none. * @return Initialised SCP transport @@ -77,7 +104,7 @@ scp_msgno_to_str(enum scp_msg_code n, char *buff, unsigned int buff_size); * The returned tranport has the is_term member set to term_func. */ struct trans * -scp_connect(const char *host, const char *port, +scp_connect(const char *port, int (*term_func)(void)); /** diff --git a/sesman/Makefile.am b/sesman/Makefile.am index 181861af..7d7052a5 100644 --- a/sesman/Makefile.am +++ b/sesman/Makefile.am @@ -8,6 +8,7 @@ AM_CPPFLAGS = \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DSESMAN_RUNTIME_PATH=\"${sesmanruntimedir}\" \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libipm diff --git a/sesman/config.c b/sesman/config.c index 61e9e403..4eabdd46 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -35,6 +35,7 @@ #include "log.h" #include "string_calls.h" #include "chansrv/chansrv_common.h" +#include "scp.h" /***************************************************************************//** * @@ -51,14 +52,11 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n, struct list *param_v) { int i; - int length; - char *buf; list_clear(param_v); list_clear(param_n); /* resetting the struct */ - cf->listen_address[0] = '\0'; cf->listen_port[0] = '\0'; cf->enable_user_wm = 0; cf->user_wm[0] = '\0'; @@ -70,47 +68,50 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n, for (i = 0; i < param_n->count; i++) { - buf = (char *)list_get_item(param_n, i); + const char *param = (const char *)list_get_item(param_n, i); + const char *val = (const char *)list_get_item(param_v, i); - if (0 == g_strcasecmp(buf, SESMAN_CFG_DEFWM)) + if (0 == g_strcasecmp(param, SESMAN_CFG_DEFWM)) { - cf->default_wm = g_strdup((char *)list_get_item(param_v, i)); + cf->default_wm = g_strdup(val); } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_USERWM)) + else if (0 == g_strcasecmp(param, SESMAN_CFG_USERWM)) { - g_strncpy(cf->user_wm, (char *)list_get_item(param_v, i), 31); + g_strncpy(cf->user_wm, val, sizeof(cf->user_wm) - 1); } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_ENABLE_USERWM)) + else if (0 == g_strcasecmp(param, SESMAN_CFG_ENABLE_USERWM)) { - cf->enable_user_wm = g_text2bool((char *)list_get_item(param_v, i)); + cf->enable_user_wm = g_text2bool(val); } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_PORT)) + else if (0 == g_strcasecmp(param, SESMAN_CFG_PORT)) { - g_strncpy(cf->listen_port, (char *)list_get_item(param_v, i), 15); + scp_port_to_unix_domain_path(val, cf->listen_port, + sizeof(cf->listen_port)); } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_ADDRESS)) + else if (0 == g_strcasecmp(param, SESMAN_CFG_AUTH_FILE_PATH)) { - g_strncpy(cf->listen_address, (char *)list_get_item(param_v, i), 31); + cf->auth_file_path = g_strdup(val); } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_AUTH_FILE_PATH)) + else if (g_strcasecmp(param, SESMAN_CFG_RECONNECT_SH) == 0) { - cf->auth_file_path = g_strdup((char *)list_get_item(param_v, i)); + cf->reconnect_sh = g_strdup(val); } - else if (g_strcasecmp(buf, SESMAN_CFG_RECONNECT_SH) == 0) + else if (0 == g_strcasecmp(param, SESMAN_CFG_ADDRESS)) { - cf->reconnect_sh = g_strdup((char *)list_get_item(param_v, i)); + /* Config must be updated for Unix Domain Sockets */ + LOG(LOG_LEVEL_WARNING, "Obsolete setting' " SESMAN_CFG_ADDRESS + "' in [" SESMAN_CFG_GLOBALS "] should be removed."); + LOG(LOG_LEVEL_WARNING, "Review setting' " SESMAN_CFG_PORT "' in [" + SESMAN_CFG_GLOBALS "]"); } } /* checking for missing required parameters */ - if ('\0' == cf->listen_address[0]) - { - g_strncpy(cf->listen_address, "0.0.0.0", 8); - } - if ('\0' == cf->listen_port[0]) { - g_strncpy(cf->listen_port, "3350", 5); + /* Load the default value */ + scp_port_to_unix_domain_path(NULL, cf->listen_port, + sizeof(cf->listen_port)); } if ('\0' == cf->user_wm[0]) @@ -118,46 +119,40 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n, cf->enable_user_wm = 0; } - if (cf->default_wm == 0) - { - cf->default_wm = g_strdup("startwm.sh"); - } - else if (g_strlen(cf->default_wm) == 0) + if (cf->default_wm == 0 || cf->default_wm[0] == '\0') { g_free(cf->default_wm); cf->default_wm = g_strdup("startwm.sh"); } - /* if default_wm doesn't begin with '/', it's a relative path to XRDP_CFG_PATH */ + /* if default_wm doesn't begin with '/', it's a relative path to + * XRDP_CFG_PATH */ if (cf->default_wm[0] != '/') { /* sizeof operator returns string length including null terminator */ - length = sizeof(XRDP_CFG_PATH) + g_strlen(cf->default_wm) + 1; /* '/' */ - buf = (char *)g_malloc(length, 0); + int length = (sizeof(XRDP_CFG_PATH) + + g_strlen(cf->default_wm) + 1); /* '/' */ + char *buf = (char *)g_malloc(length, 0); g_sprintf(buf, "%s/%s", XRDP_CFG_PATH, cf->default_wm); g_free(cf->default_wm); - cf->default_wm = g_strdup(buf); - g_free(buf); + cf->default_wm = buf; } - if (cf->reconnect_sh == 0) - { - cf->reconnect_sh = g_strdup("reconnectwm.sh"); - } - else if (g_strlen(cf->reconnect_sh) == 0) + if (cf->reconnect_sh == 0 || cf->reconnect_sh[0] == '\0') { g_free(cf->reconnect_sh); cf->reconnect_sh = g_strdup("reconnectwm.sh"); } - /* if reconnect_sh doesn't begin with '/', it's a relative path to XRDP_CFG_PATH */ + /* if reconnect_sh doesn't begin with '/', it's a relative path to + * XRDP_CFG_PATH */ if (cf->reconnect_sh[0] != '/') { /* sizeof operator returns string length including null terminator */ - length = sizeof(XRDP_CFG_PATH) + g_strlen(cf->reconnect_sh) + 1; /* '/' */ - buf = (char *)g_malloc(length, 0); + int length = (sizeof(XRDP_CFG_PATH) + + g_strlen(cf->reconnect_sh) + 1); /* '/' */ + char *buf = (char *)g_malloc(length, 0); g_sprintf(buf, "%s/%s", XRDP_CFG_PATH, cf->reconnect_sh); g_free(cf->reconnect_sh); - cf->reconnect_sh = g_strdup(buf); - g_free(buf); + cf->reconnect_sh = buf; } return 0; @@ -530,6 +525,7 @@ config_read(const char *sesman_ini) param_n->auto_free = 1; param_v = list_create(); param_v->auto_free = 1; + all_ok = 1; /* read global config */ config_read_globals(fd, cfg, param_n, param_v); @@ -552,7 +548,6 @@ config_read(const char *sesman_ini) list_delete(param_v); list_delete(param_n); g_file_close(fd); - all_ok = 1; } } } @@ -579,14 +574,13 @@ config_dump(struct config_sesman *config) /* Global sesman configuration */ g_writeln("Filename: %s", config->sesman_ini); g_writeln("Global configuration:"); - g_writeln(" ListenAddress: %s", config->listen_address); g_writeln(" ListenPort: %s", config->listen_port); g_writeln(" EnableUserWindowManager: %d", config->enable_user_wm); g_writeln(" UserWindowManager: %s", config->user_wm); g_writeln(" DefaultWindowManager: %s", config->default_wm); g_writeln(" ReconnectScript: %s", config->reconnect_sh); g_writeln(" AuthFilePath: %s", - ((config->auth_file_path) ? (config->auth_file_path) : ("disabled"))); + (config->auth_file_path ? config->auth_file_path : "disabled")); /* Session configuration */ g_writeln("Session configuration:"); diff --git a/sesman/config.h b/sesman/config.h index c6b72f8a..b73ff46c 100644 --- a/sesman/config.h +++ b/sesman/config.h @@ -201,16 +201,11 @@ struct config_sesman */ char *sesman_ini; - /** - * @var listen_address - * @brief Listening address - */ - char listen_address[32]; /** * @var listen_port * @brief Listening port */ - char listen_port[16]; + char listen_port[256]; /** * @var enable_user_wm * @brief Flag that enables user specific wm diff --git a/sesman/sesman.c b/sesman/sesman.c index b5c78f4c..96849379 100644 --- a/sesman/sesman.c +++ b/sesman/sesman.c @@ -36,6 +36,7 @@ #include "trans.h" #include "scp_process.h" +#include "lock_uds.h" /** * Maximum number of short-lived connections to sesman @@ -70,6 +71,10 @@ struct sesman_con }; static struct trans *g_list_trans; + +/* Variables used to lock g_list_trans */ +static struct lock_uds *g_list_trans_lock; + static struct list *g_con_list = NULL; static int g_pid; @@ -206,45 +211,52 @@ sesman_process_params(int argc, char **argv, } /******************************************************************************/ -static int sesman_listen_test(struct config_sesman *cfg) +static int +create_sesman_runtime_dir(void) { - int error; - int sck; - int rv = 0; + int rv = -1; + /* Make sure if we create the directory, there's no gap where it + * may have the wrong permissions */ + int entry_umask = g_umask_hex(0x755); - sck = g_tcp_socket(); - if (sck < 0) + if (!g_directory_exist(SESMAN_RUNTIME_PATH) && + !g_create_dir(SESMAN_RUNTIME_PATH)) { - return 1; + LOG(LOG_LEVEL_ERROR, + "Can't create runtime directory '" + SESMAN_RUNTIME_PATH "' [%s]", g_get_strerror()); } - - LOG(LOG_LEVEL_DEBUG, "Testing if xrdp-sesman can listen on %s port %s.", - cfg->listen_address, cfg->listen_port); - g_tcp_set_non_blocking(sck); - error = g_tcp_bind_address(sck, cfg->listen_port, cfg->listen_address); - if (error == 0) + else if (g_chown(SESMAN_RUNTIME_PATH, g_getuid(), g_getuid()) != 0) { - /* try to listen */ - error = g_tcp_listen(sck); - - if (error == 0) - { - /* if listen succeeded, stop listen immediately */ - g_sck_close(sck); - } - else - { - rv = 1; - } + LOG(LOG_LEVEL_ERROR, + "Can't set ownership of sesman runtime directory [%s]", + g_get_strerror()); + } + else if (g_chmod_hex(SESMAN_RUNTIME_PATH, 0x755) != 0) + { + /* This might seem redundant, but there's a chance the + * directory already exists */ + LOG(LOG_LEVEL_ERROR, + "Can't set permissions of sesman runtime directory [%s]", + g_get_strerror()); } else { - rv = 1; + rv = 0; } + g_umask_hex(entry_umask); return rv; } +/******************************************************************************/ +static int sesman_listen_test(struct config_sesman *cfg) +{ + int status = sesman_create_listening_transport(cfg); + sesman_delete_listening_transport(); + return status; +} + /******************************************************************************/ int sesman_close_all(void) @@ -357,8 +369,18 @@ set_reload_event(int sig) void sesman_delete_listening_transport(void) { - trans_delete(g_list_trans); + if (g_getpid() == g_pid) + { + trans_delete(g_list_trans); + } + else + { + trans_delete_from_child(g_list_trans); + } g_list_trans = NULL; + + unlock_uds(g_list_trans_lock); + g_list_trans_lock = NULL; } /******************************************************************************/ @@ -366,26 +388,43 @@ int sesman_create_listening_transport(const struct config_sesman *cfg) { int rv = 1; - g_list_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); + g_list_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); if (g_list_trans == NULL) { LOG(LOG_LEVEL_ERROR, "%s: trans_create failed", __func__); } - else + else if ((g_list_trans_lock = lock_uds(cfg->listen_port)) != NULL) { - LOG(LOG_LEVEL_DEBUG, "%s: address %s port %s", - __func__, cfg->listen_address, cfg->listen_port); - rv = trans_listen_address(g_list_trans, cfg->listen_port, - cfg->listen_address); + /* Make sure the file is always created with the correct + * permissions, if it's not there */ + int entry_umask = g_umask_hex(0x666); + LOG_DEVEL(LOG_LEVEL_DEBUG, "%s: port %s", __func__, cfg->listen_port); + rv = trans_listen_address(g_list_trans, cfg->listen_port, NULL); if (rv != 0) { LOG(LOG_LEVEL_ERROR, "%s: trans_listen_address failed", __func__); - sesman_delete_listening_transport(); + } + else if (g_chown(cfg->listen_port, g_getuid(), g_getuid()) != 0) + { + LOG(LOG_LEVEL_ERROR, + "Can't set ownership of '%s' [%s]", + cfg->listen_port, g_get_strerror()); + } + else if ((rv = g_chmod_hex(cfg->listen_port, 0x666)) != 0) + { + LOG(LOG_LEVEL_ERROR, "%s: Can't set permissions on '%s' [%s]", + __func__, cfg->listen_port, g_get_strerror()); } else { g_list_trans->trans_conn_in = sesman_listen_conn_in; } + g_umask_hex(entry_umask); + } + + if (rv != 0) + { + sesman_delete_listening_transport(); } return rv; @@ -422,6 +461,7 @@ sesman_main_loop(void) list_delete(g_con_list); return 1; } + LOG(LOG_LEVEL_INFO, "Sesman now listening on %s", g_cfg->listen_port); error = 0; while (!error) @@ -722,7 +762,6 @@ main(int argc, char **argv) LOG(LOG_LEVEL_TRACE, "config loaded in %s at %s:%d", __func__, __FILE__, __LINE__); LOG(LOG_LEVEL_TRACE, " sesman_ini = %s", g_cfg->sesman_ini); - LOG(LOG_LEVEL_TRACE, " listen_address = %s", g_cfg->listen_address); LOG(LOG_LEVEL_TRACE, " listen_port = %s", g_cfg->listen_port); LOG(LOG_LEVEL_TRACE, " enable_user_wm = %d", g_cfg->enable_user_wm); LOG(LOG_LEVEL_TRACE, " default_wm = %s", g_cfg->default_wm); @@ -751,6 +790,16 @@ main(int argc, char **argv) } } + /* Create the runtime directory before we try to listen (or + * test-listen), so there's somewhere for the default socket to live */ + if (create_sesman_runtime_dir() != 0) + { + config_free(g_cfg); + log_end(); + g_deinit(); + g_exit(1); + } + if (daemon) { /* start of daemonizing code */ @@ -759,6 +808,7 @@ main(int argc, char **argv) LOG(LOG_LEVEL_ERROR, "Failed to start xrdp-sesman daemon, " "possibly address already in use."); config_free(g_cfg); + log_end(); g_deinit(); g_exit(1); } @@ -766,14 +816,17 @@ main(int argc, char **argv) if (0 != g_fork()) { config_free(g_cfg); + log_end(); g_deinit(); g_exit(0); } } - /* signal handling */ + /* Now we've forked (if necessary), we can get the prgram PID */ g_pid = g_getpid(); + + /* signal handling */ g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_term", g_pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_sesman_%8.8x_sigchld", g_pid); diff --git a/sesman/sesman.ini.in b/sesman/sesman.ini.in index 8c5f173f..15ef50ba 100644 --- a/sesman/sesman.ini.in +++ b/sesman/sesman.ini.in @@ -1,8 +1,8 @@ ;; See `man 5 sesman.ini` for details [Globals] -ListenAddress=127.0.0.1 -ListenPort=3350 +; listening port +#ListenPort=sesman.socket EnableUserWindowManager=true ; Give in relative path to user's home directory UserWindowManager=startwm.sh diff --git a/sesman/sig.c b/sesman/sig.c index 14d4c820..65c1d288 100644 --- a/sesman/sig.c +++ b/sesman/sig.c @@ -47,16 +47,19 @@ sig_sesman_reload_cfg(void) } /* Deal with significant config changes */ - if (g_strcmp(g_cfg->listen_address, cfg->listen_address) != 0 || - g_strcmp(g_cfg->listen_port, cfg->listen_port) != 0) + if (g_strcmp(g_cfg->listen_port, cfg->listen_port) != 0) { - LOG(LOG_LEVEL_INFO, "sesman listen address changed to %s:%s", - cfg->listen_address, cfg->listen_port); + LOG(LOG_LEVEL_INFO, "sesman listen port changed to %s", + cfg->listen_port); /* We have to delete the old port before listening to the new one * in case they overlap in scope */ sesman_delete_listening_transport(); - sesman_create_listening_transport(cfg); + if (sesman_create_listening_transport(cfg) == 0) + { + LOG(LOG_LEVEL_INFO, "Sesman now listening on %s", + g_cfg->listen_port); + } } /* free old config data */ diff --git a/sesman/tools/sesadmin.c b/sesman/tools/sesadmin.c index e04e4ef2..4ef56a02 100644 --- a/sesman/tools/sesadmin.c +++ b/sesman/tools/sesadmin.c @@ -34,7 +34,6 @@ char user[257]; char pass[257]; char cmnd[257]; -char serv[257]; char port[257]; static int cmndList(struct trans *t); @@ -55,7 +54,6 @@ int main(int argc, char **argv) user[0] = '\0'; pass[0] = '\0'; cmnd[0] = '\0'; - serv[0] = '\0'; port[0] = '\0'; logging = log_config_init_for_console(LOG_LEVEL_INFO, NULL); @@ -72,10 +70,6 @@ int main(int argc, char **argv) { g_strncpy(pass, (argv[idx]) + 3, 256); } - else if (0 == g_strncmp(argv[idx], "-s=", 3)) - { - g_strncpy(serv, (argv[idx]) + 3, 256); - } else if (0 == g_strncmp(argv[idx], "-i=", 3)) { g_strncpy(port, (argv[idx]) + 3, 256); @@ -86,11 +80,6 @@ int main(int argc, char **argv) } } - if (0 == g_strncmp(serv, "", 1)) - { - g_strncpy(serv, "localhost", 256); - } - if (0 == g_strncmp(port, "", 1)) { g_strncpy(port, "3350", 256); @@ -115,7 +104,7 @@ int main(int argc, char **argv) } - t = scp_connect(serv, port, NULL); + t = scp_connect(port, NULL); if (t == NULL) diff --git a/sesman/tools/sesrun.c b/sesman/tools/sesrun.c index cbdc7a46..1429376a 100644 --- a/sesman/tools/sesrun.c +++ b/sesman/tools/sesrun.c @@ -63,10 +63,6 @@ # define DEFAULT_BPP 32 #endif -#ifndef DEFAULT_SERVER -# define DEFAULT_SERVER "localhost" -#endif - #ifndef DEFAULT_TYPE # define DEFAULT_TYPE "Xorg" #endif @@ -95,7 +91,6 @@ struct session_params int height; int bpp; enum scp_session_type session_type; - const char *server; const char *directory; const char *shell; @@ -175,9 +170,6 @@ usage(void) g_printf(" -g Default:%dx%d\n", DEFAULT_WIDTH, DEFAULT_HEIGHT); g_printf(" -b Default:%d\n", DEFAULT_BPP); - /* Don't encourage use of this one - we need to move to local sockets */ - g_printf(" -s Default:%s (Deprecated)\n", - DEFAULT_SERVER); g_printf(" -t Default:%s\n", DEFAULT_TYPE); g_printf(" -D Default: $HOME\n" " -S Default: Defined window manager\n" @@ -291,7 +283,6 @@ parse_program_args(int argc, char *argv[], struct session_params *sp, sp->height = DEFAULT_HEIGHT; sp->bpp = DEFAULT_BPP; (void)string_to_session_type(DEFAULT_TYPE, &sp->session_type); - sp->server = DEFAULT_SERVER; sp->directory = ""; sp->shell = ""; @@ -315,11 +306,6 @@ parse_program_args(int argc, char *argv[], struct session_params *sp, sp->bpp = atoi(optarg); break; - case 's': - LOG(LOG_LEVEL_WARNING, "Using deprecated option '-s'"); - sp->server = optarg; - break; - case 't': if (string_to_session_type(optarg, &sp->session_type) != 0) { @@ -419,10 +405,10 @@ send_create_session_request(struct trans *t, const struct session_params *sp) { LOG(LOG_LEVEL_DEBUG, "width:%d height:%d bpp:%d code:%d\n" - "server:\"%s\" directory:\"%s\"\n" + "directory:\"%s\"\n" "shell:\"%s\" connection_description:\"%s\"", sp->width, sp->height, sp->bpp, sp->session_type, - sp->server, sp->directory, + sp->directory, sp->shell, sp->connection_description); /* Only log the password in development builds */ LOG_DEVEL(LOG_LEVEL_DEBUG, "password:\"%s\"", sp->password); @@ -498,7 +484,7 @@ main(int argc, char **argv) LOG(LOG_LEVEL_ERROR, "error reading config file %s : %s", sesman_ini, g_get_strerror()); } - else if (!(t = scp_connect(sp.server, cfg->listen_port, NULL))) + else if (!(t = scp_connect(cfg->listen_port, NULL))) { LOG(LOG_LEVEL_ERROR, "connect error - %s", g_get_strerror()); } diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index 3b6340f8..aee9bb28 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -223,7 +223,6 @@ name=Xorg lib=libxup.@lib_extension@ username=ask password=ask -ip=127.0.0.1 port=-1 code=20 @@ -232,7 +231,6 @@ name=Xvnc lib=libvnc.@lib_extension@ username=ask password=ask -ip=127.0.0.1 port=-1 #xserverbpp=24 #delay_ms=2000 @@ -256,7 +254,6 @@ username=na password=ask #pamusername=asksame #pampassword=asksame -#pamsessionmng=127.0.0.1 #delay_ms=2000 ; Generic RDP proxy using NeutrinoRDP @@ -275,7 +272,6 @@ password=ask ; connections. #pamusername=ask #pampassword=ask -#pamsessionmng=127.0.0.1 ; Currently NeutrinoRDP doesn't support dynamic resizing. Uncomment ; this line if you're using a client which does. #enable_dynamic_resizing=false diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index fa3f9396..fb3e341b 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -51,7 +51,7 @@ getPAMError(const int pamError, char *text, int text_bytes); static const char * getPAMAdditionalErrorInfo(const int pamError, struct xrdp_mm *self); static int -xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *ip, const char *port); +xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *port); static void xrdp_mm_connect_sm(struct xrdp_mm *self); @@ -159,8 +159,6 @@ xrdp_mm_delete(struct xrdp_mm *self) trans_delete(self->sesman_trans); self->sesman_trans = 0; - trans_delete(self->pam_auth_trans); - self->pam_auth_trans = 0; list_delete(self->login_names); list_delete(self->login_values); g_free(self); @@ -229,7 +227,7 @@ xrdp_mm_send_gateway_login(struct xrdp_mm *self, const char *username, "sending login info to session manager, please wait..."); return scp_send_gateway_request( - self->pam_auth_trans, username, password, + self->sesman_trans, username, password, self->wm->client_info->connection_description); } @@ -475,7 +473,6 @@ xrdp_mm_setup_mod2(struct xrdp_mm *self) int rv; int key_flags; int device_flags; - int use_uds; rv = 1; /* failure */ g_memset(text, 0, sizeof(text)); @@ -500,22 +497,7 @@ xrdp_mm_setup_mod2(struct xrdp_mm *self) } else if (self->code == 10 || self->code == 20) /* X11rdp/Xorg */ { - use_uds = 1; - - if ((value = xrdp_mm_get_value(self, "ip")) != NULL && - g_strcmp(value, "127.0.0.1") != 0) - { - use_uds = 0; - } - - if (use_uds) - { - g_snprintf(text, 255, XRDP_X11RDP_STR, self->display); - } - else - { - g_snprintf(text, 255, "%d", 6200 + self->display); - } + g_snprintf(text, 255, XRDP_X11RDP_STR, self->display); } else { @@ -1691,10 +1673,9 @@ xrdp_mm_chan_data_in(struct trans *trans) static void cleanup_sesman_connection(struct xrdp_mm *self) { - /* Don't delete these transports here - we may be in + /* Don't delete any transports here - we may be in * an auth callback from one of them */ self->delete_sesman_trans = 1; - self->delete_pam_auth_trans = 1; if (self->wm->login_state != WMLS_CLEANUP) { @@ -1861,16 +1842,12 @@ xrdp_mm_process_gateway_response(struct xrdp_mm *self) int auth_result; int rv; - rv = scp_get_gateway_response(self->pam_auth_trans, &auth_result); + rv = scp_get_gateway_response(self->sesman_trans, &auth_result); if (rv == 0) { const char *additionalError; char pam_error[128]; - /* We no longer need the pam_auth transport - it's only used - * for the one message */ - self->delete_pam_auth_trans = 1; - xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "Reply from access control: %s", getPAMError(auth_result, @@ -1987,11 +1964,8 @@ xrdp_mm_scp_data_in(struct trans *trans) { char buff[64]; scp_msgno_to_str(msgno, buff, sizeof(buff)); - const char *src = (trans == self->pam_auth_trans) - ? "PAM authenticator" - : "sesman"; - LOG(LOG_LEVEL_ERROR, "Ignored SCP message %s from %s", - buff, src); + LOG(LOG_LEVEL_ERROR, "Ignored SCP message %s from sesman", + buff); } } @@ -2015,10 +1989,8 @@ cleanup_states(struct xrdp_mm *self) self->use_chansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */ self->use_pam_auth = 0; /* true if we're to use the PAM authentication facility */ self->sesman_trans = NULL; /* connection to sesman */ - self->pam_auth_trans = NULL; /* connection to PAM authenticator */ self->chan_trans = NULL; /* connection to chansrv */ self->delete_sesman_trans = 0; - self->delete_pam_auth_trans = 0; self->display = 0; /* 10 for :10.0, 11 for :11.0, etc */ guid_clear(&self->guid); self->code = 0; /* 0 Xvnc session, 10 X11rdp session, 20 Xorg session */ @@ -2304,28 +2276,31 @@ parse_chansrvport(const char *value, char *dest, int dest_size) /*****************************************************************************/ static struct trans * -xrdp_mm_scp_connect(struct xrdp_mm *self, const char *target, const char *ip) +xrdp_mm_scp_connect(struct xrdp_mm *self) { char port[128]; + char port_description[128]; struct trans *t; xrdp_mm_get_sesman_port(port, sizeof(port)); + scp_port_to_display_string(port, + port_description, sizeof(port_description)); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG, - "connecting to %s on %s:%s", target, ip, port); - t = scp_connect(ip, port, g_is_term); + "connecting to sesman on %s", port_description); + t = scp_connect(port, g_is_term); if (t != NULL) { /* fully connected */ t->trans_data_in = xrdp_mm_scp_data_in; t->callback_data = self; - xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "%s connect ok", target); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "sesman connect ok"); } else { xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR, - "Error connecting to %s on %s:%s", - target, ip, port); + "Error connecting to sesman on %s", port_description); trans_delete(t); t = NULL; } @@ -2334,27 +2309,17 @@ xrdp_mm_scp_connect(struct xrdp_mm *self, const char *target, const char *ip) /*****************************************************************************/ static int -xrdp_mm_pam_auth_connect(struct xrdp_mm *self, const char *ip) -{ - trans_delete(self->pam_auth_trans); - self->pam_auth_trans = xrdp_mm_scp_connect(self, "PAM authenticator", ip); - - return (self->pam_auth_trans == NULL); /* 0 for success */ -} - -/*****************************************************************************/ -static int -xrdp_mm_sesman_connect(struct xrdp_mm *self, const char *ip) +xrdp_mm_sesman_connect(struct xrdp_mm *self) { trans_delete(self->sesman_trans); - self->sesman_trans = xrdp_mm_scp_connect(self, "sesman", ip); + self->sesman_trans = xrdp_mm_scp_connect(self); return (self->sesman_trans == NULL); /* 0 for success */ } /*****************************************************************************/ static int -xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *ip, const char *port) +xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *port) { if (self->wm->client_info->channels_allowed == 0) { @@ -2365,16 +2330,7 @@ xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *ip, const char *port) } /* connect channel redir */ - if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) - { - /* unix socket */ - self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); - } - else - { - /* tcp */ - self->chan_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); - } + self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); self->chan_trans->is_term = g_is_term; self->chan_trans->si = &(self->wm->session->si); @@ -2386,7 +2342,7 @@ xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *ip, const char *port) self->chan_trans->extra_flags = 0; /* try to connect for up to 10 seconds */ - trans_connect(self->chan_trans, ip, port, 10 * 1000); + trans_connect(self->chan_trans, NULL, port, 10 * 1000); if (self->chan_trans->status != TRANS_STATUS_UP) { LOG(LOG_LEVEL_ERROR, "xrdp_mm_chansrv_connect: error in " @@ -2454,10 +2410,26 @@ xrdp_mm_connect(struct xrdp_mm *self) if (port != NULL && g_strcmp(port, "-1") == 0) { self->use_sesman = 1; + /* Connecting to a remote sesman is no longer supported */ + if (xrdp_mm_get_value(self, "ip") != NULL) + { + xrdp_wm_log_msg(self->wm, + LOG_LEVEL_WARNING, + "Parameter 'ip' is obsolete for sesman connections." + " Please remove from config"); + } } if (gateway_username != NULL) { + /* Connecting to a remote sesman is no longer supported */ + if (xrdp_mm_get_value(self, "pamsessionmng") != NULL) + { + xrdp_wm_log_msg(self->wm, + LOG_LEVEL_WARNING, + "Parameter 'pamsessionmng' is obsolete." + " Please remove from config"); + } #ifdef USE_PAM self->use_pam_auth = 1; #else @@ -2499,22 +2471,10 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) { case MMCS_CONNECT_TO_SESMAN: { - if (self->use_sesman) + if (self->use_sesman || self->use_pam_auth) { /* Synchronous call */ - const char *ip = xrdp_mm_get_value(self, "ip"); - status = xrdp_mm_sesman_connect(self, ip); - } - - if (status == 0 && self->use_pam_auth) - { - /* Synchronous call */ - const char *ip = xrdp_mm_get_value(self, "pamsessionmng"); - if (ip == NULL) - { - ip = xrdp_mm_get_value(self, "ip"); - } - status = xrdp_mm_pam_auth_connect(self, ip); + status = xrdp_mm_sesman_connect(self); } } break; @@ -2589,25 +2549,12 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) { if (self->use_chansrv) { - const char *ip = ""; char portbuff[256]; if (self->use_sesman) { - ip = xrdp_mm_get_value(self, "ip"); - - /* connect channel redir */ - if (ip == NULL || (ip[0] == '\0') || - (g_strcmp(ip, "127.0.0.1") == 0)) - { - g_snprintf(portbuff, sizeof(portbuff), - XRDP_CHANSRV_STR, self->display); - } - else - { - g_snprintf(portbuff, sizeof(portbuff), - "%d", 7200 + self->display); - } + g_snprintf(portbuff, sizeof(portbuff), + XRDP_CHANSRV_STR, self->display); } else { @@ -2617,7 +2564,7 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) } xrdp_mm_update_allowed_channels(self); - xrdp_mm_chansrv_connect(self, ip, portbuff); + xrdp_mm_chansrv_connect(self, portbuff); } } break; @@ -2668,12 +2615,6 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self, trans_get_wait_objs(self->sesman_trans, read_objs, rcount); } - if (self->pam_auth_trans != 0 && - self->pam_auth_trans->status == TRANS_STATUS_UP) - { - trans_get_wait_objs(self->pam_auth_trans, read_objs, rcount); - } - if ((self->chan_trans != 0) && self->chan_trans->status == TRANS_STATUS_UP) { trans_get_wait_objs_rw(self->chan_trans, read_objs, rcount, @@ -2898,22 +2839,6 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) self->sesman_trans = NULL; } - if (self->pam_auth_trans != NULL && - !self->delete_pam_auth_trans && - self->pam_auth_trans->status == TRANS_STATUS_UP) - { - if (trans_check_wait_objs(self->pam_auth_trans) != 0) - { - self->delete_pam_auth_trans = 1; - } - } - if (self->delete_pam_auth_trans) - { - trans_delete(self->pam_auth_trans); - self->pam_auth_trans = NULL; - } - - if (self->chan_trans != NULL && self->chan_trans->status == TRANS_STATUS_UP) { diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 8ec731fa..d800370c 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -322,7 +322,6 @@ struct xrdp_mm int use_pam_auth; /* True if we're to authenticate using PAM */ int use_chansrv; /* true if chansrvport is set in xrdp.ini or using sesman */ struct trans *sesman_trans; /* connection to sesman */ - struct trans *pam_auth_trans; /* connection to pam authenticator */ struct trans *chan_trans; /* connection to chansrv */ /* We can't delete transports while we're in a callback for that @@ -330,7 +329,6 @@ struct xrdp_mm * These flags mark transports as needing to be deleted when * we are definitely not in a transport callback */ int delete_sesman_trans; - int delete_pam_auth_trans; struct list *login_names; struct list *login_values;