Resolve the list of gids passed in from the sudo frontend (the

result of getgroups()) to names and store both the group names and
ids in the sudo_user struct.  When matching groups in the sudoers
file, match based on the names in the groups list first and
only do a gid-based match when we absolutely have to.  By matching
on the group name (as it is listed in sudoers) instead of id
(which we would have to resolve) we save a lot of group lookups
for sudoers files with a lot of groups in them.
This commit is contained in:
Todd C. Miller
2011-07-01 14:13:47 -04:00
parent 20972da410
commit 56321ec778
6 changed files with 172 additions and 104 deletions

View File

@@ -636,15 +636,55 @@ sudo_endgrent(void)
sudo_freegrcache();
}
#if defined(HAVE_GETGROUPS) && !defined(HAVE_MBR_CHECK_MEMBERSHIP)
static int
user_in_group_cached(const char *group)
{
gid_t gid = -1;
int i, retval = FALSE;
if (group[0] == '#')
gid = atoi(group + 1);
/* Check against user's primary (passwd file) group. */
if ((user_group != NULL && strcasecmp(group, user_group) == 0) ||
(group[0] == '#' && gid == user_gid)) {
retval = TRUE;
goto done;
}
/*
* If we are matching the invoking or list user and that user has a
* supplementary group vector, check it.
*/
for (i = 0; i < user_ngroups; i++) {
if (strcasecmp(group, user_groups[i]) == 0) {
retval = TRUE;
goto done;
}
}
if (group[0] == '#') {
for (i = 0; i < user_ngroups; i++) {
if (gid == user_gids[i]) {
retval = TRUE;
goto done;
}
}
}
done:
return retval;
}
#endif /* HAVE_GETGROUPS && !HAVE_MBR_CHECK_MEMBERSHIP */
int
user_in_group(struct passwd *pw, const char *group)
user_in_group_lookup(struct passwd *pw, const char *group)
{
#ifdef HAVE_MBR_CHECK_MEMBERSHIP
uuid_t gu, uu;
int ismember;
#else
char **gr_mem;
int i;
#endif
struct group *grp;
int retval = FALSE;
@@ -684,30 +724,13 @@ user_in_group(struct passwd *pw, const char *group)
}
}
#else /* HAVE_MBR_CHECK_MEMBERSHIP */
# ifdef HAVE_GETGROUPS
/*
* If we are matching the invoking or list user and that user has a
* supplementary group vector, check it.
*/
if (user_ngroups > 0 &&
strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
for (i = 0; i < user_ngroups; i++) {
if (grp->gr_gid == user_groups[i]) {
if (grp->gr_mem != NULL) {
for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) {
if (strcmp(*gr_mem, pw->pw_name) == 0) {
retval = TRUE;
goto done;
}
}
} else
# endif /* HAVE_GETGROUPS */
{
if (grp != NULL && grp->gr_mem != NULL) {
for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) {
if (strcmp(*gr_mem, pw->pw_name) == 0) {
retval = TRUE;
goto done;
}
}
}
}
#endif /* HAVE_MBR_CHECK_MEMBERSHIP */
@@ -716,3 +739,15 @@ done:
gr_delref(grp);
return retval;
}
int
user_in_group(struct passwd *pw, const char *group)
{
#if defined(HAVE_GETGROUPS) && !defined(HAVE_MBR_CHECK_MEMBERSHIP)
if (user_ngroups > 0 &&
strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
return user_in_group_cached(group);
}
#endif /* HAVE_GETGROUPS && !HAVE_MBR_CHECK_MEMBERSHIP */
return user_in_group_lookup(pw, group);
}