runaslist_matches: split out user_list and group_list matching.
This makes it possible to call the appropriate runas user or group list match function when resolving aliases instead of calling runaslist_matches() itself. Fixes a bug that prevented the group specified via "sudo -g" from matching when a Runas_Alias was used in the user or group portion of a Runas_Spec.
This commit is contained in:
@@ -58,8 +58,6 @@
|
||||
#include "sudoers.h"
|
||||
#include <gram.h>
|
||||
|
||||
static struct member_list empty = TAILQ_HEAD_INITIALIZER(empty);
|
||||
|
||||
/*
|
||||
* Check whether user described by pw matches member.
|
||||
* Returns ALLOW, DENY or UNSPEC.
|
||||
@@ -142,37 +140,22 @@ runas_getgroups(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for user described by pw in a list of members.
|
||||
* If both lists are empty compare against def_runas_default.
|
||||
* Check whether the requested runas user matches user_list, the
|
||||
* user portion of a sudoers runaslist. If user_list is NULL, a
|
||||
* list containing runas_default is used.
|
||||
* Returns ALLOW, DENY or UNSPEC.
|
||||
*/
|
||||
int
|
||||
runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||
const struct member_list *user_list, const struct member_list *group_list,
|
||||
struct member **matching_user, struct member **matching_group)
|
||||
static int
|
||||
runas_userlist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||
const struct member_list *user_list, struct member **matching_user)
|
||||
{
|
||||
const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
|
||||
const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost;
|
||||
struct member_list _user_list = TAILQ_HEAD_INITIALIZER(_user_list);
|
||||
struct member m_user;
|
||||
int user_matched = UNSPEC;
|
||||
int group_matched = UNSPEC;
|
||||
struct member *m;
|
||||
struct alias *a;
|
||||
int rc;
|
||||
debug_decl(runaslist_matches, SUDOERS_DEBUG_MATCH);
|
||||
debug_decl(runas_userlist_matches, SUDOERS_DEBUG_MATCH);
|
||||
|
||||
/* If no runas user listed in sudoers, use a default value. */
|
||||
if (user_list == NULL) {
|
||||
m_user.name = def_runas_default;
|
||||
m_user.type = WORD;
|
||||
m_user.negated = false;
|
||||
TAILQ_INSERT_HEAD(&_user_list, &m_user, entries);
|
||||
user_list = &_user_list;
|
||||
matching_user = NULL;
|
||||
}
|
||||
|
||||
/* Check runas user. */
|
||||
TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) {
|
||||
switch (m->type) {
|
||||
case ALL:
|
||||
@@ -192,8 +175,8 @@ runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||
case ALIAS:
|
||||
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
||||
if (a != NULL) {
|
||||
rc = runaslist_matches(parse_tree, &a->members,
|
||||
&empty, matching_user, NULL);
|
||||
const int rc = runas_userlist_matches(parse_tree,
|
||||
&a->members, matching_user);
|
||||
if (rc != UNSPEC)
|
||||
user_matched = m->negated ? !rc : rc;
|
||||
alias_put(a);
|
||||
@@ -216,58 +199,107 @@ runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug_return_int(user_matched);
|
||||
}
|
||||
|
||||
/* Check runas group, if one was specified. */
|
||||
if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) {
|
||||
if (group_list != NULL) {
|
||||
TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) {
|
||||
switch (m->type) {
|
||||
case ALL:
|
||||
/*
|
||||
* Check whether the requested runas group matches group_list, the
|
||||
* group portion of a sudoers runaslist, or the runas user's groups.
|
||||
* Returns ALLOW, DENY or UNSPEC.
|
||||
*/
|
||||
static int
|
||||
runas_grouplist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||
const struct member_list *group_list, struct member **matching_group)
|
||||
{
|
||||
int group_matched = UNSPEC;
|
||||
struct member *m;
|
||||
struct alias *a;
|
||||
debug_decl(runas_grouplist_matches, SUDOERS_DEBUG_MATCH);
|
||||
|
||||
if (group_list != NULL) {
|
||||
TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) {
|
||||
switch (m->type) {
|
||||
case ALL:
|
||||
group_matched = !m->negated;
|
||||
break;
|
||||
case ALIAS:
|
||||
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
||||
if (a != NULL) {
|
||||
const int rc = runas_grouplist_matches(parse_tree,
|
||||
&a->members, matching_group);
|
||||
if (rc != UNSPEC)
|
||||
group_matched = m->negated ? !rc : rc;
|
||||
alias_put(a);
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case WORD:
|
||||
if (group_matches(m->name, runas_gr))
|
||||
group_matched = !m->negated;
|
||||
break;
|
||||
case ALIAS:
|
||||
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
||||
if (a != NULL) {
|
||||
rc = runaslist_matches(parse_tree, &empty,
|
||||
&a->members, NULL, matching_group);
|
||||
if (rc != UNSPEC)
|
||||
group_matched = m->negated ? !rc : rc;
|
||||
alias_put(a);
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case WORD:
|
||||
if (group_matches(m->name, runas_gr))
|
||||
group_matched = !m->negated;
|
||||
break;
|
||||
}
|
||||
if (group_matched != UNSPEC) {
|
||||
if (matching_group != NULL && m->type != ALIAS)
|
||||
*matching_group = m;
|
||||
break;
|
||||
}
|
||||
if (group_matched != UNSPEC) {
|
||||
if (matching_group != NULL && m->type != ALIAS)
|
||||
*matching_group = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (group_matched == UNSPEC) {
|
||||
struct gid_list *runas_groups;
|
||||
/*
|
||||
* The runas group was not explicitly allowed by sudoers.
|
||||
* Check whether it is one of the target user's groups.
|
||||
*/
|
||||
if (runas_pw->pw_gid == runas_gr->gr_gid) {
|
||||
group_matched = ALLOW; /* runas group matches passwd db */
|
||||
} else if ((runas_groups = runas_getgroups()) != NULL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < runas_groups->ngids; i++) {
|
||||
if (runas_groups->gids[i] == runas_gr->gr_gid) {
|
||||
group_matched = ALLOW; /* matched aux group vector */
|
||||
break;
|
||||
}
|
||||
}
|
||||
sudo_gidlist_delref(runas_groups);
|
||||
}
|
||||
if (group_matched == UNSPEC) {
|
||||
struct gid_list *runas_groups;
|
||||
/*
|
||||
* The runas group was not explicitly allowed by sudoers.
|
||||
* Check whether it is one of the target user's groups.
|
||||
*/
|
||||
if (runas_pw->pw_gid == runas_gr->gr_gid) {
|
||||
group_matched = ALLOW; /* runas group matches passwd db */
|
||||
} else if ((runas_groups = runas_getgroups()) != NULL) {
|
||||
int i;
|
||||
}
|
||||
|
||||
for (i = 0; i < runas_groups->ngids; i++) {
|
||||
if (runas_groups->gids[i] == runas_gr->gr_gid) {
|
||||
group_matched = ALLOW; /* matched aux group vector */
|
||||
break;
|
||||
}
|
||||
}
|
||||
sudo_gidlist_delref(runas_groups);
|
||||
}
|
||||
}
|
||||
debug_return_int(group_matched);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the sudoers runaslist, composed of user_list and
|
||||
* group_list, matches the runas user/group requested by the user.
|
||||
* Either (or both) user_list and group_list may be NULL.
|
||||
* If user_list is NULL, a list containing runas_default is used.
|
||||
* Returns ALLOW, DENY or UNSPEC.
|
||||
*/
|
||||
int
|
||||
runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||
const struct member_list *user_list, const struct member_list *group_list,
|
||||
struct member **matching_user, struct member **matching_group)
|
||||
{
|
||||
struct member_list _user_list = TAILQ_HEAD_INITIALIZER(_user_list);
|
||||
int user_matched, group_matched = UNSPEC;
|
||||
struct member m_user;
|
||||
debug_decl(runaslist_matches, SUDOERS_DEBUG_MATCH);
|
||||
|
||||
/* If no runas user listed in sudoers, use the default value. */
|
||||
if (user_list == NULL) {
|
||||
m_user.name = def_runas_default;
|
||||
m_user.type = WORD;
|
||||
m_user.negated = false;
|
||||
TAILQ_INSERT_HEAD(&_user_list, &m_user, entries);
|
||||
user_list = &_user_list;
|
||||
matching_user = NULL;
|
||||
}
|
||||
|
||||
user_matched = runas_userlist_matches(parse_tree, user_list, matching_user);
|
||||
if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) {
|
||||
group_matched = runas_grouplist_matches(parse_tree, group_list,
|
||||
matching_group);
|
||||
}
|
||||
|
||||
if (user_matched == DENY || group_matched == DENY)
|
||||
|
Reference in New Issue
Block a user