Skip to content

Commit

Permalink
Merge pull request #2815 from matt335672/groups_patch
Browse files Browse the repository at this point in the history
Improve tsusers/tsadmins group support
  • Loading branch information
matt335672 authored Oct 6, 2023
2 parents 89ceaf0 + cf5c271 commit bce303c
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 130 deletions.
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

0 comments on commit bce303c

Please sign in to comment.