]> granicus.if.org Git - sudo/commitdiff
Add "headless" tail queues and use them in place of the semi-circular
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 22 Oct 2013 15:08:38 +0000 (09:08 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 22 Oct 2013 15:08:38 +0000 (09:08 -0600)
lists in sudoers.  Once the headless tail queue is built up it is
converted to a normal TAILQ.  This removes the last consumer of
list.c and list.h so those can now be removed.

17 files changed:
MANIFEST
common/Makefile.in
common/list.c [deleted file]
common/regress/tailq/hltq_test.c [new file with mode: 0644]
include/list.h [deleted file]
include/queue.h
plugins/sudoers/Makefile.in
plugins/sudoers/alias.c
plugins/sudoers/defaults.c
plugins/sudoers/gram.c
plugins/sudoers/gram.y
plugins/sudoers/match.c
plugins/sudoers/parse.c
plugins/sudoers/parse.h
plugins/sudoers/regress/parser/check_fill.c
plugins/sudoers/testsudoers.c
plugins/sudoers/visudo.c

index 2248ad338913ca66c1b2ce52005c4564dc9d3a2e..c29d8f4d7a3f927522ced1259d3b37f6d1d46909 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -20,7 +20,6 @@ common/fileops.c
 common/fmt_string.c
 common/gidlist.c
 common/lbuf.c
-common/list.c
 common/regress/sudo_conf/conf_test.c
 common/regress/sudo_conf/test1.in
 common/regress/sudo_conf/test1.out.ok
@@ -47,6 +46,7 @@ common/regress/sudo_parseln/test5.in
 common/regress/sudo_parseln/test5.out.ok
 common/regress/sudo_parseln/test6.in
 common/regress/sudo_parseln/test6.out.ok
+common/regress/tailq/hltq_test.c
 common/secure_path.c
 common/setgroups.c
 common/sudo_conf.c
@@ -145,7 +145,6 @@ include/fatal.h
 include/fileops.h
 include/gettext.h
 include/lbuf.h
-include/list.h
 include/missing.h
 include/queue.h
 include/secure_path.h
index cdbc5b99090575022d19268e5966c09b2c838c13..7b4caaf01c4dbccbecfbad010afdf4743684b426 100644 (file)
@@ -55,7 +55,7 @@ SSP_CFLAGS = @SSP_CFLAGS@
 SSP_LDFLAGS = @SSP_LDFLAGS@
 
 # Regression tests
-TEST_PROGS = conf_test parseln_test
+TEST_PROGS = conf_test parseln_test hltq_test
 TEST_LIBS = @LIBS@ @LIBINTL@ ../compat/libreplace.la
 TEST_LDFLAGS = @LDFLAGS@
 
@@ -67,7 +67,7 @@ DEFS = @OSDEFS@ -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\"
 SHELL = @SHELL@
 
 LTOBJS = alloc.lo atobool.lo atoid.lo event.lo fatal.lo fileops.lo \
-        fmt_string.lo gidlist.lo lbuf.lo list.lo secure_path.lo \
+        fmt_string.lo gidlist.lo lbuf.lo secure_path.lo \
         setgroups.lo sudo_conf.lo sudo_debug.lo sudo_printf.lo term.lo \
         ttysize.lo @COMMON_OBJS@
 
@@ -75,6 +75,8 @@ PARSELN_TEST_OBJS = parseln_test.lo
 
 CONF_TEST_OBJS = conf_test.lo
 
+HLTQ_TEST_OBJS = hltq_test.lo
+
 all: libcommon.la
 
 Makefile: $(srcdir)/Makefile.in
@@ -94,6 +96,9 @@ conf_test: $(CONF_TEST_OBJS) libcommon.la
 parseln_test: $(PARSELN_TEST_OBJS) libcommon.la
        $(LIBTOOL) --mode=link $(CC) -o $@ $(PARSELN_TEST_OBJS) libcommon.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
 
+hltq_test: $(HLTQ_TEST_OBJS) libcommon.la
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(HLTQ_TEST_OBJS) libcommon.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
+
 pre-install:
 
 install:
@@ -113,6 +118,12 @@ uninstall:
 check: $(TEST_PROGS)
        @if test X"$(cross_compiling)" != X"yes"; then \
            passed=0; failed=0; total=0; \
+           total=1; \
+           if ./hltq_test; then \
+               passed=`expr $$passed + 1`; \
+           else \
+               failed=`expr $$failed + 1`; \
+           fi; \
            for dir in sudo_conf sudo_parseln; do \
                mkdir -p regress/$$dir; \
                for t in $(srcdir)/regress/$$dir/*.in; do \
@@ -203,13 +214,14 @@ gidlist.lo: $(srcdir)/gidlist.c $(top_builddir)/config.h $(incdir)/gettext.h \
             $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/fatal.h \
             $(incdir)/sudo_debug.h
        $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/gidlist.c
+hltq_test.lo: $(srcdir)/regress/tailq/hltq_test.c $(top_builddir)/config.h \
+              $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \
+              $(incdir)/fatal.h $(incdir)/queue.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/tailq/hltq_test.c
 lbuf.lo: $(srcdir)/lbuf.c $(top_builddir)/config.h $(incdir)/missing.h \
          $(incdir)/alloc.h $(incdir)/fatal.h $(incdir)/lbuf.h \
          $(incdir)/sudo_debug.h
        $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/lbuf.c
-list.lo: $(srcdir)/list.c $(top_builddir)/config.h $(incdir)/missing.h \
-         $(incdir)/list.h $(incdir)/fatal.h
-       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/list.c
 parseln_test.lo: $(srcdir)/regress/sudo_parseln/parseln_test.c \
                  $(top_builddir)/config.h $(top_srcdir)/compat/stdbool.h \
                  $(incdir)/missing.h $(incdir)/fileops.h
diff --git a/common/list.c b/common/list.c
deleted file mode 100644 (file)
index dce6489..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2007-2008, 2010-2012 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-
-#include "missing.h"
-#include "list.h"
-#ifdef DEBUG
-# include "fatal.h"
-#endif
-
-struct list_proto {
-    struct list_proto *prev;
-    struct list_proto *next;
-};
-
-struct list_head_proto {
-    struct list_proto *first;
-    struct list_proto *last;
-};
-
-/*
- * Pop the last element off the end of vh.
- * Returns the popped element.
- */
-void *
-tq_pop(void *vh)
-{
-    struct list_head_proto *h = (struct list_head_proto *)vh;
-    void *last = NULL;
-
-    if (!tq_empty(h)) {
-       last = (void *)h->last;
-       if (h->first == h->last) {
-           h->first = NULL;
-           h->last = NULL;
-       } else {
-           h->last = h->last->prev;
-           h->last->next = NULL;
-       }
-    }
-    return last;
-}
-
-/*
- * Convert from a semi-circle queue to normal doubly-linked list
- * with a head node.
- */
-void
-list2tq(void *vh, void *vl)
-{
-    struct list_head_proto *h = (struct list_head_proto *)vh;
-    struct list_proto *l = (struct list_proto *)vl;
-
-    if (l != NULL) {
-#ifdef DEBUG
-       if (l->prev == NULL) {
-           warningx_nodebug("list2tq called with non-semicircular list");
-           abort();
-       }
-#endif
-       h->first = l;
-       h->last = l->prev;      /* l->prev points to the last member of l */
-       l->prev = NULL;         /* zero last ptr now that we have a head */
-    } else {
-       h->first = NULL;
-       h->last = NULL;
-    }
-}
-
-/*
- * Append one queue (or single entry) to another using the
- * circular properties of the prev pointer to simplify the logic.
- */
-void
-list_append(void *vl1, void *vl2)
-{
-    struct list_proto *l1 = (struct list_proto *)vl1;
-    struct list_proto *l2 = (struct list_proto *)vl2;
-    void *tail = l2->prev;
-
-    l1->prev->next = l2;
-    l2->prev = l1->prev;
-    l1->prev = tail;
-}
-
-/*
- * Append the list of entries to the head node and convert 
- * from a semi-circle queue to normal doubly-linked list. 
- */
-void
-tq_append(void *vh, void *vl)
-{
-    struct list_head_proto *h = (struct list_head_proto *)vh;
-    struct list_proto *l = (struct list_proto *)vl;
-    void *tail = l->prev;
-
-    if (h->first == NULL)
-       h->first = l;
-    else
-       h->last->next = l;
-    l->prev = h->last;
-    h->last = tail;
-}
-
-/*
- * Remove element from the tail_queue
- */
-void
-tq_remove(void *vh, void *vl)
-{
-    struct list_head_proto *h = (struct list_head_proto *)vh;
-    struct list_proto *l = (struct list_proto *)vl;
-
-    if (h->first == l && h->last == l) {
-       /* Single element in the list. */
-       h->first = NULL;
-       h->last = NULL;
-    } else {
-       /* At least two elements in the list. */
-       if (h->first == l) {
-           h->first = l->next;
-           h->first->prev = h->first;
-       } else if (h->last == l) {
-           h->last = l->prev;
-           h->last->next = NULL;
-       } else {
-           l->prev->next = l->next;
-           l->next->prev = l->prev;
-       }
-    }
-}
diff --git a/common/regress/tailq/hltq_test.c b/common/regress/tailq/hltq_test.c
new file mode 100644 (file)
index 0000000..7897a66
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include "compat/stdbool.h"
+#endif
+
+#include "missing.h"
+#include "fatal.h"
+#include "queue.h"
+
+__dso_public int main(int argc, char *argv[]);
+
+/*
+ * Note: HLTQ_ENTRY is intentionally in the middle of the struct
+ *       to catch bad assumptions in the PREV/NEXT macros.
+ */
+struct test_data {
+    int a;
+    HLTQ_ENTRY(test_data) entries;
+    char b;
+};
+
+TAILQ_HEAD(test_data_list, test_data);
+
+/*
+ * Simple tests for headless tail queue macros.
+ */
+int
+main(int argc, char *argv[])
+{
+    struct test_data d1, d2, d3;
+    struct test_data *hltq;
+    struct test_data_list tq;
+    int errors = 0;
+
+    /*
+     * Initialize three data elements and concatenate them in order.
+     */
+    HLTQ_INIT(&d1, entries);
+    d1.a = 1;
+    d1.b = 'a';
+    if (HLTQ_FIRST(&d1) != &d1) {
+       warningx_nodebug("FAIL: HLTQ_FIRST(1 entry) doesn't return first element: got %p, expected %p", HLTQ_FIRST(&d1), &d1);
+       errors++;
+    }
+    if (HLTQ_LAST(&d1, test_data, entries) != &d1) {
+       warningx_nodebug("FAIL: HLTQ_LAST(1 entry) doesn't return first element: got %p, expected %p", HLTQ_LAST(&d1, test_data, entries), &d1);
+       errors++;
+    }
+    if (HLTQ_PREV(&d1, test_data, entries) != NULL) {
+       warningx_nodebug("FAIL: HLTQ_PREV(1 entry) doesn't return NULL: got %p", HLTQ_PREV(&d1, test_data, entries));
+       errors++;
+    }
+
+    HLTQ_INIT(&d2, entries);
+    d2.a = 2;
+    d2.b = 'b';
+
+    HLTQ_INIT(&d3, entries);
+    d3.a = 3;
+    d3.b = 'c';
+
+    HLTQ_CONCAT(&d1, &d2, entries);
+    HLTQ_CONCAT(&d1, &d3, entries);
+    hltq = &d1;
+
+    /*
+     * Verify that HLTQ_FIRST, HLTQ_LAST, HLTQ_NEXT, HLTQ_PREV
+     * work as expected.
+     */
+    if (HLTQ_FIRST(hltq) != &d1) {
+       warningx_nodebug("FAIL: HLTQ_FIRST(3 entries) doesn't return first element: got %p, expected %p", HLTQ_FIRST(hltq), &d1);
+       errors++;
+    }
+    if (HLTQ_LAST(hltq, test_data, entries) != &d3) {
+       warningx_nodebug("FAIL: HLTQ_LAST(3 entries) doesn't return third element: got %p, expected %p", HLTQ_LAST(hltq, test_data, entries), &d3);
+       errors++;
+    }
+
+    if (HLTQ_NEXT(&d1, entries) != &d2) {
+       warningx_nodebug("FAIL: HLTQ_NEXT(&d1) doesn't return &d2: got %p, expected %p", HLTQ_NEXT(&d1, entries), &d2);
+       errors++;
+    }
+    if (HLTQ_NEXT(&d2, entries) != &d3) {
+       warningx_nodebug("FAIL: HLTQ_NEXT(&d2) doesn't return &d3: got %p, expected %p", HLTQ_NEXT(&d2, entries), &d3);
+       errors++;
+    }
+    if (HLTQ_NEXT(&d3, entries) != NULL) {
+       warningx_nodebug("FAIL: HLTQ_NEXT(&d3) doesn't return NULL: got %p", HLTQ_NEXT(&d3, entries));
+       errors++;
+    }
+
+    if (HLTQ_PREV(&d1, test_data, entries) != NULL) {
+       warningx_nodebug("FAIL: HLTQ_PREV(&d1) doesn't return NULL: got %p", HLTQ_PREV(&d1, test_data, entries));
+       errors++;
+    }
+    if (HLTQ_PREV(&d2, test_data, entries) != &d1) {
+       warningx_nodebug("FAIL: HLTQ_PREV(&d2) doesn't return &d1: got %p, expected %p", HLTQ_PREV(&d2, test_data, entries), &d1);
+       errors++;
+    }
+    if (HLTQ_PREV(&d3, test_data, entries) != &d2) {
+       warningx_nodebug("FAIL: HLTQ_PREV(&d3) doesn't return &d2: got %p, expected %p", HLTQ_PREV(&d3, test_data, entries), &d2);
+       errors++;
+    }
+
+    /* Test conversion to TAILQ. */
+    HLTQ_TO_TAILQ(&tq, hltq, entries);
+
+    if (TAILQ_FIRST(&tq) != &d1) {
+       warningx_nodebug("FAIL: TAILQ_FIRST(&tq) doesn't return first element: got %p, expected %p", TAILQ_FIRST(&tq), &d1);
+       errors++;
+    }
+    if (TAILQ_LAST(&tq, test_data_list) != &d3) {
+       warningx_nodebug("FAIL: TAILQ_LAST(&tq) doesn't return third element: got %p, expected %p", TAILQ_LAST(&tq, test_data_list), &d3);
+       errors++;
+    }
+
+    if (TAILQ_NEXT(&d1, entries) != &d2) {
+       warningx_nodebug("FAIL: TAILQ_NEXT(&d1) doesn't return &d2: got %p, expected %p", TAILQ_NEXT(&d1, entries), &d2);
+       errors++;
+    }
+    if (TAILQ_NEXT(&d2, entries) != &d3) {
+       warningx_nodebug("FAIL: TAILQ_NEXT(&d2) doesn't return &d3: got %p, expected %p", TAILQ_NEXT(&d2, entries), &d3);
+       errors++;
+    }
+    if (TAILQ_NEXT(&d3, entries) != NULL) {
+       warningx_nodebug("FAIL: TAILQ_NEXT(&d3) doesn't return NULL: got %p", TAILQ_NEXT(&d3, entries));
+       errors++;
+    }
+
+    if (TAILQ_PREV(&d1, test_data_list, entries) != NULL) {
+       warningx_nodebug("FAIL: TAILQ_PREV(&d1) doesn't return NULL: got %p", TAILQ_PREV(&d1, test_data_list, entries));
+       errors++;
+    }
+    if (TAILQ_PREV(&d2, test_data_list, entries) != &d1) {
+       warningx_nodebug("FAIL: TAILQ_PREV(&d2) doesn't return &d1: got %p, expected %p", TAILQ_PREV(&d2, test_data_list, entries), &d1);
+       errors++;
+    }
+    if (TAILQ_PREV(&d3, test_data_list, entries) != &d2) {
+       warningx_nodebug("FAIL: TAILQ_PREV(&d3) doesn't return &d2: got %p, expected %p", TAILQ_PREV(&d3, test_data_list, entries), &d2);
+       errors++;
+    }
+
+    exit(errors);
+}
+
+/* STUB */
+void
+warning_set_locale(void)
+{
+    return;
+}
+
+/* STUB */
+void
+warning_restore_locale(void)
+{
+    return;
+}
diff --git a/include/list.h b/include/list.h
deleted file mode 100644 (file)
index 1055e22..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2007, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SUDO_LIST_H
-#define _SUDO_LIST_H
-
-/*
- * Convenience macro for declaring a list head.
- */
-#define TQ_DECLARE(n)                                  \
-struct n##_list {                                      \
-    struct n *first;                                   \
-    struct n *last;                                    \
-};
-
-/*
- * Foreach loops: forward and reverse
- */
-#undef tq_foreach_fwd
-#define tq_foreach_fwd(h, v)                           \
-    for ((v) = (h)->first; (v) != NULL; (v) = (v)->next)
-
-#undef tq_foreach_rev
-#define tq_foreach_rev(h, v)                           \
-    for ((v) = (h)->last; (v) != NULL; (v) = (v)->prev)
-
-/*
- * Init a list head.
- */
-#undef tq_init
-#define tq_init(h) do {                                        \
-    (h)->first = NULL;                                 \
-    (h)->last = NULL;                                  \
-} while (0)
-
-/*
- * Simple macros to avoid exposing first/last and prev/next.
- */
-#undef tq_empty
-#define tq_empty(h)    ((h)->first == NULL)
-
-#undef tq_first
-#define tq_first(h)    ((h)->first)
-
-#undef tq_last
-#define tq_last(h)     ((h)->last)
-
-#undef list_next
-#define list_next(e)   ((e)->next)
-
-#undef list_prev
-#define list_prev(e)   ((e)->prev)
-
-/*
- * Prototypes for list.c
- */
-void *tq_pop(void *);
-void tq_append(void *, void *);
-void tq_remove(void *, void *);
-void list_append(void *, void *);
-void list2tq(void *, void *);
-
-#endif /* _SUDO_LIST_H */
index de4ef162a1197b20b602d597ec9f7da0c9e506f9..9392c674d2ec51acbf9e32a66dabc7fcac50b8d7 100644 (file)
  * after an existing element, at the head of the list, or at the end of
  * the list. A tail queue may be traversed in either direction.
  *
