From 76e5eb434b48aca123eacfac8f6ac35b04f7eeb0 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 15 Sep 2007 11:24:54 +0000 Subject: [PATCH] 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. --- alias.c | 17 ++++++++-- match.c | 96 ++++++++++++++++++++++++++++++++++++++------------------- parse.c | 14 +++++++-- parse.h | 6 ++++ 4 files changed, 98 insertions(+), 35 deletions(-) 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 */