Give privilege to users in TerminalServerAdmins

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.
This commit is contained in:
matt335672
2024-12-20 16:58:24 +00:00
parent dd020e971b
commit 86c7fa63b9
9 changed files with 162 additions and 133 deletions
+6
View File
@@ -36,6 +36,8 @@
#include "pre_session_list.h"
#include "scp.h"
#include "sesman.h"
#include "sesman_access.h"
#include "sesman_config.h"
/******************************************************************************/
@@ -79,6 +81,10 @@ 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;
// For system logins, don't allow admin access
//psi->is_admin = access_login_mng_allowed(&g_cfg->sec,
// psi->username);
psi->is_admin = 0;
}
}
}
+104 -118
View File
@@ -39,131 +39,90 @@
/******************************************************************************/
/**
* 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)
{
rv = 1;
}
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)
{
LOG(LOG_LEVEL_ERROR, "Can't get UID for user %s", user);
}
else if (0 == uid)
{
LOG(LOG_LEVEL_ERROR,
"ROOT login attempted, but root login is disabled");
}
else
{
rv = 1;
}
}
return rv;
}
/******************************************************************************/
/**
* 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 rv = 0;
int gid;
int ok;
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
{
LOG(LOG_LEVEL_INFO,
"%s group is not defined. Access granted for %s",
param, user);
rv = 1;
}
}
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)
{
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;
}
}
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;
}
return rv;
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 rv = 0;
int ok = 0;
if (root_login_check(cfg_sec, user))
if (!cfg_sec->allow_root && user_is_root(user))
{
rv = access_login_allowed_common(cfg_sec->ts_users,
"TerminalServerUsers",
cfg_sec->ts_always_group_check,
user);
LOG(LOG_LEVEL_ERROR,
"ROOT login attempted, but root login is disabled");
}
else
{
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)
{
/* 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 != 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);
}
}
return rv;
return ok;
}
/******************************************************************************/
@@ -171,15 +130,42 @@ int
access_login_is_admin(const struct config_security *cfg_sec,
const char *user)
{
int rv = 0;
int ok = 0;
if (root_login_check(cfg_sec, user))
const char *group = cfg_sec->ts_admins;
const char *param = "TerminalServerAdmins";
int gid = -1;
if (group == NULL || group[0] == '\0')
{
rv = access_login_allowed_common(cfg_sec->ts_admins,
"TerminalServerAdmins",
1,
user);
if (cfg_sec->ts_always_group_check)
{
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 */
if (cfg_sec->ts_always_group_check)
{
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.", param, group);
}
return rv;
// Root always has access. Do other checks and logging first
if (!ok && user_is_root(user))
{
ok = 1;
}
if (ok)
{
LOG(LOG_LEVEL_INFO, "User %s is in %s group %s", user, param, group);
}
return ok;
}
+1
View File
@@ -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;
};
+20 -3
View File
@@ -204,11 +204,21 @@ authenticate_and_authorize_uds_connection(struct pre_session_item *psi,
}
else
{
LOG(LOG_LEVEL_INFO, "Access permitted for user: %s",
username);
psi->login_state = E_PS_LOGIN_UDS;
psi->uid = uid;
psi->start_ip_addr[0] = '\0';
psi->is_admin = access_login_is_admin(&g_cfg->sec,
psi->username);
if (psi->is_admin)
{
LOG(LOG_LEVEL_INFO, "Admin access permitted for user: %s",
username);
}
else
{
LOG(LOG_LEVEL_INFO, "Normal access permitted for user: %s",
username);
}
}
}
@@ -555,7 +565,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)
{
+2 -1
View File
@@ -18,7 +18,8 @@ XAuthorityInSystemDir=no
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.
+11 -4
View File
@@ -438,7 +438,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;
@@ -447,13 +447,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++;
}
@@ -480,7 +487,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;
+3 -2
View File
@@ -140,7 +140,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
@@ -149,7 +150,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);
/**
*