Skip to content

Commit

Permalink
Give privilege to users in TerminalServerAdmins
Browse files Browse the repository at this point in the history
Revives the currently unused TerminalServerAdmins group.

Users in this group will eventually have special privileges for session
management. Currently, members of this group will be allowed to
list all sessions with the xrdp-sesadmin command.
  • Loading branch information
matt335672 committed Dec 20, 2024
1 parent 441f427 commit 4fe6827
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 115 deletions.
16 changes: 12 additions & 4 deletions docs/man/sesman.ini.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,9 @@ login for all users is enabled.

.TP
\fBTerminalServerAdmins\fR=\fIgroup\fR
\fIThis option is currently ignored!\fR Only members of this group can
have session management rights.
Members of this group have session management rights, and can view
session information for other users. The root user is always considered
to be in this group.

.TP
\fBRestrictOutboundClipboard\fR=\fI[all|none|text|file|image]\fR
Expand Down Expand Up @@ -322,8 +323,15 @@ To keep compatibility, the following aliases are also available.

.TP
\fBAlwaysGroupCheck\fR=\fI[true|false]\fR
If set to \fB1\fR, \fBtrue\fR or \fByes\fR, require group membership even
if the group specified in \fBTerminalServerUsers\fR doesn't exist.
If set to \fB1\fR, \fBtrue\fR or \fByes\fR:-
.RS
.HP 3
- For normal logins, require group membership even if the group specified
in \fBTerminalServerUsers\fR doesn't exist.
.HP 3
- For admin logins, log an error if the group specified in
\fBTerminalServerAdmins\fR doesn't exist.
.RE

.TP
\fBAllowAlternateShell\fR=\fI[true|false]\fR
Expand Down
3 changes: 2 additions & 1 deletion docs/man/xrdp-sesadmin.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ Valid commands are:
.RS 4
.TP
.B list
List active sessions for the current user.
List active sessions for the current user. Members of the
\fBTerminalServerAdmins\fR group can view active sessions for all users.
.TP
.BI kill: sid
Kills the session specified the given \fIsession id\fP.
Expand Down
4 changes: 4 additions & 0 deletions sesman/eicp_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "pre_session_list.h"
#include "scp.h"
#include "sesman.h"
#include "sesman_access.h"
#include "sesman_config.h"

/******************************************************************************/

Expand Down Expand Up @@ -79,6 +81,8 @@ process_sys_login_response(struct pre_session_item *psi)
psi->client_trans->callback_data = (void *)psi;
psi->login_state = E_PS_LOGIN_SYS;
psi->uid = uid;
psi->is_admin = access_login_mng_allowed(&g_cfg->sec,
psi->username);
}
}
}
Expand Down
191 changes: 89 additions & 102 deletions sesman/libsesman/sesman_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,147 +39,134 @@

/******************************************************************************/
/**
* Root user login check
* user is root
*
* @param cfg_sec Sesman security config
* @param user user name
* @return 0 if user is root and root accesses are not allowed
* @param username
* @return 1 if user is UID 0
*/
static int
root_login_check(const struct config_security *cfg_sec,
const char *user)
user_is_root(const char *user)
{
int rv = 0;
if (cfg_sec->allow_root)
int uid = -1;
(void)g_getuser_info_by_name(user, &uid, NULL, NULL, NULL, NULL);
return (uid == 0);
}

