diff --git a/alias.c b/alias.c index 57495fb95..0e12a0f92 100644 --- a/alias.c +++ b/alias.c @@ -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); diff --git a/match.c b/match.c index fc9fd5127..5a31e0038 100644 --- a/match.c +++ b/match.c @@ -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. diff --git a/parse.c b/parse.c index ffe7c910a..9a3af430b 100644 --- a/parse.c +++ b/parse.c @@ -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); +} diff --git a/parse.h b/parse.h index ebc6b12a0..2ae610ef9 100644 --- a/parse.h +++ b/parse.h @@ -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 */