+ * A headless tail queue lacks a head structure, The first element acts
+ * as a de facto list head.  It uses the same entry struct as a regular
+ * tail queue for easy conversion from headless to headful.
+ * It is capable of concatenating queues as well as individual elements.
+ * Traversing in reverse is more expensive due to lack of a list head.
+ * Note: elements must be initialized before use.
+ *
  * For details on the use of these macros, see the queue(3) manual page.
  *
  *
@@ -712,4 +719,88 @@ struct {                                                           \
                (head2)->tqh_last = &(head2)->tqh_first;                \
 } while (0)
 
+/*
+ * Headless Tail queue definitions.
+ */
+#undef HLTQ_ENTRY
+#define HLTQ_ENTRY(type)               TAILQ_ENTRY(type)
+
+#undef HLTQ_INIT
+#define        HLTQ_INIT(entry, field) do {                                    \
+       (entry)->field.tqe_next = NULL;                                 \
+       (entry)->field.tqe_prev = &(entry)->field.tqe_next;             \
+} while (0)
+
+#undef HLTQ_INITIALIZER
+#define HLTQ_INITIALIZER(entry, field)                         \
+       { NULL, &(entry)->field.tqe_next }
+
+#undef HLTQ_FIRST
+#define        HLTQ_FIRST(elm)         (elm)
+
+#undef HLTQ_END
+#define        HLTQ_END(elm)           NULL
+
+#undef HLTQ_NEXT
+#define        HLTQ_NEXT(elm, field)   ((elm)->field.tqe_next)
+
+#undef HLTQ_LAST
+#define HLTQ_LAST(elm, type, field)                                    \
+       ((elm)->field.tqe_next == NULL ? (elm) :                        \
+           __containerof((elm)->field.tqe_prev, struct type, field.tqe_next))
+
+#undef HLTQ_PREV
+#define HLTQ_PREV(elm, type, field)                                    \
+       (*(elm)->field.tqe_prev == NULL ? NULL :                        \
+           __containerof((elm)->field.tqe_prev, struct type, field.tqe_next))
+
+#undef HLTQ_FOREACH
+#define HLTQ_FOREACH(var, head, field)                                 \
+       for ((var) = HLTQ_FIRST(head);                                  \
+           (var) != HLTQ_END(head);                                    \
+           (var) = HLTQ_NEXT(var, field))
+
+#undef HLTQ_FOREACH_SAFE
+#define        HLTQ_FOREACH_SAFE(var, head, field, tvar)                       \
+       for ((var) = HLTQ_FIRST(head);                                  \
+           (var) != HLTQ_END(head) &&                                  \
+           ((tvar) = HLTQ_NEXT(var, field), 1);                        \
+           (var) = (tvar))
+
+#undef HLTQ_FOREACH_REVERSE
+#define HLTQ_FOREACH_REVERSE(var, head, headname, field)               \
+       for ((var) = HLTQ_LAST(head, headname);                         \
+           (var) != HLTQ_END(head);                                    \
+           (var) = HLTQ_PREV(var, headname, field))
+
+#undef HLTQ_FOREACH_REVERSE_SAFE
+#define        HLTQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)     \
+       for ((var) = HLTQ_LAST(head, headname);                         \
+           (var) != HLTQ_END(head) &&                                  \
+           ((tvar) = HLTQ_PREV(var, headname, field), 1);              \
+           (var) = (tvar))
+
+/* Concatenate queue2 to the end of queue1. */
+#undef HLTQ_CONCAT
+#define HLTQ_CONCAT(queue1, queue2, field) do {                                \
+       (queue2)->field.tqe_prev = (queue1)->field.tqe_prev;            \
+       *(queue1)->field.tqe_prev = (queue2);                           \
+       (queue1)->field.tqe_prev = &(queue2)->field.tqe_next;           \
+} while (0)
+
+/* Convert a headless tailq to a headful one. */
+#define HLTQ_TO_TAILQ(head, hl, field) do {                            \
+       (head)->tqh_first = (hl);                                       \
+       (head)->tqh_last = (hl)->field.tqe_prev;                        \
+       (hl)->field.tqe_prev = &(head)->tqh_first;                      \
+} while (0)
+
+/* Concatenate a headless tail queue to the end of a regular tail queue. */
+#define TAILQ_CONCAT_HLTQ(head, hl, field) do {                                \
+       void *last = (hl)->field.tqe_prev;                              \
+       (hl)->field.tqe_prev = (head)->tqh_last;                        \
+       *(head)->tqh_last = (hl);                                       \
+       (head)->tqh_last = last;                                        \
+} while (0)
+
 #endif /* !_SUDO_QUEUE_H_ */
index 08d4ef3529f3dfb736ac5cb32ae3715e6f3cdbdf..f861dcafd3dfc431b365dd718afa3a7fc2994e82 100644 (file)
@@ -450,8 +450,7 @@ alias.lo: $(srcdir)/alias.c $(top_builddir)/config.h $(srcdir)/sudoers.h \
           $(incdir)/queue.h $(incdir)/fileops.h $(srcdir)/defaults.h \
           $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
           $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \
-          $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/redblack.h \
-          $(devdir)/gram.h
+          $(srcdir)/parse.h $(srcdir)/redblack.h $(devdir)/gram.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/alias.c
 audit.lo: $(srcdir)/audit.c $(top_builddir)/config.h \
           $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \
@@ -491,7 +490,7 @@ check_addr.o: $(srcdir)/regress/parser/check_addr.c $(top_builddir)/config.h \
               $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \
               $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \
               $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/parse.h \
-              $(incdir)/list.h $(srcdir)/interfaces.h
+              $(srcdir)/interfaces.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/parser/check_addr.c
 check_base64.o: $(srcdir)/regress/parser/check_base64.c \
                 $(top_builddir)/config.h $(incdir)/missing.h
@@ -501,8 +500,8 @@ check_digest.o: $(srcdir)/regress/parser/check_digest.c \
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/parser/check_digest.c
 check_fill.o: $(srcdir)/regress/parser/check_fill.c $(top_builddir)/config.h \
               $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \
-              $(incdir)/list.h $(srcdir)/parse.h $(incdir)/list.h \
-              $(srcdir)/toke.h $(incdir)/sudo_plugin.h $(devdir)/gram.h
+              $(incdir)/queue.h $(srcdir)/parse.h $(srcdir)/toke.h \
+              $(incdir)/sudo_plugin.h $(devdir)/gram.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/parser/check_fill.c
 check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \
                     $(top_builddir)/config.h $(srcdir)/sudoers.h \
@@ -534,8 +533,8 @@ defaults.lo: $(srcdir)/defaults.c $(top_builddir)/config.h $(srcdir)/sudoers.h \
              $(incdir)/queue.h $(incdir)/fileops.h $(srcdir)/defaults.h \
              $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
              $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \
-             $(incdir)/gettext.h $(srcdir)/parse.h $(incdir)/list.h \
-             $(devdir)/gram.h $(devdir)/def_data.c
+             $(incdir)/gettext.h $(srcdir)/parse.h $(devdir)/gram.h \
+             $(devdir)/def_data.c
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/defaults.c
 env.lo: $(srcdir)/env.c $(top_builddir)/config.h $(srcdir)/sudoers.h \
         $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \
@@ -585,7 +584,7 @@ gram.lo: $(devdir)/gram.c $(top_builddir)/config.h $(top_builddir)/config.h \
          $(incdir)/alloc.h $(incdir)/queue.h $(incdir)/fileops.h \
          $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \
          $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \
-         $(incdir)/gettext.h $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/toke.h
+         $(incdir)/gettext.h $(srcdir)/parse.h $(srcdir)/toke.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(devdir)/gram.c
 group_plugin.lo: $(srcdir)/group_plugin.c $(top_builddir)/config.h \
                  $(top_srcdir)/compat/dlfcn.h $(srcdir)/sudoers.h \
@@ -643,7 +642,7 @@ ldap.lo: $(srcdir)/ldap.c $(top_builddir)/config.h \
          $(incdir)/queue.h $(incdir)/fileops.h $(srcdir)/defaults.h \
          $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
          $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \
-         $(srcdir)/parse.h $(incdir)/list.h $(incdir)/lbuf.h
+         $(srcdir)/parse.h $(incdir)/lbuf.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/ldap.c
 linux_audit.lo: $(srcdir)/linux_audit.c $(top_builddir)/config.h \
                 $(incdir)/missing.h $(incdir)/fatal.h $(incdir)/alloc.h \
@@ -678,8 +677,8 @@ match.lo: $(srcdir)/match.c $(top_builddir)/config.h \
           $(incdir)/alloc.h $(incdir)/queue.h $(incdir)/fileops.h \
           $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \
           $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \
-          $(incdir)/gettext.h $(srcdir)/parse.h $(incdir)/list.h \
-          $(srcdir)/sha2.h $(devdir)/gram.h
+          $(incdir)/gettext.h $(srcdir)/parse.h $(srcdir)/sha2.h \
+          $(devdir)/gram.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/match.c
 match_addr.lo: $(srcdir)/match_addr.c $(top_builddir)/config.h \
                $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \
@@ -708,7 +707,7 @@ parse.lo: $(srcdir)/parse.c $(top_builddir)/config.h $(srcdir)/sudoers.h \
           $(incdir)/queue.h $(incdir)/fileops.h $(srcdir)/defaults.h \
           $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
           $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \
-          $(srcdir)/parse.h $(incdir)/list.h $(incdir)/lbuf.h $(devdir)/gram.h
+          $(srcdir)/parse.h $(incdir)/lbuf.h $(devdir)/gram.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/parse.c
 passwd.lo: $(authdir)/passwd.c $(top_builddir)/config.h $(srcdir)/sudoers.h \
            $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \
@@ -805,8 +804,7 @@ sssd.lo: $(srcdir)/sssd.c $(top_builddir)/config.h \
          $(incdir)/queue.h $(incdir)/fileops.h $(srcdir)/defaults.h \
          $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
          $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \
-         $(srcdir)/parse.h $(incdir)/list.h $(incdir)/lbuf.h \
-         $(incdir)/sudo_debug.h
+         $(srcdir)/parse.h $(incdir)/lbuf.h $(incdir)/sudo_debug.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sssd.c
 sudo_auth.lo: $(authdir)/sudo_auth.c $(top_builddir)/config.h \
               $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \
@@ -853,8 +851,8 @@ testsudoers.o: $(srcdir)/testsudoers.c $(top_builddir)/config.h \
                $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
                $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \
                $(incdir)/gettext.h $(srcdir)/interfaces.h $(srcdir)/parse.h \
-               $(incdir)/list.h $(incdir)/sudo_conf.h $(incdir)/queue.h \
-               $(incdir)/secure_path.h $(devdir)/gram.h
+               $(incdir)/sudo_conf.h $(incdir)/queue.h $(incdir)/secure_path.h \
+               $(devdir)/gram.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/testsudoers.c
 timestamp.lo: $(srcdir)/timestamp.c $(top_builddir)/config.h \
               $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \
@@ -872,8 +870,8 @@ toke.lo: $(devdir)/toke.c $(top_builddir)/config.h $(top_builddir)/config.h \
          $(incdir)/alloc.h $(incdir)/queue.h $(incdir)/fileops.h \
          $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \
          $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \
-         $(incdir)/gettext.h $(srcdir)/parse.h $(incdir)/list.h \
-         $(srcdir)/toke.h $(devdir)/gram.h $(incdir)/lbuf.h $(srcdir)/sha2.h \
+         $(incdir)/gettext.h $(srcdir)/parse.h $(srcdir)/toke.h \
+         $(devdir)/gram.h $(incdir)/lbuf.h $(srcdir)/sha2.h \
          $(incdir)/secure_path.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(devdir)/toke.c
 toke_util.lo: $(srcdir)/toke_util.c $(top_builddir)/config.h \
@@ -883,7 +881,7 @@ toke_util.lo: $(srcdir)/toke_util.c $(top_builddir)/config.h \
               $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \
               $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \
               $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/parse.h \
-              $(incdir)/list.h $(srcdir)/toke.h $(devdir)/gram.h
+              $(srcdir)/toke.h $(devdir)/gram.h
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/toke_util.c
 toke_util.o: toke_util.lo
 tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(top_builddir)/config.h \
@@ -902,7 +900,7 @@ visudo.o: $(srcdir)/visudo.c $(top_builddir)/config.h \
           $(incdir)/queue.h $(incdir)/fileops.h $(srcdir)/defaults.h \
           $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \
           $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \
-          $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/redblack.h \
-          $(incdir)/gettext.h $(srcdir)/sudoers_version.h \
-          $(incdir)/sudo_conf.h $(incdir)/queue.h $(devdir)/gram.h
+          $(srcdir)/parse.h $(srcdir)/redblack.h $(incdir)/gettext.h \
+          $(srcdir)/sudoers_version.h $(incdir)/sudo_conf.h $(incdir)/queue.h \
+          $(devdir)/gram.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/visudo.c
index ccedd0347f3e84b82ab27415e38156e2fd14aa9b..0c1fc71836837cc263a13b761950c2cf4dfe7bf9 100644 (file)
@@ -131,7 +131,7 @@ alias_add(char *name, int type, struct member *members)
     a->name = name;
     a->type = type;
     /* a->used = false; */