/******************************************************************************/
int
access_login_allowed(const struct config_security *cfg_sec, const char *user)
{
int ok = 0;

if (!cfg_sec->allow_root && user_is_root(user))
{
rv = 1;
LOG(LOG_LEVEL_ERROR,
"ROOT login attempted, but root login is disabled");
}
else
{
// Check the UID of the user isn't 0
int uid;
if (g_getuser_info_by_name(user, &uid, NULL, NULL, NULL, NULL) != 0)
const char *group = cfg_sec->ts_users;
const char *param = "TerminalServerUsers";
int gid = -1;

if (group == NULL || group[0] == '\0')
{
/* Group is not defined. Default access depends on whether
* we must have the group or not */
if (cfg_sec->ts_always_group_check)
{
LOG(LOG_LEVEL_ERROR,
"%s group is not defined. Access denied for %s",
param, user);
}
else
{
LOG(LOG_LEVEL_INFO,
"%s group is not defined. Access granted for %s",
param, user);
ok = 1;
}
}
else if (g_getgroup_info(group, &gid) != 0)
{
LOG(LOG_LEVEL_ERROR, "Can't get UID for user %s", user);
/* Group is defined but doesn't exist. Default access depends
* on whether we must have the group or not */
if (cfg_sec->ts_always_group_check)
{
LOG(LOG_LEVEL_ERROR,
"%s group %s doesn't exist. Access denied for %s",
param, group, user);
}
else
{
LOG(LOG_LEVEL_INFO,
"%s group %s doesn't exist. Access granted for %s",
param, group, user);
ok = 1;
}
}
else if (0 == uid)
else if (0 != g_check_user_in_group(user, gid, &ok))
{
LOG(LOG_LEVEL_ERROR,
"ROOT login attempted, but root login is disabled");
LOG(LOG_LEVEL_ERROR, "Error checking %s group %s. "
"Access denied for %s", param, group, user);
}
else if (!ok)
{
LOG(LOG_LEVEL_ERROR, "User %s is not in %s group %s. Access denied",
user, param, group);
}
else
{
rv = 1;
LOG(LOG_LEVEL_INFO, "User %s is in %s group %s. Access granted",
user, param, group);
}
}
return rv;

return ok;
}

/******************************************************************************/
/**
* Common access control for group checks
* @param group Group name
* @param param Where group comes from (e.g. "TerminalServerUsers")
* @param always_check_group 0 if a missing group allows a login
* @param user Username
* @return != 0 if the access is allowed */

static int
access_login_allowed_common(const char *group, const char *param,
int always_check_group,
const char *user)
int
access_login_mng_allowed(const struct config_security *cfg_sec,
const char *user)
{
int rv = 0;
int gid;
int ok;
int ok = 0;

const char *group = cfg_sec->ts_admins;
const char *param = "TerminalServerAdmins";
int gid = -1;

if (group == NULL || group[0] == '\0')
{
/* Group is not defined. Default access depends on whether
* we must have the group or not */
if (always_check_group)
{
LOG(LOG_LEVEL_ERROR,
"%s group is not defined. Access denied for %s",
param, user);
}
else
if (cfg_sec->ts_always_group_check)
{
LOG(LOG_LEVEL_INFO,
"%s group is not defined. Access granted for %s",
param, user);
rv = 1;
LOG(LOG_LEVEL_ERROR, "%s group is not defined", param);
}
}
else if (g_getgroup_info(group, &gid) != 0)
{
/* Group is defined but doesn't exist. Default access depends
* on whether we must have the group or not */
if (always_check_group)
/* Group is defined but doesn't exist */
if (cfg_sec->ts_always_group_check)
{
LOG(LOG_LEVEL_ERROR,
"%s group %s doesn't exist. Access denied for %s",
param, group, user);
}
else
{
LOG(LOG_LEVEL_INFO,
"%s group %s doesn't exist. Access granted for %s",
param, group, user);
rv = 1;
LOG(LOG_LEVEL_ERROR, "%s group %s doesn't exist.", param, group);
}
}
else if (0 != g_check_user_in_group(user, gid, &ok))
{
LOG(LOG_LEVEL_ERROR, "Error checking %s group %s. "
"Access denied for %s", param, group, user);
}
else if (!ok)
{
LOG(LOG_LEVEL_ERROR, "User %s is not in %s group %s. Access denied",
user, param, group);
}
else
{
LOG(LOG_LEVEL_INFO, "User %s is in %s group %s. Access granted",
user, param, group);
rv = 1;
LOG(LOG_LEVEL_ERROR, "Error checking %s group %s.", param, group);
}

return rv;
}

/******************************************************************************/
int
access_login_allowed(const struct config_security *cfg_sec, const char *user)
{
int rv = 0;

if (root_login_check(cfg_sec, user))
// Root always has access. Do other checks and logging first
if (!ok && user_is_root(user))
{
rv = access_login_allowed_common(cfg_sec->ts_users,
"TerminalServerUsers",
cfg_sec->ts_always_group_check,
user);
ok = 1;
}

return rv;
}

