diff --git a/common/os_calls.c b/common/os_calls.c index 1e4f6b1894..dd0122e153 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -3141,42 +3141,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) { - if (0 == g_strcmp(groups->gr_mem[i], username)) + *ok = 1; + } + else + { + *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), diff --git a/common/os_calls.h b/common/os_calls.h index 5763019be4..5e8ebcc5e1 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -173,6 +173,15 @@ int g_sigterm(int pid); int g_getuser_info(const char *username, int *gid, int *uid, 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); diff --git a/configure.ac b/configure.ac index 55131912c8..097424a4ef 100644 --- a/configure.ac +++ b/configure.ac @@ -189,6 +189,12 @@ AM_COND_IF([DEVEL_DEBUG], [AX_APPEND_COMPILE_FLAGS([-g -O0])], [AX_APPEND_COMPILE_FLAGS([-O2])]) +# Define HAVE_XXXXX macros for some system functions +AC_CHECK_FUNCS([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 with_simd=no diff --git a/sesman/access.c b/sesman/access.c index 442d9e7b4a..b70120bb9f 100644 --- a/sesman/access.c +++ b/sesman/access.c @@ -35,7 +35,6 @@ int access_login_allowed(const char *user) { - int gid; int ok; if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) @@ -51,18 +50,6 @@ access_login_allowed(const char *user) return 1; } - if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) - { - LOG(LOG_LEVEL_ERROR, "Cannot read user info! - login denied"); - return 0; - } - - if (g_cfg->sec.ts_users == gid) - { - LOG(LOG_LEVEL_DEBUG, "ts_users is user's primary group"); - return 1; - } - if (0 != g_check_user_in_group(user, g_cfg->sec.ts_users, &ok)) { LOG(LOG_LEVEL_ERROR, "Cannot read group info! - login denied"); @@ -83,7 +70,6 @@ access_login_allowed(const char *user) int access_login_mng_allowed(const char *user) { - int gid; int ok; if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) @@ -100,18 +86,6 @@ access_login_mng_allowed(const char *user) return 1; } - if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) - { - LOG(LOG_LEVEL_ERROR, "[MNG] Cannot read user info! - login denied"); - return 0; - } - - if (g_cfg->sec.ts_admins == gid) - { - LOG(LOG_LEVEL_INFO, "[MNG] ts_users is user's primary group"); - return 1; - } - if (0 != g_check_user_in_group(user, g_cfg->sec.ts_admins, &ok)) { LOG(LOG_LEVEL_ERROR, "[MNG] Cannot read group info! - login denied");