-    list2tq(&a->members, members);
+    HLTQ_TO_TAILQ(&a->members, members, entries);
     if (rbinsert(aliases, a)) {
        snprintf(errbuf, sizeof(errbuf), N_("Alias `%s' already defined"), name);
        alias_free(a);
@@ -176,8 +176,7 @@ alias_free(void *v)
     debug_decl(alias_free, SUDO_DEBUG_ALIAS)
 
     efree(a->name);
-    for (m = a->members.first; m != NULL; m = next) {
-       next = m->next;
+    TAILQ_FOREACH_SAFE(m, &a->members, entries, next) {
        if (m->type == COMMAND) {
                c = (struct sudo_command *) m->name;
                efree(c->cmnd);
index 249e0e99914c1e7ae1ad09a01d1ebd45c4d92be5..37d9de4d1a157199e174e65b59acea35b72ee044 100644 (file)
@@ -502,7 +502,7 @@ update_defaults(int what)
     bool rc = true;
     debug_decl(update_defaults, SUDO_DEBUG_DEFAULTS)
 
-    tq_foreach_fwd(&defaults, def) {
+    TAILQ_FOREACH(def, &defaults, entries) {
        switch (def->type) {
            case DEFAULTS:
                if (ISSET(what, SETDEF_GENERIC) &&
@@ -513,7 +513,7 @@ update_defaults(int what)
 #if 1
                if (ISSET(what, SETDEF_USER)) {
                    int m;
-                   m = userlist_matches(sudo_user.pw, &def->binding);
+                   m = userlist_matches(sudo_user.pw, def->binding);
                    if (m == ALLOW) {
                        if (!set_default(def->var, def->val, def->op))
                            rc = false;
@@ -521,26 +521,26 @@ update_defaults(int what)
                }
 #else
                if (ISSET(what, SETDEF_USER) &&
-                   userlist_matches(sudo_user.pw, &def->binding) == ALLOW &&
+                   userlist_matches(sudo_user.pw, def->binding) == ALLOW &&
                    !set_default(def->var, def->val, def->op))
                    rc = false;
 #endif
                break;
            case DEFAULTS_RUNAS:
                if (ISSET(what, SETDEF_RUNAS) &&
-                   runaslist_matches(&def->binding, NULL, NULL, NULL) == ALLOW &&
+                   runaslist_matches(def->binding, NULL, NULL, NULL) == ALLOW &&
                    !set_default(def->var, def->val, def->op))
                    rc = false;
                break;
            case DEFAULTS_HOST:
                if (ISSET(what, SETDEF_HOST) &&
-                   hostlist_matches(&def->binding) == ALLOW &&
+                   hostlist_matches(def->binding) == ALLOW &&
                    !set_default(def->var, def->val, def->op))
                    rc = false;
                break;
            case DEFAULTS_CMND:
                if (ISSET(what, SETDEF_CMND) &&
-                   cmndlist_matches(&def->binding) == ALLOW &&
+                   cmndlist_matches(def->binding) == ALLOW &&
                    !set_default(def->var, def->val, def->op))
                    rc = false;
                break;
@@ -561,7 +561,7 @@ check_defaults(int what, bool quiet)
     bool rc = true;
     debug_decl(check_defaults, SUDO_DEBUG_DEFAULTS)
 
-    tq_foreach_fwd(&defaults, def) {
+    TAILQ_FOREACH(def, &defaults, entries) {
        switch (def->type) {
            case DEFAULTS:
                if (!ISSET(what, SETDEF_GENERIC))
index 46e15bea2c3d8382320a106f7f8bea5e131f5e9e..3fe555075974b08a5aa90f83cfd07571611393d1 100644 (file)
@@ -117,8 +117,8 @@ bool parse_error = false;
 int errorlineno = -1;
 char *errorfile = NULL;
 
-struct defaults_list defaults;
-struct userspec_list userspecs;
+struct defaults_list defaults = TAILQ_HEAD_INITIALIZER(defaults);
+struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs);
 
 /*
  * Local protoypes
@@ -699,7 +699,7 @@ short *yyss;
 short *yysslim;
 YYSTYPE *yyvs;
 int yystacksize;
-#line 681 "gram.y"
+#line 688 "gram.y"
 void
 sudoerserror(const char *s)
 {
@@ -741,11 +741,10 @@ new_default(char *var, char *val, int op)
     d = ecalloc(1, sizeof(struct defaults));
     d->var = var;
     d->val = val;
-    tq_init(&d->binding);
     /* d->type = 0; */
     d->op = op;
-    d->prev = d;
-    /* d->next = NULL; */
+    /* d->binding = NULL */
+    HLTQ_INIT(d, entries);
 
     debug_return_ptr(d);
 }
@@ -759,8 +758,7 @@ new_member(char *name, int type)
     m = ecalloc(1, sizeof(struct member));
     m->name = name;
     m->type = type;
-    m->prev = m;
-    /* m->next = NULL; */
+    HLTQ_INIT(m, entries);
 
     debug_return_ptr(m);
 }
@@ -787,30 +785,34 @@ static void
 add_defaults(int type, struct member *bmem, struct defaults *defs)
 {
     struct defaults *d;
-    struct member_list binding;
+    struct member_list *binding;
     debug_decl(add_defaults, SUDO_DEBUG_PARSER)
 
     /*
-     * We can only call list2tq once on bmem as it will zero
-     * out the prev pointer when it consumes bmem.
+     * We use a single binding for each entry in defs.
      */
-    list2tq(&binding, bmem);
+    binding = emalloc(sizeof(*binding));
+    if (bmem != NULL)
+       HLTQ_TO_TAILQ(binding, bmem, entries);
+    else
+       TAILQ_INIT(binding);
 
     /*
      * Set type and binding (who it applies to) for new entries.
+     * Then add to the global defaults list.
      */
-    for (d = defs; d != NULL; d = d->next) {
+    HLTQ_FOREACH(d, defs, entries) {
        d->type = type;
        d->binding = binding;
     }
-    tq_append(&defaults, defs);
+    TAILQ_CONCAT_HLTQ(&defaults, defs, entries);
 
     debug_return;
 }
 
 /*
  * Allocate a new struct userspec, populate it, and insert it at the
- * and of the userspecs list.
+ * end of the userspecs list.
  */
 static void
 add_userspec(struct member *members, struct privilege *privs)
@@ -819,11 +821,9 @@ add_userspec(struct member *members, struct privilege *privs)
     debug_decl(add_userspec, SUDO_DEBUG_PARSER)
 
     u = ecalloc(1, sizeof(*u));
-    list2tq(&u->users, members);
-    list2tq(&u->privileges, privs);
-    u->prev = u;
-    /* u->next = NULL; */
-    tq_append(&userspecs, u);
+    HLTQ_TO_TAILQ(&u->users, members, entries);
+    HLTQ_TO_TAILQ(&u->privileges, privs, entries);
+    TAILQ_INSERT_TAIL(&userspecs, u, entries);
 
     debug_return;
 }
@@ -835,21 +835,24 @@ add_userspec(struct member *members, struct privilege *privs)
 void
 init_parser(const char *path, bool quiet)
 {
+    struct member_list *binding;
+    struct member *m;
     struct defaults *d;
-    struct member *m, *binding;
     struct userspec *us;
     struct privilege *priv;
     struct cmndspec *cs;
     struct sudo_command *c;
     debug_decl(init_parser, SUDO_DEBUG_PARSER)
 
-    while ((us = tq_pop(&userspecs)) != NULL) {
-       while ((m = tq_pop(&us->users)) != NULL) {
+    while ((us = TAILQ_FIRST(&userspecs)) != NULL) {
+       TAILQ_REMOVE(&userspecs, us, entries);
+       while ((m = TAILQ_FIRST(&us->users)) != NULL) {
+           TAILQ_REMOVE(&us->users, m, entries);
            efree(m->name);
            efree(m);
        }
-       while ((priv = tq_pop(&us->privileges)) != NULL) {
-           struct member *runasuser = NULL, *runasgroup = NULL;
+       while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
+           struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
 #ifdef HAVE_SELINUX
            char *role = NULL, *type = NULL;
 #endif /* HAVE_SELINUX */
@@ -857,11 +860,14 @@ init_parser(const char *path, bool quiet)
            char *privs = NULL, *limitprivs = NULL;
 #endif /* HAVE_PRIV_SET */
 
-           while ((m = tq_pop(&priv->hostlist)) != NULL) {
+           TAILQ_REMOVE(&us->privileges, priv, entries);
+           while ((m = TAILQ_FIRST(&priv->hostlist)) != NULL) {
+               TAILQ_REMOVE(&priv->hostlist, m, entries);
                efree(m->name);
                efree(m);
            }
-           while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
+           while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) {
+               TAILQ_REMOVE(&priv->cmndlist, cs, entries);
 #ifdef HAVE_SELINUX
                /* Only free the first instance of a role/type. */
                if (cs->role != role) {
@@ -884,19 +890,24 @@ init_parser(const char *path, bool quiet)
                    efree(cs->limitprivs);
                }
 #endif /* HAVE_PRIV_SET */
-               if (tq_last(&cs->runasuserlist) != runasuser) {
-                   runasuser = tq_last(&cs->runasuserlist);
-                   while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
+               /* Only free the first instance of runas user/group lists. */
+               if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
+                   runasuserlist = cs->runasuserlist;
+                   while ((m = TAILQ_FIRST(runasuserlist)) != NULL) {
+                       TAILQ_REMOVE(runasuserlist, m, entries);
                        efree(m->name);
                        efree(m);
                    }
+                   efree(runasuserlist);
                }
-               if (tq_last(&cs->runasgrouplist) != runasgroup) {
-                   runasgroup = tq_last(&cs->runasgrouplist);
-                   while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
+               if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
+                   runasgrouplist = cs->runasgrouplist;
+                   while ((m = TAILQ_FIRST(runasgrouplist)) != NULL) {
+                       TAILQ_REMOVE(runasgrouplist, m, entries);
                        efree(m->name);
                        efree(m);
                    }
+                   efree(runasgrouplist);
                }
                if (cs->cmnd->type == COMMAND) {
                        c = (struct sudo_command *) cs->cmnd->name;
@@ -911,13 +922,15 @@ init_parser(const char *path, bool quiet)
        }
        efree(us);
     }
-    tq_init(&userspecs);
+    TAILQ_INIT(&userspecs);
 
     binding = NULL;
-    while ((d = tq_pop(&defaults)) != NULL) {
-       if (tq_last(&d->binding) != binding) {
-           binding = tq_last(&d->binding);
-           while ((m = tq_pop(&d->binding)) != NULL) {
+    while ((d = TAILQ_FIRST(&defaults)) != NULL) {
+       TAILQ_REMOVE(&defaults, d, entries);
+       if (d->binding != binding) {
+           binding = d->binding;
+           while ((m = TAILQ_FIRST(d->binding)) != NULL) {
+               TAILQ_REMOVE(d->binding, m, entries);
                if (m->type == COMMAND) {
                        c = (struct sudo_command *) m->name;
                        efree(c->cmnd);
@@ -926,12 +939,13 @@ init_parser(const char *path, bool quiet)
                efree(m->name);
                efree(m);
            }
+           efree(d->binding);
        }
        efree(d->var);
        efree(d->val);
        efree(d);
     }
-    tq_init(&defaults);
+    TAILQ_INIT(&defaults);
 
     init_aliases();
 
@@ -947,7 +961,7 @@ init_parser(const char *path, bool quiet)
 
     debug_return;
 }
-#line 898 "gram.c"
+#line 912 "gram.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -1228,7 +1242,7 @@ break;
 case 18:
 #line 232 "gram.y"
 {
-                           list_append(yyvsp[-2].defaults, yyvsp[0].defaults);
+                           HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries);
                            yyval.defaults = yyvsp[-2].defaults;
                        }
 break;
@@ -1265,7 +1279,7 @@ break;
 case 25:
 #line 256 "gram.y"
 {
-                           list_append(yyvsp[-2].privilege, yyvsp[0].privilege);
+                           HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries);
                            yyval.privilege = yyvsp[-2].privilege;
                        }
 break;
@@ -1273,108 +1287,116 @@ case 26:
 #line 262 "gram.y"
 {
                            struct privilege *p = ecalloc(1, sizeof(*p));
-                           list2tq(&p->hostlist, yyvsp[-2].member);
-                           list2tq(&p->cmndlist, yyvsp[0].cmndspec);
-                           p->prev = p;
-                           /* p->next = NULL; */
+                           HLTQ_TO_TAILQ(&p->hostlist, yyvsp[-2].member, entries);
+                           HLTQ_TO_TAILQ(&p->cmndlist, yyvsp[0].cmndspec, entries);
+                           HLTQ_INIT(p, entries);
                            yyval.privilege = p;
                        }
 break;
 case 27:
-#line 272 "gram.y"
+#line 271 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = false;
                        }
 break;
 case 28:
-#line 276 "gram.y"
+#line 275 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = true;
                        }
 break;
 case 29:
-#line 282 "gram.y"
+#line 281 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
 case 30:
-#line 285 "gram.y"
+#line 284 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
 case 31:
-#line 288 "gram.y"
+#line 287 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, NETGROUP);
                        }
 break;
 case 32:
-#line 291 "gram.y"
+#line 290 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, NTWKADDR);
                        }
 break;
 case 33:
-#line 294 "gram.y"
+#line 293 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
 case 35:
-#line 300 "gram.y"
+#line 299 "gram.y"
 {
-                           list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec);
+                           struct cmndspec *prev;
+                           prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries);
+                           HLTQ_CONCAT(yyvsp[-2].cmndspec, yyvsp[0].cmndspec, entries);
 #ifdef HAVE_SELINUX
                            /* propagate role and type */
                            if (yyvsp[0].cmndspec->role == NULL)
-                               yyvsp[0].cmndspec->role = yyvsp[0].cmndspec->prev->role;
+                               yyvsp[0].cmndspec->role = prev->role;
                            if (yyvsp[0].cmndspec->type == NULL)
-                               yyvsp[0].cmndspec->type = yyvsp[0].cmndspec->prev->type;
+                               yyvsp[0].cmndspec->type = prev->type;
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
                            /* propagate privs & limitprivs */
                            if (yyvsp[0].cmndspec->privs == NULL)
-                               yyvsp[0].cmndspec->privs = yyvsp[0].cmndspec->prev->privs;
+                               yyvsp[0].cmndspec->privs = prev->privs;
                            if (yyvsp[0].cmndspec->limitprivs == NULL)
-                               yyvsp[0].cmndspec->limitprivs = yyvsp[0].cmndspec->prev->limitprivs;
+                               yyvsp[0].cmndspec->limitprivs = prev->limitprivs;
 #endif /* HAVE_PRIV_SET */
                            /* propagate tags and runas list */
                            if (yyvsp[0].cmndspec->tags.nopasswd == UNSPEC)
-                               yyvsp[0].cmndspec->tags.nopasswd = yyvsp[0].cmndspec->prev->tags.nopasswd;
+                               yyvsp[0].cmndspec->tags.nopasswd = prev->tags.nopasswd;
                            if (yyvsp[0].cmndspec->tags.noexec == UNSPEC)
-                               yyvsp[0].cmndspec->tags.noexec = yyvsp[0].cmndspec->prev->tags.noexec;
+                               yyvsp[0].cmndspec->tags.noexec = prev->tags.noexec;
                            if (yyvsp[0].cmndspec->tags.setenv == UNSPEC &&
-                               yyvsp[0].cmndspec->prev->tags.setenv != IMPLIED)
-                               yyvsp[0].cmndspec->tags.setenv = yyvsp[0].cmndspec->prev->tags.setenv;
+                               prev->tags.setenv != IMPLIED)
+                               yyvsp[0].cmndspec->tags.setenv = prev->tags.setenv;
                            if (yyvsp[0].cmndspec->tags.log_input == UNSPEC)
-                               yyvsp[0].cmndspec->tags.log_input = yyvsp[0].cmndspec->prev->tags.log_input;
+                               yyvsp[0].cmndspec->tags.log_input = prev->tags.log_input;
                            if (yyvsp[0].cmndspec->tags.log_output == UNSPEC)
-                               yyvsp[0].cmndspec->tags.log_output = yyvsp[0].cmndspec->prev->tags.log_output;
-                           if ((tq_empty(&yyvsp[0].cmndspec->runasuserlist) &&
-                                tq_empty(&yyvsp[0].cmndspec->runasgrouplist)) &&
-                               (!tq_empty(&yyvsp[0].cmndspec->prev->runasuserlist) ||
-                                !tq_empty(&yyvsp[0].cmndspec->prev->runasgrouplist))) {
-                               yyvsp[0].cmndspec->runasuserlist = yyvsp[0].cmndspec->prev->runasuserlist;
-                               yyvsp[0].cmndspec->runasgrouplist = yyvsp[0].cmndspec->prev->runasgrouplist;
+                               yyvsp[0].cmndspec->tags.log_output = prev->tags.log_output;
+                           if ((yyvsp[0].cmndspec->runasuserlist == NULL &&
+                                yyvsp[0].cmndspec->runasgrouplist == NULL) &&
+                               (prev->runasuserlist != NULL ||
+                                prev->runasgrouplist != NULL)) {
+                               yyvsp[0].cmndspec->runasuserlist = prev->runasuserlist;
+                               yyvsp[0].cmndspec->runasgrouplist = prev->runasgrouplist;
                            }
                            yyval.cmndspec = yyvsp[-2].cmndspec;
                        }
 break;
 case 36:
-#line 339 "gram.y"
+#line 340 "gram.y"
 {
                            struct cmndspec *cs = ecalloc(1, sizeof(*cs));
                            if (yyvsp[-4].runas != NULL) {
-                               list2tq(&cs->runasuserlist, yyvsp[-4].runas->runasusers);
-                               list2tq(&cs->runasgrouplist, yyvsp[-4].runas->runasgroups);
+                               if (yyvsp[-4].runas->runasusers != NULL) {
+                                   cs->runasuserlist =
+                                       emalloc(sizeof(*cs->runasuserlist));
+                                   HLTQ_TO_TAILQ(cs->runasuserlist,
+                                       yyvsp[-4].runas->runasusers, entries);
+                               }
+                               if (yyvsp[-4].runas->runasgroups != NULL) {
+                                   cs->runasgrouplist =
+                                       emalloc(sizeof(*cs->runasgrouplist));
+                                   HLTQ_TO_TAILQ(cs->runasgrouplist,
+                                       yyvsp[-4].runas->runasgroups, entries);
+                               }
                                efree(yyvsp[-4].runas);
-                           } else {
-                               tq_init(&cs->runasuserlist);
-                               tq_init(&cs->runasgrouplist);
                            }
 #ifdef HAVE_SELINUX
                            cs->role = yyvsp[-3].seinfo.role;
@@ -1386,8 +1408,7 @@ case 36:
 #endif
                            cs->tags = yyvsp[-1].tag;
                            cs->cmnd = yyvsp[0].member;
-                           cs->prev = cs;
-                           cs->next = NULL;
+                           HLTQ_INIT(cs, entries);
                            /* sudo "ALL" implies the SETENV tag */
                            if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
                                cs->tags.setenv == UNSPEC)
@@ -1396,37 +1417,37 @@ case 36:
                        }
 break;
 case 37:
-#line 369 "gram.y"
+#line 376 "gram.y"
 {
                            yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string);
                        }
 break;
 case 38:
-#line 372 "gram.y"
+#line 379 "gram.y"
 {
                            yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string);
                        }
 break;
 case 39:
-#line 375 "gram.y"
+#line 382 "gram.y"
 {
                            yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string);
                        }
 break;
 case 40:
-#line 378 "gram.y"
+#line 385 "gram.y"
 {
                            yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string);
                        }
 break;
 case 41:
-#line 383 "gram.y"
+#line 390 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                        }
 break;
 case 42:
-#line 386 "gram.y"
+#line 393 "gram.y"
 {
                            /* XXX - yuck */
                            struct sudo_command *c = (struct sudo_command *)(yyvsp[0].member->name);
@@ -1435,127 +1456,127 @@ case 42:
                        }
 break;
 case 43:
-#line 394 "gram.y"
+#line 401 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = false;
                        }
 break;
 case 44:
-#line 398 "gram.y"
+#line 405 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = true;
                        }
 break;
 case 45:
-#line 404 "gram.y"
+#line 411 "gram.y"
 {
                            yyval.string = yyvsp[0].string;
                        }
 break;
 case 46:
-#line 409 "gram.y"
+#line 416 "gram.y"
 {
                            yyval.string = yyvsp[0].string;
                        }
 break;
 case 47:
-#line 414 "gram.y"
+#line 421 "gram.y"
 {
                            yyval.seinfo.role = NULL;
                            yyval.seinfo.type = NULL;
                        }
 break;
 case 48:
-#line 418 "gram.y"
+#line 425 "gram.y"
 {
                            yyval.seinfo.role = yyvsp[0].string;
                            yyval.seinfo.type = NULL;
                        }
 break;
 case 49:
-#line 422 "gram.y"
+#line 429 "gram.y"
 {
                            yyval.seinfo.type = yyvsp[0].string;
                            yyval.seinfo.role = NULL;
                        }
 break;
 case 50:
-#line 426 "gram.y"
+#line 433 "gram.y"
 {
                            yyval.seinfo.role = yyvsp[-1].string;
                            yyval.seinfo.type = yyvsp[0].string;
                        }
 break;
 case 51:
-#line 430 "gram.y"
+#line 437 "gram.y"
 {
                            yyval.seinfo.type = yyvsp[-1].string;
                            yyval.seinfo.role = yyvsp[0].string;
                        }
 break;
 case 52:
-#line 436 "gram.y"
+#line 443 "gram.y"
 {
                            yyval.string = yyvsp[0].string;
                        }
 break;
 case 53:
-#line 440 "gram.y"
+#line 447 "gram.y"
 {
                            yyval.string = yyvsp[0].string;
                        }
 break;
 case 54:
-#line 445 "gram.y"
+#line 452 "gram.y"
 {
                            yyval.privinfo.privs = NULL;
                            yyval.privinfo.limitprivs = NULL;
                        }
 break;
 case 55:
-#line 449 "gram.y"
+#line 456 "gram.y"
 {
                            yyval.privinfo.privs = yyvsp[0].string;
                            yyval.privinfo.limitprivs = NULL;
                        }
 break;
 case 56:
-#line 453 "gram.y"
+#line 460 "gram.y"
 {
                            yyval.privinfo.privs = NULL;
                            yyval.privinfo.limitprivs = yyvsp[0].string;
                        }
 break;
 case 57:
-#line 457 "gram.y"
+#line 464 "gram.y"
 {
                            yyval.privinfo.privs = yyvsp[-1].string;
                            yyval.privinfo.limitprivs = yyvsp[0].string;
                        }
 break;
 case 58:
-#line 461 "gram.y"
+#line 468 "gram.y"
 {
                            yyval.privinfo.limitprivs = yyvsp[-1].string;
                            yyval.privinfo.privs = yyvsp[0].string;
                        }
 break;
 case 59:
-#line 467 "gram.y"
+#line 474 "gram.y"
 {
                            yyval.runas = NULL;
                        }
 break;
 case 60:
-#line 470 "gram.y"
+#line 477 "gram.y"
 {
                            yyval.runas = yyvsp[-1].runas;
                        }
 break;
 case 61:
-#line 475 "gram.y"
+#line 482 "gram.y"
 {
                            yyval.runas = ecalloc(1, sizeof(struct runascontainer));
                            yyval.runas->runasusers = new_member(NULL, MYSELF);
@@ -1563,7 +1584,7 @@ case 61:
                        }
 break;
 case 62:
-#line 480 "gram.y"
+#line 487 "gram.y"
 {
                            yyval.runas = ecalloc(1, sizeof(struct runascontainer));
                            yyval.runas->runasusers = yyvsp[0].member;
@@ -1571,7 +1592,7 @@ case 62:
                        }
 break;
 case 63:
-#line 485 "gram.y"
+#line 492 "gram.y"
 {
                            yyval.runas = ecalloc(1, sizeof(struct runascontainer));
                            yyval.runas->runasusers = yyvsp[-2].member;
@@ -1579,7 +1600,7 @@ case 63:
                        }
 break;
 case 64:
-#line 490 "gram.y"
+#line 497 "gram.y"
 {
                            yyval.runas = ecalloc(1, sizeof(struct runascontainer));
                            /* $$->runasusers = NULL; */
@@ -1587,7 +1608,7 @@ case 64:
                        }
 break;
 case 65:
-#line 495 "gram.y"
+#line 502 "gram.y"
 {
                            yyval.runas = ecalloc(1, sizeof(struct runascontainer));
                            yyval.runas->runasusers = new_member(NULL, MYSELF);
@@ -1595,86 +1616,86 @@ case 65:
                        }
 break;
 case 66:
-#line 502 "gram.y"
+#line 509 "gram.y"
 {
                            yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv =
                                yyval.tag.log_input = yyval.tag.log_output = UNSPEC;
                        }
 break;
 case 67:
-#line 506 "gram.y"
+#line 513 "gram.y"
 {
                            yyval.tag.nopasswd = true;
                        }
 break;
 case 68:
-#line 509 "gram.y"
+#line 516 "gram.y"
 {
                            yyval.tag.nopasswd = false;
                        }
 break;
 case 69:
-#line 512 "gram.y"
+#line 519 "gram.y"
 {
                            yyval.tag.noexec = true;
                        }
 break;
 case 70:
-#line 515 "gram.y"
+#line 522 "gram.y"
 {
                            yyval.tag.noexec = false;
                        }
 break;
 case 71:
-#line 518 "gram.y"
+#line 525 "gram.y"
 {
                            yyval.tag.setenv = true;
                        }
 break;
 case 72:
-#line 521 "gram.y"
+#line 528 "gram.y"
 {
                            yyval.tag.setenv = false;
                        }
 break;
 case 73:
-#line 524 "gram.y"
+#line 531 "gram.y"
 {
                            yyval.tag.log_input = true;
                        }
 break;
 case 74:
-#line 527 "gram.y"
+#line 534 "gram.y"
 {
                            yyval.tag.log_input = false;
                        }
 break;
 case 75:
-#line 530 "gram.y"
+#line 537 "gram.y"
 {
                            yyval.tag.log_output = true;
                        }
 break;
 case 76:
-#line 533 "gram.y"
+#line 540 "gram.y"
 {
                            yyval.tag.log_output = false;
                        }
 break;
 case 77:
-#line 538 "gram.y"
+#line 545 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
 case 78:
-#line 541 "gram.y"
+#line 548 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
 case 79:
-#line 544 "gram.y"
+#line 551 "gram.y"
 {
                            struct sudo_command *c = ecalloc(1, sizeof(*c));
                            c->cmnd = yyvsp[0].command.cmnd;
@@ -1683,7 +1704,7 @@ case 79:
                        }
 break;
 case 82:
-#line 556 "gram.y"
+#line 563 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) {
@@ -1693,14 +1714,14 @@ case 82:
                        }
 break;
 case 84:
-#line 566 "gram.y"
+#line 573 "gram.y"
 {
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
 case 87:
-#line 576 "gram.y"
+#line 583 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) {
@@ -1710,14 +1731,14 @@ case 87:
                        }
 break;
 case 89:
-#line 586 "gram.y"
+#line 593 "gram.y"
 {
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
 case 92:
-#line 596 "gram.y"
+#line 603 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) {
@@ -1727,7 +1748,7 @@ case 92:
                        }
 break;
 case 95:
-#line 609 "gram.y"
+#line 616 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) {
@@ -1737,96 +1758,96 @@ case 95:
                        }
 break;
 case 97:
