Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xrdp as unprivileged user #2974

Merged
merged 7 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions common/os_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions common/os_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
7 changes: 5 additions & 2 deletions common/thread_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion docs/man/sesman.ini.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions docs/man/xrdp.ini.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions instfiles/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion instfiles/init.d/xrdp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions instfiles/rc.d/xrdp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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"
8 changes: 4 additions & 4 deletions sesman/sesman.ini.in
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
1 change: 1 addition & 0 deletions tools/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

SUBDIRS = \
chkpriv \
devel
31 changes: 31 additions & 0 deletions tools/chkpriv/Makefile.am
Original file line number Diff line number Diff line change
@@ -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

Loading