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

Improve tsusers/tsadmins group support #2815

Merged
merged 4 commits into from
Oct 6, 2023
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
85 changes: 69 additions & 16 deletions common/os_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -3573,42 +3573,95 @@ g_getgroup_info(const char *groupname, int *gid)
}

/*****************************************************************************/
/* returns error */
/* if zero is returned, then ok is set */
/* does not work in win32 */
#ifdef HAVE_GETGROUPLIST
int
g_check_user_in_group(const char *username, int gid, int *ok)
{
int rv = 1;
struct passwd *pwd_1 = getpwnam(username);
if (pwd_1 != NULL)
{
// Get number of groups for user
//
// Some implementations of getgrouplist() (i.e. muslc) don't
// allow ngroups to be <1 on entry
int ngroups = 1;
GETGROUPS_T dummy;
getgrouplist(username, pwd_1->pw_gid, &dummy, &ngroups);

if (ngroups > 0) // Should always be true
{
GETGROUPS_T *grouplist;
grouplist = (GETGROUPS_T *)malloc(ngroups * sizeof(grouplist[0]));
if (grouplist != NULL)
{
// Now get the actual groups. The number of groups returned
// by this call is not necessarily the same as the number
// returned by the first call.
int allocgroups = ngroups;
getgrouplist(username, pwd_1->pw_gid, grouplist, &ngroups);
ngroups = MIN(ngroups, allocgroups);

rv = 0;
*ok = 0;

int i;
for (i = 0 ; i < ngroups; ++i)
{
if (grouplist[i] == (GETGROUPS_T)gid)
{
*ok = 1;
break;
}
}
free(grouplist);
}
}
}
return rv;
}
/*****************************************************************************/
#else // HAVE_GETGROUPLIST
int
g_check_user_in_group(const char *username, int gid, int *ok)
{
#if defined(_WIN32)
return 1;
#else
struct group *groups;
int i;

groups = getgrgid(gid);

if (groups == 0)
struct passwd *pwd_1 = getpwnam(username);
struct group *groups = getgrgid(gid);
if (pwd_1 == NULL || groups == NULL)
{
return 1;
}

*ok = 0;
i = 0;

while (0 != groups->gr_mem[i])
if (pwd_1->pw_gid == gid)
{
*ok = 1;
}
else
{
if (0 == g_strcmp(groups->gr_mem[i], username))
*ok = 0;
i = 0;

while (0 != groups->gr_mem[i])
{
*ok = 1;
break;
}
if (0 == g_strcmp(groups->gr_mem[i], username))
{
*ok = 1;
break;
}

i++;
i++;
}
}

return 0;
#endif
}
#endif // HAVE_GETGROUPLIST

