diff --git a/docs/man/sesman.ini.5.in b/docs/man/sesman.ini.5.in index fa3b44b3..55044d73 100644 --- a/docs/man/sesman.ini.5.in +++ b/docs/man/sesman.ini.5.in @@ -365,6 +365,13 @@ because the system is unable to check whether the user is an administrator. \fBAllowAlternateShell\fR=\fI[true|false]\fR If set to \fB0\fR, \fBfalse\fR or \fBno\fR, prevent usage of alternate shells by users. +.TP +\fBPassShellAsEnv\fR=\fI\fR +If this is set, alternate shells are not actioned directly, but +passed in to the default window manager in the specified environment +variable. This allows the system manager more control over exactly +what alternate shells are permitted. + .TP \fBXorgNoNewPrivileges\fR=\fI[true|false]\fR Only applicable on Linux. If set to \fB0\fR, \fBfalse\fR or \fBno\fR, do diff --git a/sesman/libsesman/sesman_config.c b/sesman/libsesman/sesman_config.c index 16219025..028c6810 100644 --- a/sesman/libsesman/sesman_config.c +++ b/sesman/libsesman/sesman_config.c @@ -72,6 +72,7 @@ #define SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD "RestrictOutboundClipboard" #define SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD "RestrictInboundClipboard" #define SESMAN_CFG_SEC_ALLOW_ALTERNATE_SHELL "AllowAlternateShell" +#define SESMAN_CFG_SEC_PASS_SHELL_AS_ENV "PassShellAsEnv" #define SESMAN_CFG_SEC_XORG_NO_NEW_PRIVILEGES "XorgNoNewPrivileges" #define SESMAN_CFG_SEC_SESSION_SOCKDIR_GROUP "SessionSockdirGroup" @@ -319,6 +320,7 @@ config_read_security(int file, struct config_security *sc, sc->restrict_outbound_clipboard = 0; sc->restrict_inbound_clipboard = 0; sc->allow_alternate_shell = 1; + sc->pass_shell_as_env = g_strdup(""); sc->xorg_no_new_privileges = 1; sc->ts_users = g_strdup(""); sc->ts_admins = g_strdup(""); @@ -390,6 +392,11 @@ config_read_security(int file, struct config_security *sc, sc->allow_alternate_shell = g_text2bool(value); } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_PASS_SHELL_AS_ENV)) + { + g_free(sc->pass_shell_as_env); + sc->pass_shell_as_env = g_strdup(value); + } else if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_XORG_NO_NEW_PRIVILEGES)) { sc->xorg_no_new_privileges = @@ -705,6 +712,7 @@ config_dump(struct config_sesman *config) g_writeln(" XAuthorityInSystemDir: %d", sc->xauth_in_sysdir); g_writeln(" AlwaysGroupCheck: %d", sc->ts_always_group_check); g_writeln(" AllowAlternateShell: %d", sc->allow_alternate_shell); + g_writeln(" PassShellAsEnv: %s", sc->pass_shell_as_env); #ifdef HAVE_SYS_PRCTL_H g_writeln(" XorgNoNewPrivileges: %d", sc->xorg_no_new_privileges); #endif @@ -773,6 +781,7 @@ config_free(struct config_sesman *cs) list_delete(cs->xorg_params); list_delete(cs->env_names); list_delete(cs->env_values); + g_free(cs->sec.pass_shell_as_env); g_free(cs->sec.ts_users); g_free(cs->sec.ts_admins); g_free(cs->sec.session_sockdir_group); diff --git a/sesman/libsesman/sesman_config.h b/sesman/libsesman/sesman_config.h index 61aa6818..13b96f64 100644 --- a/sesman/libsesman/sesman_config.h +++ b/sesman/libsesman/sesman_config.h @@ -110,6 +110,13 @@ struct config_security */ int allow_alternate_shell; + /** + * @var pass_shell_as_env + * @brief Passes alternate shells in the environment + * @details name of environment variable to receive alternate shell + */ + char *pass_shell_as_env; + /* * @var xorg_no_new_privileges * @brief if the Xorg X11 server should be started with no_new_privs (Linux only) diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index c4249b7a..eb2ad31a 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -257,8 +257,21 @@ start_window_manager(const struct login_info *login_info, } } - if (s->shell[0] != '\0') + if (g_cfg->sec.allow_alternate_shell && + g_cfg->sec.pass_shell_as_env != NULL && + g_cfg->sec.pass_shell_as_env[0] != '0') { + // Pass the shell in to the standard startwm scripts + // in an environment variable + LOG(LOG_LEVEL_INFO, + "Setting variable '%s' to the specified shell of '%s'", + g_cfg->sec.pass_shell_as_env, + s->shell); + g_setenv(g_cfg->sec.pass_shell_as_env, s->shell, 1); + } + else if (s->shell[0] != '\0') + { + // Try to execute the shell directly (if permitted) if (g_cfg->sec.allow_alternate_shell) { if (g_strchr(s->shell, ' ') != 0 || g_strchr(s->shell, '\t') != 0) diff --git a/sesman/sesman.ini.in b/sesman/sesman.ini.in index 6f6c167b..617544f7 100644 --- a/sesman/sesman.ini.in +++ b/sesman/sesman.ini.in @@ -45,6 +45,13 @@ RestrictOutboundClipboard=none RestrictInboundClipboard=none ; Set to 'no' to prevent users from logging in with alternate shells #AllowAlternateShell=true +; Normally, alternate shells (if permitted) are executed directly, as +; specified. +; If this is set, alternate shells are not actioned directly, but +; passed in to the default window manager in the specified environment +; variable. This allows the system manager more control over exactly +; what alternate shells are permitted. +#PassShellAsEnv=XRDP_ALTERNATE_SHELL ; On Linux systems, the Xorg X11 server is normally invoked using ; no_new_privs to avoid problems if the executable is suid. This may, ; however, interfere with the use of security modules such as AppArmor. diff --git a/sesman/startwm.sh b/sesman/startwm.sh index 7c39f24c..dda0ea43 100755 --- a/sesman/startwm.sh +++ b/sesman/startwm.sh @@ -93,6 +93,9 @@ wm_start() # shall be one of "ls -1 /usr/share/xsessions/|cut -d. -f1" # e.g. [ -n "$XRDP_SESSION" ] && export DESKTOP_SESSION=ubuntu + # Alternatively, set "PassShellAsEnv=DESKTOP_SESSION" in sesman.ini, which + # lets the user specify the required session directly. + # STARTUP is the default startup command. # if $1 is empty and STARTUP was not set # /etc/X11/Xsession.d/50x11-common_determine-startup will fallback to