/******************************************************************************/
int
access_login_mng_allowed(const struct config_security *cfg_sec,
const char *user)
{
int rv = 0;

if (root_login_check(cfg_sec, user))
if (ok)
{
rv = access_login_allowed_common(cfg_sec->ts_admins,
"TerminalServerAdmins",
1,
user);
LOG(LOG_LEVEL_INFO, "User %s is in %s group %s. Admin access granted",
user, param, group);
}

return rv;
return ok;
}
1 change: 1 addition & 0 deletions sesman/pre_session_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct pre_session_item
uid_t uid; ///< User
char *username; ///< Username from UID (at time of logon)
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
int is_admin;
};


Expand Down
11 changes: 10 additions & 1 deletion sesman/scp_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ authenticate_and_authorize_uds_connection(struct pre_session_item *psi,
psi->login_state = E_PS_LOGIN_UDS;
psi->uid = uid;
psi->start_ip_addr[0] = '\0';
psi->is_admin = access_login_mng_allowed(&g_cfg->sec,
psi->username);
}
}

Expand Down Expand Up @@ -555,7 +557,14 @@ process_list_sessions_request(struct pre_session_item *psi)
"Received request from %s to list sessions for user %s",
psi->peername, psi->username);

info = session_list_get_byuid(psi->uid, &cnt, 0);
if (psi->is_admin)
{
info = session_list_get_byuid(NULL, &cnt, 0);
}
else
{
info = session_list_get_byuid(&psi->uid, &cnt, 0);
}

for (i = 0; rv == 0 && i < cnt; ++i)
{
Expand Down
3 changes: 2 additions & 1 deletion sesman/sesman.ini.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ MaxLoginRetry=4
TerminalServerUsers=tsusers
TerminalServerAdmins=tsadmins
; When AlwaysGroupCheck=false access will be permitted
; if the group TerminalServerUsers is not defined.
; if the group TerminalServerUsers is not defined, and the
; non-existence of TerminalServerAdmins will not be reported
AlwaysGroupCheck=false
; When RestrictOutboundClipboard=all clipboard from the
; server is not pushed to the client.
Expand Down
15 changes: 11 additions & 4 deletions sesman/session_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ session_list_get_bydata(uid_t uid,

/******************************************************************************/
struct scp_session_info *
session_list_get_byuid(uid_t uid, unsigned int *cnt, unsigned int flags)
session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags)
{
int i;
struct scp_session_info *sess;
Expand All @@ -429,13 +429,20 @@ session_list_get_byuid(uid_t uid, unsigned int *cnt, unsigned int flags)

count = 0;

LOG(LOG_LEVEL_DEBUG, "searching for session by UID: %d", uid);
if (uid != NULL)
{
LOG(LOG_LEVEL_DEBUG, "searching for session by UID: %d", (int)*uid);
}
else
{
LOG(LOG_LEVEL_DEBUG, "searching for all sessions");
}

for (i = 0 ; i < g_session_list->count ; ++i)
{
const struct session_item *si;
si = (const struct session_item *)list_get_item(g_session_list, i);
if (SESSION_IN_USE(si) && uid == si->uid)
if (SESSION_IN_USE(si) && (uid == NULL || *uid == si->uid))
{
count++;
}
Expand All @@ -462,7 +469,7 @@ session_list_get_byuid(uid_t uid, unsigned int *cnt, unsigned int flags)
const struct session_item *si;
si = (const struct session_item *)list_get_item(g_session_list, i);

if (SESSION_IN_USE(si) && uid == si->uid)
if (SESSION_IN_USE(si) && (uid == NULL || *uid == si->uid))
{
(sess[index]).sid = si->sesexec_pid;
(sess[index]).display = si->display;
Expand Down
5 changes: 3 additions & 2 deletions sesman/session_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ session_list_get_bydata(uid_t uid,

/**
* @brief retrieves session descriptions
* @param uid the UID for the descriptions
* @param uid the UID for the descriptions by reference, or NULL for
* all UIDs
* @param[out] cnt The number of sessions returned
* @param flags Future expansion
* @return A block of session descriptions
Expand All @@ -141,7 +142,7 @@ session_list_get_bydata(uid_t uid,
*
*/
struct scp_session_info *
session_list_get_byuid(uid_t uid, unsigned int *cnt, unsigned int flags);
session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags);

/**
*
Expand Down

0 comments on commit 4fe6827

Please sign in to comment.