-#line 619 "gram.y"
+#line 626 "gram.y"
 {
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
 case 98:
-#line 625 "gram.y"
+#line 632 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = false;
                        }
 break;
 case 99:
-#line 629 "gram.y"
+#line 636 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = true;
                        }
 break;
 case 100:
-#line 635 "gram.y"
+#line 642 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
 case 101:
-#line 638 "gram.y"
+#line 645 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
 case 102:
-#line 641 "gram.y"
+#line 648 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, NETGROUP);
                        }
 break;
 case 103:
-#line 644 "gram.y"
+#line 651 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, USERGROUP);
                        }
 break;
 case 104:
-#line 647 "gram.y"
+#line 654 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
 case 106:
-#line 653 "gram.y"
+#line 660 "gram.y"
 {
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
 case 107:
-#line 659 "gram.y"
+#line 666 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = false;
                        }
 break;
 case 108:
-#line 663 "gram.y"
+#line 670 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = true;
                        }
 break;
 case 109:
-#line 669 "gram.y"
+#line 676 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
 case 110:
-#line 672 "gram.y"
+#line 679 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
 case 111:
-#line 675 "gram.y"
+#line 682 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
-#line 1777 "gram.c"
+#line 1798 "gram.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
index 0642802b57753a2a9c786fd717d3c9b798fe47bc..6b4212ce40d034e920ed0b798081c8e7eaf2302f 100644 (file)
@@ -79,8 +79,8 @@ bool parse_error = false;
 int errorlineno = -1;
 char *errorfile = NULL;
 
-struct defaults_list defaults;
-struct userspec_list userspecs;
+struct defaults_list defaults = TAILQ_HEAD_INITIALIZER(defaults);
+struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs);
 
 /*
  * Local protoypes
@@ -230,7 +230,7 @@ entry               :       COMMENT {
 
 defaults_list  :       defaults_entry
                |       defaults_list ',' defaults_entry {
-                           list_append($1, $3);
+                           HLTQ_CONCAT($1, $3, entries);
                            $$ = $1;
                        }
                ;
@@ -254,17 +254,16 @@ defaults_entry    :       DEFVAR {
 
 privileges     :       privilege
                |       privileges ':' privilege {
-                           list_append($1, $3);
+                           HLTQ_CONCAT($1, $3, entries);
                            $$ = $1;
                        }
                ;
 
 privilege      :       hostlist '=' cmndspeclist {
                            struct privilege *p = ecalloc(1, sizeof(*p));
-                           list2tq(&p->hostlist, $1);
-                           list2tq(&p->cmndlist, $3);
-                           p->prev = p;
-                           /* p->next = NULL; */
+                           HLTQ_TO_TAILQ(&p->hostlist, $1, entries);
+                           HLTQ_TO_TAILQ(&p->cmndlist, $3, entries);
+                           HLTQ_INIT(p, entries);
                            $$ = p;
                        }
                ;
