mirror of https://github.com/neutrinolabs/xrdp
Merge pull request #2974 from matt335672/xrdp_as_unprivileged_user
Xrdp as unprivileged user
This commit is contained in:
commit
fced0002bd
|
@ -3167,6 +3167,48 @@ g_setgid(int pid)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Used by daemonizing code */
|
||||
/* returns error, zero is success, non zero is error */
|
||||
int
|
||||
g_drop_privileges(const char *user, const char *group)
|
||||
{
|
||||
int rv = 1;
|
||||
int uid;
|
||||
int gid;
|
||||
if (g_getuser_info_by_name(user, &uid, NULL, NULL, NULL, NULL) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to get UID for user '%s' [%s]", user,
|
||||
g_get_strerror());
|
||||
}
|
||||
else if (g_getgroup_info(group, &gid) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to get GID for group '%s' [%s]", group,
|
||||
g_get_strerror());
|
||||
}
|
||||
else if (initgroups(user, gid) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to init groups for '%s' [%s]", user,
|
||||
g_get_strerror());
|
||||
}
|
||||
else if (g_setgid(gid) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to set group to '%s' [%s]", group,
|
||||
g_get_strerror());
|
||||
}
|
||||
else if (g_setuid(uid) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to set user to '%s' [%s]", user,
|
||||
g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error, zero is success, non zero is error */
|
||||
/* does not work in win32 */
|
||||
|
@ -3496,6 +3538,12 @@ g_sigterm(int pid)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int g_pid_is_active(int pid)
|
||||
{
|
||||
return (kill(pid, 0) == 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32 */
|
||||
int
|
||||
|
|
|
@ -338,6 +338,7 @@ void g_signal_pipe(void (*func)(int));
|
|||
void g_signal_usr1(void (*func)(int));
|
||||
int g_fork(void);
|
||||
int g_setgid(int pid);
|
||||
int g_drop_privileges(const char *user, const char *group);
|
||||
int g_initgroups(const char *user);
|
||||
int g_getuid(void);
|
||||
int g_getgid(void);
|
||||
|
@ -371,6 +372,12 @@ int g_exit(int exit_code);
|
|||
int g_getpid(void);
|
||||
int g_sigterm(int pid);
|
||||
int g_sighup(int pid);
|
||||
/*
|
||||
* Is a particular PID active?
|
||||
* @param pid PID to check
|
||||
* Returns boolean
|
||||
*/
|
||||
int g_pid_is_active(int pid);
|
||||
int g_getuser_info_by_name(const char *username, int *uid, int *gid,
|
||||
char **shell, char **dir, char **gecos);
|
||||
int g_getuser_info_by_uid(int uid, char **username, int *gid,
|
||||
|
|
|
@ -122,8 +122,11 @@ tc_mutex_delete(tbus mutex)
|
|||
pthread_mutex_t *lmutex;
|
||||
|
||||
lmutex = (pthread_mutex_t *)mutex;
|
||||
pthread_mutex_destroy(lmutex);
|
||||
g_free(lmutex);
|
||||
if (lmutex != NULL)
|
||||
{
|
||||
pthread_mutex_destroy(lmutex);
|
||||
g_free(lmutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -646,6 +646,7 @@ AC_CONFIG_FILES([
|
|||
tools/Makefile
|
||||
tools/devel/Makefile
|
||||
tools/devel/tcp_proxy/Makefile
|
||||
tools/chkpriv/Makefile
|
||||
vnc/Makefile
|
||||
xrdpapi/Makefile
|
||||
xrdp/Makefile
|
||||
|
|
|
@ -315,7 +315,8 @@ 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.
|
||||
MUST be the same as runtime_group in xrdp.ini, or xrdp will not
|
||||
be able to connect to any sessions.
|
||||
|
||||
.SH "X11 SERVER"
|
||||
Following parameters can be used in the \fB[Xvnc]\fR and
|
||||
|
|
|
@ -119,6 +119,29 @@ The default port for RDP is \fB3389\fP.
|
|||
Multiple address:port instances must be separated by spaces or commas. Check the .ini file for examples.
|
||||
Specifying interfaces requires said interfaces to be UP before xrdp starts.
|
||||
|
||||
.TP
|
||||
\fBruntime_user\fP=\fIusername\fP
|
||||
.TP
|
||||
\fBruntime_group\fP=\fIgroupname\fP
|
||||
User name and group to run the xrdp daemon under.
|
||||
|
||||
After xrdp starts, it sets its UID and GID to values derived from these
|
||||
settings, so that it's running without system privilege.
|
||||
|
||||
The \fBruntime_group\fP MUST be set to the same value as
|
||||
\fBSessionSockdirGroup\fP in \fBsesman.ini\fP if you want to run sessions.
|
||||
|
||||
A suitable user and group can be added with a command like this (Linux):-
|
||||
|
||||
useradd xrdp -d / -c 'xrdp daemon' -s /usr/sbin/nologin
|
||||
|
||||
In order to establish secure connections, the xrdp daemon needs permission
|
||||
to access sensitive cryptographic files. After changing either or both
|
||||
of these values, check that xrdp has access to required files by running
|
||||
this script:-
|
||||
|
||||
@xrdpdatadir@/xrdp-chkpriv
|
||||
|
||||
.TP
|
||||
\fBenable_token_login\fP=\fI[true|false]\fP
|
||||
If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP will scan the user name provided by the
|
||||
|
|
|
@ -98,6 +98,9 @@ endif
|
|||
if FREEBSD
|
||||
# must be tab below
|
||||
install-data-hook:
|
||||
sed -i '' 's|%%PREFIX%%|$(prefix)|g' $(DESTDIR)$(sysconfdir)/rc.d/xrdp \
|
||||
$(DESTDIR)$(sysconfdir)/rc.d/xrdp-sesman
|
||||
sed -e 's|%%PREFIX%%|$(prefix)|g' \
|
||||
-e 's|%%LOCALSTATEDIR%%|$(localstatedir)|g' \
|
||||
-i '' \
|
||||
$(DESTDIR)$(sysconfdir)/rc.d/xrdp \
|
||||
$(DESTDIR)$(sysconfdir)/rc.d/xrdp-sesman
|
||||
endif
|
||||
|
|
|
@ -116,7 +116,7 @@ case "$1" in
|
|||
log_progress_msg $NAME
|
||||
if pidofproc -p $PIDDIR/$NAME.pid $DAEMON > /dev/null; then
|
||||
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDDIR/$NAME.pid \
|
||||
--exec $DAEMON
|
||||
--remove-pidfile --exec $DAEMON
|
||||
value=$?
|
||||
[ $value -gt 0 ] && exitval=$value
|
||||
else
|
||||
|
|
|
@ -48,6 +48,7 @@ command="%%PREFIX%%/sbin/xrdp"
|
|||
allstart_cmd="xrdp_allstart"
|
||||
allstop_cmd="xrdp_allstop"
|
||||
allrestart_cmd="xrdp_allrestart"
|
||||
stop_postcmd="xrdp_poststop"
|
||||
|
||||
xrdp_allstart()
|
||||
{
|
||||
|
@ -79,4 +80,10 @@ xrdp_allrestart()
|
|||
run_rc_command "restart"
|
||||
}
|
||||
|
||||
xrdp_poststop()
|
||||
{
|
||||
# If running with dropped privileges, xrdp can't delete its own
|
||||
# PID file
|
||||
rm -f %%LOCALSTATEDIR%%/run/xrdp.pid
|
||||
}
|
||||
run_rc_command "$1"
|
||||
|
|
|
@ -45,10 +45,10 @@ RestrictInboundClipboard=none
|
|||
; 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
|
||||
; local sockets for the session are created.
|
||||
; This MUST be the same as runtime_group in xrdp.ini, or xrdp will not
|
||||
; be able to connect to your sessions.
|
||||
#SessionSockdirGroup=xrdp
|
||||
|
||||
|
||||
[Sessions]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
SUBDIRS = \
|
||||
chkpriv \
|
||||
devel
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
xrdppkgdatadir=$(datadir)/xrdp
|
||||
|
||||
pkglibexec_PROGRAMS = \
|
||||
xrdp-droppriv
|
||||
|
||||
dist_xrdppkgdata_SCRIPTS = \
|
||||
xrdp-chkpriv
|
||||
|
||||
AM_LDFLAGS =
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
xrdp_droppriv_SOURCES = xrdp-droppriv.c
|
||||
|
||||
xrdp_droppriv_LDADD = \
|
||||
$(top_builddir)/common/libcommon.la
|
||||
|
||||
SUBST_VARS = sed \
|
||||
-e 's|@pkglibexecdir[@]|$(pkglibexecdir)|g'
|
||||
|
||||
subst_verbose = $(subst_verbose_@AM_V@)
|
||||
subst_verbose_ = $(subst_verbose_@AM_DEFAULT_V@)
|
||||
subst_verbose_0 = @echo " SUBST $@";
|
||||
|
||||
SUFFIXES = .in
|
||||
.in:
|
||||
$(subst_verbose)$(SUBST_VARS) $< > $@
|
||||
|
||||
CLEANFILES = xrdp-chkpriv
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# xrdp: A Remote Desktop Protocol server.
|
||||
#
|
||||
# Copyright (C) Jay Sorg and contributors 2004-2024
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Program to check permissions for xrdp when running in a non-privileged
|
||||
# mode
|
||||
|
||||
# Change these if they do not match your installation
|
||||
CONF_DIR=/etc/xrdp
|
||||
XRDP_INI="$CONF_DIR"/xrdp.ini
|
||||
SESMAN_INI="$CONF_DIR"/sesman.ini
|
||||
RSAKEYS_INI="$CONF_DIR"/rsakeys.ini
|
||||
DROPPRIV=@pkglibexecdir@/xrdp-droppriv
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# G E T I N I V A L U E
|
||||
#
|
||||
# Gets a value from an ini file.
|
||||
#
|
||||
# Params [ini_file] [key]
|
||||
# -----------------------------------------------------------------------------
|
||||
GetIniValue()
|
||||
{
|
||||
# Look for a line matching 'key=' with optional whitespace
|
||||
# either side of the key. When we find one, strip everything
|
||||
# up to and including the first '=', print it, and quit
|
||||
#
|
||||
# This doesn't take sections into account
|
||||
sed -n -e '/^ *'"$2"' *=/{
|
||||
s/^[^=]*=//p
|
||||
q
|
||||
}' "$1"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# M A I N
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "** Must run this script as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OS=$(uname)
|
||||
case "$OS" in
|
||||
FreeBSD | Linux) ;;
|
||||
*) echo "Unsupported operating system $OS" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
errors=0
|
||||
|
||||
runtime_user=$(GetIniValue "$XRDP_INI" runtime_user)
|
||||
runtime_group=$(GetIniValue "$XRDP_INI" runtime_group)
|
||||
certificate=$(GetIniValue "$XRDP_INI" certificate)
|
||||
key_file=$(GetIniValue "$XRDP_INI" key_file)
|
||||
SessionSockdirGroup=$(GetIniValue "$SESMAN_INI" SessionSockdirGroup)
|
||||
|
||||
case "$certificate" in
|
||||
'') certificate="$CONF_DIR"/cert.pem ;;
|
||||
/*) ;;
|
||||
*) certificate="$CONF_DIR"/"$certificate"
|
||||
esac
|
||||
|
||||
case "$key_file" in
|
||||
'') key_file="$CONF_DIR"/key.pem ;;
|
||||
/*) ;;
|
||||
*) key_file="$CONF_DIR"/"$key_file"
|
||||
esac
|
||||
|
||||
echo "Settings"
|
||||
echo " - [xrdp.ini] runtime_user : $runtime_user"
|
||||
echo " - [xrdp.ini] runtime_group : $runtime_group"
|
||||
echo " - [xrdp.ini] certificate : $certificate"
|
||||
echo " - [xrdp.ini] key_file : $key_file"
|
||||
echo " - [sesman.ini] SessionSockdirGroup : $SessionSockdirGroup"
|
||||
echo
|
||||
|
||||
# Basic checks on runtime user/group
|
||||
if [ -z "$runtime_user" ] && [ -z "$runtime_group" ]; then
|
||||
echo "-Info- This system is not configured to run xrdp without privilege"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$runtime_user" ] || [ -z "$runtime_group" ]; then
|
||||
echo "-Error- Both 'runtime_user' and 'runtime_group' must be set"
|
||||
errors=$(( errors + 1 ))
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if getent passwd "$runtime_user" >/dev/null ; then
|
||||
echo "-Info- runtime_user '$runtime_user' appears to exist"
|
||||
else
|
||||
echo "-Error- runtime_user '$runtime_user' does not exist"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
|
||||
GID=
|
||||
if getent group "$runtime_group" >/dev/null ; then
|
||||
echo "-Info- runtime_group '$runtime_group' appears to exist"
|
||||
GID=$(getent group xrdp | cut -d: -f3)
|
||||
else
|
||||
echo "-Error- runtime_group '$runtime_group' does not exist"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
|
||||
# Groups agree between sesman and xrdp?
|
||||
if [ "$runtime_user" = "$SessionSockdirGroup" ]; then
|
||||
echo "-Info- xrdp.ini and sesman.ini agree on group ownership"
|
||||
else
|
||||
echo "-Error- xrdp.ini and sesman.ini do not agree on group ownership"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
|
||||
# Check we can access rsakeys.ini
|
||||
#
|
||||
# This is our file, so we can be completely prescriptive about
|
||||
# the permissions
|
||||
if [ -e $RSAKEYS_INI ]; then
|
||||
# Only check if we have a GID
|
||||
if [ -n "$GID" ]; then
|
||||
# Get the permissions, UID and GID in $1..$3
|
||||
case "$OS" in
|
||||
FreeBSD)
|
||||
# shellcheck disable=SC2046
|
||||
set -- $(stat -f "%Lp %u %g" $RSAKEYS_INI)
|
||||
;;
|
||||
*)
|
||||
# shellcheck disable=SC2046
|
||||
set -- $(stat -c "%a %u %g" $RSAKEYS_INI)
|
||||
esac
|
||||
if [ "$1/$2/$3" = "640/0/$GID" ]; then
|
||||
echo "-Info- $RSAKEYS_INI has correct permissions"
|
||||
else
|
||||
if [ "$1" != 640 ]; then
|
||||
echo "-Error- $RSAKEYS_INI should have permissions -rw-r-----"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
if [ "$2" != 0 ]; then
|
||||
echo "-Error- $RSAKEYS_INI should be owned by root"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
if [ "$3" != "$GID" ]; then
|
||||
echo "-Error- $RSAKEYS_INI should be in the $runtime_group group"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "-Error- $RSAKEYS_INI does not exist"
|
||||
errors=$(( errors + 1 ))
|
||||
fi
|
||||
|
||||
# Are cert and key readable (but NOT writeable) by the user?
|
||||
#
|
||||
# These aren't necessarily our files, so we can't be too prescriptive about
|
||||
# privileges. On Debian for example, we might be using the 'ssl-cert'
|
||||
# group to obtain access to /etc/ssl/private/ssl-cert-snakeoil.key
|
||||
for file in "$certificate" "$key_file"; do
|
||||
if ! [ -e $file ]; then
|
||||
echo "-Error- $file does not exist"
|
||||
errors=$(( errors + 1 ))
|
||||
elif ! $DROPPRIV "$runtime_user" "$runtime_group" sh -c '[ -r '"$file"' ]'
|
||||
then
|
||||
echo "-Error- $file is not readable by $runtime_user:$runtime_group"
|
||||
errors=$(( errors + 1 ))
|
||||
elif $DROPPRIV "$runtime_user" "$runtime_group" sh -c '[ -w '"$file"' ]'
|
||||
then
|
||||
echo "-Error- $file is writeable by $runtime_user:$runtime_group"
|
||||
errors=$(( errors + 1 ))
|
||||
else
|
||||
echo "-Info- $file is read-only for $runtime_user:$runtime_group"
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
if [ $errors -eq 0 ]; then
|
||||
echo "-Summary- Permissions appear to be correct to run xrdp unprivileged"
|
||||
status=0
|
||||
else
|
||||
echo "-Summary- $errors error(s) found. Please correct these and try again"
|
||||
status=1
|
||||
fi
|
||||
|
||||
exit $status
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
*
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg and contributors 2004-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Shell around the g_drop_privileges() call
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "os_calls.c"
|
||||
#include "log.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct log_config *logging;
|
||||
int status = 1;
|
||||
logging = log_config_init_for_console(LOG_LEVEL_WARNING,
|
||||
g_getenv("DROPPRIV_LOG_LEVEL"));
|
||||
log_start_from_param(logging);
|
||||
log_config_free(logging);
|
||||
|
||||
if (argc < 4)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Usage : %s [user] [group] [cmd...]\n", argv[0]);
|
||||
}
|
||||
else if (g_drop_privileges(argv[1], argv[2]) == 0)
|
||||
{
|
||||
status = g_execvp(argv[3], &argv[3]);
|
||||
}
|
||||
|
||||
log_end();
|
||||
return status;
|
||||
}
|
408
xrdp/xrdp.c
408
xrdp/xrdp.c
|
@ -240,6 +240,127 @@ xrdp_process_params(int argc, char **argv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
*
|
||||
* @brief Read additional startup parameters from xrdp.ini
|
||||
*
|
||||
* @param [in,out] startup parameters from the command line
|
||||
* @return 0 on success
|
||||
*
|
||||
*/
|
||||
static int
|
||||
read_xrdp_ini_startup_params(struct xrdp_startup_params *startup_params)
|
||||
{
|
||||
int rv = 0;
|
||||
int fd;
|
||||
int index;
|
||||
int port_override;
|
||||
int fork_override;
|
||||
const char *name;
|
||||
const char *val;
|
||||
struct list *names;
|
||||
struct list *values;
|
||||
|
||||
port_override = startup_params->port[0] != 0;
|
||||
fork_override = startup_params->fork;
|
||||
names = list_create();
|
||||
names->auto_free = 1;
|
||||
values = list_create();
|
||||
values->auto_free = 1;
|
||||
|
||||
fd = g_file_open_ro(startup_params->xrdp_ini);
|
||||
if (fd < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't open %s [%s]", startup_params->xrdp_ini,
|
||||
g_get_strerror());
|
||||
rv = 1;
|
||||
}
|
||||
else if (file_read_section(fd, "globals", names, values) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't read [Globals] from %s",
|
||||
startup_params->xrdp_ini);
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (index = 0; index < names->count; index++)
|
||||
{
|
||||
name = (const char *)list_get_item(names, index);
|
||||
val = (const char *)list_get_item(values, index);
|
||||
if (name == 0 || val == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_strcasecmp(name, "port") == 0)
|
||||
{
|
||||
if (port_override == 0)
|
||||
{
|
||||
g_strncpy(startup_params->port, val,
|
||||
sizeof(startup_params->port) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "fork") == 0)
|
||||
{
|
||||
if (fork_override == 0)
|
||||
{
|
||||
startup_params->fork = g_text2bool(val);
|
||||
}
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "tcp_nodelay") == 0)
|
||||
{
|
||||
startup_params->tcp_nodelay = g_text2bool(val);
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "tcp_keepalive") == 0)
|
||||
{
|
||||
startup_params->tcp_keepalive = g_text2bool(val);
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "tcp_send_buffer_bytes") == 0)
|
||||
{
|
||||
startup_params->tcp_send_buffer_bytes = g_atoi(val);
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "tcp_recv_buffer_bytes") == 0)
|
||||
{
|
||||
startup_params->tcp_recv_buffer_bytes = g_atoi(val);
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "use_vsock") == 0)
|
||||
{
|
||||
startup_params->use_vsock = g_text2bool(val);
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "runtime_user") == 0)
|
||||
{
|
||||
g_snprintf(startup_params->runtime_user,
|
||||
sizeof(startup_params->runtime_user),
|
||||
"%s", val);
|
||||
}
|
||||
|
||||
else if (g_strcasecmp(name, "runtime_group") == 0)
|
||||
{
|
||||
g_snprintf(startup_params->runtime_group,
|
||||
sizeof(startup_params->runtime_group),
|
||||
"%s", val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_delete(names);
|
||||
list_delete(values);
|
||||
if (fd >= 0)
|
||||
{
|
||||
g_file_close(fd);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Basic sanity checks before any forking */
|
||||
static int
|
||||
|
@ -295,15 +416,123 @@ xrdp_sanity_check(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
check_drop_privileges(struct xrdp_startup_params *startup_params)
|
||||
{
|
||||
int rv = 1;
|
||||
const char *user = startup_params->runtime_user;
|
||||
const char *group = startup_params->runtime_group;
|
||||
|
||||
if (user[0] == '\0' && group[0] == '\0')
|
||||
{
|
||||
// Allow this for now
|
||||
LOG(LOG_LEVEL_ALWAYS,
|
||||
"You are running xrdp as root. This is not safe.");
|
||||
rv = 0;
|
||||
}
|
||||
else if (user[0] == '\0' || group[0] == '\0')
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Both a runtime_user and a runtime_group MUST be specified");
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = g_drop_privileges(user, group);
|
||||
if (rv == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Switched user:group to %s:%s", user, group);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
read_pid_file(const char *pid_file)
|
||||
{
|
||||
int pid = -1;
|
||||
int fd = g_file_open_ro(pid_file); /* xrdp.pid */
|
||||
if (fd >= 0)
|
||||
{
|
||||
char text[32];
|
||||
g_memset(text, 0, sizeof(text));
|
||||
g_file_read(fd, text, sizeof(text) - 1);
|
||||
pid = g_atoi(text);
|
||||
g_file_close(fd);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Kills an active xrdp daemon
|
||||
*
|
||||
* It is assumed that logging is not active
|
||||
*
|
||||
* @param pid_file PID file
|
||||
* @return 0 for success
|
||||
*/
|
||||
static int
|
||||
kill_daemon(const char *pid_file)
|
||||
{
|
||||
int status = 1;
|
||||
int pid;
|
||||
if (g_getuid() != 0)
|
||||
{
|
||||
g_writeln("Must be root");
|
||||
}
|
||||
else if ((pid = read_pid_file(pid_file)) > 0)
|
||||
{
|
||||
if (!g_pid_is_active(pid))
|
||||
{
|
||||
g_writeln("Daemon not active");
|
||||
status = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_writeln("stopping process id %d", pid);
|
||||
int i;
|
||||
g_sigterm(pid);
|
||||
g_sleep(100);
|
||||
i = 5 * 1000 / 500;
|
||||
while (i > 0 && g_pid_is_active(pid))
|
||||
{
|
||||
g_sleep(500);
|
||||
--i;
|
||||
}
|
||||
|
||||
if (g_pid_is_active(pid))
|
||||
{
|
||||
g_writeln("Can't stop process");
|
||||
}
|
||||
else
|
||||
{
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
/* delete the xrdp.pid file, as xrdp can't do this
|
||||
* if it's running without privilege */
|
||||
g_file_delete(pid_file);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int exit_status = 0;
|
||||
int exit_status = 1;
|
||||
enum logReturns error;
|
||||
struct xrdp_startup_params startup_params = {0};
|
||||
int pid;
|
||||
int fd;
|
||||
int daemon;
|
||||
char text[256];
|
||||
const char *pid_file = XRDP_PID_PATH "/xrdp.pid";
|
||||
|
@ -368,36 +597,9 @@ main(int argc, char **argv)
|
|||
|
||||
if (startup_params.kill)
|
||||
{
|
||||
g_writeln("stopping xrdp");
|
||||
/* read the xrdp.pid file */
|
||||
fd = -1;
|
||||
|
||||
if (g_file_exist(pid_file)) /* xrdp.pid */
|
||||
{
|
||||
fd = g_file_open_ro(pid_file); /* xrdp.pid */
|
||||
}
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
g_writeln("cannot open %s, maybe xrdp is not running", pid_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memset(text, 0, 32);
|
||||
g_file_read(fd, text, 31);
|
||||
pid = g_atoi(text);
|
||||
g_writeln("stopping process id %d", pid);
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
g_sigterm(pid);
|
||||
}
|
||||
|
||||
g_file_close(fd);
|
||||
}
|
||||
|
||||
int status = kill_daemon(pid_file);
|
||||
g_deinit();
|
||||
g_exit(0);
|
||||
g_exit(status);
|
||||
}
|
||||
|
||||
/* starting logging subsystem */
|
||||
|
@ -428,11 +630,17 @@ main(int argc, char **argv)
|
|||
g_exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (g_file_exist(pid_file)) /* xrdp.pid */
|
||||
if (read_xrdp_ini_startup_params(&startup_params) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS, "It looks like xrdp is already running.");
|
||||
log_end();
|
||||
g_deinit();
|
||||
g_exit(1);
|
||||
}
|
||||
|
||||
if ((pid = read_pid_file(pid_file)) > 0 && g_pid_is_active(pid))
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS,
|
||||
"It looks like xrdp (pid=%d) is already running.", pid);
|
||||
LOG(LOG_LEVEL_ALWAYS, "If not, delete %s and try again.", pid_file);
|
||||
log_end();
|
||||
g_deinit();
|
||||
|
@ -444,14 +652,13 @@ main(int argc, char **argv)
|
|||
|
||||
if (daemon)
|
||||
{
|
||||
|
||||
/* make sure containing directory exists */
|
||||
g_create_path(pid_file);
|
||||
|
||||
/* make sure we can write to pid file */
|
||||
fd = g_file_open_rw(pid_file); /* xrdp.pid */
|
||||
int pid_fd = g_file_open_rw(pid_file); /* xrdp.pid */
|
||||
|
||||
if (fd == -1)
|
||||
if (pid_fd == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS,
|
||||
"running in daemon mode with no access to pid files, quitting");
|
||||
|
@ -460,23 +667,14 @@ main(int argc, char **argv)
|
|||
g_exit(1);
|
||||
}
|
||||
|
||||
if (g_file_write(fd, "0", 1) == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS,
|
||||
"running in daemon mode with no access to pid files, quitting");
|
||||
log_end();
|
||||
g_deinit();
|
||||
g_exit(1);
|
||||
}
|
||||
/* Before daemonising, check we can listen.
|
||||
* If we can't listen, exit with failure status */
|
||||
struct xrdp_listen *xrdp_listen;
|
||||
xrdp_listen = xrdp_listen_create(&startup_params);
|
||||
int status = xrdp_listen_init(xrdp_listen);
|
||||
xrdp_listen_delete(xrdp_listen);
|
||||
|
||||
g_file_close(fd);
|
||||
g_file_delete(pid_file);
|
||||
}
|
||||
|
||||
if (daemon)
|
||||
{
|
||||
/* if can't listen, exit with failure status */
|
||||
if (xrdp_listen_test(&startup_params) != 0)
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS, "Failed to start xrdp daemon, "
|
||||
"possibly address already in use.");
|
||||
|
@ -486,6 +684,7 @@ main(int argc, char **argv)
|
|||
or systemd cannot detect xrdp daemon couldn't start properly */
|
||||
g_exit(1);
|
||||
}
|
||||
|
||||
/* start of daemonizing code */
|
||||
pid = g_fork();
|
||||
|
||||
|
@ -506,21 +705,10 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
g_sleep(1000);
|
||||
/* write the pid to file */
|
||||
pid = g_getpid();
|
||||
fd = g_file_open_rw(pid_file); /* xrdp.pid */
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Can't open %s for writing [%s]",
|
||||
pid_file, g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
g_sprintf(text, "%d", pid);
|
||||
g_file_write(fd, text, g_strlen(text));
|
||||
g_file_close(fd);
|
||||
}
|
||||
/* write our pid to file */
|
||||
g_sprintf(text, "%d", g_getpid());
|
||||
g_file_write(pid_fd, text, g_strlen(text));
|
||||
g_file_close(pid_fd);
|
||||
|
||||
g_sleep(1000);
|
||||
g_file_close(0);
|
||||
|
@ -542,43 +730,51 @@ main(int argc, char **argv)
|
|||
/* end of daemonizing code */
|
||||
}
|
||||
|
||||
g_set_threadid(tc_get_threadid());
|
||||
g_listen = xrdp_listen_create();
|
||||
g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */
|
||||
g_signal_pipe(xrdp_sig_no_op); /* SIGPIPE */
|
||||
g_signal_terminate(xrdp_shutdown); /* SIGTERM */
|
||||
g_signal_child_stop(xrdp_child); /* SIGCHLD */
|
||||
g_signal_hang_up(xrdp_sig_no_op); /* SIGHUP */
|
||||
g_set_sync_mutex(tc_mutex_create());
|
||||
g_set_sync1_mutex(tc_mutex_create());
|
||||
pid = g_getpid();
|
||||
LOG(LOG_LEVEL_INFO, "starting xrdp with pid %d", pid);
|
||||
g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid);
|
||||
g_set_term_event(g_create_wait_obj(text));
|
||||
|
||||
if (g_get_term() == 0)
|
||||
g_listen = xrdp_listen_create(&startup_params);
|
||||
if (xrdp_listen_init(g_listen) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error creating g_term_event");
|
||||
LOG(LOG_LEVEL_ALWAYS, "Failed to start xrdp daemon, "
|
||||
"possibly address already in use.");
|
||||
}
|
||||
else if (check_drop_privileges(&startup_params) == 0)
|
||||
{
|
||||
g_set_threadid(tc_get_threadid());
|
||||
g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */
|
||||
g_signal_pipe(xrdp_sig_no_op); /* SIGPIPE */
|
||||
g_signal_terminate(xrdp_shutdown); /* SIGTERM */
|
||||
g_signal_child_stop(xrdp_child); /* SIGCHLD */
|
||||
g_signal_hang_up(xrdp_sig_no_op); /* SIGHUP */
|
||||
g_set_sync_mutex(tc_mutex_create());
|
||||
g_set_sync1_mutex(tc_mutex_create());
|
||||
pid = g_getpid();
|
||||
LOG(LOG_LEVEL_INFO, "starting xrdp with pid %d", pid);
|
||||
g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid);
|
||||
g_set_term_event(g_create_wait_obj(text));
|
||||
|
||||
if (g_get_term() == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error creating g_term_event");
|
||||
}
|
||||
|
||||
g_snprintf(text, 255, "xrdp_%8.8x_main_sigchld", pid);
|
||||
g_set_sigchld_event(g_create_wait_obj(text));
|
||||
|
||||
if (g_get_sigchld() == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error creating g_sigchld_event");
|
||||
}
|
||||
|
||||
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
|
||||
g_set_sync_event(g_create_wait_obj(text));
|
||||
|
||||
if (g_get_sync_event() == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error creating g_sync_event");
|
||||
}
|
||||
|
||||
exit_status = xrdp_listen_main_loop(g_listen);
|
||||
}
|
||||
|
||||
g_snprintf(text, 255, "xrdp_%8.8x_main_sigchld", pid);
|
||||
g_set_sigchld_event(g_create_wait_obj(text));
|
||||
|
||||
if (g_get_sigchld() == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error creating g_sigchld_event");
|
||||
}
|
||||
|
||||
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
|
||||
g_set_sync_event(g_create_wait_obj(text));
|
||||
|
||||
if (g_get_sync_event() == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error creating g_sync_event");
|
||||
}
|
||||
|
||||
g_listen->startup_params = &startup_params;
|
||||
exit_status = xrdp_listen_main_loop(g_listen);
|
||||
xrdp_listen_delete(g_listen);
|
||||
|
||||
tc_mutex_delete(g_get_sync_mutex());
|
||||
|
@ -596,10 +792,10 @@ main(int argc, char **argv)
|
|||
g_delete_wait_obj(g_get_sync_event());
|
||||
g_set_sync_event(0);
|
||||
|
||||
/* only main process should delete pid file */
|
||||
if (daemon && (pid == g_getpid()))
|
||||
if (daemon)
|
||||
{
|
||||
/* delete the xrdp.pid file */
|
||||
/* Try to delete the PID file, although if we've dropped
|
||||
* privileges this won't be successful */
|
||||
g_file_delete(pid_file);
|
||||
}
|
||||
|
||||
|
|
|
@ -194,13 +194,14 @@ xrdp_process_main_loop(struct xrdp_process *self);
|
|||
|
||||
/* xrdp_listen.c */
|
||||
struct xrdp_listen *
|
||||
xrdp_listen_create(void);
|
||||
xrdp_listen_create(struct xrdp_startup_params *startup_params);
|
||||
int
|
||||
xrdp_listen_init(struct xrdp_listen *self);
|
||||
void
|
||||
xrdp_listen_delete(struct xrdp_listen *self);
|
||||
int
|
||||
xrdp_listen_main_loop(struct xrdp_listen *self);
|
||||
int
|
||||
xrdp_listen_test(struct xrdp_startup_params *startup_params);
|
||||
|
||||
|
||||
/* xrdp_region.c */
|
||||
struct xrdp_region *
|
||||
|
|
|
@ -27,6 +27,12 @@ port=3389
|
|||
; prefer use vsock://<cid>:<port> above
|
||||
use_vsock=false
|
||||
|
||||
; Unprivileged User name and group to run the xrdp daemon.
|
||||
; It is HIGHLY RECOMMENDED you set these values. See the xrdp.ini(5)
|
||||
; manpage for more information on setting and checking these.
|
||||
#runtime_user=xrdp
|
||||
#runtime_group=xrdp
|
||||
|
||||
; regulate if the listening socket use socket option tcp_nodelay
|
||||
; no buffering will be performed in the TCP stack
|
||||
tcp_nodelay=true
|
||||
|
|
|
@ -55,7 +55,7 @@ xrdp_listen_create_pro_done(struct xrdp_listen *self)
|
|||
|
||||
/*****************************************************************************/
|
||||
struct xrdp_listen *
|
||||
xrdp_listen_create(void)
|
||||
xrdp_listen_create(struct xrdp_startup_params *startup_params)
|
||||
{
|
||||
struct xrdp_listen *self;
|
||||
|
||||
|
@ -64,6 +64,7 @@ xrdp_listen_create(void)
|
|||
self->trans_list = list_create();
|
||||
self->process_list = list_create();
|
||||
self->fork_list = list_create();
|
||||
self->startup_params = startup_params;
|
||||
|
||||
if (g_process_sem == 0)
|
||||
{
|
||||
|
@ -153,95 +154,6 @@ xrdp_process_run(void *in_val)
|
|||
LOG_DEVEL(LOG_LEVEL_TRACE, "process done");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_listen_get_startup_params(struct xrdp_listen *self)
|
||||
{
|
||||
int fd;
|
||||
int index;
|
||||
int port_override;
|
||||
int fork_override;
|
||||
char *val;
|
||||
struct list *names;
|
||||
struct list *values;
|
||||
struct xrdp_startup_params *startup_params;
|
||||
|
||||
startup_params = self->startup_params;
|
||||
port_override = startup_params->port[0] != 0;
|
||||
fork_override = startup_params->fork;
|
||||
fd = g_file_open_ro(startup_params->xrdp_ini);
|
||||
if (fd != -1)
|
||||
{
|
||||
names = list_create();
|
||||
names->auto_free = 1;
|
||||
values = list_create();
|
||||
values->auto_free = 1;
|
||||
if (file_read_section(fd, "globals", names, values) == 0)
|
||||
{
|
||||
for (index = 0; index < names->count; index++)
|
||||
{
|
||||
val = (char *)list_get_item(names, index);
|
||||
if (val != 0)
|
||||
{
|
||||
if (g_strcasecmp(val, "port") == 0)
|
||||
{
|
||||
if (port_override == 0)
|
||||
{
|
||||
val = (char *) list_get_item(values, index);
|
||||
g_strncpy(startup_params->port, val,
|
||||
sizeof(startup_params->port) - 1);
|
||||
}
|
||||
}
|
||||
if (g_strcasecmp(val, "fork") == 0)
|
||||
{
|
||||
if (fork_override == 0)
|
||||
{
|
||||
val = (char *) list_get_item(values, index);
|
||||
startup_params->fork = g_text2bool(val);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_strcasecmp(val, "tcp_nodelay") == 0)
|
||||
{
|
||||
val = (char *)list_get_item(values, index);
|
||||
startup_params->tcp_nodelay = g_text2bool(val);
|
||||
}
|
||||
|
||||
if (g_strcasecmp(val, "tcp_keepalive") == 0)
|
||||
{
|
||||
val = (char *)list_get_item(values, index);
|
||||
startup_params->tcp_keepalive = g_text2bool(val);
|
||||
}
|
||||
|
||||
if (g_strcasecmp(val, "tcp_send_buffer_bytes") == 0)
|
||||
{
|
||||
val = (char *)list_get_item(values, index);
|
||||
startup_params->tcp_send_buffer_bytes = g_atoi(val);
|
||||
}
|
||||
|
||||
if (g_strcasecmp(val, "tcp_recv_buffer_bytes") == 0)
|
||||
{
|
||||
val = (char *)list_get_item(values, index);
|
||||
startup_params->tcp_recv_buffer_bytes = g_atoi(val);
|
||||
}
|
||||
|
||||
if (g_strcasecmp(val, "use_vsock") == 0)
|
||||
{
|
||||
val = (char *)list_get_item(values, index);
|
||||
startup_params->use_vsock = g_text2bool(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_delete(names);
|
||||
list_delete(values);
|
||||
g_file_close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_listen_stop_all_listen(struct xrdp_listen *self)
|
||||
|
@ -651,8 +563,10 @@ xrdp_listen_pp(struct xrdp_listen *self, int *index,
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_listen_process_startup_params(struct xrdp_listen *self)
|
||||
/* returns 0 if xrdp is listening correctly
|
||||
returns 1 if xrdp is not listening correctly */
|
||||
int
|
||||
xrdp_listen_init(struct xrdp_listen *self)
|
||||
{
|
||||
int mode; /* TRANS_MODE_TCP*, TRANS_MODE_UNIX, TRANS_MODE_VSOCK */
|
||||
int error;
|
||||
|
@ -886,18 +800,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
|
|||
struct trans *ltrans;
|
||||
|
||||
self->status = 1;
|
||||
if (xrdp_listen_get_startup_params(self) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_listen_main_loop: xrdp_listen_get_port failed");
|
||||
self->status = -1;
|
||||
return 1;
|
||||
}
|
||||
if (xrdp_listen_process_startup_params(self) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_listen_main_loop: xrdp_listen_get_port failed");
|
||||
self->status = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
term_obj = g_get_term(); /*Global termination event */
|
||||
sigchld_obj = g_get_sigchld();
|
||||
sync_obj = g_get_sync_event();
|
||||
|
@ -1037,27 +940,3 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
|
|||
self->status = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns 0 if xrdp can listen
|
||||
returns 1 if xrdp cannot listen */
|
||||
int
|
||||
xrdp_listen_test(struct xrdp_startup_params *startup_params)
|
||||
{
|
||||
struct xrdp_listen *xrdp_listen;
|
||||
|
||||
xrdp_listen = xrdp_listen_create();
|
||||
xrdp_listen->startup_params = startup_params;
|
||||
if (xrdp_listen_get_startup_params(xrdp_listen) != 0)
|
||||
{
|
||||
xrdp_listen_delete(xrdp_listen);
|
||||
return 1;
|
||||
}
|
||||
if (xrdp_listen_process_startup_params(xrdp_listen) != 0)
|
||||
{
|
||||
xrdp_listen_delete(xrdp_listen);
|
||||
return 1;
|
||||
}
|
||||
xrdp_listen_delete(xrdp_listen);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -750,6 +750,10 @@ struct xrdp_startup_params
|
|||
int tcp_nodelay;
|
||||
int tcp_keepalive;
|
||||
int use_vsock;
|
||||
// These should be local users/groups, and so we shouldn't need
|
||||
// a lot of storage for them.
|
||||
char runtime_user[64];
|
||||
char runtime_group[64];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue