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.
This commit is contained in:
Todd C. Miller
2007-08-30 17:26:35 +00:00
parent a05abf5c88
commit 8cdea0b941
8 changed files with 307 additions and 191 deletions

View File

@@ -114,7 +114,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->first_member = members; LIST2HEAD(a->members, members);
if (rbinsert(aliases, a)) { if (rbinsert(aliases, a)) {
efree(a); efree(a);
snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name); snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
@@ -154,7 +154,7 @@ alias_free(v)
struct member *m; struct member *m;
VOID *next; VOID *next;
for (m = a->first_member; m != NULL; m = next) { for (m = a->members.first; m != NULL; m = next) {
next = m->next; next = m->next;
efree(m->name); efree(m->name);
efree(m); efree(m);

View File

@@ -92,8 +92,6 @@ static struct strmap priorities[] = {
{ NULL, -1 } { NULL, -1 }
}; };
extern struct defaults *defaults;
/* /*
* Local prototypes. * Local prototypes.
*/ */
@@ -503,7 +501,7 @@ update_defaults(skip_cmnd)
{ {
struct defaults *def; struct defaults *def;
for (def = defaults; def != NULL; def = def->next) { LH_FOREACH_FWD(defaults, def) {
if (skip_cmnd == (def->type == DEFAULTS_CMND)) if (skip_cmnd == (def->type == DEFAULTS_CMND))
continue; continue;
switch (def->type) { switch (def->type) {
@@ -511,22 +509,22 @@ update_defaults(skip_cmnd)
if (!set_default(def->var, def->val, def->op)) if (!set_default(def->var, def->val, def->op))
return(FALSE); return(FALSE);
case DEFAULTS_USER: 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)) !set_default(def->var, def->val, def->op))
return(FALSE); return(FALSE);
break; break;
case DEFAULTS_RUNAS: case DEFAULTS_RUNAS:
if (runas_matches(def->binding) && if (runaslist_matches(&def->binding) &&
!set_default(def->var, def->val, def->op)) !set_default(def->var, def->val, def->op))
return(FALSE); return(FALSE);
break; break;
case DEFAULTS_HOST: case DEFAULTS_HOST:
if (host_matches(def->binding) && if (hostlist_matches(&def->binding) &&
!set_default(def->var, def->val, def->op)) !set_default(def->var, def->val, def->op))
return(FALSE); return(FALSE);
break; break;
case DEFAULTS_CMND: case DEFAULTS_CMND:
if (cmnd_matches(def->binding) && if (cmndlist_matches(&def->binding) &&
!set_default(def->var, def->val, def->op)) !set_default(def->var, def->val, def->op))
return(FALSE); return(FALSE);
} }

68
gram.y
View File

@@ -67,8 +67,8 @@ int verbose = FALSE;
int errorlineno = -1; int errorlineno = -1;
char *errorfile = NULL; char *errorfile = NULL;
struct defaults *defaults; struct defaults_list defaults;
struct userspec *userspecs; struct userspec_list userspecs;
/* /*
* Local protoypes * Local protoypes
@@ -242,8 +242,8 @@ privilege : hostlist '=' cmndspeclist {
struct cmndtag tags; struct cmndtag tags;
struct privilege *p = emalloc(sizeof(*p)); struct privilege *p = emalloc(sizeof(*p));
struct cmndspec *cs; struct cmndspec *cs;
p->hostlist = $1; LIST2HEAD(p->hostlist, $1);
p->cmndlist = $3; LIST2HEAD(p->cmndlist, $3);
tags.nopasswd = tags.noexec = tags.setenv = UNSPEC; tags.nopasswd = tags.noexec = tags.setenv = UNSPEC;
/* propagate tags */ /* propagate tags */
for (cs = $3; cs != NULL; cs = cs->next) { for (cs = $3; cs != NULL; cs = cs->next) {
@@ -297,7 +297,7 @@ cmndspeclist : cmndspec
cmndspec : runasspec cmndtag opcmnd { cmndspec : runasspec cmndtag opcmnd {
struct cmndspec *cs = emalloc(sizeof(*cs)); struct cmndspec *cs = emalloc(sizeof(*cs));
cs->runaslist = $1; LIST2HEAD(cs->runaslist, $1);
cs->tags = $2; cs->tags = $2;
cs->cmnd = $3; cs->cmnd = $3;
cs->prev = cs; cs->prev = cs;
@@ -514,12 +514,9 @@ add_defaults(type, binding, defs)
*/ */
for (d = defs; d != NULL; d = d->next) { for (d = defs; d != NULL; d = d->next) {
d->type = type; d->type = type;
d->binding = binding; LIST2HEAD(d->binding, binding);
} }
if (defaults == NULL) HEAD_APPEND(defaults, defs);
defaults = defs;
else
LIST_APPEND(defaults, defs);
} }
/* /*
@@ -534,14 +531,11 @@ add_userspec(members, privs)
struct userspec *u; struct userspec *u;
u = emalloc(sizeof(*u)); u = emalloc(sizeof(*u));
u->user = members; LIST2HEAD(u->users, members);
u->privileges = privs; LIST2HEAD(u->privileges, privs);
u->prev = u; u->prev = u;
u->next = NULL; u->next = NULL;
if (userspecs == NULL) HEAD_APPEND(userspecs, u);
userspecs = u;
else
LIST_APPEND(userspecs, u);
} }
/* /*
@@ -558,55 +552,53 @@ init_parser(path, quiet)
struct userspec *us; struct userspec *us;
struct privilege *priv; struct privilege *priv;
struct cmndspec *cs; struct cmndspec *cs;
VOID *next;
for (us = userspecs; us != NULL; us = next) { while ((us = LH_LAST(userspecs)) != NULL) {
for (m = us->user; m != NULL; m = next) { LH_POP(userspecs);
next = m->next; while ((m = LH_LAST(us->users)) != NULL) {
LH_POP(us->users);
efree(m->name); efree(m->name);
efree(m); efree(m);
} }
for (priv = us->privileges; priv != NULL; priv = next) { while ((priv = LH_LAST(us->privileges)) != NULL) {
for (m = priv->hostlist; m != NULL; m = next) { LH_POP(us->privileges);
next = m->next; while ((m = LH_LAST(priv->hostlist)) != NULL) {
LH_POP(priv->hostlist);
efree(m->name); efree(m->name);
efree(m); efree(m);
} }
for (cs = priv->cmndlist; cs != NULL; cs = next) { while ((cs = LH_LAST(priv->cmndlist)) != NULL) {
for (m = cs->runaslist; m != NULL; m = next) { LH_POP(priv->cmndlist);
next = m->next; while ((m = LH_LAST(cs->runaslist)) != NULL) {
LH_POP(cs->runaslist);
efree(m->name); efree(m->name);
efree(m); efree(m);
} }
efree(cs->cmnd->name); efree(cs->cmnd->name);
efree(cs->cmnd); efree(cs->cmnd);
next = cs->next;
efree(cs); efree(cs);
} }
next = priv->next;
efree(priv); efree(priv);
} }
next = us->next;
efree(us);
} }
userspecs = NULL; LH_INIT(userspecs);
lastbinding = NULL; lastbinding = NULL;
for (d = defaults; d != NULL; d = next) { while ((d = LH_LAST(defaults)) != NULL) {
if (d->binding != lastbinding) { LH_POP(defaults);
for (m = d->binding; m != NULL; m = next) { if (LH_FIRST(d->binding) != lastbinding) {
next = m->next; lastbinding = LH_FIRST(d->binding);
while ((m = LH_LAST(d->binding)) != NULL) {
LH_POP(d->binding);
efree(m->name); efree(m->name);
efree(m); efree(m);
} }
lastbinding = d->binding;
} }
next = d->next;
efree(d->var); efree(d->var);
efree(d->val); efree(d->val);
efree(d); efree(d);
} }
defaults = NULL; LH_INIT(defaults);
init_aliases(); init_aliases();

84
match.c
View File

@@ -103,15 +103,15 @@ static int has_meta __P((char *));
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int int
user_matches(pw, list) userlist_matches(pw, list)
struct passwd *pw; struct passwd *pw;
struct member *list; struct member_list *list;
{ {
struct member *m; struct member *m;
struct alias *a; struct alias *a;
int rval, matched = UNSPEC; int rval, matched = UNSPEC;
for (m = list; m != NULL; m = m->next) { for (m = list->first; m != NULL; m = m->next) {
switch (m->type) { switch (m->type) {
case ALL: case ALL:
matched = !m->negated; matched = !m->negated;
@@ -126,7 +126,7 @@ user_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 = user_matches(pw, a->first_member); rval = userlist_matches(pw, &a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
break; break;
@@ -147,8 +147,8 @@ user_matches(pw, list)
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int int
runas_matches(list) runaslist_matches(list)
struct member *list; struct member_list *list;
{ {
struct member *m; struct member *m;
struct alias *a; struct alias *a;
@@ -157,7 +157,7 @@ runas_matches(list)
if (list == NULL) if (list == NULL)
return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw)); 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) { switch (m->type) {
case ALL: case ALL:
matched = !m->negated; matched = !m->negated;
@@ -172,7 +172,7 @@ runas_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 = runas_matches(a->first_member); rval = runaslist_matches(&a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
break; break;
@@ -192,14 +192,14 @@ runas_matches(list)
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int int
host_matches(list) hostlist_matches(list)
struct member *list; struct member_list *list;
{ {
struct member *m; struct member *m;
struct alias *a; struct alias *a;
int rval, matched = UNSPEC; int rval, matched = UNSPEC;
for (m = list; m != NULL; m = m->next) { for (m = list->first; m != NULL; m = m->next) {
switch (m->type) { switch (m->type) {
case ALL: case ALL:
matched = !m->negated; matched = !m->negated;
@@ -214,7 +214,7 @@ host_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 = host_matches(a->first_member); rval = hostlist_matches(&a->members);
if (rval != UNSPEC) if (rval != UNSPEC)
matched = m->negated ? !rval : rval; matched = m->negated ? !rval : rval;
break; break;
@@ -229,37 +229,53 @@ host_matches(list)
return(matched); return(matched);
} }
/*
* Check cmnd and args.
* Returns ALLOW, DENY or UNSPEC.
*/
int
cmnd_matches(m)
struct member *m;
{
struct alias *a;
struct sudo_command *c;
int rval, matched = UNSPEC;
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;
}
return(matched);
}
/* /*
* Check for cmnd and args in a list of members. * Check for cmnd and args in a list of members.
* Returns ALLOW, DENY or UNSPEC. * Returns ALLOW, DENY or UNSPEC.
*/ */
int int
cmnd_matches(list) cmndlist_matches(list)
struct member *list; struct member_list *list;
{ {
struct sudo_command *c;
struct member *m; struct member *m;
struct alias *a;
int rval, matched = UNSPEC; int rval, matched = UNSPEC;
for (m = list; m != NULL; m = m->next) { for (m = list->first; m != NULL; m = m->next) {
switch (m->type) { rval = cmnd_matches(m);
case ALL: if (rval != UNSPEC)
matched = !m->negated; matched = m->negated ? !rval : rval;
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;
}
} }
return(matched); return(matched);
} }

97
parse.c
View File

@@ -55,12 +55,6 @@ __unused static const char rcsid[] = "$Sudo$";
/* Characters that must be quoted in sudoers */ /* Characters that must be quoted in sudoers */
#define SUDOERS_QUOTED "*?[]!:\\,=#\"" #define SUDOERS_QUOTED "*?[]!:\\,=#\""
/*
* Parsed sudoers info.
*/
extern struct userspec *userspecs;
extern struct defaults *defaults;
/* /*
* Local prototypes. * Local prototypes.
*/ */
@@ -93,7 +87,7 @@ sudoers_lookup(pwflag)
int validated, match, host_match, runas_match, cmnd_match; int validated, match, host_match, runas_match, cmnd_match;
struct cmndspec *cs; struct cmndspec *cs;
struct cmndtag *tags = NULL; struct cmndtag *tags = NULL;
struct member *runas; struct member_list *runas;
struct privilege *priv; struct privilege *priv;
struct userspec *us; struct userspec *us;
@@ -116,13 +110,15 @@ sudoers_lookup(pwflag)
CLR(validated, FLAG_NO_USER); CLR(validated, FLAG_NO_USER);
CLR(validated, FLAG_NO_HOST); CLR(validated, FLAG_NO_HOST);
match = DENY; match = DENY;
for (us = userspecs; us != NULL; us = us->next) { /* XXX - it should be faster to start from the bottom and
if (user_matches(sudo_user.pw, us->user) != ALLOW) 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; continue;
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
if (host_matches(priv->hostlist) != ALLOW) if (hostlist_matches(&priv->hostlist) != ALLOW)
continue; continue;
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
/* Only check the command when listing another user. */ /* Only check the command when listing another user. */
if (user_uid == 0 || list_pw == NULL || if (user_uid == 0 || list_pw == NULL ||
user_uid == list_pw->pw_uid || user_uid == list_pw->pw_uid ||
@@ -149,22 +145,24 @@ sudoers_lookup(pwflag)
/* Need to be runas user while stat'ing things. */ /* Need to be runas user while stat'ing things. */
set_perms(PERM_RUNAS); 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; match = UNSPEC;
for (us = userspecs; us != NULL; us = us->next) { LH_FOREACH_FWD(userspecs, us) {
if (user_matches(sudo_user.pw, us->user) != ALLOW) if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
continue; continue;
CLR(validated, FLAG_NO_USER); CLR(validated, FLAG_NO_USER);
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
host_match = host_matches(priv->hostlist); host_match = hostlist_matches(&priv->hostlist);
if (host_match == UNSPEC) if (host_match == UNSPEC)
continue; continue;
if (host_match == ALLOW) if (host_match == ALLOW)
CLR(validated, FLAG_NO_HOST); CLR(validated, FLAG_NO_HOST);
runas = NULL; runas = NULL;
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
if (cs->runaslist != NULL) if (!LH_EMPTY(cs->runaslist))
runas = cs->runaslist; runas = &cs->runaslist;
runas_match = runas_matches(runas); runas_match = runaslist_matches(runas);
if (runas_match != UNSPEC) { if (runas_match != UNSPEC) {
cmnd_match = cmnd_matches(cs->cmnd); cmnd_match = cmnd_matches(cs->cmnd);
if (cmnd_match != UNSPEC) if (cmnd_match != UNSPEC)
@@ -229,23 +227,24 @@ display_privs(v, pw)
printf("User %s may run the following commands on this host:\n", printf("User %s may run the following commands on this host:\n",
pw->pw_name); pw->pw_name);
for (us = userspecs; us != NULL; us = us->next) { LH_FOREACH_FWD(userspecs, us) {
if (user_matches(pw, us->user) != ALLOW || /* XXX - why only check the first privilege here? */
host_matches(us->privileges->hostlist) != ALLOW) if (userlist_matches(pw, &us->users) != ALLOW ||
hostlist_matches(&us->privileges.first->hostlist) != ALLOW)
continue; continue;
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
tags.noexec = def_noexec; tags.noexec = def_noexec;
tags.setenv = def_setenv; tags.setenv = def_setenv;
tags.nopasswd = !def_authenticate; tags.nopasswd = !def_authenticate;
lbuf_append(&lbuf, " ", NULL); lbuf_append(&lbuf, " ", NULL);
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
if (cs != priv->cmndlist) if (cs != LH_FIRST(priv->cmndlist))
lbuf_append(&lbuf, ", ", NULL); lbuf_append(&lbuf, ", ", NULL);
lbuf_append(&lbuf, "(", NULL); lbuf_append(&lbuf, "(", NULL);
if (cs->runaslist != NULL) { if (!LH_EMPTY(cs->runaslist)) {
for (m = cs->runaslist; m != NULL; m = m->next) { LH_FOREACH_FWD(cs->runaslist, m) {
if (m != cs->runaslist) if (m != LH_FIRST(cs->runaslist))
lbuf_append(&lbuf, ", ", NULL); lbuf_append(&lbuf, ", ", NULL);
print_member(&lbuf, m->name, m->type, m->negated, print_member(&lbuf, m->name, m->type, m->negated,
RUNASALIAS); RUNASALIAS);
@@ -293,19 +292,19 @@ display_defaults(pw)
{ {
struct defaults *d; struct defaults *d;
struct lbuf lbuf; struct lbuf lbuf;
char *prefix; char *prefix = NULL;
int per_runas = 0, per_cmnd = 0; int per_runas = 0, per_cmnd = 0;
lbuf_init(&lbuf, NULL, 4, 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) { switch (d->type) {
case DEFAULTS_HOST: case DEFAULTS_HOST:
if (host_matches(d->binding) != ALLOW) if (hostlist_matches(&d->binding) != ALLOW)
continue; continue;
break; break;
case DEFAULTS_USER: case DEFAULTS_USER:
if (user_matches(pw, d->binding) != ALLOW) if (userlist_matches(pw, &d->binding) != ALLOW)
continue; continue;
break; break;
case DEFAULTS_RUNAS: case DEFAULTS_RUNAS:
@@ -355,7 +354,7 @@ display_bound_defaults(dtype)
{ {
struct lbuf lbuf; struct lbuf lbuf;
struct defaults *d; struct defaults *d;
struct member *m, *binding; struct member *m, *binding = NULL;
char *dname, *dsep; char *dname, *dsep;
int atype; int atype;
@@ -385,12 +384,12 @@ display_bound_defaults(dtype)
} }
lbuf_init(&lbuf, NULL, 4, 0); lbuf_init(&lbuf, NULL, 4, 0);
printf("Per-%s Defaults entries:\n", dname); 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) if (d->type != dtype)
continue; continue;
if (d->binding != binding) { if (binding != LH_FIRST(d->binding)) {
binding = d->binding; binding = LH_FIRST(d->binding);
lbuf_append(&lbuf, " Defaults", dsep, NULL); lbuf_append(&lbuf, " Defaults", dsep, NULL);
for (m = binding; m != NULL; m = m->next) { for (m = binding; m != NULL; m = m->next) {
if (m != binding) if (m != binding)
@@ -421,7 +420,8 @@ display_cmnd(v, pw)
struct passwd *pw; struct passwd *pw;
{ {
struct cmndspec *cs; struct cmndspec *cs;
struct member *match, *runas; struct member *match;
struct member_list *runas;
struct privilege *priv; struct privilege *priv;
struct userspec *us; struct userspec *us;
int rval = 1; int rval = 1;
@@ -432,19 +432,20 @@ display_cmnd(v, pw)
rval = sudo_ldap_display_cmnd(v, pw); rval = sudo_ldap_display_cmnd(v, pw);
#endif #endif
if (rval != 0 && !def_ignore_local_sudoers) { if (rval != 0 && !def_ignore_local_sudoers) {
for (match = NULL, us = userspecs; us != NULL; us = us->next) { match = NULL;
if (user_matches(pw, us->user) != ALLOW) LH_FOREACH_FWD(userspecs, us) {
if (userlist_matches(pw, &us->users) != ALLOW)
continue; continue;
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
host_match = host_matches(priv->hostlist); host_match = hostlist_matches(&priv->hostlist);
if (host_match == UNSPEC) if (host_match == UNSPEC)
continue; continue;
runas = NULL; runas = NULL;
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
if (cs->runaslist != NULL) if (!LH_EMPTY(cs->runaslist) != NULL)
runas = cs->runaslist; runas = &cs->runaslist;
runas_match = runas_matches(runas); runas_match = runaslist_matches(runas);
if (runas_match != UNSPEC) { if (runas_match != UNSPEC) {
cmnd_match = cmnd_matches(cs->cmnd); cmnd_match = cmnd_matches(cs->cmnd);
if (cmnd_match != UNSPEC) if (cmnd_match != UNSPEC)
@@ -492,8 +493,8 @@ print_member(lbuf, name, type, negated, alias_type)
break; break;
case ALIAS: case ALIAS:
if ((a = find_alias(name, alias_type)) != NULL) { if ((a = find_alias(name, alias_type)) != NULL) {
for (m = a->first_member; m != NULL; m = m->next) { LH_FOREACH_FWD(a->members, m) {
if (m != a->first_member) if (m != LH_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);

134
parse.h
View File

@@ -60,12 +60,40 @@ struct cmndtag {
* pointer of the last entry is NULL and does not point back to the head. * 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. * Structure describing a user specification and list thereof.
*/ */
struct userspec { struct userspec {
struct member *user; /* list of users */ struct member_list users; /* list of users */
struct privilege *privileges; /* list of privileges */ struct privilege_list privileges; /* list of privileges */
struct userspec *prev, *next; struct userspec *prev, *next;
}; };
@@ -73,8 +101,8 @@ struct userspec {
* Structure describing a privilege specification. * Structure describing a privilege specification.
*/ */
struct privilege { struct privilege {
struct member *hostlist; /* list of hosts */ struct member_list hostlist; /* list of hosts */
struct cmndspec *cmndlist; /* list of Cmnd_Specs */ struct cmndspec_list cmndlist; /* list of Cmnd_Specs */
struct privilege *prev, *next; struct privilege *prev, *next;
}; };
@@ -82,7 +110,7 @@ struct privilege {
* Structure describing a linked list of Cmnd_Specs. * Structure describing a linked list of Cmnd_Specs.
*/ */
struct cmndspec { 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 member *cmnd; /* command to allow/deny */
struct cmndtag tags; /* tag specificaion */ struct cmndtag tags; /* tag specificaion */
struct cmndspec *prev, *next; struct cmndspec *prev, *next;
@@ -105,7 +133,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 */
struct member *first_member; /* list of alias members */ struct member_list members; /* list of alias members */
}; };
/* /*
@@ -114,7 +142,7 @@ struct alias {
struct defaults { struct defaults {
char *var; /* variable name */ char *var; /* variable name */
char *val; /* variable value */ 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 type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */
int op; /* TRUE, FALSE, '+', '-' */ int op; /* TRUE, FALSE, '+', '-' */
struct defaults *prev, *next; struct defaults *prev, *next;
@@ -123,6 +151,7 @@ struct defaults {
/* /*
* Allocate space for a defaults entry and populate it. * Allocate space for a defaults entry and populate it.
*/ */
#undef NEW_DEFAULT
#define NEW_DEFAULT(r, v1, v2, o) do { \ #define NEW_DEFAULT(r, v1, v2, o) do { \
(r) = emalloc(sizeof(struct defaults)); \ (r) = emalloc(sizeof(struct defaults)); \
(r)->var = (v1); \ (r)->var = (v1); \
@@ -135,6 +164,7 @@ struct defaults {
/* /*
* Allocate space for a member and populate it. * Allocate space for a member and populate it.
*/ */
#undef NEW_MEMBER
#define NEW_MEMBER(r, n, t) do { \ #define NEW_MEMBER(r, n, t) do { \
(r) = emalloc(sizeof(struct member)); \ (r) = emalloc(sizeof(struct member)); \
(r)->name = (n); \ (r)->name = (n); \
@@ -147,6 +177,7 @@ struct defaults {
* Append one queue (or single entry) to another using the * Append one queue (or single entry) to another using the
* circular properties of the prev pointer to simplify the logic. * circular properties of the prev pointer to simplify the logic.
*/ */
#undef LIST_APPEND
#define LIST_APPEND(h, e) do { \ #define LIST_APPEND(h, e) do { \
void *_tail = (e)->prev; \ void *_tail = (e)->prev; \
(h)->prev->next = (e); \ (h)->prev->next = (e); \
@@ -154,6 +185,88 @@ struct defaults {
(h)->prev = _tail; \ (h)->prev = _tail; \
} while (0) } 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 * Prototypes
*/ */
@@ -161,13 +274,14 @@ char *alias_add __P((char *, int, struct member *));
int addr_matches __P((char *)); int addr_matches __P((char *));
int alias_remove __P((char *, int)); int alias_remove __P((char *, int));
int cmnd_matches __P((struct member *)); int cmnd_matches __P((struct member *));
int cmndlist_matches __P((struct member_list *));
int command_matches __P((char *, char *)); 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 hostname_matches __P((char *, char *, char *));
int netgr_matches __P((char *, char *, char *, char *)); int netgr_matches __P((char *, char *, char *, char *));
int no_aliases __P((void)); int no_aliases __P((void));
int runas_matches __P((struct member *)); int runaslist_matches __P((struct member_list *));
int user_matches __P((struct passwd *, struct member *)); int userlist_matches __P((struct passwd *, struct member_list *));
int usergr_matches __P((char *, char *, struct passwd *)); int usergr_matches __P((char *, char *, struct passwd *));
int userpw_matches __P((char *, char *, struct passwd *)); int userpw_matches __P((char *, char *, struct passwd *));
struct alias *find_alias __P((char *, int)); struct alias *find_alias __P((char *, int));

View File

@@ -99,9 +99,6 @@ struct passwd *(*my_getpwuid) __P((uid_t)) = getpwuid;
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
extern struct defaults *defaults;
extern struct userspec *userspecs;
int print_alias __P((VOID *, VOID *)); int print_alias __P((VOID *, VOID *));
void dump_sudoers __P((void)); void dump_sudoers __P((void));
void print_defaults __P((void)); void print_defaults __P((void));
@@ -128,7 +125,7 @@ main(argc, argv)
char **argv; char **argv;
{ {
struct cmndspec *cs; struct cmndspec *cs;
struct member *runas; struct member_list *runas;
struct privilege *priv; struct privilege *priv;
struct userspec *us; struct userspec *us;
char *p, *grfile, *pwfile, *uflag, hbuf[MAXHOSTNAMELEN]; char *p, *grfile, *pwfile, *uflag, hbuf[MAXHOSTNAMELEN];
@@ -272,20 +269,20 @@ main(argc, argv)
/* This loop must match the one in sudoers_lookup() */ /* This loop must match the one in sudoers_lookup() */
printf("\nEntries for user %s:\n", user_name); printf("\nEntries for user %s:\n", user_name);
matched = UNSPEC; matched = UNSPEC;
for (us = userspecs; us != NULL; us = us->next) { LH_FOREACH_FWD(userspecs, us) {
if (user_matches(sudo_user.pw, us->user) != TRUE) if (userlist_matches(sudo_user.pw, &us->users) != TRUE)
continue; continue;
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
putchar('\n'); putchar('\n');
print_privilege(priv); print_privilege(priv); /* XXX */
putchar('\n'); putchar('\n');
if (host_matches(priv->hostlist) == TRUE) { if (hostlist_matches(&priv->hostlist) == TRUE) {
puts("\thost matched"); puts("\thost matched");
runas = NULL; runas = NULL;
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
if (cs->runaslist != NULL) if (!LH_EMPTY(cs->runaslist))
runas = cs->runaslist; runas = &cs->runaslist;
if (runas_matches(runas) == TRUE) { if (runaslist_matches(runas) == TRUE) {
puts("\trunas matched"); puts("\trunas matched");
rval = cmnd_matches(cs->cmnd); rval = cmnd_matches(cs->cmnd);
if (rval != UNSPEC) if (rval != UNSPEC)
@@ -391,7 +388,7 @@ print_defaults()
struct defaults *d; struct defaults *d;
struct member *m; struct member *m;
for (d = defaults; d != NULL; d = d->next) { LH_FOREACH_FWD(defaults, d) {
(void) fputs("Defaults", stdout); (void) fputs("Defaults", stdout);
switch (d->type) { switch (d->type) {
case DEFAULTS_HOST: case DEFAULTS_HOST:
@@ -407,8 +404,8 @@ print_defaults()
putchar('!'); putchar('!');
break; break;
} }
for (m = d->binding; m != NULL; m = m->next) { LH_FOREACH_FWD(d->binding, m) {
if (m != d->binding) if (m != LH_FIRST(d->binding))
putchar(','); putchar(',');
print_member(m); print_member(m);
} }
@@ -442,8 +439,8 @@ print_alias(v1, v2)
(void) printf("Runas_Alias\t%s = ", a->name); (void) printf("Runas_Alias\t%s = ", a->name);
break; break;
} }
for (m = a->first_member; m != NULL; m = m->next) { LH_FOREACH_FWD(a->members, m) {
if (m != a->first_member) if (m != LH_FIRST(a->members))
fputs(", ", stdout); fputs(", ", stdout);
if (m->type == COMMAND) { if (m->type == COMMAND) {
c = (struct sudo_command *) m->name; c = (struct sudo_command *) m->name;
@@ -468,20 +465,20 @@ print_privilege(priv)
for (p = priv; p != NULL; p = p->next) { for (p = priv; p != NULL; p = p->next) {
if (p != priv) if (p != priv)
fputs(" : ", stdout); fputs(" : ", stdout);
for (m = p->hostlist; m != NULL; m = m->next) { LH_FOREACH_FWD(p->hostlist, m) {
if (m != p->hostlist) if (m != LH_FIRST(p->hostlist))
fputs(", ", stdout); fputs(", ", stdout);
print_member(m); print_member(m);
} }
fputs(" = ", stdout); fputs(" = ", stdout);
tags.nopasswd = tags.noexec = UNSPEC; tags.nopasswd = tags.noexec = UNSPEC;
for (cs = p->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(p->cmndlist, cs) {
if (cs != p->cmndlist) if (cs != LH_FIRST(p->cmndlist))
fputs(", ", stdout); fputs(", ", stdout);
if (cs->runaslist) { if (!LH_EMPTY(cs->runaslist)) {
fputs("(", stdout); fputs("(", stdout);
for (m = cs->runaslist; m != NULL; m = m->next) { LH_FOREACH_FWD(cs->runaslist, m) {
if (m != cs->runaslist) if (m != LH_FIRST(cs->runaslist))
fputs(", ", stdout); fputs(", ", stdout);
print_member(m); print_member(m);
} }
@@ -503,14 +500,14 @@ print_userspecs()
struct member *m; struct member *m;
struct userspec *us; struct userspec *us;
for (us = userspecs; us != NULL; us = us->next) { LH_FOREACH_FWD(userspecs, us) {
for (m = us->user; m != NULL; m = m->next) { LH_FOREACH_FWD(us->users, m) {
if (m != us->user) if (m != LH_FIRST(us->users))
fputs(", ", stdout); fputs(", ", stdout);
print_member(m); print_member(m);
} }
putchar('\t'); putchar('\t');
print_privilege(us->privileges); print_privilege(us->privileges.first); /* XXX */
putchar('\n'); putchar('\n');
} }
} }

View File

@@ -128,9 +128,6 @@ extern int errorlineno, parse_error;
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
extern struct defaults *defaults;
extern struct userspec *userspecs;
/* /*
* Globals * Globals
*/ */
@@ -215,8 +212,8 @@ main(argc, argv)
setup_signals(); setup_signals();
/* Edit the sudoers file(s) */ /* Edit the sudoers file(s) */
for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { LH_FOREACH_FWD(sudoerslist, sp) {
if (sp != sudoerslist.first) { if (sp != LH_FIRST(sudoerslist)) {
printf("press return to edit %s: ", sp->path); printf("press return to edit %s: ", sp->path);
while ((ch = getchar()) != EOF && ch != '\n') while ((ch = getchar()) != EOF && ch != '\n')
continue; continue;
@@ -228,7 +225,7 @@ main(argc, argv)
reparse_sudoers(editor, args, strict, quiet); reparse_sudoers(editor, args, strict, quiet);
/* Install the sudoers temp files. */ /* Install the sudoers temp files. */
for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { LH_FOREACH_FWD(sudoerslist, sp) {
if (!sp->modified) if (!sp->modified)
(void) unlink(sp->tpath); (void) unlink(sp->tpath);
else else
@@ -403,8 +400,8 @@ reparse_sudoers(editor, args, strict, quiet)
* Parse the edited sudoers files and do sanity checking * Parse the edited sudoers files and do sanity checking
*/ */
do { do {
sp = sudoerslist.first; sp = LH_FIRST(sudoerslist);
last = sudoerslist.last; last = LH_LAST(sudoerslist);
fp = fopen(sp->tpath, "r+"); fp = fopen(sp->tpath, "r+");
if (fp == NULL) if (fp == NULL)
errorx(1, "can't re-open temporary file (%s), %s unchanged.", errorx(1, "can't re-open temporary file (%s), %s unchanged.",
@@ -440,7 +437,7 @@ reparse_sudoers(editor, args, strict, quiet)
} }
if (parse_error) { if (parse_error) {
/* Edit file with the 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) { if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) {
edit_sudoers(sp, editor, args, errorlineno); edit_sudoers(sp, editor, args, errorlineno);
break; break;
@@ -711,7 +708,7 @@ open_sudoers(path, keepopen)
FILE *fp; FILE *fp;
/* Check for existing entry */ /* Check for existing entry */
for (entry = sudoerslist.first; entry != NULL; entry = entry->next) { LH_FOREACH_FWD(sudoerslist, entry) {
if (strcmp(path, entry->path) == 0) if (strcmp(path, entry->path) == 0)
break; break;
} }
@@ -731,6 +728,7 @@ open_sudoers(path, keepopen)
errorx(1, "%s busy, try again later", entry->path); errorx(1, "%s busy, try again later", entry->path);
if ((fp = fdopen(entry->fd, "r")) == NULL) if ((fp = fdopen(entry->fd, "r")) == NULL)
error(1, "%s", entry->path); error(1, "%s", entry->path);
/* XXX - macro here? */
if (sudoerslist.last == NULL) if (sudoerslist.last == NULL)
sudoerslist.first = sudoerslist.last = entry; sudoerslist.first = sudoerslist.last = entry;
else { else {
@@ -888,8 +886,8 @@ check_aliases(strict)
int error = 0; int error = 0;
/* Forward check. */ /* Forward check. */
for (us = userspecs; us != NULL; us = us->next) { LH_FOREACH_FWD(userspecs, us) {
for (m = us->user; m != NULL; m = m->next) { LH_FOREACH_FWD(us->users, m) {
if (m->type == USERALIAS) { if (m->type == USERALIAS) {
if (find_alias(m->name, m->type) == NULL) { if (find_alias(m->name, m->type) == NULL) {
fprintf(stderr, fprintf(stderr,
@@ -899,8 +897,8 @@ check_aliases(strict)
} }
} }
} }
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
for (m = priv->hostlist; m != NULL; m = m->next) { LH_FOREACH_FWD(priv->hostlist, m) {
if (m->type == HOSTALIAS) { if (m->type == HOSTALIAS) {
if (find_alias(m->name, m->type) == NULL) { if (find_alias(m->name, m->type) == NULL) {
fprintf(stderr, fprintf(stderr,
@@ -910,8 +908,8 @@ check_aliases(strict)
} }
} }
} }
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
for (m = cs->runaslist; m != NULL; m = m->next) { LH_FOREACH_FWD(cs->runaslist, m) {
if (m->type == RUNASALIAS) { if (m->type == RUNASALIAS) {
if (find_alias(m->name, m->type) == NULL) { if (find_alias(m->name, m->type) == NULL) {
fprintf(stderr, fprintf(stderr,
@@ -934,18 +932,18 @@ check_aliases(strict)
} }
/* Reverse check (destructive) */ /* Reverse check (destructive) */
for (us = userspecs; us != NULL; us = us->next) { LH_FOREACH_FWD(userspecs, us) {
for (m = us->user; m != NULL; m = m->next) { LH_FOREACH_FWD(us->users, m) {
if (m->type == USERALIAS) if (m->type == USERALIAS)
(void) alias_remove(m->name, m->type); (void) alias_remove(m->name, m->type);
} }
for (priv = us->privileges; priv != NULL; priv = priv->next) { LH_FOREACH_FWD(us->privileges, priv) {
for (m = priv->hostlist; m != NULL; m = m->next) { LH_FOREACH_FWD(priv->hostlist, m) {
if (m->type == HOSTALIAS) if (m->type == HOSTALIAS)
(void) alias_remove(m->name, m->type); (void) alias_remove(m->name, m->type);
} }
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { LH_FOREACH_FWD(priv->cmndlist, cs) {
for (m = cs->runaslist; m != NULL; m = m->next) { LH_FOREACH_FWD(cs->runaslist, m) {
if (m->type == RUNASALIAS) if (m->type == RUNASALIAS)
(void) alias_remove(m->name, m->type); (void) alias_remove(m->name, m->type);
} }
@@ -985,7 +983,7 @@ cleanup(gotsignal)
{ {
struct sudoersfile *sp; struct sudoersfile *sp;
for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { LH_FOREACH_FWD(sudoerslist, sp) {
if (sp->tpath != NULL) if (sp->tpath != NULL)
(void) unlink(sp->tpath); (void) unlink(sp->tpath);
} }