@@ -298,39 +297,41 @@ host              :       ALIAS {
 
 cmndspeclist   :       cmndspec
                |       cmndspeclist ',' cmndspec {
-                           list_append($1, $3);
+                           struct cmndspec *prev;
+                           prev = HLTQ_LAST($1, cmndspec, entries);
+                           HLTQ_CONCAT($1, $3, entries);
 #ifdef HAVE_SELINUX
                            /* propagate role and type */
                            if ($3->role == NULL)
-                               $3->role = $3->prev->role;
+                               $3->role = prev->role;
                            if ($3->type == NULL)
-                               $3->type = $3->prev->type;
+                               $3->type = prev->type;
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
                            /* propagate privs & limitprivs */
                            if ($3->privs == NULL)
-                               $3->privs = $3->prev->privs;
+                               $3->privs = prev->privs;
                            if ($3->limitprivs == NULL)
-                               $3->limitprivs = $3->prev->limitprivs;
+                               $3->limitprivs = prev->limitprivs;
 #endif /* HAVE_PRIV_SET */
                            /* propagate tags and runas list */
                            if ($3->tags.nopasswd == UNSPEC)
-                               $3->tags.nopasswd = $3->prev->tags.nopasswd;
+                               $3->tags.nopasswd = prev->tags.nopasswd;
                            if ($3->tags.noexec == UNSPEC)
-                               $3->tags.noexec = $3->prev->tags.noexec;
+                               $3->tags.noexec = prev->tags.noexec;
                            if ($3->tags.setenv == UNSPEC &&
-                               $3->prev->tags.setenv != IMPLIED)
-                               $3->tags.setenv = $3->prev->tags.setenv;
+                               prev->tags.setenv != IMPLIED)
+                               $3->tags.setenv = prev->tags.setenv;
                            if ($3->tags.log_input == UNSPEC)
-                               $3->tags.log_input = $3->prev->tags.log_input;
+                               $3->tags.log_input = prev->tags.log_input;
                            if ($3->tags.log_output == UNSPEC)
-                               $3->tags.log_output = $3->prev->tags.log_output;
-                           if ((tq_empty(&$3->runasuserlist) &&
-                                tq_empty(&$3->runasgrouplist)) &&
-                               (!tq_empty(&$3->prev->runasuserlist) ||
-                                !tq_empty(&$3->prev->runasgrouplist))) {
-                               $3->runasuserlist = $3->prev->runasuserlist;
-                               $3->runasgrouplist = $3->prev->runasgrouplist;
+                               $3->tags.log_output = prev->tags.log_output;
+                           if (($3->runasuserlist == NULL &&
+                                $3->runasgrouplist == NULL) &&
+                               (prev->runasuserlist != NULL ||
+                                prev->runasgrouplist != NULL)) {
+                               $3->runasuserlist = prev->runasuserlist;
+                               $3->runasgrouplist = prev->runasgrouplist;
                            }
                            $$ = $1;
                        }
@@ -339,12 +340,19 @@ cmndspeclist      :       cmndspec
 cmndspec       :       runasspec selinux solarisprivs cmndtag digcmnd {
                            struct cmndspec *cs = ecalloc(1, sizeof(*cs));
                            if ($1 != NULL) {
-                               list2tq(&cs->runasuserlist, $1->runasusers);
-                               list2tq(&cs->runasgrouplist, $1->runasgroups);
+                               if ($1->runasusers != NULL) {
+                                   cs->runasuserlist =
+                                       emalloc(sizeof(*cs->runasuserlist));
+                                   HLTQ_TO_TAILQ(cs->runasuserlist,
+                                       $1->runasusers, entries);
+                               }
+                               if ($1->runasgroups != NULL) {
+                                   cs->runasgrouplist =
+                                       emalloc(sizeof(*cs->runasgrouplist));
+                                   HLTQ_TO_TAILQ(cs->runasgrouplist,
+                                       $1->runasgroups, entries);
+                               }
                                efree($1);
-                           } else {
-                               tq_init(&cs->runasuserlist);
-                               tq_init(&cs->runasgrouplist);
                            }
 #ifdef HAVE_SELINUX
                            cs->role = $2.role;
@@ -356,8 +364,7 @@ cmndspec    :       runasspec selinux solarisprivs cmndtag digcmnd {
 #endif
                            cs->tags = $4;
                            cs->cmnd = $5;
-                           cs->prev = cs;
-                           cs->next = NULL;
+                           HLTQ_INIT(cs, entries);
                            /* sudo "ALL" implies the SETENV tag */
                            if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
                                cs->tags.setenv == UNSPEC)
@@ -564,7 +571,7 @@ hostalias   :       ALIAS '=' hostlist {
 
 hostlist       :       ophost
                |       hostlist ',' ophost {
-                           list_append($1, $3);
+                           HLTQ_CONCAT($1, $3, entries);
                            $$ = $1;
                        }
                ;
@@ -584,7 +591,7 @@ cmndalias   :       ALIAS '=' cmndlist {
 
 cmndlist       :       digcmnd
                |       cmndlist ',' digcmnd {
-                           list_append($1, $3);
+                           HLTQ_CONCAT($1, $3, entries);
                            $$ = $1;
                        }
                ;
@@ -617,7 +624,7 @@ useralias   :       ALIAS '=' userlist {
 
 userlist       :       opuser
                |       userlist ',' opuser {
-                           list_append($1, $3);
+                           HLTQ_CONCAT($1, $3, entries);
                            $$ = $1;
                        }
                ;
@@ -651,7 +658,7 @@ user                :       ALIAS {
 
 grouplist      :       opgroup
                |       grouplist ',' opgroup {
-                           list_append($1, $3);
+                           HLTQ_CONCAT($1, $3, entries);
                            $$ = $1;
                        }
                ;
@@ -719,11 +726,10 @@ new_default(char *var, char *val, int op)
     d = ecalloc(1, sizeof(struct defaults));
     d->var = var;
     d->val = val;
-    tq_init(&d->binding);
     /* d->type = 0; */
     d->op = op;
-    d->prev = d;
-    /* d->next = NULL; */
+    /* d->binding = NULL */
+    HLTQ_INIT(d, entries);
 
     debug_return_ptr(d);
 }
@@ -737,8 +743,7 @@ new_member(char *name, int type)
     m = ecalloc(1, sizeof(struct member));
     m->name = name;
     m->type = type;
-    m->prev = m;
-    /* m->next = NULL; */
+    HLTQ_INIT(m, entries);
 
     debug_return_ptr(m);
 }
@@ -765,30 +770,34 @@ static void
 add_defaults(int type, struct member *bmem, struct defaults *defs)
 {
     struct defaults *d;
-    struct member_list binding;
+    struct member_list *binding;
     debug_decl(add_defaults, SUDO_DEBUG_PARSER)
 
     /*
-     * We can only call list2tq once on bmem as it will zero
-     * out the prev pointer when it consumes bmem.
+     * We use a single binding for each entry in defs.
      */
-    list2tq(&binding, bmem);
+    binding = emalloc(sizeof(*binding));
+    if (bmem != NULL)
+       HLTQ_TO_TAILQ(binding, bmem, entries);
+    else
+       TAILQ_INIT(binding);
 
     /*
      * Set type and binding (who it applies to) for new entries.
+     * Then add to the global defaults list.
      */
-    for (d = defs; d != NULL; d = d->next) {
+    HLTQ_FOREACH(d, defs, entries) {
        d->type = type;
        d->binding = binding;
     }
-    tq_append(&defaults, defs);
+    TAILQ_CONCAT_HLTQ(&defaults, defs, entries);
 
     debug_return;
 }
 
 /*
  * Allocate a new struct userspec, populate it, and insert it at the
- * and of the userspecs list.
+ * end of the userspecs list.
  */
 static void
 add_userspec(struct member *members, struct privilege *privs)
@@ -797,11 +806,9 @@ add_userspec(struct member *members, struct privilege *privs)
     debug_decl(add_userspec, SUDO_DEBUG_PARSER)
 
     u = ecalloc(1, sizeof(*u));
-    list2tq(&u->users, members);
-    list2tq(&u->privileges, privs);
-    u->prev = u;
-    /* u->next = NULL; */
-    tq_append(&userspecs, u);
+    HLTQ_TO_TAILQ(&u->users, members, entries);
+    HLTQ_TO_TAILQ(&u->privileges, privs, entries);
+    TAILQ_INSERT_TAIL(&userspecs, u, entries);
 
     debug_return;
 }
@@ -813,21 +820,24 @@ add_userspec(struct member *members, struct privilege *privs)
 void
 init_parser(const char *path, bool quiet)
 {
+    struct member_list *binding;
+    struct member *m;
     struct defaults *d;
-    struct member *m, *binding;
     struct userspec *us;
     struct privilege *priv;
     struct cmndspec *cs;
     struct sudo_command *c;
     debug_decl(init_parser, SUDO_DEBUG_PARSER)
 
-    while ((us = tq_pop(&userspecs)) != NULL) {
-       while ((m = tq_pop(&us->users)) != NULL) {
+    while ((us = TAILQ_FIRST(&userspecs)) != NULL) {
+       TAILQ_REMOVE(&userspecs, us, entries);
+       while ((m = TAILQ_FIRST(&us->users)) != NULL) {
+           TAILQ_REMOVE(&us->users, m, entries);
            efree(m->name);
            efree(m);
        }
-       while ((priv = tq_pop(&us->privileges)) != NULL) {
-           struct member *runasuser = NULL, *runasgroup = NULL;
+       while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
+           struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
 #ifdef HAVE_SELINUX
            char *role = NULL, *type = NULL;
 #endif /* HAVE_SELINUX */
@@ -835,11 +845,14 @@ init_parser(const char *path, bool quiet)
            char *privs = NULL, *limitprivs = NULL;
 #endif /* HAVE_PRIV_SET */
 
-           while ((m = tq_pop(&priv->hostlist)) != NULL) {
+           TAILQ_REMOVE(&us->privileges, priv, entries);
+           while ((m = TAILQ_FIRST(&priv->hostlist)) != NULL) {
+               TAILQ_REMOVE(&priv->hostlist, m, entries);
                efree(m->name);
                efree(m);
            }
-           while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
+           while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) {
+               TAILQ_REMOVE(&priv->cmndlist, cs, entries);
 #ifdef HAVE_SELINUX
                /* Only free the first instance of a role/type. */
                if (cs->role != role) {
@@ -862,19 +875,24 @@ init_parser(const char *path, bool quiet)
                    efree(cs->limitprivs);
                }
 #endif /* HAVE_PRIV_SET */
-               if (tq_last(&cs->runasuserlist) != runasuser) {
-                   runasuser = tq_last(&cs->runasuserlist);
-                   while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
+               /* Only free the first instance of runas user/group lists. */
+               if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
+                   runasuserlist = cs->runasuserlist;
+                   while ((m = TAILQ_FIRST(runasuserlist)) != NULL) {
+                       TAILQ_REMOVE(runasuserlist, m, entries);
                        efree(m->name);
                        efree(m);
                    }
+                   efree(runasuserlist);
                }
-               if (tq_last(&cs->runasgrouplist) != runasgroup) {
-                   runasgroup = tq_last(&cs->runasgrouplist);
-                   while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
+               if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
+                   runasgrouplist = cs->runasgrouplist;
+                   while ((m = TAILQ_FIRST(runasgrouplist)) != NULL) {
+                       TAILQ_REMOVE(runasgrouplist, m, entries);
                        efree(m->name);
                        efree(m);
                    }
+                   efree(runasgrouplist);
                }
                if (cs->cmnd->type == COMMAND) {
                        c = (struct sudo_command *) cs->cmnd->name;
@@ -889,13 +907,15 @@ init_parser(const char *path, bool quiet)
        }
        efree(us);
     }
-    tq_init(&userspecs);
+    TAILQ_INIT(&userspecs);
 
     binding = NULL;
-    while ((d = tq_pop(&defaults)) != NULL) {
-       if (tq_last(&d->binding) != binding) {
-           binding = tq_last(&d->binding);
-           while ((m = tq_pop(&d->binding)) != NULL) {
+    while ((d = TAILQ_FIRST(&defaults)) != NULL) {
+       TAILQ_REMOVE(&defaults, d, entries);
+       if (d->binding != binding) {
+           binding = d->binding;
+           while ((m = TAILQ_FIRST(d->binding)) != NULL) {
+               TAILQ_REMOVE(d->binding, m, entries);
                if (m->type == COMMAND) {
                        c = (struct sudo_command *) m->name;
                        efree(c->cmnd);
@@ -904,12 +924,13 @@ init_parser(const char *path, bool quiet)
                efree(m->name);
                efree(m);
            }
+           efree(d->binding);
        }
        efree(d->var);
        efree(d->val);
        efree(d);
     }
-    tq_init(&defaults);
+    TAILQ_INIT(&defaults);
 
     init_aliases();
 
index dd7f8bc24bfaaecf7f80c4b324122af72c810d91..1e7892e53e91e8d092d68022ff36e0fe4eeb9997 100644 (file)
@@ -91,7 +91,7 @@
 #include "sha2.h"
 #include <gram.h>
 
-static struct member_list empty;
+static struct member_list empty = TAILQ_HEAD_INITIALIZER(empty);
 
 static bool command_matches_dir(char *, size_t);
 #ifndef SUDOERS_NAME_MATCH
@@ -117,7 +117,7 @@ userlist_matches(struct passwd *pw, struct member_list *list)
     int rval, matched = UNSPEC;
     debug_decl(userlist_matches, SUDO_DEBUG_MATCH)
 
-    tq_foreach_rev(list, m) {
+    TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
        switch (m->type) {
            case ALL:
                matched = !m->negated;
@@ -169,46 +169,48 @@ runaslist_matches(struct member_list *user_list,
 
     if (runas_pw != NULL) {
        /* If no runas user or runas group listed in sudoers, use default. */
-       if (tq_empty(user_list) && tq_empty(group_list))
+       if (user_list == NULL && group_list == NULL)
            debug_return_int(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
 
-       tq_foreach_rev(user_list, m) {
-           switch (m->type) {
-               case ALL:
-                   user_matched = !m->negated;
-                   break;
-               case NETGROUP:
-                   if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
-                       user_matched = !m->negated;
-                   break;
-               case USERGROUP:
-                   if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
+       if (user_list != NULL) {
+           TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) {
+               switch (m->type) {
+                   case ALL:
                        user_matched = !m->negated;
-                   break;
-               case ALIAS:
-                   if ((a = alias_get(m->name, RUNASALIAS)) != NULL) {
-                       rval = runaslist_matches(&a->members, &empty,
-                           matching_user, NULL);
-                       if (rval != UNSPEC)
-                           user_matched = m->negated ? !rval : rval;
-                       alias_put(a);
                        break;
-                   }
-                   /* FALLTHROUGH */
-               case WORD:
-                   if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
-                       user_matched = !m->negated;
-                   break;
-               case MYSELF:
-                   if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) ||
-                       strcmp(user_name, runas_pw->pw_name) == 0)
-                       user_matched = !m->negated;
+                   case NETGROUP:
+                       if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
+                           user_matched = !m->negated;
+                       break;
+                   case USERGROUP:
+                       if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
+                           user_matched = !m->negated;
+                       break;
+                   case ALIAS:
+                       if ((a = alias_get(m->name, RUNASALIAS)) != NULL) {
+                           rval = runaslist_matches(&a->members, &empty,
+                               matching_user, NULL);
+                           if (rval != UNSPEC)
+                               user_matched = m->negated ? !rval : rval;
+                           alias_put(a);
+                           break;
+                       }
+                       /* FALLTHROUGH */
+                   case WORD:
+                       if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
+                           user_matched = !m->negated;
+                       break;
+                   case MYSELF:
+                       if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) ||
+                           strcmp(user_name, runas_pw->pw_name) == 0)
+                           user_matched = !m->negated;
+                       break;
+               }
+               if (user_matched != UNSPEC) {
+                   if (matching_user != NULL && m->type != ALIAS)
+                       *matching_user = m;
                    break;
-           }
-           if (user_matched != UNSPEC) {
-               if (matching_user != NULL && m->type != ALIAS)
-                   *matching_user = m;
-               break;
+               }
            }
        }
     }
@@ -218,30 +220,32 @@ runaslist_matches(struct member_list *user_list,
            if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
                user_matched = ALLOW;   /* only changing group */
        }
-       tq_foreach_rev(group_list, m) {
-           switch (m->type) {
-               case ALL:
-                   group_matched = !m->negated;
-                   break;
-               case ALIAS:
-                   if ((a = alias_get(m->name, RUNASALIAS)) != NULL) {
-                       rval = runaslist_matches(&empty, &a->members,
-                           NULL, matching_group);
-                       if (rval != UNSPEC)
-                           group_matched = m->negated ? !rval : rval;
-                       alias_put(a);
-                       break;
-                   }
-                   /* FALLTHROUGH */
-               case WORD:
-                   if (group_matches(m->name, runas_gr))
+       if (group_list != NULL) {
+           TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) {
+               switch (m->type) {
+                   case ALL:
                        group_matched = !m->negated;
+                       break;
+                   case ALIAS:
+                       if ((a = alias_get(m->name, RUNASALIAS)) != NULL) {
+                           rval = runaslist_matches(&empty, &a->members,
+                               NULL, matching_group);
+                           if (rval != UNSPEC)
+                               group_matched = m->negated ? !rval : rval;
+                           alias_put(a);
+                           break;
+                       }
+                       /* FALLTHROUGH */
+                   case WORD:
+                       if (group_matches(m->name, runas_gr))
+                           group_matched = !m->negated;
+                       break;
+               }
+               if (group_matched != UNSPEC) {
+                   if (matching_group != NULL && m->type != ALIAS)
+                       *matching_group = m;
                    break;
-           }
-           if (group_matched != UNSPEC) {
-               if (matching_group != NULL && m->type != ALIAS)
-                   *matching_group = m;
-               break;
+               }
            }
        }
        if (group_matched == UNSPEC) {
@@ -269,7 +273,7 @@ hostlist_matches(struct member_list *list)
     int rval, matched = UNSPEC;
     debug_decl(hostlist_matches, SUDO_DEBUG_MATCH)
 
-    tq_foreach_rev(list, m) {
+    TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
        switch (m->type) {
            case ALL:
                matched = !m->negated;
@@ -313,7 +317,7 @@ cmndlist_matches(struct member_list *list)
     int matched = UNSPEC;
     debug_decl(cmndlist_matches, SUDO_DEBUG_MATCH)
 
-    tq_foreach_rev(list, m) {
+    TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
        matched = cmnd_matches(m);
        if (matched != UNSPEC)
            break;
index f91e413087d951f715424460b7af2c4f1f5542cf..4daf9ab54d064069e65abc84b01ddd66d07deb07 100644 (file)
@@ -181,13 +181,13 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
        CLR(validated, FLAG_NO_USER);
        CLR(validated, FLAG_NO_HOST);
        match = DENY;
-       tq_foreach_fwd(&userspecs, us) {
+       TAILQ_FOREACH(us, &userspecs, entries) {
            if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
                continue;
-           tq_foreach_fwd(&us->privileges, priv) {
+           TAILQ_FOREACH(priv, &us->privileges, entries) {
                if (hostlist_matches(&priv->hostlist) != ALLOW)
                    continue;
-               tq_foreach_fwd(&priv->cmndlist, cs) {
+               TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
                    /* Only check the command when listing another user. */
                    if (user_uid == 0 || list_pw == NULL ||
                        user_uid == list_pw->pw_uid ||
@@ -215,20 +215,20 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
     set_perms(PERM_RUNAS);
 
     match = UNSPEC;
-    tq_foreach_rev(&userspecs, us) {
+    TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
            continue;
        CLR(validated, FLAG_NO_USER);
-       tq_foreach_rev(&us->privileges, priv) {
+       TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
            host_match = hostlist_matches(&priv->hostlist);
            if (host_match == ALLOW)
                CLR(validated, FLAG_NO_HOST);
            else
                continue;
-           tq_foreach_rev(&priv->cmndlist, cs) {
+           TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
                matching_user = NULL;
-               runas_match = runaslist_matches(&cs->runasuserlist,
-                   &cs->runasgrouplist, &matching_user, NULL);
+               runas_match = runaslist_matches(cs->runasuserlist,
+                   cs->runasgrouplist, &matching_user, NULL);
                if (runas_match == ALLOW) {
                    cmnd_match = cmnd_matches(cs->cmnd);
                    if (cmnd_match != UNSPEC) {
@@ -340,10 +340,8 @@ sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
 
 #define        RUNAS_CHANGED(cs1, cs2) \
        (cs1 == NULL || cs2 == NULL || \
-        cs1->runasuserlist.first != cs2->runasuserlist.first || \
-        cs1->runasuserlist.last != cs2->runasuserlist.last || \
-        cs1->runasgrouplist.first != cs2->runasgrouplist.first || \
-        cs1->runasgrouplist.last != cs2->runasgrouplist.last)
+        cs1->runasuserlist != cs2->runasuserlist || \
+        cs1->runasgrouplist != cs2->runasgrouplist)
 
 static int
 sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
@@ -362,30 +360,30 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
     tags.nopasswd = UNSPEC;
     tags.log_input = UNSPEC;
     tags.log_output = UNSPEC;
-    tq_foreach_fwd(&us->privileges, priv) {
+    TAILQ_FOREACH(priv, &us->privileges, entries) {
        if (hostlist_matches(&priv->hostlist) != ALLOW)
            continue;
        prev_cs = NULL;
-       tq_foreach_fwd(&priv->cmndlist, cs) {
+       TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
            if (RUNAS_CHANGED(cs, prev_cs)) {
-               if (cs != tq_first(&priv->cmndlist))
+               if (cs != TAILQ_FIRST(&priv->cmndlist))
                    lbuf_append(lbuf, "\n");
                lbuf_append(lbuf, "    (");
-               if (!tq_empty(&cs->runasuserlist)) {
-                   tq_foreach_fwd(&cs->runasuserlist, m) {
-                       if (m != tq_first(&cs->runasuserlist))
+               if (cs->runasuserlist != NULL) {
+                   TAILQ_FOREACH(m, cs->runasuserlist, entries) {
+                       if (m != TAILQ_FIRST(cs->runasuserlist))
                            lbuf_append(lbuf, ", ");
                        print_member(lbuf, m, RUNASALIAS);
                    }
-               } else if (tq_empty(&cs->runasgrouplist)) {
+               } else if (cs->runasgrouplist == NULL) {
                    lbuf_append(lbuf, "%s", def_runas_default);
                } else {
                    lbuf_append(lbuf, "%s", pw->pw_name);
                }
-               if (!tq_empty(&cs->runasgrouplist)) {
+               if (cs->runasgrouplist != NULL) {
                    lbuf_append(lbuf, " : ");
-                   tq_foreach_fwd(&cs->runasgrouplist, m) {
-                       if (m != tq_first(&cs->runasgrouplist))
+                   TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
+                       if (m != TAILQ_FIRST(cs->runasgrouplist))
                            lbuf_append(lbuf, ", ");
                        print_member(lbuf, m, RUNASALIAS);
                    }
@@ -396,7 +394,7 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
                tags.nopasswd = UNSPEC;
                tags.log_input = UNSPEC;
                tags.log_output = UNSPEC;
-           } else if (cs != tq_first(&priv->cmndlist)) {
+           } else if (cs != TAILQ_FIRST(&priv->cmndlist)) {
                lbuf_append(lbuf, ", ");
            }
            sudo_file_append_cmnd(cs, &tags, lbuf);
@@ -452,30 +450,30 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
     int nfound = 0, olen;
     debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS)
 
-    tq_foreach_fwd(&us->privileges, priv) {
+    TAILQ_FOREACH(priv, &us->privileges, entries) {
        if (hostlist_matches(&priv->hostlist) != ALLOW)
            continue;
        prev_cs = NULL;
-       tq_foreach_fwd(&priv->cmndlist, cs) {
+       TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
            if (new_long_entry(cs, prev_cs)) {
                lbuf_append(lbuf, _("\nSudoers entry:\n"));
                lbuf_append(lbuf, _("    RunAsUsers: "));
-               if (!tq_empty(&cs->runasuserlist)) {
-                   tq_foreach_fwd(&cs->runasuserlist, m) {
-                       if (m != tq_first(&cs->runasuserlist))
+               if (cs->runasuserlist != NULL) {
+                   TAILQ_FOREACH(m, cs->runasuserlist, entries) {
+                       if (m != TAILQ_FIRST(cs->runasuserlist))
                            lbuf_append(lbuf, ", ");
                        print_member(lbuf, m, RUNASALIAS);
                    }
-               } else if (tq_empty(&cs->runasgrouplist)) {
+               } else if (cs->runasgrouplist == NULL) {
                    lbuf_append(lbuf, "%s", def_runas_default);
                } else {
                    lbuf_append(lbuf, "%s", pw->pw_name);
                }
                lbuf_append(lbuf, "\n");
-               if (!tq_empty(&cs->runasgrouplist)) {
+               if (cs->runasgrouplist != NULL) {
                    lbuf_append(lbuf, _("    RunAsGroups: "));
-                   tq_foreach_fwd(&cs->runasgrouplist, m) {
-                       if (m != tq_first(&cs->runasgrouplist))
+                   TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
+                       if (m != TAILQ_FIRST(cs->runasgrouplist))
                            lbuf_append(lbuf, ", ");
                        print_member(lbuf, m, RUNASALIAS);
                    }
@@ -534,7 +532,7 @@ sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw,
     if (nss->handle == NULL)
        goto done;
 
-    tq_foreach_fwd(&userspecs, us) {
+    TAILQ_FOREACH(us, &userspecs, entries) {
        if (userlist_matches(pw, &us->users) != ALLOW)
            continue;
 
@@ -567,14 +565,14 @@ sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
     else
        prefix = ", ";
 
-    tq_foreach_fwd(&defaults, d) {
+    TAILQ_FOREACH(d, &defaults, entries) {
        switch (d->type) {
            case DEFAULTS_HOST:
-               if (hostlist_matches(&d->binding) != ALLOW)
+               if (hostlist_matches(d->binding) != ALLOW)
                    continue;
                break;
            case DEFAULTS_USER:
-               if (userlist_matches(pw, &d->binding) != ALLOW)
+               if (userlist_matches(pw, d->binding) != ALLOW)
                    continue;
                break;
            case DEFAULTS_RUNAS:
@@ -624,7 +622,8 @@ static int
 display_bound_defaults(int dtype, struct lbuf *lbuf)
 {
     struct defaults *d;
-    struct member *m, *binding = NULL;
+    struct member_list *binding = NULL;
+    struct member *m;
     char *dsep;
     int atype, nfound = 0;
     debug_decl(display_bound_defaults, SUDO_DEBUG_NSS)
@@ -649,18 +648,18 @@ display_bound_defaults(int dtype, struct lbuf *lbuf)
        default:
            debug_return_int(-1);
     }
-    tq_foreach_fwd(&defaults, d) {
+    TAILQ_FOREACH(d, &defaults, entries) {
        if (d->type != dtype)
            continue;
 
        nfound++;
-       if (binding != tq_first(&d->binding)) {
-           binding = tq_first(&d->binding);
+       if (binding != d->binding) {
+           binding = d->binding;
            if (nfound != 1)
                lbuf_append(lbuf, "\n");
            lbuf_append(lbuf, "    Defaults%s", dsep);
-           for (m = binding; m != NULL; m = m->next) {
-               if (m != binding)
+           TAILQ_FOREACH(m, binding, entries) {
+               if (m != TAILQ_FIRST(binding))
                    lbuf_append(lbuf, ",");
                print_member(lbuf, m, atype);
                lbuf_append(lbuf, " ");
@@ -692,17 +691,17 @@ sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
        goto done;
 
     match = NULL;
-    tq_foreach_rev(&userspecs, us) {
+    TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
        if (userlist_matches(pw, &us->users) != ALLOW)
            continue;
 
-       tq_foreach_rev(&us->privileges, priv) {
+       TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
            host_match = hostlist_matches(&priv->hostlist);
            if (host_match != ALLOW)
                continue;
-           tq_foreach_rev(&priv->cmndlist, cs) {
-               runas_match = runaslist_matches(&cs->runasuserlist,
-                   &cs->runasgrouplist, NULL, NULL);
+           TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
+               runas_match = runaslist_matches(cs->runasuserlist,
+                   cs->runasgrouplist, NULL, NULL);
                if (runas_match == ALLOW) {
                    cmnd_match = cmnd_matches(cs->cmnd);
                    if (cmnd_match != UNSPEC) {
@@ -754,8 +753,8 @@ _print_member(struct lbuf *lbuf, char *name, int type, int negated,
            break;
        case ALIAS:
            if ((a = alias_get(name, alias_type)) != NULL) {
-               tq_foreach_fwd(&a->members, m) {
-                   if (m != tq_first(&a->members))
+               TAILQ_FOREACH(m, &a->members, entries) {
+                   if (m != TAILQ_FIRST(&a->members))
                        lbuf_append(lbuf, "%s", separator);
                    _print_member(lbuf, m->name, m->type,
                        negated ? !m->negated : m->negated, separator,
index b396da52dab674a6d2cfcd0777c2b7834c9def57..62bb8acbcd966f7021cbd2f067655dc6ecbb63ec 100644 (file)
@@ -18,8 +18,6 @@
 #ifndef _SUDOERS_PARSE_H
 #define _SUDOERS_PARSE_H
 
-#include "list.h"      /* XXX */
-
 #undef UNSPEC
 #define UNSPEC -1
 #undef DENY
@@ -86,31 +84,30 @@ struct solaris_privs_info {
  * modelled after the yacc grammar.
  *
  * Other than the alias struct, which is stored in a red-black tree,
- * the data structure used is basically a doubly-linked tail queue without
- * a separate head struct--the first entry acts as the head where the prev
- * pointer does double duty as the tail pointer.  This makes it possible
- * to trivally append sub-lists.  In addition, the prev pointer is always
- * valid (even if it points to itself).  Unlike a circle queue, the next
- * pointer of the last entry is NULL and does not point back to the head.
- *
- * Note that each list struct must contain a "prev" and "next" pointer as
- * the first two members of the struct (in that order).
+ * the data structure used is a doubly-linked tail queue.  While sudoers
+ * is being parsed, a headless tail queue is used where the first entry
+ * acts as the head and the prev pointer does double duty as the tail pointer.
+ * This makes it possible to trivally append sub-lists.  In addition, the prev
+ * pointer is always valid (even if it points to itself).  Unlike a circle
+ * queue, the next pointer of the last entry is NULL and does not point back
+ * to the head.  When the tail queue is finalized, it is converted to a
+ * normal BSD tail queue.
  */
 
 /*
  * Tail queue list head structure.
  */
-TQ_DECLARE(defaults)
-TQ_DECLARE(userspec)
-TQ_DECLARE(member)
-TQ_DECLARE(privilege)
-TQ_DECLARE(cmndspec)
+TAILQ_HEAD(defaults_list, defaults);
+TAILQ_HEAD(userspec_list, userspec);
+TAILQ_HEAD(member_list, member);
+TAILQ_HEAD(privilege_list, privilege);
+TAILQ_HEAD(cmndspec_list, cmndspec);
 
 /*
  * Structure describing a user specification and list thereof.
  */
 struct userspec {
-    struct userspec *prev, *next;
+    TAILQ_ENTRY(userspec) entries;
     struct member_list users;          /* list of users */
     struct privilege_list privileges;  /* list of privileges */
 };
@@ -119,7 +116,7 @@ struct userspec {
  * Structure describing a privilege specification.
  */
 struct privilege {
-    struct privilege *prev, *next;
+    TAILQ_ENTRY(privilege) entries;
     struct member_list hostlist;       /* list of hosts */
     struct cmndspec_list cmndlist;     /* list of Cmnd_Specs */
 };
@@ -128,9 +125,9 @@ struct privilege {
  * Structure describing a linked list of Cmnd_Specs.
  */
 struct cmndspec {
-    struct cmndspec *prev, *next;
-    struct member_list runasuserlist;  /* list of runas users */
-    struct member_list runasgrouplist; /* list of runas groups */
+    TAILQ_ENTRY(cmndspec) entries;
+    struct member_list *runasuserlist; /* list of runas users */
+    struct member_list *runasgrouplist;        /* list of runas groups */
     struct member *cmnd;               /* command to allow/deny */
     char *digest;                      /* optional command digest */
     struct cmndtag tags;               /* tag specificaion */
@@ -146,7 +143,7 @@ struct cmndspec {
  * Generic structure to hold users, hosts, commands.
  */
 struct member {
-    struct member *prev, *next;
+    TAILQ_ENTRY(member) entries;
     char *name;                                /* member name */
     short type;                                /* type (see gram.h) */
     short negated;                     /* negated via '!'? */
@@ -172,10 +169,10 @@ struct alias {
  * Structure describing a Defaults entry and a list thereof.
  */
 struct defaults {
-    struct defaults *prev, *next;
+    TAILQ_ENTRY(defaults) entries;
     char *var;                         /* variable name */
     char *val;                         /* variable value */
-    struct member_list binding;                /* user/host/runas binding */
+    struct member_list *binding;       /* user/host/runas binding */
     int type;                          /* DEFAULTS{,_USER,_RUNAS,_HOST} */
     int op;                            /* true, false, '+', '-' */
 };
index 5fc96d7264dc86fe70ba51991a788d9f24497dc7..6ff807628f5bb844eff11e836fd8b835b0402b18 100644 (file)
@@ -43,7 +43,7 @@
 #define SUDO_ERROR_WRAP 0
 
 #include "missing.h"
-#include "list.h"
+#include "queue.h"
 #include "parse.h"
 #include "toke.h"
 #include "sudo_plugin.h"
index 6ee46726c19df9b4a75208338d7f3c174ae618bd..88d9f4e1d436ecf182bafaaeb76bcfa0572fa68e 100644 (file)
@@ -304,19 +304,19 @@ main(int argc, char *argv[])
     /* This loop must match the one in sudo_file_lookup() */
     printf("\nEntries for user %s:\n", user_name);
     match = UNSPEC;
-    tq_foreach_rev(&userspecs, us) {
+    TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
            continue;
-       tq_foreach_rev(&us->privileges, priv) {
+       TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
            putchar('\n');
-           print_privilege(priv); /* XXX */
+           print_privilege(priv);
            putchar('\n');
            host_match = hostlist_matches(&priv->hostlist);
            if (host_match == ALLOW) {
                puts("\thost  matched");
-               tq_foreach_rev(&priv->cmndlist, cs) {
-                   runas_match = runaslist_matches(&cs->runasuserlist,
-                       &cs->runasgrouplist, NULL, NULL);
+               TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
+                   runas_match = runaslist_matches(cs->runasuserlist,
+                       cs->runasgrouplist, NULL, NULL);
                    if (runas_match == ALLOW) {
                        puts("\trunas matched");
                        cmnd_match = cmnd_matches(cs->cmnd);
@@ -342,6 +342,8 @@ main(int argc, char *argv[])
      */
     exitcode = parse_error ? 1 : (match == ALLOW ? 0 : match + 3);
 done:
+    sudo_endpwent();
+    sudo_endgrent();
     sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
     exit(exitcode);
 }
@@ -492,7 +494,7 @@ print_defaults(void)
     struct member *m;
     debug_decl(print_member, SUDO_DEBUG_UTIL)
 
-    tq_foreach_fwd(&defaults, d) {
+    TAILQ_FOREACH(d, &defaults, entries) {
        (void) fputs("Defaults", stdout);
        switch (d->type) {
            case DEFAULTS_HOST:
@@ -508,8 +510,8 @@ print_defaults(void)
                putchar('!');
                break;
        }
-       tq_foreach_fwd(&d->binding, m) {
-           if (m != tq_first(&d->binding))
+       TAILQ_FOREACH(m, d->binding, entries) {
+           if (m != TAILQ_FIRST(d->binding))
                putchar(',');
            print_member(m);
        }
@@ -545,8 +547,8 @@ print_alias(void *v1, void *v2)
            (void) printf("Runas_Alias\t%s = ", a->name);
            break;
     }
-    tq_foreach_fwd(&a->members, m) {
-       if (m != tq_first(&a->members))
+    TAILQ_FOREACH(m, &a->members, entries) {
+       if (m != TAILQ_FIRST(&a->members))
            fputs(", ", stdout);
        if (m->type == COMMAND) {
            c = (struct sudo_command *) m->name;
@@ -567,66 +569,61 @@ print_privilege(struct privilege *priv)
 {
     struct cmndspec *cs;
     struct member *m;
-    struct privilege *p;
     struct cmndtag tags;
     debug_decl(print_privilege, SUDO_DEBUG_UTIL)
 
-    for (p = priv; p != NULL; p = p->next) {
-       if (p != priv)
-           fputs(" : ", stdout);
-       tq_foreach_fwd(&p->hostlist, m) {
-           if (m != tq_first(&p->hostlist))
-               fputs(", ", stdout);
-           print_member(m);
-       }
-       fputs(" = ", stdout);
-       tags.nopasswd = UNSPEC;
-       tags.noexec = UNSPEC;
-       tq_foreach_fwd(&p->cmndlist, cs) {
-           if (cs != tq_first(&p->cmndlist))
-               fputs(", ", stdout);
-           if (!tq_empty(&cs->runasuserlist) || !tq_empty(&cs->runasgrouplist)) {
-               fputs("(", stdout);
-               if (!tq_empty(&cs->runasuserlist)) {
-                   tq_foreach_fwd(&cs->runasuserlist, m) {
-                       if (m != tq_first(&cs->runasuserlist))
-                           fputs(", ", stdout);
-                       print_member(m);
-                   }  
-               } else if (tq_empty(&cs->runasgrouplist)) {
-                   fputs(def_runas_default, stdout);
-               } else {
-                   fputs(sudo_user.pw->pw_name, stdout);
-               }
-               if (!tq_empty(&cs->runasgrouplist)) {
-                   fputs(" : ", stdout);
-                   tq_foreach_fwd(&cs->runasgrouplist, m) {
-                       if (m != tq_first(&cs->runasgrouplist))
-                           fputs(", ", stdout);
-                       print_member(m);
-                   }
+    TAILQ_FOREACH(m, &priv->hostlist, entries) {
+       if (m != TAILQ_FIRST(&priv->hostlist))
+           fputs(", ", stdout);
+       print_member(m);
+    }
+    fputs(" = ", stdout);
+    tags.nopasswd = UNSPEC;
+    tags.noexec = UNSPEC;
+    TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
+       if (cs != TAILQ_FIRST(&priv->cmndlist))
+           fputs(", ", stdout);
+       if (cs->runasuserlist != NULL || cs->runasgrouplist != NULL) {
+           fputs("(", stdout);
+           if (cs->runasuserlist != NULL) {
+               TAILQ_FOREACH(m, cs->runasuserlist, entries) {
+                   if (m != TAILQ_FIRST(cs->runasuserlist))
+                       fputs(", ", stdout);
+                   print_member(m);
+               }  
+           } else if (cs->runasgrouplist == NULL) {
+               fputs(def_runas_default, stdout);
+           } else {
+               fputs(sudo_user.pw->pw_name, stdout);
+           }
+           if (cs->runasgrouplist != NULL) {
+               fputs(" : ", stdout);
+               TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
+                   if (m != TAILQ_FIRST(cs->runasgrouplist))
+                       fputs(", ", stdout);
+                   print_member(m);
                }
-               fputs(") ", stdout);
            }
+           fputs(") ", stdout);
+       }
 #ifdef HAVE_SELINUX
-           if (cs->role)
-               printf("ROLE=%s ", cs->role);
-           if (cs->type)
-               printf("TYPE=%s ", cs->type);
+       if (cs->role)
+           printf("ROLE=%s ", cs->role);
+       if (cs->type)
+           printf("TYPE=%s ", cs->type);
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
-           if (cs->privs)
-               printf("PRIVS=%s ", cs->privs);
-           if (cs->limitprivs)
-               printf("LIMITPRIVS=%s ", cs->limitprivs);
+       if (cs->privs)
+           printf("PRIVS=%s ", cs->privs);
+       if (cs->limitprivs)
+           printf("LIMITPRIVS=%s ", cs->limitprivs);
 #endif /* HAVE_PRIV_SET */
-           if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd)
-               printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : "");
-           if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec)
-               printf("%sEXEC: ", cs->tags.noexec ? "NO" : "");
-           print_member(cs->cmnd);
-           memcpy(&tags, &cs->tags, sizeof(tags));
-       }
+       if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd)
+           printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : "");
+       if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec)
+           printf("%sEXEC: ", cs->tags.noexec ? "NO" : "");
+       print_member(cs->cmnd);
+       memcpy(&tags, &cs->tags, sizeof(tags));
     }
     debug_return;
 }
@@ -636,16 +633,21 @@ print_userspecs(void)
 {
     struct member *m;
     struct userspec *us;
+    struct privilege *priv;
     debug_decl(print_userspecs, SUDO_DEBUG_UTIL)
 
-    tq_foreach_fwd(&userspecs, us) {
-       tq_foreach_fwd(&us->users, m) {
-           if (m != tq_first(&us->users))
+    TAILQ_FOREACH(us, &userspecs, entries) {
+       TAILQ_FOREACH(m, &us->users, entries) {
+           if (m != TAILQ_FIRST(&us->users))
                fputs(", ", stdout);
            print_member(m);
        }
        putchar('\t');
-       print_privilege(us->privileges.first); /* XXX */
+       TAILQ_FOREACH(priv, &us->privileges, entries) {
+           if (priv != TAILQ_FIRST(&us->privileges))
+               fputs(" : ", stdout);
+           print_privilege(priv);
+       }
        putchar('\n');
     }
     debug_return;
index 5228083c262e3873c3915a0495fec0a419b188ee..e7c3997eab877d4ec368cb41002432d84db1ce36 100644 (file)
@@ -1085,7 +1085,7 @@ alias_remove_recursive(char *name, int type)
     debug_decl(alias_remove_recursive, SUDO_DEBUG_ALIAS)
 
     if ((a = alias_remove(name, type)) != NULL) {
-       tq_foreach_fwd(&a->members, m) {
+       TAILQ_FOREACH(m, &a->members, entries) {
            if (m->type == ALIAS) {
                if (!alias_remove_recursive(m->name, type))
                    rval = false;
@@ -1106,7 +1106,7 @@ check_alias(char *name, int type, int strict, int quiet)
 
     if ((a = alias_get(name, type)) != NULL) {
        /* check alias contents */
-       tq_foreach_fwd(&a->members, m) {
+       TAILQ_FOREACH(m, &a->members, entries) {
            if (m->type == ALIAS)
                errors += check_alias(m->name, type, strict, quiet);
        }
@@ -1143,7 +1143,7 @@ static int
 check_aliases(bool strict, bool quiet)
 {
     struct cmndspec *cs;
-    struct member *m, *binding;
+    struct member *m;
     struct privilege *priv;
     struct userspec *us;
     struct defaults *d;
@@ -1153,22 +1153,31 @@ check_aliases(bool strict, bool quiet)
     alias_freelist = rbcreate(alias_compare);
 
     /* Forward check. */
-    tq_foreach_fwd(&userspecs, us) {
-       tq_foreach_fwd(&us->users, m) {
+    TAILQ_FOREACH(us, &userspecs, entries) {
+       TAILQ_FOREACH(m, &us->users, entries) {
            if (m->type == ALIAS) {
                errors += check_alias(m->name, USERALIAS, strict, quiet);
            }
        }
-       tq_foreach_fwd(&us->privileges, priv) {
-           tq_foreach_fwd(&priv->hostlist, m) {
+       TAILQ_FOREACH(priv, &us->privileges, entries) {
+           TAILQ_FOREACH(m, &priv->hostlist, entries) {
                if (m->type == ALIAS) {
                    errors += check_alias(m->name, HOSTALIAS, strict, quiet);
                }
            }
-           tq_foreach_fwd(&priv->cmndlist, cs) {
-               tq_foreach_fwd(&cs->runasuserlist, m) {
-                   if (m->type == ALIAS) {
-                       errors += check_alias(m->name, RUNASALIAS, strict, quiet);
+           TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
+               if (cs->runasuserlist != NULL) {
+                   TAILQ_FOREACH(m, cs->runasuserlist, entries) {
+                       if (m->type == ALIAS) {
+                           errors += check_alias(m->name, RUNASALIAS, strict, quiet);
+                       }
+                   }
+               }
+               if (cs->runasgrouplist != NULL) {
+                   TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
+                       if (m->type == ALIAS) {
+                           errors += check_alias(m->name, RUNASALIAS, strict, quiet);
+                       }
                    }
                }
                if ((m = cs->cmnd)->type == ALIAS) {
@@ -1179,31 +1188,35 @@ check_aliases(bool strict, bool quiet)
     }
 
     /* Reverse check (destructive) */
-    tq_foreach_fwd(&userspecs, us) {
-       tq_foreach_fwd(&us->users, m) {
+    TAILQ_FOREACH(us, &userspecs, entries) {
+       TAILQ_FOREACH(m, &us->users, entries) {
            if (m->type == ALIAS) {
                if (!alias_remove_recursive(m->name, USERALIAS))
                    errors++;
            }
        }
-       tq_foreach_fwd(&us->privileges, priv) {
-           tq_foreach_fwd(&priv->hostlist, m) {
+       TAILQ_FOREACH(priv, &us->privileges, entries) {
+           TAILQ_FOREACH(m, &priv->hostlist, entries) {
                if (m->type == ALIAS) {
                    if (!alias_remove_recursive(m->name, HOSTALIAS))
                        errors++;
                }
            }
-           tq_foreach_fwd(&priv->cmndlist, cs) {
-               tq_foreach_fwd(&cs->runasuserlist, m) {
-                   if (m->type == ALIAS) {
-                       if (!alias_remove_recursive(m->name, RUNASALIAS))
-                           errors++;
+           TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
+               if (cs->runasuserlist != NULL) {
+                   TAILQ_FOREACH(m, cs->runasuserlist, entries) {
+                       if (m->type == ALIAS) {
+                           if (!alias_remove_recursive(m->name, RUNASALIAS))
+                               errors++;
+                       }
                    }
                }
-               tq_foreach_fwd(&cs->runasgrouplist, m) {
-                   if (m->type == ALIAS) {
-                       if (!alias_remove_recursive(m->name, RUNASALIAS))
-                           errors++;
+               if (cs->runasgrouplist != NULL) {
+                   TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
+                       if (m->type == ALIAS) {
+                           if (!alias_remove_recursive(m->name, RUNASALIAS))
+                               errors++;
+                       }
                    }
                }
                if ((m = cs->cmnd)->type == ALIAS) {
@@ -1213,7 +1226,7 @@ check_aliases(bool strict, bool quiet)
            }
        }
     }
-    tq_foreach_fwd(&defaults, d) {
+    TAILQ_FOREACH(d, &defaults, entries) {
        switch (d->type) {
            case DEFAULTS_HOST:
                atype = HOSTALIAS;
@@ -1230,12 +1243,10 @@ check_aliases(bool strict, bool quiet)
            default:
                continue; /* not an alias */
        }
-       tq_foreach_fwd(&d->binding, binding) {
-           for (m = binding; m != NULL; m = m->next) {
-               if (m->type == ALIAS) {
-                   if (!alias_remove_recursive(m->name, atype))
-                       errors++;
-               }
+       TAILQ_FOREACH(m, d->binding, entries) {
+           if (m->type == ALIAS) {
+               if (!alias_remove_recursive(m->name, atype))
+                   errors++;
            }
        }
     }