/*****************************************************************************/
/* returns the time since the Epoch (00:00:00 UTC, January 1, 1970),
Expand Down
9 changes: 9 additions & 0 deletions common/os_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,15 @@ int g_getuser_info_by_name(const char *username, int *uid, int *gid,
int g_getuser_info_by_uid(int uid, char **username, int *gid,
char **shell, char **dir, char **gecos);
int g_getgroup_info(const char *groupname, int *gid);
/**
* Checks whether a user is in the specified group
* @param username Name of user
* @param gid GID of group
* @param[out] ok Whether user is in group
* @return Non-zero if a system error occurred. In this instance OK is not set
*
* Primary group of username is also checked
*/
int g_check_user_in_group(const char *username, int gid, int *ok);
int g_time1(void);
int g_time2(void);
Expand Down
5 changes: 4 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,10 @@ AM_COND_IF([DEVEL_DEBUG],
AC_SEARCH_LIBS([setusercontext], [util])

# Define HAVE_XXXXX macros for some system functions
AC_CHECK_FUNCS([setusercontext])
AC_CHECK_FUNCS([setusercontext getgrouplist])

# The type used by getgrouplist() is the same type used by getgroups()
AC_TYPE_GETGROUPS

# Don't fail without working nasm if rfxcodec is not enabled
if test "x$enable_rfxcodec" != xyes; then
Expand Down
184 changes: 117 additions & 67 deletions sesman/libsesman/sesman_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,108 +28,158 @@
#include <config_ac.h>
#endif

#include <stdio.h>

#include "arch.h"

#include "sesman_access.h"
#include "sesman_config.h"
#include "log.h"
#include "os_calls.h"
#include "string_calls.h"

/******************************************************************************/
int
access_login_allowed(const struct config_security *cfg_sec, const char *user)
/**
* Root user login check
*
* @param cfg_sec Sesman security config
* @param user user name
* @return 0 if user is root and root accesses are not allowed
*/
static int
root_login_check(const struct config_security *cfg_sec,
const char *user)
{
int gid;
int ok;

if ((0 == g_strncmp(user, "root", 5)) && (0 == cfg_sec->allow_root))
int rv = 0;
if (cfg_sec->allow_root)
{
LOG(LOG_LEVEL_WARNING,
"ROOT login attempted, but root login is disabled");
return 0;
rv = 1;
}

if ((0 == cfg_sec->ts_users_enable) && (0 == cfg_sec->ts_always_group_check))
else
{
LOG(LOG_LEVEL_INFO, "Terminal Server Users group is disabled, allowing authentication");
return 1;
// 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;
}

if (0 != g_getuser_info_by_name(user, 0, &gid, 0, 0, 0))
/******************************************************************************/
/**
* 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')
{
LOG(LOG_LEVEL_ERROR, "Cannot read user info! - login denied");
return 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;
}
}

if (cfg_sec->ts_users == gid)
else if (g_getgroup_info(group, &gid) != 0)
{
LOG(LOG_LEVEL_DEBUG, "ts_users is user's primary group");
return 1;
/* 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;
}
}

if (0 != g_check_user_in_group(user, cfg_sec->ts_users, &ok))
else if (0 != g_check_user_in_group(user, gid, &ok))
{
LOG(LOG_LEVEL_ERROR, "Cannot read group info! - login denied");
return 0;
LOG(LOG_LEVEL_ERROR, "Error checking %s group %s. "
"Access denied for %s", param, group, user);
}

if (ok)
else if (!ok)
{
return 1;
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_INFO, "login denied for user %s", user);

return 0;
return rv;
}

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

if ((0 == g_strncmp(user, "root", 5)) && (0 == cfg_sec->allow_root))
{
LOG(LOG_LEVEL_WARNING,
"[MNG] ROOT login attempted, but root login is disabled");
return 0;
}

if (0 == cfg_sec->ts_admins_enable)
{
LOG(LOG_LEVEL_INFO, "[MNG] Terminal Server Admin group is disabled, "
"allowing authentication");
return 1;
}
int rv = 0;

if (0 != g_getuser_info_by_name(user, 0, &gid, 0, 0, 0))
if (root_login_check(cfg_sec, user))
{
LOG(LOG_LEVEL_ERROR, "[MNG] Cannot read user info! - login denied");
return 0;
rv = access_login_allowed_common(cfg_sec->ts_users,
"TerminalServerUsers",
cfg_sec->ts_always_group_check,
user);
}

if (cfg_sec->ts_admins == gid)
{
LOG(LOG_LEVEL_INFO, "[MNG] ts_users is user's primary group");
return 1;
}
return rv;
}

if (0 != g_check_user_in_group(user, cfg_sec->ts_admins, &ok))
{
LOG(LOG_LEVEL_ERROR, "[MNG] Cannot read group info! - login denied");
return 0;
}
/******************************************************************************/
int
access_login_mng_allowed(const struct config_security *cfg_sec,
const char *user)
{
int rv = 0;

if (ok)
if (root_login_check(cfg_sec, user))
{
return 1;
rv = access_login_allowed_common(cfg_sec->ts_admins,
"TerminalServerAdmins",
1,
user);
}

LOG(LOG_LEVEL_INFO, "[MNG] login denied for user %s", user);

return 0;
return rv;
}
Loading