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 * Globals
*/ */
struct rbtree *aliases; struct rbtree *aliases;
unsigned int alias_seqno;
/* /*
* Local protoypes * Local protoypes
@@ -91,11 +92,22 @@ find_alias(name, type)
{ {
struct alias key; struct alias key;
struct rbnode *node; struct rbnode *node;
struct alias *a = NULL;
key.name = name; key.name = name;
key.type = type; key.type = type;
node = rbfind(aliases, &key); if ((node = rbfind(aliases, &key)) != NULL) {
return(node ? node->data : 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 = emalloc(sizeof(*a));
a->name = name; a->name = name;
a->type = type; a->type = type;
a->seqno = 0;
list2tq(&a->members, members); list2tq(&a->members, members);
if (rbinsert(aliases, a)) { if (rbinsert(aliases, a)) {
efree(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. * Check for user described by pw in a list of members.
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int static int
userlist_matches(pw, list) _userlist_matches(pw, list)
struct passwd *pw; struct passwd *pw;
struct member_list *list; struct member_list *list;
{ {
@@ -126,7 +126,7 @@ userlist_matches(pw, list)
break; break;
case ALIAS: case ALIAS:
if ((a = find_alias(m->name, USERALIAS)) != NULL) { if ((a = find_alias(m->name, USERALIAS)) != NULL) {
rval = userlist_matches(pw, &a->members); rval = _userlist_matches(pw, &a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
break; break;
@@ -143,13 +143,22 @@ userlist_matches(pw, list)
return(matched); 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. * Check for user described by pw in a list of members.
* If list is NULL compare against def_runas_default. * If list is NULL compare against def_runas_default.
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int static int
runaslist_matches(list) _runaslist_matches(list)
struct member_list *list; struct member_list *list;
{ {
struct member *m; struct member *m;
@@ -174,7 +183,7 @@ runaslist_matches(list)
break; break;
case ALIAS: case ALIAS:
if ((a = find_alias(m->name, RUNASALIAS)) != NULL) { if ((a = find_alias(m->name, RUNASALIAS)) != NULL) {
rval = runaslist_matches(&a->members); rval = _runaslist_matches(&a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
break; break;
@@ -191,12 +200,20 @@ runaslist_matches(list)
return(matched); 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. * Check for host and shost in a list of members.
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int static int
hostlist_matches(list) _hostlist_matches(list)
struct member_list *list; struct member_list *list;
{ {
struct member *m; struct member *m;
@@ -218,7 +235,7 @@ hostlist_matches(list)
break; break;
case ALIAS: case ALIAS:
if ((a = find_alias(m->name, HOSTALIAS)) != NULL) { if ((a = find_alias(m->name, HOSTALIAS)) != NULL) {
rval = hostlist_matches(&a->members); rval = _hostlist_matches(&a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
break; break;
@@ -235,6 +252,43 @@ hostlist_matches(list)
return(matched); 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. * Check cmnd and args.
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
@@ -252,8 +306,9 @@ cmnd_matches(m)
matched = !m->negated; matched = !m->negated;
break; break;
case ALIAS: case ALIAS:
alias_seqno++;
if ((a = find_alias(m->name, CMNDALIAS)) != NULL) { if ((a = find_alias(m->name, CMNDALIAS)) != NULL) {
rval = cmndlist_matches(&a->members); rval = _cmndlist_matches(&a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
} }
@@ -267,27 +322,6 @@ cmnd_matches(m)
return(matched); 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; * 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. * 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 * Print the contents of a struct member to stdout
*/ */
static void static void
print_member(lbuf, name, type, negated, alias_type) _print_member(lbuf, name, type, negated, alias_type)
struct lbuf *lbuf; struct lbuf *lbuf;
char *name; char *name;
int type, negated, alias_type; int type, negated, alias_type;
@@ -492,7 +492,7 @@ print_member(lbuf, name, type, negated, alias_type)
tq_foreach_fwd(&a->members, m) { tq_foreach_fwd(&a->members, m) {
if (m != tq_first(&a->members)) if (m != tq_first(&a->members))
lbuf_append(lbuf, ", ", NULL); 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); negated ? !m->negated : m->negated, alias_type);
} }
break; break;
@@ -503,3 +503,13 @@ print_member(lbuf, name, type, negated, alias_type)
break; 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 { struct alias {
char *name; /* alias name */ char *name; /* alias name */
int type; /* {USER,HOST,RUNAS,CMND}ALIAS */ int type; /* {USER,HOST,RUNAS,CMND}ALIAS */
unsigned int seqno; /* sequence number */
struct member_list members; /* list of alias members */ struct member_list members; /* list of alias members */
}; };
@@ -140,6 +141,11 @@ struct defaults {
extern struct userspec_list userspecs; extern struct userspec_list userspecs;
extern struct defaults_list defaults; extern struct defaults_list defaults;
/*
* Alias sequence number to avoid loops.
*/
extern unsigned int alias_seqno;
/* /*
* Prototypes * Prototypes
*/ */