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.
This commit is contained in:
@@ -777,7 +777,7 @@ get_group_list(struct passwd *pw)
|
|||||||
* Cache group db entry if it exists or a negative response if not.
|
* Cache group db entry if it exists or a negative response if not.
|
||||||
*/
|
*/
|
||||||
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
|
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
|
||||||
ngids = sysconf(_SC_NGROUPS_MAX) * 2;
|
ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;
|
||||||
if (ngids < 0)
|
if (ngids < 0)
|
||||||
#endif
|
#endif
|
||||||
ngids = NGROUPS_MAX * 2;
|
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)
|
|
||||||
{
|
|
||||||
struct group *grp = NULL;
|
|
||||||
int i, retval = 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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* HAVE_MBR_CHECK_MEMBERSHIP */
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (grp != NULL)
|
|
||||||
gr_delref(grp);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
user_in_group(struct passwd *pw, const char *group)
|
user_in_group(struct passwd *pw, const char *group)
|
||||||
{
|
{
|
||||||
#ifndef HAVE_MBR_CHECK_MEMBERSHIP
|
|
||||||
struct group_list *grlist;
|
struct group_list *grlist;
|
||||||
|
struct group *grp = NULL;
|
||||||
|
int i, matched = FALSE;
|
||||||
|
|
||||||
if ((grlist = get_group_list(pw)) != NULL) {
|
if ((grlist = get_group_list(pw)) != NULL) {
|
||||||
/* The base gid (from passwd) is always present. */
|
/*
|
||||||
if (grlist->ngids > 1) {
|
* If it could be a sudo-style group ID check gids first.
|
||||||
int matched = user_in_group_list(pw, grlist, group);
|
*/
|
||||||
grlist_delref(grlist);
|
if (group[0] == '#') {
|
||||||
return matched;
|
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) {
|
||||||
|
matched = 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) {
|
||||||
|
matched = TRUE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
if (grp != NULL)
|
||||||
|
gr_delref(grp);
|
||||||
grlist_delref(grlist);
|
grlist_delref(grlist);
|
||||||
}
|
}
|
||||||
#endif /* !HAVE_MBR_CHECK_MEMBERSHIP */
|
return matched;
|
||||||
return user_in_group_lookup(pw, group);
|
|
||||||
}
|
}
|
||||||
|
@@ -74,9 +74,6 @@
|
|||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
# include <selinux/selinux.h>
|
# include <selinux/selinux.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_MBR_CHECK_MEMBERSHIP
|
|
||||||
# include <membership.h>
|
|
||||||
#endif
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
@@ -455,9 +452,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
|
|||||||
if (sudo_user.pw != NULL)
|
if (sudo_user.pw != NULL)
|
||||||
pw_delref(sudo_user.pw);
|
pw_delref(sudo_user.pw);
|
||||||
sudo_user.pw = 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)
|
if (user_group_list == NULL)
|
||||||
user_group_list = get_group_list(sudo_user.pw);
|
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() */
|
/* It is now safe to use log_error() and set_perms() */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,10 +38,6 @@
|
|||||||
#define DEFAULT_TEXT_DOMAIN "sudoers"
|
#define DEFAULT_TEXT_DOMAIN "sudoers"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
|
||||||
#ifdef HAVE_MBR_CHECK_MEMBERSHIP
|
|
||||||
# include <membership.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Password db and supplementary group IDs with associated group names.
|
* Password db and supplementary group IDs with associated group names.
|
||||||
*/
|
*/
|
||||||
@@ -86,9 +82,6 @@ struct sudo_user {
|
|||||||
int cols;
|
int cols;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
uid_t gid;
|
uid_t gid;
|
||||||
#ifdef HAVE_MBR_CHECK_MEMBERSHIP
|
|
||||||
uuid_t uuid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
60
src/sudo.c
60
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 *
|
static char *
|
||||||
get_user_groups(struct user_details *ud)
|
get_user_groups(struct user_details *ud)
|
||||||
{
|
{
|
||||||
char *gid_list = NULL;
|
char *cp, *gid_list = NULL;
|
||||||
size_t glsize;
|
size_t glsize;
|
||||||
char *cp;
|
|
||||||
int i, len;
|
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)
|
* Format group list as a comma-separated string of gids.
|
||||||
error(1, _("unable to get group vector"));
|
*/
|
||||||
glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
|
glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
|
||||||
gid_list = emalloc(glsize);
|
gid_list = emalloc(glsize);
|
||||||
memcpy(gid_list, "groups=", sizeof("groups=") - 1);
|
memcpy(gid_list, "groups=", sizeof("groups=") - 1);
|
||||||
|
Reference in New Issue
Block a user