From: Todd C. Miller Date: Thu, 30 Aug 2007 17:26:35 +0000 (+0000) Subject: Use a list head struct when storing the semi-circular lists and X-Git-Tag: SUDO_1_7_0~397 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8cdea0b941d3f7abd67b40bace89812c073fa3d9;p=sudo Use a list head struct when storing the semi-circular lists and convert to tail queues in the process. This will allow us to reverse foreach loops more easily and it makes it clearer which functions expect a list as opposed to a single member. Add macros for manipulating lists. Some of these should become functions. When freeing up a list, just pop off the last item in the queue instead of going from head to tail. This is simpler since we don't have to stash a pointer to the next member, we always just use the last one in the queue until the queue is empty. Rename match functions that take a list to have list in the name. Break cmnd_matches() into cmnd_matches() and cmndlist_matches. --- diff --git a/alias.c b/alias.c index e0a974cf4..847131a54 100644 --- a/alias.c +++ b/alias.c @@ -114,7 +114,7 @@ alias_add(name, type, members) a = emalloc(sizeof(*a)); a->name = name; a->type = type; - a->first_member = members; + LIST2HEAD(a->members, members); if (rbinsert(aliases, a)) { efree(a); snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name); @@ -154,7 +154,7 @@ alias_free(v) struct member *m; VOID *next; - for (m = a->first_member; m != NULL; m = next) { + for (m = a->members.first; m != NULL; m = next) { next = m->next; efree(m->name); efree(m); diff --git a/defaults.c b/defaults.c index ea533089c..ec016b879 100644 --- a/defaults.c +++ b/defaults.c @@ -92,8 +92,6 @@ static struct strmap priorities[] = { { NULL, -1 } }; -extern struct defaults *defaults; - /* * Local prototypes. */ @@ -503,7 +501,7 @@ update_defaults(skip_cmnd) { struct defaults *def; - for (def = defaults; def != NULL; def = def->next) { + LH_FOREACH_FWD(defaults, def) { if (skip_cmnd == (def->type == DEFAULTS_CMND)) continue; switch (def->type) { @@ -511,22 +509,22 @@ update_defaults(skip_cmnd) if (!set_default(def->var, def->val, def->op)) return(FALSE); case DEFAULTS_USER: - if (user_matches(sudo_user.pw, def->binding) && + if (userlist_matches(sudo_user.pw, &def->binding) && !set_default(def->var, def->val, def->op)) return(FALSE); break; case DEFAULTS_RUNAS: - if (runas_matches(def->binding) && + if (runaslist_matches(&def->binding) && !set_default(def->var, def->val, def->op)) return(FALSE); break; case DEFAULTS_HOST: - if (host_matches(def->binding) && + if (hostlist_matches(&def->binding) && !set_default(def->var, def->val, def->op)) return(FALSE); break; case DEFAULTS_CMND: - if (cmnd_matches(def->binding) && + if (cmndlist_matches(&def->binding) && !set_default(def->var, def->val, def->op)) return(FALSE); } diff --git a/gram.y b/gram.y index ebe99ff80..3178ed559 100644 --- a/gram.y +++ b/gram.y @@ -67,8 +67,8 @@ int verbose = FALSE; int errorlineno = -1; char *errorfile = NULL; -struct defaults *defaults; -struct userspec *userspecs; +struct defaults_list defaults; +struct userspec_list userspecs; /* * Local protoypes @@ -242,8 +242,8 @@ privilege : hostlist '=' cmndspeclist { struct cmndtag tags; struct privilege *p = emalloc(sizeof(*p)); struct cmndspec *cs; - p->hostlist = $1; - p->cmndlist = $3; + LIST2HEAD(p->hostlist, $1); + LIST2HEAD(p->cmndlist, $3); tags.nopasswd = tags.noexec = tags.setenv = UNSPEC; /* propagate tags */ for (cs = $3; cs != NULL; cs = cs->next) { @@ -297,7 +297,7 @@ cmndspeclist : cmndspec cmndspec : runasspec cmndtag opcmnd { struct cmndspec *cs = emalloc(sizeof(*cs)); - cs->runaslist = $1; + LIST2HEAD(cs->runaslist, $1); cs->tags = $2; cs->cmnd = $3; cs->prev = cs; @@ -514,12 +514,9 @@ add_defaults(type, binding, defs) */ for (d = defs; d != NULL; d = d->next) { d->type = type; - d->binding = binding; + LIST2HEAD(d->binding, binding); } - if (defaults == NULL) - defaults = defs; - else - LIST_APPEND(defaults, defs); + HEAD_APPEND(defaults, defs); } /* @@ -534,14 +531,11 @@ add_userspec(members, privs) struct userspec *u; u = emalloc(sizeof(*u)); - u->user = members; - u->privileges = privs; + LIST2HEAD(u->users, members); + LIST2HEAD(u->privileges, privs); u->prev = u; u->next = NULL; - if (userspecs == NULL) - userspecs = u; - else - LIST_APPEND(userspecs, u); + HEAD_APPEND(userspecs, u); } /* @@ -558,55 +552,53 @@ init_parser(path, quiet) struct userspec *us; struct privilege *priv; struct cmndspec *cs; - VOID *next; - for (us = userspecs; us != NULL; us = next) { - for (m = us->user; m != NULL; m = next) { - next = m->next; + while ((us = LH_LAST(userspecs)) != NULL) { + LH_POP(userspecs); + while ((m = LH_LAST(us->users)) != NULL) { + LH_POP(us->users); efree(m->name); efree(m); } - for (priv = us->privileges; priv != NULL; priv = next) { - for (m = priv->hostlist; m != NULL; m = next) { - next = m->next; + while ((priv = LH_LAST(us->privileges)) != NULL) { + LH_POP(us->privileges); + while ((m = LH_LAST(priv->hostlist)) != NULL) { + LH_POP(priv->hostlist); efree(m->name); efree(m); } - for (cs = priv->cmndlist; cs != NULL; cs = next) { - for (m = cs->runaslist; m != NULL; m = next) { - next = m->next; + while ((cs = LH_LAST(priv->cmndlist)) != NULL) { + LH_POP(priv->cmndlist); + while ((m = LH_LAST(cs->runaslist)) != NULL) { + LH_POP(cs->runaslist); efree(m->name); efree(m); } efree(cs->cmnd->name); efree(cs->cmnd); - next = cs->next; efree(cs); } - next = priv->next; efree(priv); } - next = us->next; - efree(us); } - userspecs = NULL; + LH_INIT(userspecs); lastbinding = NULL; - for (d = defaults; d != NULL; d = next) { - if (d->binding != lastbinding) { - for (m = d->binding; m != NULL; m = next) { - next = m->next; + while ((d = LH_LAST(defaults)) != NULL) { + LH_POP(defaults); + if (LH_FIRST(d->binding) != lastbinding) { + lastbinding = LH_FIRST(d->binding); + while ((m = LH_LAST(d->binding)) != NULL) { + LH_POP(d->binding); efree(m->name); efree(m); } - lastbinding = d->binding; } - next = d->next; efree(d->var); efree(d->val); efree(d); } - defaults = NULL; + LH_INIT(defaults); init_aliases(); diff --git a/match.c b/match.c index 266f86ac5..0597dfc99 100644 --- a/match.c +++ b/match.c @@ -103,15 +103,15 @@ static int has_meta __P((char *)); * Returns ALLOW, DENY or UNSPEC. */ int -user_matches(pw, list) +userlist_matches(pw, list) struct passwd *pw; - struct member *list; + struct member_list *list; { struct member *m; struct alias *a; int rval, matched = UNSPEC; - for (m = list; m != NULL; m = m->next) { + for (m = list->first; m != NULL; m = m->next) { switch (m->type) { case ALL: matched = !m->negated; @@ -126,7 +126,7 @@ user_matches(pw, list) break; case ALIAS: if ((a = find_alias(m->name, USERALIAS)) != NULL) { - rval = user_matches(pw, a->first_member); + rval = userlist_matches(pw, &a->members); if (rval != UNSPEC) matched = m->negated ? !rval : rval; break; @@ -147,8 +147,8 @@ user_matches(pw, list) * Returns ALLOW, DENY or UNSPEC. */ int -runas_matches(list) - struct member *list; +runaslist_matches(list) + struct member_list *list; { struct member *m; struct alias *a; @@ -157,7 +157,7 @@ runas_matches(list) if (list == NULL) return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw)); - for (m = list; m != NULL; m = m->next) { + for (m = list->first; m != NULL; m = m->next) { switch (m->type) { case ALL: matched = !m->negated; @@ -172,7 +172,7 @@ runas_matches(list) break; case ALIAS: if ((a = find_alias(m->name, RUNASALIAS)) != NULL) { - rval = runas_matches(a->first_member); + rval = runaslist_matches(&a->members); if (rval != UNSPEC) matched = m->negated ? !rval : rval; break; @@ -192,14 +192,14 @@ runas_matches(list) * Returns ALLOW, DENY or UNSPEC. */ int -host_matches(list) - struct member *list; +hostlist_matches(list) + struct member_list *list; { struct member *m; struct alias *a; int rval, matched = UNSPEC; - for (m = list; m != NULL; m = m->next) { + for (m = list->first; m != NULL; m = m->next) { switch (m->type) { case ALL: matched = !m->negated; @@ -214,7 +214,7 @@ host_matches(list) break; case ALIAS: if ((a = find_alias(m->name, HOSTALIAS)) != NULL) { - rval = host_matches(a->first_member); + rval = hostlist_matches(&a->members); if (rval != UNSPEC) matched = m->negated ? !rval : rval; break; @@ -230,36 +230,52 @@ host_matches(list) } /* - * Check for cmnd and args in a list of members. + * Check cmnd and args. * Returns ALLOW, DENY or UNSPEC. */ int -cmnd_matches(list) - struct member *list; -{ - struct sudo_command *c; +cmnd_matches(m) struct member *m; +{ struct alias *a; + struct sudo_command *c; int rval, matched = UNSPEC; - for (m = list; m != NULL; m = m->next) { - switch (m->type) { - case ALL: + switch (m->type) { + case ALL: + matched = !m->negated; + break; + case ALIAS: + if ((a = find_alias(m->name, CMNDALIAS)) != NULL) { + rval = cmndlist_matches(&a->members); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; + } + break; + case COMMAND: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args)) matched = !m->negated; - break; - case ALIAS: - if ((a = find_alias(m->name, CMNDALIAS)) != NULL) { - rval = cmnd_matches(a->first_member); - if (rval != UNSPEC) - matched = m->negated ? !rval : rval; - } - break; - case COMMAND: - c = (struct sudo_command *)m->name; - if (command_matches(c->cmnd, c->args)) - matched = !m->negated; - break; - } + break; + } + 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; + + for (m = list->first; m != NULL; m = m->next) { + rval = cmnd_matches(m); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; } return(matched); } diff --git a/parse.c b/parse.c index c32ceb3c6..56ff01bef 100644 --- a/parse.c +++ b/parse.c @@ -55,12 +55,6 @@ __unused static const char rcsid[] = "$Sudo$"; /* Characters that must be quoted in sudoers */ #define SUDOERS_QUOTED "*?[]!:\\,=#\"" -/* - * Parsed sudoers info. - */ -extern struct userspec *userspecs; -extern struct defaults *defaults; - /* * Local prototypes. */ @@ -93,7 +87,7 @@ sudoers_lookup(pwflag) int validated, match, host_match, runas_match, cmnd_match; struct cmndspec *cs; struct cmndtag *tags = NULL; - struct member *runas; + struct member_list *runas; struct privilege *priv; struct userspec *us; @@ -116,13 +110,15 @@ sudoers_lookup(pwflag) CLR(validated, FLAG_NO_USER); CLR(validated, FLAG_NO_HOST); match = DENY; - for (us = userspecs; us != NULL; us = us->next) { - if (user_matches(sudo_user.pw, us->user) != ALLOW) + /* XXX - it should be faster to start from the bottom and + work our way up and then just stop at the first match. */ + LH_FOREACH_FWD(userspecs, us) { + if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) continue; - for (priv = us->privileges; priv != NULL; priv = priv->next) { - if (host_matches(priv->hostlist) != ALLOW) + LH_FOREACH_FWD(us->privileges, priv) { + if (hostlist_matches(&priv->hostlist) != ALLOW) continue; - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { + LH_FOREACH_FWD(priv->cmndlist, cs) { /* Only check the command when listing another user. */ if (user_uid == 0 || list_pw == NULL || user_uid == list_pw->pw_uid || @@ -149,22 +145,24 @@ sudoers_lookup(pwflag) /* Need to be runas user while stat'ing things. */ set_perms(PERM_RUNAS); + /* XXX - it should be faster to start from the bottom and + work our way up and then just stop at the first match. */ match = UNSPEC; - for (us = userspecs; us != NULL; us = us->next) { - if (user_matches(sudo_user.pw, us->user) != ALLOW) + LH_FOREACH_FWD(userspecs, us) { + if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) continue; CLR(validated, FLAG_NO_USER); - for (priv = us->privileges; priv != NULL; priv = priv->next) { - host_match = host_matches(priv->hostlist); + LH_FOREACH_FWD(us->privileges, priv) { + host_match = hostlist_matches(&priv->hostlist); if (host_match == UNSPEC) continue; if (host_match == ALLOW) CLR(validated, FLAG_NO_HOST); runas = NULL; - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { - if (cs->runaslist != NULL) - runas = cs->runaslist; - runas_match = runas_matches(runas); + LH_FOREACH_FWD(priv->cmndlist, cs) { + if (!LH_EMPTY(cs->runaslist)) + runas = &cs->runaslist; + runas_match = runaslist_matches(runas); if (runas_match != UNSPEC) { cmnd_match = cmnd_matches(cs->cmnd); if (cmnd_match != UNSPEC) @@ -229,23 +227,24 @@ display_privs(v, pw) printf("User %s may run the following commands on this host:\n", pw->pw_name); - for (us = userspecs; us != NULL; us = us->next) { - if (user_matches(pw, us->user) != ALLOW || - host_matches(us->privileges->hostlist) != ALLOW) + LH_FOREACH_FWD(userspecs, us) { + /* XXX - why only check the first privilege here? */ + if (userlist_matches(pw, &us->users) != ALLOW || + hostlist_matches(&us->privileges.first->hostlist) != ALLOW) continue; - for (priv = us->privileges; priv != NULL; priv = priv->next) { + LH_FOREACH_FWD(us->privileges, priv) { tags.noexec = def_noexec; tags.setenv = def_setenv; tags.nopasswd = !def_authenticate; lbuf_append(&lbuf, " ", NULL); - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { - if (cs != priv->cmndlist) + LH_FOREACH_FWD(priv->cmndlist, cs) { + if (cs != LH_FIRST(priv->cmndlist)) lbuf_append(&lbuf, ", ", NULL); lbuf_append(&lbuf, "(", NULL); - if (cs->runaslist != NULL) { - for (m = cs->runaslist; m != NULL; m = m->next) { - if (m != cs->runaslist) + if (!LH_EMPTY(cs->runaslist)) { + LH_FOREACH_FWD(cs->runaslist, m) { + if (m != LH_FIRST(cs->runaslist)) lbuf_append(&lbuf, ", ", NULL); print_member(&lbuf, m->name, m->type, m->negated, RUNASALIAS); @@ -293,19 +292,19 @@ display_defaults(pw) { struct defaults *d; struct lbuf lbuf; - char *prefix; + char *prefix = NULL; int per_runas = 0, per_cmnd = 0; lbuf_init(&lbuf, NULL, 4, 0); - for (d = defaults, prefix = NULL; d != NULL; d = d->next) { + LH_FOREACH_FWD(defaults, d) { switch (d->type) { case DEFAULTS_HOST: - if (host_matches(d->binding) != ALLOW) + if (hostlist_matches(&d->binding) != ALLOW) continue; break; case DEFAULTS_USER: - if (user_matches(pw, d->binding) != ALLOW) + if (userlist_matches(pw, &d->binding) != ALLOW) continue; break; case DEFAULTS_RUNAS: @@ -355,7 +354,7 @@ display_bound_defaults(dtype) { struct lbuf lbuf; struct defaults *d; - struct member *m, *binding; + struct member *m, *binding = NULL; char *dname, *dsep; int atype; @@ -385,12 +384,12 @@ display_bound_defaults(dtype) } lbuf_init(&lbuf, NULL, 4, 0); printf("Per-%s Defaults entries:\n", dname); - for (d = defaults, binding = NULL; d != NULL; d = d->next) { + LH_FOREACH_FWD(defaults, d) { if (d->type != dtype) continue; - if (d->binding != binding) { - binding = d->binding; + if (binding != LH_FIRST(d->binding)) { + binding = LH_FIRST(d->binding); lbuf_append(&lbuf, " Defaults", dsep, NULL); for (m = binding; m != NULL; m = m->next) { if (m != binding) @@ -421,7 +420,8 @@ display_cmnd(v, pw) struct passwd *pw; { struct cmndspec *cs; - struct member *match, *runas; + struct member *match; + struct member_list *runas; struct privilege *priv; struct userspec *us; int rval = 1; @@ -432,19 +432,20 @@ display_cmnd(v, pw) rval = sudo_ldap_display_cmnd(v, pw); #endif if (rval != 0 && !def_ignore_local_sudoers) { - for (match = NULL, us = userspecs; us != NULL; us = us->next) { - if (user_matches(pw, us->user) != ALLOW) + match = NULL; + LH_FOREACH_FWD(userspecs, us) { + if (userlist_matches(pw, &us->users) != ALLOW) continue; - for (priv = us->privileges; priv != NULL; priv = priv->next) { - host_match = host_matches(priv->hostlist); + LH_FOREACH_FWD(us->privileges, priv) { + host_match = hostlist_matches(&priv->hostlist); if (host_match == UNSPEC) continue; runas = NULL; - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { - if (cs->runaslist != NULL) - runas = cs->runaslist; - runas_match = runas_matches(runas); + LH_FOREACH_FWD(priv->cmndlist, cs) { + if (!LH_EMPTY(cs->runaslist) != NULL) + runas = &cs->runaslist; + runas_match = runaslist_matches(runas); if (runas_match != UNSPEC) { cmnd_match = cmnd_matches(cs->cmnd); if (cmnd_match != UNSPEC) @@ -492,8 +493,8 @@ print_member(lbuf, name, type, negated, alias_type) break; case ALIAS: if ((a = find_alias(name, alias_type)) != NULL) { - for (m = a->first_member; m != NULL; m = m->next) { - if (m != a->first_member) + LH_FOREACH_FWD(a->members, m) { + if (m != LH_FIRST(a->members)) lbuf_append(lbuf, ", ", NULL); print_member(lbuf, m->name, m->type, negated ? !m->negated : m->negated, alias_type); diff --git a/parse.h b/parse.h index 6d14ca3c8..b181f414c 100644 --- a/parse.h +++ b/parse.h @@ -60,12 +60,40 @@ struct cmndtag { * pointer of the last entry is NULL and does not point back to the head. */ +/* + * Tail queue list head structure. + */ +struct defaults_list { + struct defaults *first; + struct defaults *last; +}; + +struct userspec_list { + struct userspec *first; + struct userspec *last; +}; + +struct member_list { + struct member *first; + struct member *last; +}; + +struct privilege_list { + struct privilege *first; + struct privilege *last; +}; + +struct cmndspec_list { + struct cmndspec *first; + struct cmndspec *last; +}; + /* * Structure describing a user specification and list thereof. */ struct userspec { - struct member *user; /* list of users */ - struct privilege *privileges; /* list of privileges */ + struct member_list users; /* list of users */ + struct privilege_list privileges; /* list of privileges */ struct userspec *prev, *next; }; @@ -73,8 +101,8 @@ struct userspec { * Structure describing a privilege specification. */ struct privilege { - struct member *hostlist; /* list of hosts */ - struct cmndspec *cmndlist; /* list of Cmnd_Specs */ + struct member_list hostlist; /* list of hosts */ + struct cmndspec_list cmndlist; /* list of Cmnd_Specs */ struct privilege *prev, *next; }; @@ -82,7 +110,7 @@ struct privilege { * Structure describing a linked list of Cmnd_Specs. */ struct cmndspec { - struct member *runaslist; /* list of runas users */ + struct member_list runaslist; /* list of runas users */ struct member *cmnd; /* command to allow/deny */ struct cmndtag tags; /* tag specificaion */ struct cmndspec *prev, *next; @@ -105,7 +133,7 @@ struct member { struct alias { char *name; /* alias name */ int type; /* {USER,HOST,RUNAS,CMND}ALIAS */ - struct member *first_member; /* list of alias members */ + struct member_list members; /* list of alias members */ }; /* @@ -114,7 +142,7 @@ struct alias { struct defaults { char *var; /* variable name */ char *val; /* variable value */ - struct member *binding; /* user/host/runas binding */ + struct member_list binding; /* user/host/runas binding */ int type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */ int op; /* TRUE, FALSE, '+', '-' */ struct defaults *prev, *next; @@ -123,6 +151,7 @@ struct defaults { /* * Allocate space for a defaults entry and populate it. */ +#undef NEW_DEFAULT #define NEW_DEFAULT(r, v1, v2, o) do { \ (r) = emalloc(sizeof(struct defaults)); \ (r)->var = (v1); \ @@ -135,6 +164,7 @@ struct defaults { /* * Allocate space for a member and populate it. */ +#undef NEW_MEMBER #define NEW_MEMBER(r, n, t) do { \ (r) = emalloc(sizeof(struct member)); \ (r)->name = (n); \ @@ -147,6 +177,7 @@ struct defaults { * Append one queue (or single entry) to another using the * circular properties of the prev pointer to simplify the logic. */ +#undef LIST_APPEND #define LIST_APPEND(h, e) do { \ void *_tail = (e)->prev; \ (h)->prev->next = (e); \ @@ -154,6 +185,88 @@ struct defaults { (h)->prev = _tail; \ } while (0) +/* + * Append the list of entries to the head node and convert + * e from a semi-circle queue to normal doubly-linked list. + */ +#undef HEAD_APPEND +#define HEAD_APPEND(h, e) do { \ + void *_tail = (e)->prev; \ + if ((h).first == NULL) \ + (h).first = (e); \ + else \ + (h).last->next = (e); \ + (e)->prev = (h).last; \ + (h).last = _tail; \ +} while (0) + +/* + * Convert from a semi-circle queue to normal doubly-linked list + * with a head node. + */ +#undef LIST2HEAD +#define LIST2HEAD(h, e) do { \ + if ((e) != NULL) { \ + (h).first = (e); \ + (h).last = (e)->prev; \ + (e)->prev = NULL; \ + } else { \ + (h).first = NULL; \ + (h).last = NULL; \ + } \ +} while (0) + +#undef LH_FOREACH_FWD +#define LH_FOREACH_FWD(h, v) \ + for ((v) = (h).first; (v) != NULL; (v) = (v)->next) + +#undef LH_FOREACH_REV +#define LH_FOREACH_REV(h, v) \ + for ((v) = (h).last; (v) != NULL; (v) = (v)->prev) + +/* + * Pop the last element off the end of h. + * XXX - really should return the popped element. + */ +#undef LH_POP +#define LH_POP(h) do { \ + if (!LH_EMPTY(h)) { \ + if ((h).first == (h).last) \ + (h).first = (h).last = NULL; \ + else { \ + (h).last = (h).last->prev; \ + (h).last->next = NULL; \ + } \ + } \ +} while (0) + +#undef LH_INIT +#define LH_INIT(h) do { \ + (h).first = NULL; \ + (h).last = NULL; \ +} while (0) + +#undef LH_EMPTY +#define LH_EMPTY(h) ((h).first == NULL) + +#undef LH_FIRST +#define LH_FIRST(h) ((h).first) + +#undef LH_LAST +#define LH_LAST(h) ((h).last) + +#undef LIST_NEXT +#define LIST_NEXT(e) ((e)->next) + +#undef LIST_PREV +#define LIST_PREV(e) ((e)->prev) + +/* + * Parsed sudoers info. + */ +extern struct userspec_list userspecs; +extern struct defaults_list defaults; + /* * Prototypes */ @@ -161,13 +274,14 @@ char *alias_add __P((char *, int, struct member *)); int addr_matches __P((char *)); int alias_remove __P((char *, int)); int cmnd_matches __P((struct member *)); +int cmndlist_matches __P((struct member_list *)); int command_matches __P((char *, char *)); -int host_matches __P((struct member *)); +int hostlist_matches __P((struct member_list *)); int hostname_matches __P((char *, char *, char *)); int netgr_matches __P((char *, char *, char *, char *)); int no_aliases __P((void)); -int runas_matches __P((struct member *)); -int user_matches __P((struct passwd *, struct member *)); +int runaslist_matches __P((struct member_list *)); +int userlist_matches __P((struct passwd *, struct member_list *)); int usergr_matches __P((char *, char *, struct passwd *)); int userpw_matches __P((char *, char *, struct passwd *)); struct alias *find_alias __P((char *, int)); diff --git a/testsudoers.c b/testsudoers.c index a1f7a54b8..cf9a0b4f6 100644 --- a/testsudoers.c +++ b/testsudoers.c @@ -99,9 +99,6 @@ struct passwd *(*my_getpwuid) __P((uid_t)) = getpwuid; extern char *optarg; extern int optind; -extern struct defaults *defaults; -extern struct userspec *userspecs; - int print_alias __P((VOID *, VOID *)); void dump_sudoers __P((void)); void print_defaults __P((void)); @@ -128,7 +125,7 @@ main(argc, argv) char **argv; { struct cmndspec *cs; - struct member *runas; + struct member_list *runas; struct privilege *priv; struct userspec *us; char *p, *grfile, *pwfile, *uflag, hbuf[MAXHOSTNAMELEN]; @@ -272,20 +269,20 @@ main(argc, argv) /* This loop must match the one in sudoers_lookup() */ printf("\nEntries for user %s:\n", user_name); matched = UNSPEC; - for (us = userspecs; us != NULL; us = us->next) { - if (user_matches(sudo_user.pw, us->user) != TRUE) + LH_FOREACH_FWD(userspecs, us) { + if (userlist_matches(sudo_user.pw, &us->users) != TRUE) continue; - for (priv = us->privileges; priv != NULL; priv = priv->next) { + LH_FOREACH_FWD(us->privileges, priv) { putchar('\n'); - print_privilege(priv); + print_privilege(priv); /* XXX */ putchar('\n'); - if (host_matches(priv->hostlist) == TRUE) { + if (hostlist_matches(&priv->hostlist) == TRUE) { puts("\thost matched"); runas = NULL; - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { - if (cs->runaslist != NULL) - runas = cs->runaslist; - if (runas_matches(runas) == TRUE) { + LH_FOREACH_FWD(priv->cmndlist, cs) { + if (!LH_EMPTY(cs->runaslist)) + runas = &cs->runaslist; + if (runaslist_matches(runas) == TRUE) { puts("\trunas matched"); rval = cmnd_matches(cs->cmnd); if (rval != UNSPEC) @@ -391,7 +388,7 @@ print_defaults() struct defaults *d; struct member *m; - for (d = defaults; d != NULL; d = d->next) { + LH_FOREACH_FWD(defaults, d) { (void) fputs("Defaults", stdout); switch (d->type) { case DEFAULTS_HOST: @@ -407,8 +404,8 @@ print_defaults() putchar('!'); break; } - for (m = d->binding; m != NULL; m = m->next) { - if (m != d->binding) + LH_FOREACH_FWD(d->binding, m) { + if (m != LH_FIRST(d->binding)) putchar(','); print_member(m); } @@ -442,8 +439,8 @@ print_alias(v1, v2) (void) printf("Runas_Alias\t%s = ", a->name); break; } - for (m = a->first_member; m != NULL; m = m->next) { - if (m != a->first_member) + LH_FOREACH_FWD(a->members, m) { + if (m != LH_FIRST(a->members)) fputs(", ", stdout); if (m->type == COMMAND) { c = (struct sudo_command *) m->name; @@ -468,20 +465,20 @@ print_privilege(priv) for (p = priv; p != NULL; p = p->next) { if (p != priv) fputs(" : ", stdout); - for (m = p->hostlist; m != NULL; m = m->next) { - if (m != p->hostlist) + LH_FOREACH_FWD(p->hostlist, m) { + if (m != LH_FIRST(p->hostlist)) fputs(", ", stdout); print_member(m); } fputs(" = ", stdout); tags.nopasswd = tags.noexec = UNSPEC; - for (cs = p->cmndlist; cs != NULL; cs = cs->next) { - if (cs != p->cmndlist) + LH_FOREACH_FWD(p->cmndlist, cs) { + if (cs != LH_FIRST(p->cmndlist)) fputs(", ", stdout); - if (cs->runaslist) { + if (!LH_EMPTY(cs->runaslist)) { fputs("(", stdout); - for (m = cs->runaslist; m != NULL; m = m->next) { - if (m != cs->runaslist) + LH_FOREACH_FWD(cs->runaslist, m) { + if (m != LH_FIRST(cs->runaslist)) fputs(", ", stdout); print_member(m); } @@ -503,14 +500,14 @@ print_userspecs() struct member *m; struct userspec *us; - for (us = userspecs; us != NULL; us = us->next) { - for (m = us->user; m != NULL; m = m->next) { - if (m != us->user) + LH_FOREACH_FWD(userspecs, us) { + LH_FOREACH_FWD(us->users, m) { + if (m != LH_FIRST(us->users)) fputs(", ", stdout); print_member(m); } putchar('\t'); - print_privilege(us->privileges); + print_privilege(us->privileges.first); /* XXX */ putchar('\n'); } } diff --git a/visudo.c b/visudo.c index 4834365cc..59954857c 100644 --- a/visudo.c +++ b/visudo.c @@ -128,9 +128,6 @@ extern int errorlineno, parse_error; extern char *optarg; extern int optind; -extern struct defaults *defaults; -extern struct userspec *userspecs; - /* * Globals */ @@ -215,8 +212,8 @@ main(argc, argv) setup_signals(); /* Edit the sudoers file(s) */ - for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { - if (sp != sudoerslist.first) { + LH_FOREACH_FWD(sudoerslist, sp) { + if (sp != LH_FIRST(sudoerslist)) { printf("press return to edit %s: ", sp->path); while ((ch = getchar()) != EOF && ch != '\n') continue; @@ -228,7 +225,7 @@ main(argc, argv) reparse_sudoers(editor, args, strict, quiet); /* Install the sudoers temp files. */ - for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { + LH_FOREACH_FWD(sudoerslist, sp) { if (!sp->modified) (void) unlink(sp->tpath); else @@ -403,8 +400,8 @@ reparse_sudoers(editor, args, strict, quiet) * Parse the edited sudoers files and do sanity checking */ do { - sp = sudoerslist.first; - last = sudoerslist.last; + sp = LH_FIRST(sudoerslist); + last = LH_LAST(sudoerslist); fp = fopen(sp->tpath, "r+"); if (fp == NULL) errorx(1, "can't re-open temporary file (%s), %s unchanged.", @@ -440,7 +437,7 @@ reparse_sudoers(editor, args, strict, quiet) } if (parse_error) { /* Edit file with the parse error */ - for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { + LH_FOREACH_FWD(sudoerslist, sp) { if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { edit_sudoers(sp, editor, args, errorlineno); break; @@ -711,7 +708,7 @@ open_sudoers(path, keepopen) FILE *fp; /* Check for existing entry */ - for (entry = sudoerslist.first; entry != NULL; entry = entry->next) { + LH_FOREACH_FWD(sudoerslist, entry) { if (strcmp(path, entry->path) == 0) break; } @@ -731,6 +728,7 @@ open_sudoers(path, keepopen) errorx(1, "%s busy, try again later", entry->path); if ((fp = fdopen(entry->fd, "r")) == NULL) error(1, "%s", entry->path); + /* XXX - macro here? */ if (sudoerslist.last == NULL) sudoerslist.first = sudoerslist.last = entry; else { @@ -888,8 +886,8 @@ check_aliases(strict) int error = 0; /* Forward check. */ - for (us = userspecs; us != NULL; us = us->next) { - for (m = us->user; m != NULL; m = m->next) { + LH_FOREACH_FWD(userspecs, us) { + LH_FOREACH_FWD(us->users, m) { if (m->type == USERALIAS) { if (find_alias(m->name, m->type) == NULL) { fprintf(stderr, @@ -899,8 +897,8 @@ check_aliases(strict) } } } - for (priv = us->privileges; priv != NULL; priv = priv->next) { - for (m = priv->hostlist; m != NULL; m = m->next) { + LH_FOREACH_FWD(us->privileges, priv) { + LH_FOREACH_FWD(priv->hostlist, m) { if (m->type == HOSTALIAS) { if (find_alias(m->name, m->type) == NULL) { fprintf(stderr, @@ -910,8 +908,8 @@ check_aliases(strict) } } } - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { - for (m = cs->runaslist; m != NULL; m = m->next) { + LH_FOREACH_FWD(priv->cmndlist, cs) { + LH_FOREACH_FWD(cs->runaslist, m) { if (m->type == RUNASALIAS) { if (find_alias(m->name, m->type) == NULL) { fprintf(stderr, @@ -934,18 +932,18 @@ check_aliases(strict) } /* Reverse check (destructive) */ - for (us = userspecs; us != NULL; us = us->next) { - for (m = us->user; m != NULL; m = m->next) { + LH_FOREACH_FWD(userspecs, us) { + LH_FOREACH_FWD(us->users, m) { if (m->type == USERALIAS) (void) alias_remove(m->name, m->type); } - for (priv = us->privileges; priv != NULL; priv = priv->next) { - for (m = priv->hostlist; m != NULL; m = m->next) { + LH_FOREACH_FWD(us->privileges, priv) { + LH_FOREACH_FWD(priv->hostlist, m) { if (m->type == HOSTALIAS) (void) alias_remove(m->name, m->type); } - for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { - for (m = cs->runaslist; m != NULL; m = m->next) { + LH_FOREACH_FWD(priv->cmndlist, cs) { + LH_FOREACH_FWD(cs->runaslist, m) { if (m->type == RUNASALIAS) (void) alias_remove(m->name, m->type); } @@ -985,7 +983,7 @@ cleanup(gotsignal) { struct sudoersfile *sp; - for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { + LH_FOREACH_FWD(sudoerslist, sp) { if (sp->tpath != NULL) (void) unlink(sp->tpath); }