Use a list head struct when storing the semi-circular lists and
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 30 Aug 2007 17:26:35 +0000 (17:26 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 30 Aug 2007 17:26:35 +0000 (17:26 +0000)
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.

alias.c
defaults.c
gram.y
match.c
parse.c
parse.h
testsudoers.c
visudo.c

diff --git a/alias.c b/alias.c
index e0a974cf4fe0a45dd1eb05042b6a343fcc702455..847131a54b8d1f67be592f041e539a02498facbd 100644 (file)
--- 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);
index ea533089c0d3f48c3a61432c3b4b09d7ba8273ce..ec016b87949cba20cbb198f121e898ce5ed0758b 100644 (file)
@@ -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 ebe99ff80eb946ba3e03c375a3bc6d7a9bfb6db1..3178ed559d8d01fa7a21ea6172c16c2ec5e9c4bb 100644 (file)
--- 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 266f86ac5e8ccfc1c66829b22b69ab7cb7993dda..0597dfc992745fbdc7f38901fcb09cc82b27dd4f 100644 (file)
--- 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 c32ceb3c6d2be518d52d1112e7079f15ceee574c..56ff01bef9e9b9a8dec97737ea6fce996393439a 100644 (file)
--- 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 6d14ca3c8356600c663b3bececbed96fe221fccc..b181f414cac05b54033be16b7f5dfe9ef2c05437 100644 (file)
--- 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));
index a1f7a54b83895c0c02c1ebe36497129744830d77..cf9a0b4f6d24b7f464bf49057ed3a4be6ab3e5b9 100644 (file)
@@ -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');
     }
 }
index 4834365cc3d9c2df2785527ffae26789a6ba2fd9..59954857cfbca9863cc49b6b2f650399aa88a15f 100644 (file)
--- 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);
     }