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 "sudoers.h"
|
||||||
#include <gram.h>
|
#include <gram.h>
|
||||||
|
|
||||||
static struct member_list empty = TAILQ_HEAD_INITIALIZER(empty);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether user described by pw matches member.
|
* Check whether user described by pw matches member.
|
||||||
* Returns ALLOW, DENY or UNSPEC.
|
* Returns ALLOW, DENY or UNSPEC.
|
||||||
@@ -142,37 +140,22 @@ runas_getgroups(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for user described by pw in a list of members.
|
* Check whether the requested runas user matches user_list, the
|
||||||
* If both lists are empty compare against def_runas_default.
|
* user portion of a sudoers runaslist. If user_list is NULL, a
|
||||||
|
* list containing runas_default is used.
|
||||||
* Returns ALLOW, DENY or UNSPEC.
|
* Returns ALLOW, DENY or UNSPEC.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
runas_userlist_matches(const struct sudoers_parse_tree *parse_tree,
|
||||||
const struct member_list *user_list, const struct member_list *group_list,
|
const struct member_list *user_list, struct member **matching_user)
|
||||||
struct member **matching_user, struct member **matching_group)
|
|
||||||
{
|
{
|
||||||
const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
|
const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
|
||||||
const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost;
|
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 user_matched = UNSPEC;
|
||||||
int group_matched = UNSPEC;
|
|
||||||
struct member *m;
|
struct member *m;
|
||||||
struct alias *a;
|
struct alias *a;
|
||||||
int rc;
|
debug_decl(runas_userlist_matches, SUDOERS_DEBUG_MATCH);
|
||||||
debug_decl(runaslist_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) {
|
TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) {
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
case ALL:
|
case ALL:
|
||||||
@@ -192,8 +175,8 @@ runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
|||||||
case ALIAS:
|
case ALIAS:
|
||||||
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
||||||
if (a != NULL) {
|
if (a != NULL) {
|
||||||
rc = runaslist_matches(parse_tree, &a->members,
|
const int rc = runas_userlist_matches(parse_tree,
|
||||||
&empty, matching_user, NULL);
|
&a->members, matching_user);
|
||||||
if (rc != UNSPEC)
|
if (rc != UNSPEC)
|
||||||
user_matched = m->negated ? !rc : rc;
|
user_matched = m->negated ? !rc : rc;
|
||||||
alias_put(a);
|
alias_put(a);
|
||||||
@@ -216,58 +199,107 @@ runaslist_matches(const struct sudoers_parse_tree *parse_tree,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debug_return_int(user_matched);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check runas group, if one was specified. */
|
/*
|
||||||
if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) {
|
* Check whether the requested runas group matches group_list, the
|
||||||
if (group_list != NULL) {
|
* group portion of a sudoers runaslist, or the runas user's groups.
|
||||||
TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) {
|
* Returns ALLOW, DENY or UNSPEC.
|
||||||
switch (m->type) {
|
*/
|
||||||
case ALL:
|
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;
|
group_matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
case ALIAS:
|
}
|
||||||
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
if (group_matched != UNSPEC) {
|
||||||
if (a != NULL) {
|
if (matching_group != NULL && m->type != ALIAS)
|
||||||
rc = runaslist_matches(parse_tree, &empty,
|
*matching_group = m;
|
||||||
&a->members, NULL, matching_group);
|
break;
|
||||||
if (rc != UNSPEC)
|
}
|
||||||
group_matched = m->negated ? !rc : rc;
|
}
|
||||||
alias_put(a);
|
}
|
||||||
break;
|
if (group_matched == UNSPEC) {
|
||||||
}
|
struct gid_list *runas_groups;
|
||||||
FALLTHROUGH;
|
/*
|
||||||
case WORD:
|
* The runas group was not explicitly allowed by sudoers.
|
||||||
if (group_matches(m->name, runas_gr))
|
* Check whether it is one of the target user's groups.
|
||||||
group_matched = !m->negated;
|
*/
|
||||||
break;
|
if (runas_pw->pw_gid == runas_gr->gr_gid) {
|
||||||
}
|
group_matched = ALLOW; /* runas group matches passwd db */
|
||||||
if (group_matched != UNSPEC) {
|
} else if ((runas_groups = runas_getgroups()) != NULL) {
|
||||||
if (matching_group != NULL && m->type != ALIAS)
|
int i;
|
||||||
*matching_group = m;
|
|
||||||
|
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;
|
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++) {
|
debug_return_int(group_matched);
|
||||||
if (runas_groups->gids[i] == runas_gr->gr_gid) {
|
}
|
||||||
group_matched = ALLOW; /* matched aux group vector */
|
|
||||||
break;
|
/*
|
||||||
}
|
* Check whether the sudoers runaslist, composed of user_list and
|
||||||
}
|
* group_list, matches the runas user/group requested by the user.
|
||||||
sudo_gidlist_delref(runas_groups);
|
* 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)
|
if (user_matched == DENY || group_matched == DENY)
|
||||||
|
Reference in New Issue
Block a user