From 80138c88ba32a8f285f0b712f8d45738312027a2 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 25 Jul 2011 09:17:18 -0400 Subject: [PATCH] Remove fallback to per-group lookup when matching groups in sudoers. The sudo front-end will now use getgrouplist() to get the user's list of groups if getgroups() fails or returns zero groups so we always have a list of the user's groups. For systems with mbr_check_membership() which support more that NGROUPS_MAX groups (Mac OS X), skip the call to getgroups() and use getgrouplist() so we get all the groups. --- plugins/sudoers/pwutil.c | 152 +++++++++----------------------------- plugins/sudoers/sudoers.c | 10 --- plugins/sudoers/sudoers.h | 7 -- src/sudo.c | 60 +++++++++++++-- 4 files changed, 88 insertions(+), 141 deletions(-) diff --git a/plugins/sudoers/pwutil.c b/plugins/sudoers/pwutil.c index 5d4cd0589..b511472c3 100644 --- a/plugins/sudoers/pwutil.c +++ b/plugins/sudoers/pwutil.c @@ -777,7 +777,7 @@ get_group_list(struct passwd *pw) * Cache group db entry if it exists or a negative response if not. */ #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) - ngids = sysconf(_SC_NGROUPS_MAX) * 2; + ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2; if (ngids < 0) #endif ngids = NGROUPS_MAX * 2; @@ -833,135 +833,53 @@ set_group_list(const char *user, GETGROUPS_T *gids, int ngids) } } -#ifndef HAVE_MBR_CHECK_MEMBERSHIP -static int -user_in_group_list(struct passwd *pw, struct group_list *grlist, const char *group) +int +user_in_group(struct passwd *pw, const char *group) { + struct group_list *grlist; struct group *grp = NULL; - int i, retval = FALSE; + int i, matched = FALSE; - /* - * If it could be a sudo-style group ID check gids first. - */ - if (group[0] == '#') { - gid_t gid = atoi(group + 1); - if (gid == pw->pw_gid) { - retval = TRUE; - goto done; - } - for (i = 0; i < grlist->ngids; i++) { - if (gid == grlist->gids[i]) { - retval = TRUE; + if ((grlist = get_group_list(pw)) != NULL) { + /* + * If it could be a sudo-style group ID check gids first. + */ + if (group[0] == '#') { + gid_t gid = atoi(group + 1); + if (gid == pw->pw_gid) { + matched = TRUE; goto done; } + for (i = 0; i < grlist->ngids; i++) { + if (gid == grlist->gids[i]) { + matched = TRUE; + goto done; + } + } } - } - - - /* - * Next check the supplementary group vector. - * It usually includes the password db group too. - */ - for (i = 0; i < grlist->ngroups; i++) { - if (strcasecmp(group, grlist->groups[i]) == 0) { - retval = TRUE; - goto done; - } - } - /* Finally check against user's primary (passwd file) group. */ - if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { - if (strcasecmp(group, grp->gr_name) == 0) { - retval = TRUE; - goto done; + /* + * Next check the supplementary group vector. + * It usually includes the password db group too. + */ + for (i = 0; i < grlist->ngroups; i++) { + if (strcasecmp(group, grlist->groups[i]) == 0) { + matched = TRUE; + goto done; + } } - } - -done: - if (grp != NULL) - gr_delref(grp); - return retval; -} -#endif /* !HAVE_MBR_CHECK_MEMBERSHIP */ - -int -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; -#endif - struct group *grp; - int retval = FALSE; - -#ifdef HAVE_SETAUTHDB - aix_setauthdb(pw->pw_name); -#endif - /* A group name that begins with a '#' may be a gid. */ - if ((grp = sudo_getgrnam(group)) == NULL && *group == '#') - grp = sudo_getgrgid(atoi(group + 1)); -#ifdef HAVE_SETAUTHDB - aix_restoreauthdb(); -#endif - if (grp == NULL) - goto done; - - /* check against user's primary (passwd file) gid */ - if (grp->gr_gid == pw->pw_gid) { - retval = TRUE; - goto done; - } -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - /* If we are matching the invoking user use the stashed uuid. */ - if (strcmp(pw->pw_name, user_name) == 0) { - if (mbr_gid_to_uuid(grp->gr_gid, gu) == 0 && - mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) { - retval = TRUE; - goto done; - } - } else { - if (mbr_uid_to_uuid(pw->pw_uid, uu) == 0 && - mbr_gid_to_uuid(grp->gr_gid, gu) == 0 && - mbr_check_membership(uu, gu, &ismember) == 0 && ismember) { - retval = TRUE; - goto done; - } - } -#else /* HAVE_MBR_CHECK_MEMBERSHIP */ - 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; + /* Finally check against user's primary (passwd file) group. */ + if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { + if (strcasecmp(group, grp->gr_name) == 0) { + matched = TRUE; goto done; } } - } -#endif /* HAVE_MBR_CHECK_MEMBERSHIP */ - done: - if (grp != NULL) - gr_delref(grp); - return retval; -} - -int -user_in_group(struct passwd *pw, const char *group) -{ -#ifndef HAVE_MBR_CHECK_MEMBERSHIP - struct group_list *grlist; - - if ((grlist = get_group_list(pw)) != NULL) { - /* The base gid (from passwd) is always present. */ - if (grlist->ngids > 1) { - int matched = user_in_group_list(pw, grlist, group); - grlist_delref(grlist); - return matched; - } + if (grp != NULL) + gr_delref(grp); grlist_delref(grlist); } -#endif /* !HAVE_MBR_CHECK_MEMBERSHIP */ - return user_in_group_lookup(pw, group); + return matched; } diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 90a7a9cec..db897d5f2 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -74,9 +74,6 @@ #ifdef HAVE_SELINUX # include #endif -#ifdef HAVE_MBR_CHECK_MEMBERSHIP -# include -#endif #include #include @@ -455,9 +452,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], if (sudo_user.pw != NULL) pw_delref(sudo_user.pw); sudo_user.pw = pw; -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - mbr_uid_to_uuid(user_uid, user_uuid); -#endif } } } @@ -827,10 +821,6 @@ init_vars(char * const envp[]) if (user_group_list == NULL) user_group_list = get_group_list(sudo_user.pw); -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - mbr_uid_to_uuid(user_uid, user_uuid); -#endif - /* It is now safe to use log_error() and set_perms() */ } diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 6b26746e4..3c8c6a1e3 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -38,10 +38,6 @@ #define DEFAULT_TEXT_DOMAIN "sudoers" #include "gettext.h" -#ifdef HAVE_MBR_CHECK_MEMBERSHIP -# include -#endif - /* * Password db and supplementary group IDs with associated group names. */ @@ -86,9 +82,6 @@ struct sudo_user { int cols; uid_t uid; uid_t gid; -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - uuid_t uuid; -#endif }; /* diff --git a/src/sudo.c b/src/sudo.c index 6fccf46d6..c0eb9942d 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -339,20 +339,66 @@ fix_fds(void) } } +/* + * Allocate space for groups and fill in using getgrouplist() + * for when we cannot use getgroups(). + */ +static int +fill_group_list(struct user_details *ud) +{ + int maxgroups, tries, rval = -1; + +#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) + maxgroups = (int)sysconf(_SC_NGROUPS_MAX); + if (maxgroups < 0) +#endif + maxgroups = NGROUPS_MAX; + + /* + * It is possible to belong to more groups in the group database + * than NGROUPS_MAX. We start off with NGROUPS_MAX * 2 entries + * and double this as needed. + */ + ud->groups = NULL; + ud->ngroups = maxgroups; + for (tries = 0; tries < 10 && rval == -1; tries++) { + ud->ngroups *= 2; + efree(ud->groups); + ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); + rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); + } + return rval; +} + static char * get_user_groups(struct user_details *ud) { - char *gid_list = NULL; + char *cp, *gid_list = NULL; size_t glsize; - char *cp; int i, len; - if ((ud->ngroups = getgroups(0, NULL)) <= 0) - return NULL; + /* + * Systems with mbr_check_membership() support more than NGROUPS_MAX + * groups so we cannot use getgroups(). + */ + ud->groups = NULL; +#ifndef HAVE_MBR_CHECK_MEMBERSHIP + if ((ud->ngroups = getgroups(0, NULL)) > 0) { + ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); + if (getgroups(ud->ngroups, ud->groups) < 0) { + efree(ud->groups); + ud->groups = NULL; + } + } +#endif /* HAVE_MBR_CHECK_MEMBERSHIP */ + if (ud->groups == NULL) { + if (fill_group_list(ud) == -1) + error(1, _("unable to get group vector")); + } - ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); - if (getgroups(ud->ngroups, ud->groups) < 0) - error(1, _("unable to get group vector")); + /* + * Format group list as a comma-separated string of gids. + */ glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1)); gid_list = emalloc(glsize); memcpy(gid_list, "groups=", sizeof("groups=") - 1); -- 2.40.0