Add getgrouplist() support to os_calls

On enterprise systems, using getgrouplist() (if available)
is more efficient than iterating over the members of the group,
and is also more likely to work
This commit is contained in:
matt335672
2023-10-02 11:04:47 +01:00
parent 84a0befd30
commit cf677da22c
2 changed files with 79 additions and 17 deletions
+70 -17
View File
@@ -3573,42 +3573,95 @@ g_getgroup_info(const char *groupname, int *gid)
} }
/*****************************************************************************/ /*****************************************************************************/
/* returns error */ #ifdef HAVE_GETGROUPLIST
/* if zero is returned, then ok is set */ int
/* does not work in win32 */ 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 int
g_check_user_in_group(const char *username, int gid, int *ok) g_check_user_in_group(const char *username, int gid, int *ok)
{ {
#if defined(_WIN32) #if defined(_WIN32)
return 1; return 1;
#else #else
struct group *groups;
int i; int i;
groups = getgrgid(gid); struct passwd *pwd_1 = getpwnam(username);
struct group *groups = getgrgid(gid);
if (groups == 0) if (pwd_1 == NULL || groups == NULL)
{ {
return 1; return 1;
} }
*ok = 0; if (pwd_1->pw_gid == gid)
i = 0;
while (0 != groups->gr_mem[i])
{ {
if (0 == g_strcmp(groups->gr_mem[i], username)) *ok = 1;
{ }
*ok = 1; else
break; {
} *ok = 0;
i = 0;
i++; while (0 != groups->gr_mem[i])
{
if (0 == g_strcmp(groups->gr_mem[i], username))
{
*ok = 1;
break;
}
i++;
}
} }
return 0; return 0;
#endif #endif
} }
#endif // HAVE_GETGROUPLIST
/*****************************************************************************/ /*****************************************************************************/
/* returns the time since the Epoch (00:00:00 UTC, January 1, 1970), /* returns the time since the Epoch (00:00:00 UTC, January 1, 1970),
+9
View File
@@ -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, int g_getuser_info_by_uid(int uid, char **username, int *gid,
char **shell, char **dir, char **gecos); char **shell, char **dir, char **gecos);
int g_getgroup_info(const char *groupname, int *gid); 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_check_user_in_group(const char *username, int gid, int *ok);
int g_time1(void); int g_time1(void);
int g_time2(void); int g_time2(void);