diff --git a/common/os_calls.c b/common/os_calls.c index 6de4360b..53181f8c 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -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 */ diff --git a/common/os_calls.h b/common/os_calls.h index 9fdbad8b..99e339b3 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -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); diff --git a/xrdp/xrdp.c b/xrdp/xrdp.c index 9646d9e2..33aeb7b7 100644 --- a/xrdp/xrdp.c +++ b/xrdp/xrdp.c @@ -416,6 +416,38 @@ 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; +} + /*****************************************************************************/ int main(int argc, char **argv) @@ -548,7 +580,7 @@ main(int argc, char **argv) g_exit(1); } - if (!read_xrdp_ini_startup_params(&startup_params)) + if (read_xrdp_ini_startup_params(&startup_params) != 0) { log_end(); g_deinit(); @@ -653,7 +685,7 @@ main(int argc, char **argv) LOG(LOG_LEVEL_ALWAYS, "Failed to start xrdp daemon, " "possibly address already in use."); } - else + else if (check_drop_privileges(&startup_params) == 0) { g_set_threadid(tc_get_threadid()); g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */