Add a sequence number in the aliases for loop detection. If we find

an alias with the seqno already set to the current (global) value we
know we've visited it before so ignore it.
This commit is contained in:
Todd C. Miller
2007-09-15 11:24:54 +00:00
parent 4f5e88532f
commit 76e5eb434b
4 changed files with 98 additions and 35 deletions

17
alias.c
View File

@@ -52,6 +52,7 @@ __unused static const char rcsid[] = "$Sudo$";
* Globals
*/
struct rbtree *aliases;
unsigned int alias_seqno;
/*
* Local protoypes
@@ -91,11 +92,22 @@ find_alias(name, type)
{
struct alias key;
struct rbnode *node;
struct alias *a = NULL;
key.name = name;
key.type = type;
node = rbfind(aliases, &key);
return(node ? node->data : NULL);
if ((node = rbfind(aliases, &key)) != NULL) {
/*
* Compare the global sequence number with the one stored
* in the alias. If they match then we've seen this alias
* before and found a loop.
*/
a = node->data;
if (a->seqno == alias_seqno)
return(NULL);
a->seqno = alias_seqno;
}
return(a);
}
/*
@@ -114,6 +126,7 @@ alias_add(name, type, members)
a = emalloc(sizeof(*a));
a->name = name;
a->type = type;
a->seqno = 0;
list2tq(&a->members, members);
if (rbinsert(aliases, a)) {
efree(a);

96
match.c
View File

@@ -102,8 +102,8 @@ __unused static const char rcsid[] = "$Sudo$";
* Check for user described by pw in a list of members.
* Returns ALLOW, DENY or UNSPEC.
*/
int
userlist_matches(pw, list)
static int
_userlist_matches(pw, list)
struct passwd *pw;
struct member_list *list;
{
@@ -126,7 +126,7 @@ userlist_matches(pw, list)
break;
case ALIAS:
if ((a = find_alias(m->name, USERALIAS)) != NULL) {
rval = userlist_matches(pw, &a->members);
rval = _userlist_matches(pw, &a->members);
if (rval != UNSPEC)
matched = m->negated ? !rval : rval;
break;
@@ -143,13 +143,22 @@ userlist_matches(pw, list)
return(matched);
}
int
userlist_matches(pw, list)
struct passwd *pw;
struct member_list *list;
{
alias_seqno++;
return(_userlist_matches(pw, list));
}
/*
* Check for user described by pw in a list of members.
* If list is NULL compare against def_runas_default.
* Returns ALLOW, DENY or UNSPEC.
*/
int
runaslist_matches(list)
static int
_runaslist_matches(list)
struct member_list *list;
{
struct member *m;
@@ -174,7 +183,7 @@ runaslist_matches(list)
break;
case ALIAS:
if ((a = find_alias(m->name, RUNASALIAS)) != NULL) {
rval = runaslist_matches(&a->members);
rval = _runaslist_matches(&a->members);
if (rval != UNSPEC)
matched = m->negated ? !rval : rval;
break;
@@ -191,12 +200,20 @@ runaslist_matches(list)
return(matched);
}
int
runaslist_matches(list)
struct member_list *list;
{
alias_seqno++;
return(_runaslist_matches(list));
}
/*
* Check for host and shost in a list of members.
* Returns ALLOW, DENY or UNSPEC.
*/
int
hostlist_matches(list)
static int
_hostlist_matches(list)
struct member_list *list;
{
struct member *m;
@@ -218,7 +235,7 @@ hostlist_matches(list)
break;
case ALIAS:
if ((a = find_alias(m->name, HOSTALIAS)) != NULL) {
rval = hostlist_matches(&a->members);
rval = _hostlist_matches(&a->members);
if (rval != UNSPEC)
matched = m->negated ? !rval : rval;
break;
@@ -235,6 +252,43 @@ hostlist_matches(list)
return(matched);
}
int
hostlist_matches(list)
struct member_list *list;
{
alias_seqno++;
return(_hostlist_matches(list));
}
/*
* Check for cmnd and args in a list of members.
* Returns ALLOW, DENY or UNSPEC.
*/
static int
_cmndlist_matches(list)
struct member_list *list;
{
struct member *m;
int rval, matched = UNSPEC;
tq_foreach_rev(list, m) {
rval = cmnd_matches(m);
if (rval != UNSPEC) {
matched = m->negated ? !rval : rval;
break;
}
}
return(matched);
}
int
cmndlist_matches(list)
struct member_list *list;
{
alias_seqno++;
return(_cmndlist_matches(list));
}
/*
* Check cmnd and args.
* Returns ALLOW, DENY or UNSPEC.
@@ -252,8 +306,9 @@ cmnd_matches(m)
matched = !m->negated;
break;
case ALIAS:
alias_seqno++;
if ((a = find_alias(m->name, CMNDALIAS)) != NULL) {
rval = cmndlist_matches(&a->members);
rval = _cmndlist_matches(&a->members);
if (rval != UNSPEC)
matched = m->negated ? !rval : rval;
}
@@ -267,27 +322,6 @@ cmnd_matches(m)
return(matched);
}
/*
* Check for cmnd and args in a list of members.
* Returns ALLOW, DENY or UNSPEC.
*/
int
cmndlist_matches(list)
struct member_list *list;
{
struct member *m;
int rval, matched = UNSPEC;
tq_foreach_rev(list, m) {
rval = cmnd_matches(m);
if (rval != UNSPEC) {
matched = m->negated ? !rval : rval;
break;
}
}
return(matched);
}
/*
* If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
* otherwise, return TRUE if user_cmnd names one of the inodes in path.

14
parse.c
View File

@@ -464,7 +464,7 @@ display_cmnd(v, pw)
* Print the contents of a struct member to stdout
*/
static void
print_member(lbuf, name, type, negated, alias_type)
_print_member(lbuf, name, type, negated, alias_type)
struct lbuf *lbuf;
char *name;
int type, negated, alias_type;
@@ -492,7 +492,7 @@ print_member(lbuf, name, type, negated, alias_type)
tq_foreach_fwd(&a->members, m) {
if (m != tq_first(&a->members))
lbuf_append(lbuf, ", ", NULL);
print_member(lbuf, m->name, m->type,
_print_member(lbuf, m->name, m->type,
negated ? !m->negated : m->negated, alias_type);
}
break;
@@ -503,3 +503,13 @@ print_member(lbuf, name, type, negated, alias_type)
break;
}
}
static void
print_member(lbuf, name, type, negated, alias_type)
struct lbuf *lbuf;
char *name;
int type, negated, alias_type;
{
alias_seqno++;
_print_member(lbuf, name, type, negated, alias_type);
}

View File

@@ -119,6 +119,7 @@ struct member {
struct alias {
char *name; /* alias name */
int type; /* {USER,HOST,RUNAS,CMND}ALIAS */
unsigned int seqno; /* sequence number */
struct member_list members; /* list of alias members */
};
@@ -140,6 +141,11 @@ struct defaults {
extern struct userspec_list userspecs;
extern struct defaults_list defaults;
/*
* Alias sequence number to avoid loops.
*/
extern unsigned int alias_seqno;
/*
* Prototypes
*/