* 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;
}
}
-#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;
}
}
}
+/*
+ * 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);