]> granicus.if.org Git - sudo/commitdiff
Simplify the nss interface such that each sudoers provider fills
authorTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 14 May 2018 15:05:03 +0000 (09:05 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 14 May 2018 15:05:03 +0000 (09:05 -0600)
in a per-nss list of userspecs and defaults instead of using separate
lookup and list functions.  This makes it possible to have a single
implementation of the code for sudoers lookup and listing.

17 files changed:
MANIFEST
plugins/sudoers/Makefile.in
plugins/sudoers/defaults.c
plugins/sudoers/defaults.h
plugins/sudoers/file.c [new file with mode: 0644]
plugins/sudoers/ldap.c
plugins/sudoers/ldap_util.c
plugins/sudoers/parse.c
plugins/sudoers/parse.h
plugins/sudoers/sssd.c
plugins/sudoers/sudo_ldap.h
plugins/sudoers/sudo_nss.c
plugins/sudoers/sudo_nss.h
plugins/sudoers/sudoers.c
plugins/sudoers/sudoers.h
plugins/sudoers/testsudoers.c
plugins/sudoers/visudo.c

index 5fe9eaa3ebbe68fb4a024a01f1cca4f47ed4a51c..88a6d9b20c2e0f55822ce0366de236fa17000636 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -278,6 +278,7 @@ plugins/sudoers/digestname.c
 plugins/sudoers/editor.c
 plugins/sudoers/env.c
 plugins/sudoers/env_pattern.c
+plugins/sudoers/file.c
 plugins/sudoers/filedigest.c
 plugins/sudoers/filedigest_gcrypt.c
 plugins/sudoers/filedigest_openssl.c
index 15ca1f9e7a0a6ec57556df6936c365a37c45835c..030e3cb8120d90a29a3e436432724bb5d900ac4a 100644 (file)
@@ -154,11 +154,11 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo digestname.lo \
                       timestr.lo toke.lo toke_util.lo
 
 SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
-              env_pattern.lo find_path.lo fmtsudoers.lo gc.lo goodpath.lo \
-              group_plugin.lo interfaces.lo iolog.lo iolog_path.lo locale.lo \
-              logging.lo logwrap.lo mkdir_parents.lo parse.lo policy.lo \
-              prompt.lo set_perms.lo starttime.lo sudo_nss.lo sudoers.lo \
-              timestamp.lo @SUDOERS_OBJS@
+              env_pattern.lo file.lo find_path.lo fmtsudoers.lo gc.lo \
+              goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
+              iolog_path.lo locale.lo logging.lo logwrap.lo mkdir_parents.lo \
+              parse.lo policy.lo prompt.lo set_perms.lo starttime.lo \
+              sudo_nss.lo sudoers.lo timestamp.lo @SUDOERS_OBJS@
 
 VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o stubs.o sudo_printf.o visudo.o
 
@@ -1111,6 +1111,15 @@ pam.lo: $(authdir)/pam.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
         $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
         $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(authdir)/pam.c
+file.lo: $(srcdir)/file.c $(devdir)/def_data.h $(devdir)/gram.h \
+          $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+          $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
+          $(incdir)/sudo_gettext.h $(incdir)/sudo_lbuf.h \
+          $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
+          $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
+          $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
+          $(top_builddir)/config.h $(top_builddir)/pathnames.h
+       $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/file.c
 parse.lo: $(srcdir)/parse.c $(devdir)/def_data.h $(devdir)/gram.h \
           $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
           $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
index bc5c1fc78a335670af372a3315a930273129958a..d4715f72fc47f08d0b4342c1e3dc77b3b1c0162b 100644 (file)
@@ -725,11 +725,11 @@ default_binding_matches(struct defaults *d, int what)
 }
 
 /*
- * Update the defaults based on what was set by sudoers.
+ * Update the global defaults based on the given defaults list.
  * Pass in an OR'd list of which default types to update.
  */
 bool
-update_defaults(int what, bool quiet)
+update_defaults(struct defaults_list *defs, int what, bool quiet)
 {
     struct defaults *d;
     bool ret = true;
@@ -741,7 +741,7 @@ update_defaults(int what, bool quiet)
     /*
      * First apply Defaults values marked as early.
      */
-    TAILQ_FOREACH(d, &defaults, entries) {
+    TAILQ_FOREACH(d, defs, entries) {
        struct early_default *early = is_early_default(d->var);
        if (early == NULL)
            continue;
@@ -763,7 +763,7 @@ update_defaults(int what, bool quiet)
     /*
      * Then set the rest of the defaults.
      */
-    TAILQ_FOREACH(d, &defaults, entries) {
+    TAILQ_FOREACH(d, defs, entries) {
        /* Skip Defaults marked as early, we already did them. */
        if (is_early_default(d->var))
            continue;
index c0016e294d0e023397ea96ae070f2a9fa09557c9..41582accec08897697d979f480476c056921abdf 100644 (file)
@@ -122,13 +122,14 @@ struct early_default {
 /*
  * Prototypes
  */
+struct defaults_list;
 void dump_default(void);
 bool init_defaults(void);
 struct early_default *is_early_default(const char *name);
 bool run_early_defaults(void);
 bool set_early_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet, struct early_default *early);
 bool set_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet);
-bool update_defaults(int what, bool quiet);
+bool update_defaults(struct defaults_list *defs, int what, bool quiet);
 bool check_defaults(bool quiet);
 
 extern struct sudo_defs_types sudo_defs_table[];
diff --git a/plugins/sudoers/file.c b/plugins/sudoers/file.c
new file mode 100644 (file)
index 0000000..85a0163
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2004-2005, 2007-2018 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * 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>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <unistd.h>
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+#include <time.h>
+
+#include "sudoers.h"
+#include "parse.h"
+#include "sudo_lbuf.h"
+#include <gram.h>
+
+/*
+ * Local prototypes.
+ */
+static int sudo_file_close(struct sudo_nss *);
+static int sudo_file_open(struct sudo_nss *);
+static int sudo_file_parse(struct sudo_nss *);
+static int sudo_file_query(struct sudo_nss *, struct passwd *pw);
+static int sudo_file_getdefs(struct sudo_nss *);
+
+/* sudo_nss implementation */
+struct sudo_nss sudo_nss_file = {
+    { NULL, NULL },
+    sudo_file_open,
+    sudo_file_close,
+    sudo_file_parse,
+    sudo_file_query,
+    sudo_file_getdefs
+};
+
+static int
+sudo_file_open(struct sudo_nss *nss)
+{
+    debug_decl(sudo_file_open, SUDOERS_DEBUG_NSS)
+
+    if (def_ignore_local_sudoers)
+       debug_return_int(-1);
+    nss->handle = open_sudoers(sudoers_file, false, NULL);
+    debug_return_int(nss->handle ? 0 : -1);
+}
+
+static int
+sudo_file_close(struct sudo_nss *nss)
+{
+    struct member_list *prev_binding = NULL;
+    struct defaults *def;
+    struct userspec *us;
+    debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
+
+    if (nss->handle != NULL) {
+       fclose(nss->handle);
+       nss->handle = NULL;
+       sudoersin = NULL;
+
+       /* XXX - do in main module? */
+       while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+           TAILQ_REMOVE(&nss->userspecs, us, entries);
+           free_userspec(us);
+       }
+       while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
+           TAILQ_REMOVE(&nss->defaults, def, entries);
+           free_default(def, &prev_binding);
+       }
+    }
+
+    debug_return_int(0);
+}
+
+/*
+ * Parse the specified sudoers file.
+ */
+static int
+sudo_file_parse(struct sudo_nss *nss)
+{
+    debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
+
+    if (nss->handle == NULL)
+       debug_return_int(-1);
+
+    sudoersin = nss->handle;
+    if (sudoersparse() != 0 || parse_error) {
+       if (errorlineno != -1) {
+           log_warningx(SLOG_SEND_MAIL, N_("parse error in %s near line %d"),
+               errorfile, errorlineno);
+       } else {
+           log_warningx(SLOG_SEND_MAIL, N_("parse error in %s"), errorfile);
+       }
+       debug_return_int(-1);
+    }
+
+    /* Move parsed userspecs and defaults to nss structure. */
+    TAILQ_CONCAT(&nss->userspecs, &userspecs, entries);
+    TAILQ_CONCAT(&nss->defaults, &defaults, entries);
+
+    debug_return_int(0);
+}
+
+/*
+ * No need for explicit queries for sudoers file, we have it all in memory.
+ */
+static int
+sudo_file_query(struct sudo_nss *nss, struct passwd *pw)
+{
+    debug_decl(sudo_file_query, SUDOERS_DEBUG_NSS)
+    debug_return_int(0);
+}
+
+/*
+ * No need to get defaults for sudoers file, the parse function handled it.
+ */
+static int
+sudo_file_getdefs(struct sudo_nss *nss)
+{
+    debug_decl(sudo_file_getdefs, SUDOERS_DEBUG_NSS)
+    debug_return_int(0);
+}
index 26617329cc26ea995ade91a2d71166ac2fefaffb..912b6db526ba33296fa9ebcbdca70d2841df2b01 100644 (file)
@@ -142,31 +142,20 @@ STAILQ_HEAD(ldap_netgroup_list, ldap_netgroup);
 static int sudo_ldap_open(struct sudo_nss *nss);
 static int sudo_ldap_close(struct sudo_nss *nss);
 static int sudo_ldap_parse(struct sudo_nss *nss);
-static int sudo_ldap_setdefs(struct sudo_nss *nss);
-static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag);
-static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
-static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf);
-static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss,
-    struct passwd *pw, struct sudo_lbuf *lbuf);
-static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf);
+static int sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw);
+static int sudo_ldap_getdefs(struct sudo_nss *nss);
 static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
     struct passwd *pw);
 static char *sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry);
 
 /*
  * LDAP sudo_nss handle.
- * We store the connection to the LDAP server, the cached ldap_result object
- * (if any), and the name of the user the query was performed for.
- * If a new query is launched with sudo_ldap_result_get() that specifies a
- * different user, the old cached result is freed before the new query is run.
+ * We store the connection to the LDAP server and the passwd struct of the
+ * user the last query was performed for.
  */
 struct sudo_ldap_handle {
     LDAP *ld;
-    struct ldap_result *result;
-    const char *username;
-    struct gid_list *gidlist;
+    struct passwd *pw;
 };
 
 struct sudo_nss sudo_nss_ldap = {
@@ -174,12 +163,8 @@ struct sudo_nss sudo_nss_ldap = {
     sudo_ldap_open,
     sudo_ldap_close,
     sudo_ldap_parse,
-    sudo_ldap_setdefs,
-    sudo_ldap_lookup,
-    sudo_ldap_display_cmnd,
-    sudo_ldap_display_defaults,
-    sudo_ldap_display_bound_defaults,
-    sudo_ldap_display_privs
+    sudo_ldap_query,
+    sudo_ldap_getdefs
 };
 
 #ifdef HAVE_LDAP_INITIALIZE
@@ -397,321 +382,60 @@ sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry, struct passwd *pw)
     debug_return_bool(matched == true);
 }
 
-static int
-sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry, int *group_matched)
-{
-    struct berval **bv, **p;
-    char *val;
-    bool ret = false;
-    debug_decl(sudo_ldap_check_runas_user, SUDOERS_DEBUG_LDAP)
-
-    /* get the runas user from the entry */
-    bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
-    if (bv == NULL)
-       bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
-    if (bv == NULL) {
-       DPRINTF2("sudoRunAsUser: no result.");
-       if (*group_matched == UNSPEC) {
-           /* We haven't check for sudoRunAsGroup yet, check now. */
-           bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
-           if (bv != NULL) {
-               *group_matched = false;
-               ldap_value_free_len(bv);
-           }
-       }
-       if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED))
-           debug_return_int(UNSPEC);
-       switch (*group_matched) {
-       case UNSPEC:
-           /*
-            * No runas user or group entries.  Match runas_default
-            * against what the user specified on the command line.
-            */
-           ret = userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
-           break;
-       case true:
-           /*
-            * No runas user entries but have a matching runas group entry.
-            * If trying to run as the invoking user, allow it.
-            */
-           if (userpw_matches(user_name, runas_pw->pw_name, runas_pw))
-               ret = true;
-           break;
-       }
-       debug_return_int(ret);
-    }
-
-    /*
-     * BUG:
-     *
-     * if runas is not specified on the command line, the only information
-     * as to which user to run as is in the runas_default option.  We should
-     * check to see if we have the local option present.  Unfortunately we
-     * don't parse these options until after this routine says yes or no.
-     * The query has already returned, so we could peek at the attribute
-     * values here though.
-     *
-     * For now just require users to always use -u option unless its set
-     * in the global defaults. This behaviour is no different than the global
-     * /etc/sudoers.
-     *
-     * Sigh - maybe add this feature later
-     */
-
-    /* walk through values returned, looking for a match */
-    for (p = bv; *p != NULL && !ret; p++) {
-       val = (*p)->bv_val;
-       switch (val[0]) {
-       case '+':
-           if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL,
-               def_netgroup_tuple ? user_srunhost : NULL, runas_pw->pw_name))
-               ret = true;
-           break;
-       case '%':
-           if (usergr_matches(val, runas_pw->pw_name, runas_pw))
-               ret = true;
-           break;
-       case '\0':
-           /* Empty RunAsUser means run as the invoking user. */
-           if (ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) &&
-               userpw_matches(user_name, runas_pw->pw_name, runas_pw))
-               ret = true;
-           break;
-       case 'A':
-           if (strcmp(val, "ALL") == 0) {
-               ret = true;
-               break;
-           }
-           /* FALLTHROUGH */
-       default:
-           if (userpw_matches(val, runas_pw->pw_name, runas_pw))
-               ret = true;
-           break;
-       }
-       DPRINTF2("ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
-    }
-
-    ldap_value_free_len(bv);   /* cleanup */
-
-    debug_return_int(ret);
-}
-
-static int
-sudo_ldap_check_runas_group(LDAP *ld, LDAPMessage *entry)
-{
-    struct berval **bv, **p;
-    char *val;
-    bool ret = false;
-    debug_decl(sudo_ldap_check_runas_group, SUDOERS_DEBUG_LDAP)
-
-    /* get the values from the entry */
-    bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
-    if (bv == NULL) {
-       DPRINTF2("sudoRunAsGroup: no result.");
-       if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED)) {
-           if (runas_pw->pw_gid == runas_gr->gr_gid)
-               ret = true;     /* runas group matches passwd db */
-       }
-       debug_return_int(ret);
-    }
-
-    /* walk through values returned, looking for a match */
-    for (p = bv; *p != NULL && !ret; p++) {
-       val = (*p)->bv_val;
-       if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
-           ret = true;
-       DPRINTF2("ldap sudoRunAsGroup '%s' ... %s",
-           val, ret ? "MATCH!" : "not");
-    }
-
-    ldap_value_free_len(bv);   /* cleanup */
-
-    debug_return_int(ret);
-}
-
 /*
- * Walk through search results and return true if we have a runas match,
- * else false.  RunAs info is optional.
+ * Read sudoOption and fill in the defaults list.
+ * This is used to parse the cn=defaults entry.
  */
 static bool
-sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry)
+sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs)
 {
-    int user_matched = UNSPEC;
-    int group_matched = UNSPEC;
-    debug_decl(sudo_ldap_check_runas, SUDOERS_DEBUG_LDAP)
-
-    if (!entry)
-       debug_return_bool(false);
-
-    if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED))
-       group_matched = sudo_ldap_check_runas_group(ld, entry);
-    user_matched = sudo_ldap_check_runas_user(ld, entry, &group_matched);
-
-    debug_return_bool(group_matched != false && user_matched != false);
-}
-
-/*
- * Walk through search results and return true if we have a command match,
- * false if disallowed and UNSPEC if not matched.
- */
-static int
-sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied)
-{
-    struct sudo_digest digest, *allowed_digest = NULL;
     struct berval **bv, **p;
-    char *allowed_cmnd, *allowed_args, *val;
-    int ret = UNSPEC;
-    bool negated;
-    debug_decl(sudo_ldap_check_command, SUDOERS_DEBUG_LDAP)
-
-    if (!entry)
-       debug_return_int(ret);
-
-    bv = ldap_get_values_len(ld, entry, "sudoCommand");
-    if (bv == NULL)
-       debug_return_int(ret);
-
-    for (p = bv; *p != NULL && ret != false; p++) {
-       val = (*p)->bv_val;
-
-       /* Match against ALL ? */
-       if (strcmp(val, "ALL") == 0) {
-           ret = true;
-           if (setenv_implied != NULL)
-               *setenv_implied = true;
-           DPRINTF2("ldap sudoCommand '%s' ... MATCH!", val);
-           continue;
-       }
-
-       /* check for sha-2 digest */
-       allowed_digest = sudo_ldap_extract_digest(&val, &digest);
-
-       /* check for !command */
-       allowed_cmnd = val;
-       negated = sudo_ldap_is_negated(&allowed_cmnd);
-
-       /* split optional args away from command */
-       allowed_args = strchr(allowed_cmnd, ' ');
-       if (allowed_args)
-           *allowed_args++ = '\0';
-
-       /* check the command like normal */
-       if (command_matches(allowed_cmnd, allowed_args, allowed_digest)) {
-           /*
-            * If allowed (no bang) set ret but keep on checking.
-            * If disallowed (bang), exit loop.
-            */
-           ret = negated ? false : true;
-       }
-       if (allowed_args != NULL)
-           allowed_args[-1] = ' ';     /* restore val */
-
-       DPRINTF2("ldap sudoCommand '%s' ... %s",
-           val, ret == true ? "MATCH!" : "not");
-
-       if (allowed_digest != NULL)
-           free(allowed_digest->digest_str);
-    }
-
-    ldap_value_free_len(bv);   /* more cleanup */
-
-    debug_return_int(ret);
-}
-
-/*
- * Search for boolean "option" in sudoOption.
- * Returns true if found and allowed, false if negated, else UNSPEC.
- */
-static int
-sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option)
-{
-    struct berval **bv, **p;
-    char *var;
-    bool negated;
-    int ret = UNSPEC;
-    debug_decl(sudo_ldap_check_bool, SUDOERS_DEBUG_LDAP)
-
-    if (entry == NULL)
-       debug_return_int(ret);
-
-    bv = ldap_get_values_len(ld, entry, "sudoOption");
-    if (bv == NULL)
-       debug_return_int(ret);
-
-    /* walk through options */
-    for (p = bv; *p != NULL; p++) {
-       var = (*p)->bv_val;
-       DPRINTF2("ldap sudoOption: '%s'", var);
-
-       negated = sudo_ldap_is_negated(&var);
-       if (strcmp(var, option) == 0)
-           ret = negated ? false : true;
-    }
-
-    ldap_value_free_len(bv);
-
-    debug_return_int(ret);
-}
-
-/*
- * Read sudoOption and modify the defaults as we go.  This is used once
- * from the cn=defaults entry and also once when a final sudoRole is matched.
- */
-static bool
-sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
-{
-    struct berval **bv, **p;
-    char *cn, *var, *val, *source = NULL;
+    char *cn, *cp, *source = NULL;
     bool ret = false;
-    int op;
     debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP)
 
     bv = ldap_get_values_len(ld, entry, "sudoOption");
     if (bv == NULL)
        debug_return_bool(true);
 
-    /* get the entry's dn for option error reporting */
+    /* Use sudoRole in place of file name in defaults. */
     cn = sudo_ldap_get_first_rdn(ld, entry);
-    if (cn != NULL) {
-       if (asprintf(&source, "sudoRole %s", cn) == -1) {
-           sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-           source = NULL;
-           goto done;
-       }
+    if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) {
+       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+       goto done;
+    }
+    if ((source = rcstr_dup(cp)) == NULL) {
+       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+       free(cp);
+       goto done;
     }
 
-    /* walk through options, early ones first */
+    /* Walk through options, appending to defs. */
     for (p = bv; *p != NULL; p++) {
-       struct early_default *early;
-       char *copy;
+       char *copy, *var, *val;
+       int op;
 
-       /* Avoid modifying bv as we need to use it again below. */
-       if ((copy = strdup((*p)->bv_val)) == NULL) {
+       copy = strdup((*p)->bv_val);    /* XXX - should not need to copy */
+       if (copy == NULL) {
            sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+           free(copy);
            goto done;
        }
+
        op = sudo_ldap_parse_option(copy, &var, &val);
-       early = is_early_default(var);
-       if (early != NULL) {
-           set_early_default(var, val, op,
-               source ? source : "sudoRole UNKNOWN", 0, false, early);
+       if (!sudo_ldap_add_default(var, val, op, source, defs)) {
+           sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+           free(copy);
+           goto done;
        }
+
        free(copy);
     }
-    run_early_defaults();
 
-    /* walk through options again, skipping early ones */
-    for (p = bv; *p != NULL; p++) {
-       op = sudo_ldap_parse_option((*p)->bv_val, &var, &val);
-       if (is_early_default(var) == NULL) {
-           set_default(var, val, op,
-               source ? source : "sudoRole UNKNOWN", 0, false);
-       }
-    }
     ret = true;
 
 done:
-    free(source);
+    rcstr_delref(source);
     if (cn)
        ldap_memfree(cn);
     ldap_value_free_len(bv);
@@ -1416,81 +1140,6 @@ sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
 #endif
 }
 
-/*
- * Fetch and display the global Options.
- */
-static int
-sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    struct berval **bv, **p;
-    struct timeval tv, *tvp = NULL;
-    struct ldap_config_str *base;
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    LDAPMessage *entry, *result;
-    char *prefix, *filt;
-    int rc, count = 0;
-    debug_decl(sudo_ldap_display_defaults, SUDOERS_DEBUG_LDAP)
-
-    if (handle == NULL || handle->ld == NULL)
-       goto done;
-    ld = handle->ld;
-
-    filt = sudo_ldap_build_default_filter();
-    if (filt == NULL) {
-       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-       count = -1;
-       goto done;
-    }
-    STAILQ_FOREACH(base, &ldap_conf.base, entries) {
-       if (ldap_conf.timeout > 0) {
-           tv.tv_sec = ldap_conf.timeout;
-           tv.tv_usec = 0;
-           tvp = &tv;
-       }
-       result = NULL;
-       rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
-           filt, NULL, 0, NULL, NULL, tvp, 0, &result);
-       if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
-           bv = ldap_get_values_len(ld, entry, "sudoOption");
-           if (bv != NULL) {
-               if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
-                   prefix = "    ";
-               else
-                   prefix = ", ";
-               for (p = bv; *p != NULL; p++) {
-                   struct defaults d;
-
-                   sudo_lbuf_append(lbuf, "%s", prefix);
-                   d.op = sudo_ldap_parse_option((*p)->bv_val, &d.var, &d.val);
-                   sudoers_format_default(lbuf, &d);
-                   prefix = ", ";
-                   count++;
-               }
-               ldap_value_free_len(bv);
-           }
-       }
-       ldap_msgfree(result);
-    }
-    free(filt);
-done:
-    if (sudo_lbuf_error(lbuf))
-       debug_return_int(-1);
-    debug_return_int(count);
-}
-
-/*
- * STUB
- */
-static int
-sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    debug_decl(sudo_ldap_display_bound_defaults, SUDOERS_DEBUG_LDAP)
-    debug_return_int(0);
-}
-
 static char *
 berval_iter(void **vp)
 {
@@ -1500,19 +1149,15 @@ berval_iter(void **vp)
     return *bv ? (*bv)->bv_val : NULL;
 }
 
-static struct userspec_list *
-ldap_to_sudoers(LDAP *ld, struct ldap_result *lres)
+static bool
+ldap_to_sudoers(LDAP *ld, struct ldap_result *lres,
+    struct userspec_list *ldap_userspecs)
 {
-    struct userspec_list *ldap_userspecs;
     struct userspec *us;
     struct member *m;
     unsigned int i;
     debug_decl(ldap_to_sudoers, SUDOERS_DEBUG_LDAP)
 
-    if ((ldap_userspecs = calloc(1, sizeof(*ldap_userspecs))) == NULL)
-       goto oom;
-    TAILQ_INIT(ldap_userspecs);
-
     /* We only have a single userspec */
     if ((us = calloc(1, sizeof(*us))) == NULL)
        goto oom;
@@ -1586,103 +1231,13 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres)
 
 oom:
     sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-    if (ldap_userspecs != NULL) {
-       while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
-           TAILQ_REMOVE(ldap_userspecs, us, entries);
-           free_userspec(us);
-       }
-       free(ldap_userspecs);
+    while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
+       TAILQ_REMOVE(ldap_userspecs, us, entries);
+       free_userspec(us);
     }
     debug_return_ptr(NULL);
 }
 
-/*
- * Like sudo_ldap_lookup(), except we just print entries.
- */
-static int
-sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    struct userspec_list *ldap_userspecs = NULL;
-    struct ldap_result *lres;
-    LDAP *ld;
-    int ret = 0;
-    debug_decl(sudo_ldap_display_privs, SUDOERS_DEBUG_LDAP)
-
-    if (handle == NULL || handle->ld == NULL)
-       goto done;
-    ld = handle->ld;
-
-    DPRINTF1("ldap search for command list");
-    lres = sudo_ldap_result_get(nss, pw);
-    if (lres == NULL)
-       goto done;
-
-    /* Convert to sudoers parse tree. */
-    if ((ldap_userspecs = ldap_to_sudoers(ld, lres)) == NULL) {
-       ret = -1;
-       goto done;
-    }
-
-    /* Call common display code. */
-    ret = sudo_display_userspecs(ldap_userspecs, pw, lbuf);
-
-done:
-    if (ldap_userspecs != NULL) {
-       struct userspec *us;
-       while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
-           TAILQ_REMOVE(ldap_userspecs, us, entries);
-           free_userspec(us);
-       }
-       free(ldap_userspecs);
-    }
-    if (sudo_lbuf_error(lbuf))
-       debug_return_int(-1);
-    debug_return_int(ret);
-}
-
-static int
-sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    struct ldap_result *lres;
-    LDAPMessage *entry;
-    bool found = false;
-    unsigned int i;
-    debug_decl(sudo_ldap_display_cmnd, SUDOERS_DEBUG_LDAP)
-
-    if (handle == NULL || handle->ld == NULL)
-       goto done;
-    ld = handle->ld;
-
-    /*
-     * The sudo_ldap_result_get() function returns all nodes that match
-     * the user and the host.
-     */
-    DPRINTF1("ldap search for command list");
-    lres = sudo_ldap_result_get(nss, pw);
-    if (lres == NULL)
-       goto done;
-    for (i = 0; i < lres->nentries; i++) {
-       entry = lres->entries[i].entry;
-       if (!sudo_ldap_check_runas(ld, entry))
-           continue;
-       if (sudo_ldap_check_command(ld, entry, NULL) == true) {
-           found = true;
-           goto done;
-       }
-    }
-
-done:
-    if (found)
-       sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
-           safe_cmnd ? safe_cmnd : user_cmnd,
-           user_args ? " " : "", user_args ? user_args : "");
-   debug_return_int(!found);
-}
-
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
 static unsigned int (*sudo_gss_krb5_ccache_name)(unsigned int *minor_status, const char *name, const char **old_name);
 
@@ -2087,21 +1642,29 @@ done:
 }
 
 static int
-sudo_ldap_setdefs(struct sudo_nss *nss)
+sudo_ldap_getdefs(struct sudo_nss *nss)
 {
     struct ldap_config_str *base;
     struct sudo_ldap_handle *handle = nss->handle;
+    struct member_list *prev_binding = NULL;
     struct timeval tv, *tvp = NULL;
+    struct defaults *def;
     LDAP *ld;
     LDAPMessage *entry, *result = NULL;
     char *filt;
-    int ret;
-    debug_decl(sudo_ldap_setdefs, SUDOERS_DEBUG_LDAP)
+    int rc, ret = -1;
+    debug_decl(sudo_ldap_getdefs, SUDOERS_DEBUG_LDAP)
 
     if (handle == NULL || handle->ld == NULL)
        debug_return_int(-1);
     ld = handle->ld;
 
+    /* Free old defaults, if any. */
+    while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
+       TAILQ_REMOVE(&nss->defaults, def, entries);
+       free_default(def, &prev_binding);
+    }
+
     filt = sudo_ldap_build_default_filter();
     if (filt == NULL) {
        sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
@@ -2117,14 +1680,12 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
        }
        ldap_msgfree(result);
        result = NULL;
-       ret = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
+       rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
            filt, NULL, 0, NULL, NULL, tvp, 0, &result);
-       if (ret == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
+       if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
            DPRINTF1("found:%s", ldap_get_dn(ld, entry));
-           if (!sudo_ldap_parse_options(ld, entry)) {
-               ret = -1;
+           if (!sudo_ldap_parse_options(ld, entry, &nss->defaults))
                goto done;
-           }
        } else {
            DPRINTF1("no default options found in %s", base->val);
        }
@@ -2138,132 +1699,6 @@ done:
     debug_return_int(ret);
 }
 
-/*
- * like sudoers_lookup() - only LDAP style
- */
-static int
-sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    LDAPMessage *entry;
-    int rc, setenv_implied;
-    unsigned int i;
-    struct ldap_result *lres = NULL;
-    debug_decl(sudo_ldap_lookup, SUDOERS_DEBUG_LDAP)
-
-    if (handle == NULL || handle->ld == NULL)
-       debug_return_int(ret);
-    ld = handle->ld;
-
-    /* Fetch list of sudoRole entries that match user and host. */
-    lres = sudo_ldap_result_get(nss, sudo_user.pw);
-    if (lres == NULL)
-       debug_return_int(ret);
-
-    /*
-     * The following queries only determine whether or not a password
-     * is required, so the order of the entries doesn't matter.
-     */
-    if (pwflag) {
-       int doauth = UNSPEC;
-       int matched = UNSPEC;
-       enum def_tuple pwcheck =
-           (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-
-       DPRINTF1("perform search for pwflag %d", pwflag);
-       for (i = 0; i < lres->nentries; i++) {
-           entry = lres->entries[i].entry;
-           if ((pwcheck == any && doauth != false) ||
-               (pwcheck == all && doauth != true)) {
-               doauth = !!sudo_ldap_check_bool(ld, entry, "authenticate");
-           }
-           if (matched == true)
-               continue;
-           /* Only check the command when listing another user. */
-           if (user_uid == 0 || list_pw == NULL ||
-               user_uid == list_pw->pw_uid ||
-               sudo_ldap_check_command(ld, entry, NULL) == true) {
-               matched = true;
-           }
-       }
-       if (matched == true || user_uid == 0) {
-           SET(ret, VALIDATE_SUCCESS);
-           CLR(ret, VALIDATE_FAILURE);
-           switch (pwcheck) {
-               case always:
-                   SET(ret, FLAG_CHECK_USER);
-                   break;
-               case all:
-               case any:
-                   if (doauth == false)
-                       SET(ret, FLAG_NOPASSWD);
-                   else
-                       CLR(ret, FLAG_NOPASSWD);
-                   break;
-               default:
-                   break;
-           }
-       }
-       goto done;
-    }
-
-    DPRINTF1("searching LDAP for sudoers entries");
-
-    setenv_implied = false;
-    for (i = 0; i < lres->nentries; i++) {
-       entry = lres->entries[i].entry;
-       if (!sudo_ldap_check_runas(ld, entry))
-           continue;
-       rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
-       if (rc != UNSPEC) {
-           /* We have a match. */
-           DPRINTF1("Command %sallowed", rc == true ? "" : "NOT ");
-           if (rc == true) {
-               DPRINTF1("LDAP entry: %p", entry);
-               /* Apply entry-specific options. */
-               if (setenv_implied)
-                   def_setenv = true;
-               if (sudo_ldap_parse_options(ld, entry)) {
-#ifdef HAVE_SELINUX
-                   /* Set role and type if not specified on command line. */
-                   if (user_role == NULL)
-                       user_role = def_role;
-                   if (user_type == NULL)
-                       user_type = def_type;
-#endif /* HAVE_SELINUX */
-                   SET(ret, VALIDATE_SUCCESS);
-                   CLR(ret, VALIDATE_FAILURE);
-               } else {
-                   SET(ret, VALIDATE_ERROR);
-               }
-           } else {
-               SET(ret, VALIDATE_FAILURE);
-               CLR(ret, VALIDATE_SUCCESS);
-           }
-           break;
-       }
-    }
-
-done:
-    DPRINTF1("done with LDAP searches");
-    DPRINTF1("user_matches=%s", lres->user_matches ? "true" : "false");
-    DPRINTF1("host_matches=%s", lres->host_matches ? "true" : "false");
-
-    if (!ISSET(ret, VALIDATE_SUCCESS)) {
-       /* No matching entries. */
-       if (pwflag && list_pw == NULL)
-           SET(ret, FLAG_NO_CHECK);
-    }
-    if (pwflag || lres->user_matches)
-       CLR(ret, FLAG_NO_USER);
-    if (pwflag || lres->host_matches)
-       CLR(ret, FLAG_NO_HOST);
-    DPRINTF1("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret);
-
-    debug_return_int(ret);
-}
-
 /*
  * Comparison function for ldap_entry_wrapper structures, descending order.
  */
@@ -2344,27 +1779,36 @@ sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry)
 }
 
 /*
- * Free the ldap result structure in the sudo_nss handle.
+ * Free the cached results in the sudo_nss handle, if present.
  */
 static void
 sudo_ldap_result_free_nss(struct sudo_nss *nss)
 {
     struct sudo_ldap_handle *handle = nss->handle;
+    struct member_list *prev_binding = NULL;
+    struct defaults *def;
+    struct userspec *us;
     debug_decl(sudo_ldap_result_free_nss, SUDOERS_DEBUG_LDAP)
 
-    if (handle->result != NULL) {
-       DPRINTF1("removing reusable search result");
-       sudo_ldap_result_free(handle->result);
-       handle->username = NULL;
-       handle->gidlist = NULL;
-       handle->result = NULL;
+    if (handle->pw != NULL)
+       sudo_pw_delref(handle->pw);
+
+    /* XXX - do in main module? */
+    while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+       TAILQ_REMOVE(&nss->userspecs, us, entries);
+       free_userspec(us);
+    }
+    while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
+       TAILQ_REMOVE(&nss->defaults, def, entries);
+       free_default(def, &prev_binding);
     }
+
     debug_return;
 }
 
 /*
- * Perform the LDAP query for the user or return a cached query if
- * there is one for this user.
+ * Perform the LDAP query for the user.  The caller is responsible for
+ * freeing the result with sudo_ldap_result_free().
  */
 static struct ldap_result *
 sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
@@ -2379,23 +1823,6 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
     char *filt;
     debug_decl(sudo_ldap_result_get, SUDOERS_DEBUG_LDAP)
 
-    /*
-     * If we already have a cached result, return it so we don't have to
-     * have to contact the LDAP server again.
-     */
-    if (handle->result) {
-       if (handle->gidlist == user_gid_list &&
-           strcmp(pw->pw_name, handle->username) == 0) {
-           DPRINTF1("reusing previous result (user %s) with %d entries",
-               handle->username, handle->result->nentries);
-           debug_return_ptr(handle->result);
-       }
-       /* User mismatch, cached result cannot be used. */
-       DPRINTF1("removing result (user %s), new search (user %s)",
-           handle->username, pw->pw_name);
-       sudo_ldap_result_free_nss(nss);
-    }
-
     /*
      * Okay - time to search for anything that matches this user
      * Lets limit it to only two queries of the LDAP server
@@ -2483,13 +1910,6 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
            ldap_entry_compare);
     }
 
-    /* Store everything in the sudo_nss handle. */
-    /* XXX - store pw and take a reference to it. */
-    /* XXX - take refs for gidlist and grlist */
-    handle->result = lres;
-    handle->username = pw->pw_name;
-    handle->gidlist = user_gid_list;
-
     debug_return_ptr(lres);
 }
 
@@ -2503,7 +1923,7 @@ sudo_ldap_close(struct sudo_nss *nss)
     debug_decl(sudo_ldap_close, SUDOERS_DEBUG_LDAP)
 
     if (handle != NULL) {
-       /* Free the result before unbinding; it may use the LDAP connection. */
+       /* Free the cached result. */
        sudo_ldap_result_free_nss(nss);
 
        /* Unbind and close the LDAP connection. */
@@ -2519,6 +1939,65 @@ sudo_ldap_close(struct sudo_nss *nss)
     debug_return_int(0);
 }
 
+/*
+ * Perform LDAP query for user and host and convert to sudoers
+ * parse tree.
+ */
+static int
+sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+    struct ldap_result *lres = NULL;
+    struct userspec *us;
+    int ret = 0;
+    LDAP *ld;
+    debug_decl(sudo_ldap_query, SUDOERS_DEBUG_LDAP)
+
+    if (handle == NULL || handle->ld == NULL)
+       goto done;
+    ld = handle->ld;
+
+    /* Use cached result if it matches pw. */
+    if (handle->pw != NULL) {
+       if (pw == handle->pw)
+           goto done;
+       sudo_pw_delref(handle->pw);
+       handle->pw = NULL;
+    }
+
+    /* Free old userspecs, if any. */
+    while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+       TAILQ_REMOVE(&nss->userspecs, us, entries);
+       free_userspec(us);
+    }
+
+    DPRINTF1("%s: ldap search user %s, host %s", __func__, pw->pw_name,
+       user_runhost);
+    if ((lres = sudo_ldap_result_get(nss, pw)) == NULL)
+       goto done;
+
+    /* Convert to sudoers parse tree. */
+    if (!ldap_to_sudoers(ld, lres, &nss->userspecs)) {
+       ret = -1;
+       goto done;
+    }
+
+    /* Stash a ref to the passwd struct in the handle. */
+    sudo_pw_addref(pw);
+    handle->pw = pw;
+
+done:
+    /* Cleanup. */
+    sudo_ldap_result_free(lres);
+    if (ret == -1) {
+       while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+           TAILQ_REMOVE(&nss->userspecs, us, entries);
+           free_userspec(us);
+       }
+    }
+    debug_return_int(ret);
+}
+
 /*
  * STUB
  */
index aa468a33a48e39d313c326845eb219e732075fac..74fb11d786079e930f06e54a9af1818f5aa41362 100644 (file)
@@ -241,6 +241,39 @@ oom:
     debug_return_ptr(NULL);
 }
 
+bool
+sudo_ldap_add_default(const char *var, const char *val, int op,
+    char *source, struct defaults_list *defs)
+{
+    struct defaults *def;
+    debug_decl(sudo_ldap_add_default, SUDOERS_DEBUG_LDAP)
+
+    if ((def = calloc(1, sizeof(*def))) == NULL)
+       goto oom;
+
+    def->type = DEFAULTS;
+    def->op = op;
+    if ((def->var = strdup(var)) == NULL) {
+       goto oom;
+    }
+    if (val != NULL) {
+       if ((def->val = strdup(val)) == NULL)
+           goto oom;
+    }
+    def->file = source;
+    rcstr_addref(source);
+    TAILQ_INSERT_TAIL(defs, def, entries);
+    debug_return_bool(true);
+
+oom:
+    if (def != NULL) {
+       free(def->var);
+       free(def->val);
+       free(def);
+    }
+    debug_return_bool(false);
+}
+
 /*
  * Convert an LDAP sudoRole to a sudoers privilege.
  * Pass in struct berval ** for LDAP or char *** for SSSD.
@@ -384,7 +417,15 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
 
            /* Parse sudoOptions. */
            if (opts != NULL) {
-               char *opt;
+               char *opt, *source = NULL;
+
+               if (store_options) {
+                   /* Use sudoRole in place of file name in defaults. */
+                   size_t slen = sizeof("sudoRole") + strlen(priv->ldap_role);
+                   if ((source = rcstr_alloc(slen)) == NULL)
+                       goto oom;
+                   snprintf(source, slen, "sudoRole %s", priv->ldap_role);
+               }
 
                while ((opt = iter(&opts)) != NULL) {
                    char *var, *val;
@@ -419,23 +460,10 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
                        }
 #endif /* HAVE_PRIV_SET */
                    } else if (store_options) {
-                       struct defaults *def = calloc(1, sizeof(*def));
-                       if (def == NULL)
+                       if (!sudo_ldap_add_default(var, val, op, source,
+                           &priv->defaults)) {
                            goto oom;
-                       def->type = DEFAULTS;
-                       def->op = op;
-                       if ((def->var = strdup(var)) == NULL) {
-                           free(def);
-                           goto oom;
-                       }
-                       if (val != NULL) {
-                           if ((def->val = strdup(val)) == NULL) {
-                               free(def->var);
-                               free(def);
-                               goto oom;
-                           }
                        }
-                       TAILQ_INSERT_TAIL(&priv->defaults, def, entries);
                    } else {
                        /* Convert to tags. */
                        bool handled = true;
@@ -474,6 +502,7 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
                        }
                    }
                }
+               rcstr_delref(source);
            }
 
            /* So we can inherit previous values. */
index 587c64b8cfbfdb7e39243ec0497280080d2b5a1e..b3ae3b807948427bffa89335fb1c18a7a4667a36 100644 (file)
@@ -19,6 +19,7 @@
 #include <config.h>
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <stdio.h>
 #include <stdlib.h>
 #ifdef HAVE_STRING_H
 #include <gram.h>
 
 /*
- * Local prototypes.
+ * Look up the user in the sudoers prase tree for pseudo-commands like
+ * list, verify and kill.
  */
-static int display_bound_defaults(int deftype, struct sudo_lbuf *lbuf);
-static int sudo_file_close(struct sudo_nss *);
-static int sudo_file_display_bound_defaults(struct sudo_nss *, struct passwd *, struct sudo_lbuf *);
-static int sudo_file_display_cmnd(struct sudo_nss *, struct passwd *);
-static int sudo_file_display_defaults(struct sudo_nss *, struct passwd *, struct sudo_lbuf *);
-static int sudo_file_display_privs(struct sudo_nss *, struct passwd *, struct sudo_lbuf *);
-static int sudo_file_lookup(struct sudo_nss *, int, int);
-static int sudo_file_open(struct sudo_nss *);
-static int sudo_file_parse(struct sudo_nss *);
-static int sudo_file_setdefs(struct sudo_nss *);
-
-/* sudo_nss implementation */
-struct sudo_nss sudo_nss_file = {
-    { NULL, NULL },
-    sudo_file_open,
-    sudo_file_close,
-    sudo_file_parse,
-    sudo_file_setdefs,
-    sudo_file_lookup,
-    sudo_file_display_cmnd,
-    sudo_file_display_defaults,
-    sudo_file_display_bound_defaults,
-    sudo_file_display_privs
-};
-
-int
-sudo_file_open(struct sudo_nss *nss)
-{
-    debug_decl(sudo_file_open, SUDOERS_DEBUG_NSS)
-
-    if (def_ignore_local_sudoers)
-       debug_return_int(-1);
-    nss->handle = open_sudoers(sudoers_file, false, NULL);
-    debug_return_int(nss->handle ? 0 : -1);
-}
-
-int
-sudo_file_close(struct sudo_nss *nss)
-{
-    debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
-
-    /* Free parser data structures and close sudoers file. */
-    init_parser(NULL, false);
-    if (nss->handle != NULL) {
-       fclose(nss->handle);
-       nss->handle = NULL;
-       sudoersin = NULL;
-    }
-    debug_return_int(0);
-}
-
-/*
- * Parse the specified sudoers file.
- */
-int
-sudo_file_parse(struct sudo_nss *nss)
-{
-    debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
-
-    if (nss->handle == NULL)
-       debug_return_int(-1);
-
-    init_parser(sudoers_file, false);
-    sudoersin = nss->handle;
-    if (sudoersparse() != 0 || parse_error) {
-       if (errorlineno != -1) {
-           log_warningx(SLOG_SEND_MAIL, N_("parse error in %s near line %d"),
-               errorfile, errorlineno);
-       } else {
-           log_warningx(SLOG_SEND_MAIL, N_("parse error in %s"), errorfile);
-       }
-       debug_return_int(-1);
-    }
-    debug_return_int(0);
-}
-
-/*
- * Wrapper around update_defaults() for nsswitch code.
- */
-int
-sudo_file_setdefs(struct sudo_nss *nss)
-{
-    debug_decl(sudo_file_setdefs, SUDOERS_DEBUG_NSS)
-
-    if (nss->handle == NULL)
-       debug_return_int(-1);
-
-    if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS,
-       false))
-       debug_return_int(-1);
-    debug_return_int(0);
-}
-
-/*
- * Look up the user in the parsed sudoers file and check to see if they are
- * allowed to run the specified command on this host as the target user.
- */
-int
-sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
+static int
+sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
+    int validated, int pwflag)
 {
-    int match, host_match, runas_match, cmnd_match, timeout;
+    int match;
+    struct sudo_nss *nss;
     struct cmndspec *cs;
-    struct cmndtag *tags = NULL;
     struct privilege *priv;
     struct userspec *us;
-    struct member *matching_user;
-    time_t now;
-    debug_decl(sudo_file_lookup, SUDOERS_DEBUG_NSS)
-
-    if (nss->handle == NULL)
-       debug_return_int(validated);
-
-    /*
-     * Only check the actual command if pwflag is not set.
-     * It is set for the "validate", "list" and "kill" pseudo-commands.
-     * Always check the host and user.
-     */
-    if (pwflag) {
-       int nopass;
-       enum def_tuple pwcheck;
-
-       pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-       nopass = (pwcheck == all) ? true : false;
-
-       if (list_pw == NULL)
-           SET(validated, FLAG_NO_CHECK);
-       CLR(validated, FLAG_NO_USER);
-       CLR(validated, FLAG_NO_HOST);
-       match = DENY;
-       TAILQ_FOREACH(us, &userspecs, entries) {
-           if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
+    struct defaults *def;
+    int nopass;
+    enum def_tuple pwcheck;
+    debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER)
+
+    pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
+    nopass = (pwcheck == all) ? true : false;
+
+    if (list_pw == NULL)
+       SET(validated, FLAG_NO_CHECK);
+    CLR(validated, FLAG_NO_USER);
+    CLR(validated, FLAG_NO_HOST);
+    match = DENY;
+    TAILQ_FOREACH(nss, snl, entries) {
+       if (nss->query(nss, pw) == -1) {
+           /* The query function should have printed an error message. */
+           SET(validated, VALIDATE_ERROR);
+           break;
+       }
+       TAILQ_FOREACH(us, &nss->userspecs, entries) {
+           if (userlist_matches(pw, &us->users) != ALLOW)
                continue;
            TAILQ_FOREACH(priv, &us->privileges, entries) {
-               if (hostlist_matches(sudo_user.pw, &priv->hostlist) != ALLOW)
+               int priv_nopass = UNSPEC;
+
+               if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
                    continue;
+               TAILQ_FOREACH(def, &priv->defaults, entries) {
+                   if (strcmp(def->var, "authenticate") == 0)
+                       priv_nopass = def->op;
+               }
                TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
-                   if ((pwcheck == any && cs->tags.nopasswd == true) ||
-                       (pwcheck == all && cs->tags.nopasswd != true))
-                       nopass = cs->tags.nopasswd;
+                   if (pwcheck == any) {
+                       if (cs->tags.nopasswd == true || priv_nopass == true)
+                           nopass = true;
+                   } else if (pwcheck == all) {
+                       if (cs->tags.nopasswd != true && priv_nopass != true)
+                           nopass = false;
+                   }
                    if (match == ALLOW)
                        continue;
                    /* Only check the command when listing another user. */
@@ -189,34 +100,38 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
                }
            }
        }
-       if (match == ALLOW || user_uid == 0) {
-           /* User has an entry for this host. */
-           SET(validated, VALIDATE_SUCCESS);
-       } else if (match == DENY)
-           SET(validated, VALIDATE_FAILURE);
-       if (pwcheck == always && def_authenticate)
-           SET(validated, FLAG_CHECK_USER);
-       else if (nopass == true)
-           SET(validated, FLAG_NOPASSWD);
-       else
-           CLR(validated, FLAG_NOPASSWD);
-       debug_return_int(validated);
     }
+    if (match == ALLOW || user_uid == 0) {
+       /* User has an entry for this host. */
+       SET(validated, VALIDATE_SUCCESS);
+    } else if (match == DENY)
+       SET(validated, VALIDATE_FAILURE);
+    if (pwcheck == always && def_authenticate)
+       SET(validated, FLAG_CHECK_USER);
+    else if (nopass == true)
+       def_authenticate = false;
+    debug_return_int(validated);
+}
 
-    /* Need to be runas user while stat'ing things. */
-    if (!set_perms(PERM_RUNAS))
-       debug_return_int(validated);
+static int
+sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, int *validated,
+    struct cmndspec **matching_cs, struct defaults_list **defs, time_t now)
+{
+    int host_match, runas_match, cmnd_match;
+    struct cmndspec *cs;
+    struct privilege *priv;
+    struct userspec *us;
+    struct member *matching_user;
+    debug_decl(sudoers_lookup_check, SUDOERS_DEBUG_PARSER)
 
-    time(&now);
-    match = UNSPEC;
-    TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
-       if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
+    TAILQ_FOREACH_REVERSE(us, &nss->userspecs, userspec_list, entries) {
+       if (userlist_matches(pw, &us->users) != ALLOW)
            continue;
-       CLR(validated, FLAG_NO_USER);
+       CLR(*validated, FLAG_NO_USER);
        TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
-           host_match = hostlist_matches(sudo_user.pw, &priv->hostlist);
+           host_match = hostlist_matches(pw, &priv->hostlist);
            if (host_match == ALLOW)
-               CLR(validated, FLAG_NO_HOST);
+               CLR(*validated, FLAG_NO_HOST);
            else
                continue;
            TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
@@ -234,63 +149,6 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
                if (runas_match == ALLOW) {
                    cmnd_match = cmnd_matches(cs->cmnd);
                    if (cmnd_match != UNSPEC) {
-                       match = cmnd_match;
-                       tags = &cs->tags;
-                       timeout = cs->timeout;
-#ifdef HAVE_SELINUX
-                       /* Set role and type if not specified on command line. */
-                       if (user_role == NULL) {
-                           if (cs->role != NULL) {
-                               user_role = strdup(cs->role);
-                               if (user_role == NULL) {
-                                   sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-                                   SET(validated, VALIDATE_ERROR);
-                                   goto done;
-                               }
-                           } else {
-                               user_role = def_role;
-                           }
-                       }
-                       if (user_type == NULL) {
-                           if (cs->type != NULL) {
-                               user_type = strdup(cs->type);
-                               if (user_type == NULL) {
-                                   sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-                                   SET(validated, VALIDATE_ERROR);
-                                   goto done;
-                               }
-                           } else {
-                               user_type = def_type;
-                           }
-                       }
-#endif /* HAVE_SELINUX */
-#ifdef HAVE_PRIV_SET
-                       /* Set Solaris privilege sets */
-                       if (runas_privs == NULL) {
-                           if (cs->privs != NULL) {
-                               runas_privs = strdup(cs->privs);
-                               if (runas_privs == NULL) {
-                                   sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-                                   SET(validated, VALIDATE_ERROR);
-                                   goto done;
-                               }
-                           } else {
-                               runas_privs = def_privs;
-                           }
-                       }
-                       if (runas_limitprivs == NULL) {
-                           if (cs->limitprivs != NULL) {
-                               runas_limitprivs = strdup(cs->limitprivs);
-                               if (runas_limitprivs == NULL) {
-                                   sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-                                   SET(validated, VALIDATE_ERROR);
-                                   goto done;
-                               }
-                           } else {
-                               runas_limitprivs = def_limitprivs;
-                           }
-                       }
-#endif /* HAVE_PRIV_SET */
                        /*
                         * If user is running command as himself,
                         * set runas_pw = sudo_user.pw.
@@ -301,75 +159,174 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
                            sudo_pw_addref(sudo_user.pw);
                            runas_pw = sudo_user.pw;
                        }
-                       goto matched2;
+                       *matching_cs = cs;
+                       *defs = &priv->defaults;
+                       debug_return_int(cmnd_match);
                    }
                }
            }
        }
     }
-    matched2:
-    if (match == ALLOW) {
-       SET(validated, VALIDATE_SUCCESS);
-       CLR(validated, VALIDATE_FAILURE);
-       if (timeout > 0)
-           def_command_timeout = timeout;
-       if (tags != NULL) {
-           if (tags->nopasswd != UNSPEC)
-               def_authenticate = !tags->nopasswd;
-           if (tags->noexec != UNSPEC)
-               def_noexec = tags->noexec;
-           if (tags->setenv != UNSPEC)
-               def_setenv = tags->setenv;
-           if (tags->log_input != UNSPEC)
-               def_log_input = tags->log_input;
-           if (tags->log_output != UNSPEC)
-               def_log_output = tags->log_output;
-           if (tags->send_mail != UNSPEC) {
-               if (tags->send_mail) {
-                   def_mail_all_cmnds = true;
-               } else {
-                   def_mail_all_cmnds = false;
-                   def_mail_always = false;
-                   def_mail_no_perms = false;
+    debug_return_int(UNSPEC);
+}
+
+/*
+ * Apply cmndspec-specific settngs including SELinux role/type,
+ * Solaris privs, and command tags.
+ */
+static bool
+apply_cmndspec(struct cmndspec *cs)
+{
+    debug_decl(apply_cmndspec, SUDOERS_DEBUG_PARSER)
+
+    if (cs != NULL) {
+#ifdef HAVE_SELINUX
+       /* Set role and type if not specified on command line. */
+       if (user_role == NULL) {
+           if (cs->role != NULL) {
+               user_role = strdup(cs->role);
+               if (user_role == NULL) {
+                   sudo_warnx(U_("%s: %s"), __func__,
+                       U_("unable to allocate memory"));
+                   debug_return_bool(false);
                }
+           } else {
+               user_role = def_role;
            }
-           if (tags->follow != UNSPEC)
-               def_sudoedit_follow = tags->follow;
        }
-    } else if (match == DENY) {
-       SET(validated, VALIDATE_FAILURE);
-       CLR(validated, VALIDATE_SUCCESS);
-       if (tags != NULL) {
-           if (tags->nopasswd != UNSPEC)
-               def_authenticate = !tags->nopasswd;
-           if (tags->send_mail != UNSPEC) {
-               if (tags->send_mail) {
-                   def_mail_all_cmnds = true;
-               } else {
-                   def_mail_all_cmnds = false;
-                   def_mail_always = false;
-                   def_mail_no_perms = false;
+       if (user_type == NULL) {
+           if (cs->type != NULL) {
+               user_type = strdup(cs->type);
+               if (user_type == NULL) {
+                   sudo_warnx(U_("%s: %s"), __func__,
+                       U_("unable to allocate memory"));
+                   debug_return_bool(false);
                }
+           } else {
+               user_type = def_type;
            }
        }
+#endif /* HAVE_SELINUX */
+#ifdef HAVE_PRIV_SET
+       /* Set Solaris privilege sets */
+       if (runas_privs == NULL) {
+           if (cs->privs != NULL) {
+               runas_privs = strdup(cs->privs);
+               if (runas_privs == NULL) {
+                   sudo_warnx(U_("%s: %s"), __func__,
+                       U_("unable to allocate memory"));
+                   debug_return_bool(false);
+               }
+           } else {
+               runas_privs = def_privs;
+           }
+       }
+       if (runas_limitprivs == NULL) {
+           if (cs->limitprivs != NULL) {
+               runas_limitprivs = strdup(cs->limitprivs);
+               if (runas_limitprivs == NULL) {
+                   sudo_warnx(U_("%s: %s"), __func__,
+                       U_("unable to allocate memory"));
+                   debug_return_bool(false);
+               }
+           } else {
+               runas_limitprivs = def_limitprivs;
+           }
+       }
+#endif /* HAVE_PRIV_SET */
+       if (cs->timeout > 0)
+           def_command_timeout = cs->timeout;
+       if (cs->tags.nopasswd != UNSPEC)
+           def_authenticate = !cs->tags.nopasswd;
+       if (cs->tags.noexec != UNSPEC)
+           def_noexec = cs->tags.noexec;
+       if (cs->tags.setenv != UNSPEC)
+           def_setenv = cs->tags.setenv;
+       if (cs->tags.log_input != UNSPEC)
+           def_log_input = cs->tags.log_input;
+       if (cs->tags.log_output != UNSPEC)
+           def_log_output = cs->tags.log_output;
+       if (cs->tags.send_mail != UNSPEC) {
+           if (cs->tags.send_mail) {
+               def_mail_all_cmnds = true;
+           } else {
+               def_mail_all_cmnds = false;
+               def_mail_always = false;
+               def_mail_no_perms = false;
+           }
+       }
+       if (cs->tags.follow != UNSPEC)
+           def_sudoedit_follow = cs->tags.follow;
+    }
+
+    debug_return_bool(true);
+}
+
+/*
+ * Look up the user in the sudoers prase tree and check to see if they are
+ * allowed to run the specified command on this host as the target user.
+ */
+int
+sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated,
+    int pwflag)
+{
+    struct defaults_list *defs = NULL;
+    struct cmndspec *cs = NULL;
+    struct sudo_nss *nss;
+    int m, match = UNSPEC;
+    time_t now;
+    debug_decl(sudoers_lookup, SUDOERS_DEBUG_PARSER)
+
+    /*
+     * Special case checking the "validate", "list" and "kill" pseudo-commands.
+     */
+    if (pwflag)
+       debug_return_int(sudoers_lookup_pseudo(snl, pw, validated, pwflag));
+
+    /* Need to be runas user while stat'ing things. */
+    if (!set_perms(PERM_RUNAS))
+       debug_return_int(validated);
+
+    /* Query each sudoers source and check the user. */
+    time(&now);
+    TAILQ_FOREACH(nss, snl, entries) {
+       if (nss->query(nss, pw) == -1) {
+           /* The query function should have printed an error message. */
+           SET(validated, VALIDATE_ERROR);
+           break;
+       }
+
+       m = sudoers_lookup_check(nss, pw, &validated, &cs, &defs, now);
+       if (m != UNSPEC)
+           match = m;
+
+       if (!sudo_nss_can_continue(nss, m))
+           break;
+    }
+    if (defs != NULL)
+       update_defaults(defs, SETDEF_GENERIC, false);
+    if (match != UNSPEC) {
+       if (!apply_cmndspec(cs))
+           SET(validated, VALIDATE_ERROR);
+       else if (match == ALLOW)
+           SET(validated, VALIDATE_SUCCESS);
+       else
+           SET(validated, VALIDATE_FAILURE);
     }
-#if defined(HAVE_SELINUX) || defined(HAVE_PRIV_SET)
-done:
-#endif
     if (!restore_perms())
        SET(validated, VALIDATE_ERROR);
     debug_return_int(validated);
 }
 
 static int
-sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
+display_priv_short(struct passwd *pw, struct userspec *us,
     struct sudo_lbuf *lbuf)
 {
     struct cmndspec *cs, *prev_cs;
     struct member *m;
     struct privilege *priv;
     int nfound = 0;
-    debug_decl(sudo_file_display_priv_short, SUDOERS_DEBUG_NSS)
+    debug_decl(display_priv_short, SUDOERS_DEBUG_PARSER)
 
     TAILQ_FOREACH(priv, &us->privileges, entries) {
        if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
@@ -421,39 +378,41 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
 static bool
 new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs)
 {
+    debug_decl(new_long_entry, SUDOERS_DEBUG_PARSER)
+
     if (prev_cs == NULL)
-       return true;
+       debug_return_bool(true);
     if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(prev_cs->tags, cs->tags))
-       return true;
+       debug_return_bool(true);
 #ifdef HAVE_PRIV_SET
     if (cs->privs && (!prev_cs->privs || strcmp(cs->privs, prev_cs->privs) != 0))
-       return true;
+       debug_return_bool(true);
     if (cs->limitprivs && (!prev_cs->limitprivs || strcmp(cs->limitprivs, prev_cs->limitprivs) != 0))
-       return true;
+       debug_return_bool(true);
 #endif /* HAVE_PRIV_SET */
 #ifdef HAVE_SELINUX
     if (cs->role && (!prev_cs->role || strcmp(cs->role, prev_cs->role) != 0))
-       return true;
+       debug_return_bool(true);
     if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0))
-       return true;
+       debug_return_bool(true);
 #endif /* HAVE_SELINUX */
     if (cs->timeout != prev_cs->timeout)
-       return true;
+       debug_return_bool(true);
     if (cs->notbefore != prev_cs->notbefore)
-       return true;
+       debug_return_bool(true);
     if (cs->notafter != prev_cs->notafter)
-       return true;
-    return false;
+       debug_return_bool(true);
+    debug_return_bool(false);
 }
 
 static int
-sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
+display_priv_long(struct passwd *pw, struct userspec *us,
     struct sudo_lbuf *lbuf)
 {
     struct cmndspec *cs, *prev_cs;
     struct privilege *priv;
     int nfound = 0, olen;
-    debug_decl(sudo_file_display_priv_long, SUDOERS_DEBUG_NSS)
+    debug_decl(display_priv_long, SUDOERS_DEBUG_PARSER)
 
     TAILQ_FOREACH(priv, &us->privileges, entries) {
        if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
@@ -559,65 +518,46 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
     debug_return_int(nfound);
 }
 
-/* XXX - better naming */
-int
+static int
 sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw,
     struct sudo_lbuf *lbuf)
 {
     struct userspec *us;
     int nfound = 0;
-    debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_NSS)
+    debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_PARSER)
 
     TAILQ_FOREACH(us, usl, entries) {
        if (userlist_matches(pw, &us->users) != ALLOW)
            continue;
 
        if (long_list)
-           nfound += sudo_file_display_priv_long(pw, us, lbuf);
+           nfound += display_priv_long(pw, us, lbuf);
        else
-           nfound += sudo_file_display_priv_short(pw, us, lbuf);
+           nfound += display_priv_short(pw, us, lbuf);
     }
     if (sudo_lbuf_error(lbuf))
        debug_return_int(-1);
     debug_return_int(nfound);
 }
 
-/*
- * Returns the number of matching privileges or -1 on error.
- */
-static int
-sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    debug_decl(sudo_file_display_priv, SUDOERS_DEBUG_NSS)
-
-    if (nss->handle == NULL)
-       debug_return_int(0);
-
-    debug_return_int(sudo_display_userspecs(&userspecs, pw, lbuf));
-}
-
 /*
  * Display matching Defaults entries for the given user on this host.
  */
-int
-sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
+static int
+display_defaults(struct defaults_list *defs, struct passwd *pw,
     struct sudo_lbuf *lbuf)
 {
     struct defaults *d;
     char *prefix;
     int nfound = 0;
-    debug_decl(sudo_file_display_defaults, SUDOERS_DEBUG_NSS)
-
-    if (nss->handle == NULL)
-       goto done;
+    debug_decl(display_defaults, SUDOERS_DEBUG_PARSER)
 
     if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
        prefix = "    ";
     else
        prefix = ", ";
 
-    TAILQ_FOREACH(d, &defaults, entries) {
+    TAILQ_FOREACH(d, defs, entries) {
        switch (d->type) {
            case DEFAULTS_HOST:
                if (hostlist_matches(pw, d->binding) != ALLOW)
@@ -636,26 +576,6 @@ sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
        prefix = ", ";
        nfound++;
     }
-    if (sudo_lbuf_error(lbuf))
-       debug_return_int(-1);
-done:
-    debug_return_int(nfound);
-}
-
-/*
- * Display Defaults entries that are per-runas or per-command
- */
-int
-sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    int nfound = 0;
-    debug_decl(sudo_file_display_bound_defaults, SUDOERS_DEBUG_NSS)
-
-    /* XXX - should only print ones that match what the user can do. */
-    nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
-    nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
-
     if (sudo_lbuf_error(lbuf))
        debug_return_int(-1);
     debug_return_int(nfound);
@@ -665,14 +585,15 @@ sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
  * Display Defaults entries of the given type.
  */
 static int
-display_bound_defaults(int deftype, struct sudo_lbuf *lbuf)
+display_bound_defaults_by_type(struct defaults_list *defs, int deftype,
+    struct sudo_lbuf *lbuf)
 {
     struct defaults *d;
     struct member_list *binding = NULL;
     struct member *m;
     char *dsep;
     int atype, nfound = 0;
-    debug_decl(display_bound_defaults, SUDOERS_DEBUG_NSS)
+    debug_decl(display_bound_defaults_by_type, SUDOERS_DEBUG_PARSER)
 
     switch (deftype) {
        case DEFAULTS_HOST:
@@ -694,7 +615,7 @@ display_bound_defaults(int deftype, struct sudo_lbuf *lbuf)
        default:
            debug_return_int(-1);
     }
-    TAILQ_FOREACH(d, &defaults, entries) {
+    TAILQ_FOREACH(d, defs, entries) {
        if (d->type != deftype)
            continue;
 
@@ -721,51 +642,208 @@ display_bound_defaults(int deftype, struct sudo_lbuf *lbuf)
 }
 
 /*
- * Returns 0 if the command is allowed, 1 if not or -1 on error.
+ * Display Defaults entries that are per-runas or per-command
+ */
+static int
+display_bound_defaults(struct defaults_list *defs, struct passwd *pw,
+    struct sudo_lbuf *lbuf)
+{
+    int nfound = 0;
+    debug_decl(display_bound_defaults, SUDOERS_DEBUG_PARSER)
+
+    /* XXX - should only print ones that match what the user can do. */
+    nfound += display_bound_defaults_by_type(defs, DEFAULTS_RUNAS, lbuf);
+    nfound += display_bound_defaults_by_type(defs, DEFAULTS_CMND, lbuf);
+
+    if (sudo_lbuf_error(lbuf))
+       debug_return_int(-1);
+    debug_return_int(nfound);
+}
+
+static int
+output(const char *buf)
+{
+    struct sudo_conv_message msg;
+    struct sudo_conv_reply repl;
+    debug_decl(output, SUDOERS_DEBUG_NSS)
+
+    /* Call conversation function */
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_type = SUDO_CONV_INFO_MSG;
+    msg.msg = buf;
+    memset(&repl, 0, sizeof(repl));
+    if (sudo_conv(1, &msg, &repl, NULL) == -1)
+       debug_return_int(0);
+    debug_return_int(strlen(buf));
+}
+
+/*
+ * Print out privileges for the specified user.
+ * Returns true on success or -1 on error.
  */
 int
-sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
+display_privs(struct sudo_nss_list *snl, struct passwd *pw)
 {
+    struct sudo_nss *nss;
+    struct sudo_lbuf def_buf, priv_buf;
+    struct stat sb;
+    int cols, count, olen, n;
+    debug_decl(display_privs, SUDOERS_DEBUG_PARSER)
+
+    /* Query all sudoers sources first. */
+    TAILQ_FOREACH(nss, snl, entries) {
+       if (nss->query(nss, pw) == -1) {
+           /* The query function should have printed an error message. */
+           debug_return_int(-1);
+       }
+    }
+
+    cols = sudo_user.cols;
+    if (fstat(STDOUT_FILENO, &sb) == 0 && S_ISFIFO(sb.st_mode))
+       cols = 0;
+    sudo_lbuf_init(&def_buf, output, 4, NULL, cols);
+    sudo_lbuf_init(&priv_buf, output, 8, NULL, cols);
+
+    sudo_lbuf_append(&def_buf, _("Matching Defaults entries for %s on %s:\n"),
+       pw->pw_name, user_srunhost);
+    count = 0;
+    TAILQ_FOREACH(nss, snl, entries) {
+       n = display_defaults(&nss->defaults, pw, &def_buf);
+       if (n == -1)
+           goto bad;
+       count += n;
+    }
+    if (count != 0) {
+       sudo_lbuf_append(&def_buf, "\n\n");
+    } else {
+       /* Undo Defaults header. */
+       def_buf.len = 0;
+    }
+
+    /* Display Runas and Cmnd-specific defaults. */
+    olen = def_buf.len;
+    sudo_lbuf_append(&def_buf, _("Runas and Command-specific defaults for %s:\n"),
+       pw->pw_name);
+    count = 0;
+    TAILQ_FOREACH(nss, snl, entries) {
+       n = display_bound_defaults(&nss->defaults, pw, &def_buf);
+       if (n == -1)
+           goto bad;
+       count += n;
+    }
+    if (count != 0) {
+       sudo_lbuf_append(&def_buf, "\n\n");
+    } else {
+       /* Undo Defaults header. */
+       def_buf.len = olen;
+    }
+
+    /* Display privileges from all sources. */
+    sudo_lbuf_append(&priv_buf,
+       _("User %s may run the following commands on %s:\n"),
+       pw->pw_name, user_srunhost);
+    count = 0;
+    TAILQ_FOREACH(nss, snl, entries) {
+       n = sudo_display_userspecs(&nss->userspecs, pw, &priv_buf);
+       if (n == -1)
+           goto bad;
+       count += n;
+    }
+    if (count == 0) {
+       def_buf.len = 0;
+       priv_buf.len = 0;
+       sudo_lbuf_append(&priv_buf,
+           _("User %s is not allowed to run sudo on %s.\n"),
+           pw->pw_name, user_shost);
+    }
+    if (sudo_lbuf_error(&def_buf) || sudo_lbuf_error(&priv_buf))
+       goto bad;
+
+    sudo_lbuf_print(&def_buf);
+    sudo_lbuf_print(&priv_buf);
+
+    sudo_lbuf_destroy(&def_buf);
+    sudo_lbuf_destroy(&priv_buf);
+
+    debug_return_int(true);
+bad:
+    sudo_lbuf_destroy(&def_buf);
+    sudo_lbuf_destroy(&priv_buf);
+
+    debug_return_int(-1);
+}
+
+static int
+display_cmnd_check(struct sudo_nss *nss, struct passwd *pw, time_t now)
+{
+    int host_match, runas_match, cmnd_match;
     struct cmndspec *cs;
-    struct member *match;
     struct privilege *priv;
     struct userspec *us;
-    int ret = 1;
-    int host_match, runas_match, cmnd_match;
-    debug_decl(sudo_file_display_cmnd, SUDOERS_DEBUG_NSS)
-
-    if (nss->handle == NULL)
-       goto done;
+    debug_decl(display_cmnd_check, SUDOERS_DEBUG_PARSER)
 
-    match = NULL;
-    TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
+    TAILQ_FOREACH_REVERSE(us, &nss->userspecs, userspec_list, entries) {
        if (userlist_matches(pw, &us->users) != ALLOW)
            continue;
-
        TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
            host_match = hostlist_matches(pw, &priv->hostlist);
            if (host_match != ALLOW)
                continue;
            TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
+               if (cs->notbefore != UNSPEC) {
+                   if (now < cs->notbefore)
+                       continue;
+               }
+               if (cs->notafter != UNSPEC) {
+                   if (now > cs->notafter)
+                       continue;
+               }
                runas_match = runaslist_matches(cs->runasuserlist,
                    cs->runasgrouplist, NULL, NULL);
                if (runas_match == ALLOW) {
                    cmnd_match = cmnd_matches(cs->cmnd);
-                   if (cmnd_match != UNSPEC) {
-                       if (cmnd_match == ALLOW)
-                           match = cs->cmnd;
-                       goto matched;
-                   }
+                   if (cmnd_match != UNSPEC)
+                       debug_return_int(cmnd_match);
                }
            }
        }
     }
-    matched:
-    if (match != NULL && !match->negated) {
+    debug_return_int(UNSPEC);
+}
+
+/*
+ * Check user_cmnd against sudoers and print the matching entry if the
+ * command is allowed.
+ * Returns true if the command is allowed, false if not or -1 on error.
+ */
+int
+display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
+{
+    struct sudo_nss *nss;
+    int m, match = UNSPEC;
+    int ret = false;
+    time_t now;
+    debug_decl(display_cmnd, SUDOERS_DEBUG_PARSER)
+
+    /* Iterate over each source, checking for the command. */
+    time(&now);
+    TAILQ_FOREACH(nss, snl, entries) {
+       if (nss->query(nss, pw) == -1) {
+           /* The query function should have printed an error message. */
+           debug_return_int(-1);
+       }
+
+       m = display_cmnd_check(nss, pw, now);
+       if (m != UNSPEC)
+           match = m;
+
+       if (!sudo_nss_can_continue(nss, m))
+           break;
+    }
+    if (match == ALLOW) {
        const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
            safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
-       ret = len < 0 ? -1 : 0;
+       ret = len < 0 ? -1 : true;
     }
-done:
     debug_return_int(ret);
 }
index a24df094b13b243e8f7eafeda211ec30a4064a9f..94fb6c369376070295c17e4ba608546866989db0 100644 (file)
@@ -318,10 +318,13 @@ unsigned char *sudo_filedigest(int fd, const char *file, int digest_type, size_t
 const char *digest_type_to_name(int digest_type);
 
 /* parse.c */
-struct sudo_lbuf;
-int sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, struct sudo_lbuf *lbuf);
+struct sudo_nss_list;
+int sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, int pwflag);
+int display_privs(struct sudo_nss_list *snl, struct passwd *pw);
+int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw);
 
 /* fmtsudoers.c */
+struct sudo_lbuf;
 bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, struct cmndspec *prev_cs, bool expand_aliases);
 bool sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d);
 bool sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, struct defaults **next, bool expand_aliases);
index bcd70b623bf785288c847b107922e17ec5f8edd1..5cd3d30421ad22da8ba8d5c3b517ef0a3fd48887 100644 (file)
@@ -94,24 +94,19 @@ struct sudo_sss_handle {
 static int sudo_sss_open(struct sudo_nss *nss);
 static int sudo_sss_close(struct sudo_nss *nss);
 static int sudo_sss_parse(struct sudo_nss *nss);
+static int sudo_sss_query(struct sudo_nss *nss, struct passwd *pw);
 static bool sudo_sss_parse_options(struct sudo_sss_handle *handle,
-                                  struct sss_sudo_rule *rule);
-static int sudo_sss_setdefs(struct sudo_nss *nss);
-static int sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag);
-static int sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
-static int sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
-                                    struct sudo_lbuf *lbuf);
-
-static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
-                                          struct passwd *pw, struct sudo_lbuf *lbuf);
-
-static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
-                                 struct sudo_lbuf *sudo_lbuf);
+                                  struct sss_sudo_rule *rule,
+                                  struct defaults_list *defs);
 
+static int sudo_sss_getdefs(struct sudo_nss *nss);
 
 static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
-                                                  struct passwd *pw,
-                                                  uint32_t *state);
+                                                  struct passwd *pw);
+
+static bool sss_to_sudoers(struct sudo_sss_handle *handle,
+                          struct sss_sudo_result *sss_result,
+                          struct userspec_list *sss_userspecs);
 
 static void
 sudo_sss_attrfree(struct sss_sudo_attr *attr)
@@ -208,9 +203,7 @@ sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
 #define SUDO_SSS_FILTER_INCLUDE 0
 #define SUDO_SSS_FILTER_EXCLUDE 1
 
-#define SUDO_SSS_STATE_HOSTMATCH 0x01
-#define SUDO_SSS_STATE_USERMATCH 0x02
-
+/* XXX - insted of filtering result, include user and host in sudoers parse tree */
 static struct sss_sudo_result *
 sudo_sss_filter_result(struct sudo_sss_handle *handle,
     struct sss_sudo_result *in_res,
@@ -367,12 +360,8 @@ struct sudo_nss sudo_nss_sss = {
     sudo_sss_open,
     sudo_sss_close,
     sudo_sss_parse,
-    sudo_sss_setdefs,
-    sudo_sss_lookup,
-    sudo_sss_display_cmnd,
-    sudo_sss_display_defaults,
-    sudo_sss_display_bound_defaults,
-    sudo_sss_display_privs
+    sudo_sss_query,
+    sudo_sss_getdefs
 };
 
 /* sudo_nss implementation */
@@ -447,7 +436,6 @@ sudo_sss_open(struct sudo_nss *nss)
        debug_return_int(EFAULT);
     }
 
-    handle->pw = sudo_user.pw;
     nss->handle = handle;
 
     /*
@@ -470,21 +458,97 @@ sudo_sss_open(struct sudo_nss *nss)
 static int
 sudo_sss_close(struct sudo_nss *nss)
 {
+    struct member_list *prev_binding = NULL;
+    struct defaults *def;
+    struct userspec *us;
     struct sudo_sss_handle *handle;
     debug_decl(sudo_sss_close, SUDOERS_DEBUG_SSSD);
 
     if (nss && nss->handle) {
        handle = nss->handle;
        sudo_dso_unload(handle->ssslib);
+       if (handle->pw != NULL)
+           sudo_pw_delref(handle->pw);
        free(handle->ipa_host);
        if (handle->ipa_host != handle->ipa_shost)
            free(handle->ipa_shost);
        free(handle);
        nss->handle = NULL;
+
+       /* XXX - do in main module? */
+       while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+           TAILQ_REMOVE(&nss->userspecs, us, entries);
+           free_userspec(us);
+       }
+       while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
+           TAILQ_REMOVE(&nss->defaults, def, entries);
+           free_default(def, &prev_binding);
+       }
     }
     debug_return_int(0);
 }
 
+/*
+ * Perform query for user and host and convert to sudoers parse tree.
+ */
+static int
+sudo_sss_query(struct sudo_nss *nss, struct passwd *pw)
+{
+    struct sudo_sss_handle *handle = nss->handle;
+    struct sss_sudo_result *sss_result = NULL;
+    struct userspec *us;
+    int ret = 0;
+    debug_decl(sudo_sss_query, SUDOERS_DEBUG_SSSD);
+
+    /* Use cached result if it matches pw. */
+    if (handle->pw != NULL) {
+       if (pw == handle->pw)
+           goto done;
+       sudo_pw_delref(handle->pw);
+       handle->pw = NULL;
+    }
+
+    /* Free old userspecs, if any. */
+    while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+       TAILQ_REMOVE(&nss->userspecs, us, entries);
+       free_userspec(us);
+    }
+
+    /* Fetch list of sudoRole entries that match user and host. */
+    sss_result = sudo_sss_result_get(nss, pw);
+
+    sudo_debug_printf(SUDO_DEBUG_DIAG,
+       "searching SSSD/LDAP for sudoers entries for user %s, host %s",
+        pw->pw_name, user_runhost);
+
+    if (sss_result == NULL)
+       goto done;
+
+    /* Convert to sudoers parse tree. */
+    if (!sss_to_sudoers(handle, sss_result, &nss->userspecs)) {
+       ret = -1;
+       goto done;
+    }
+
+    /* Stash a ref to the passwd struct in the handle. */
+    sudo_pw_addref(pw);
+    handle->pw = pw;
+
+done:
+    /* Cleanup */
+    handle->fn_free_result(sss_result);
+    if (ret == -1) {
+       while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+           TAILQ_REMOVE(&nss->userspecs, us, entries);
+           free_userspec(us);
+       }
+    }
+
+    sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
+
+    debug_return_int(ret);
+}
+
 // ok
 static int
 sudo_sss_parse(struct sudo_nss *nss)
@@ -494,23 +558,32 @@ sudo_sss_parse(struct sudo_nss *nss)
 }
 
 static int
-sudo_sss_setdefs(struct sudo_nss *nss)
+sudo_sss_getdefs(struct sudo_nss *nss)
 {
     struct sudo_sss_handle *handle = nss->handle;
     struct sss_sudo_result *sss_result = NULL;
     struct sss_sudo_rule   *sss_rule;
+    struct member_list *prev_binding = NULL;
+    struct defaults *def;
     uint32_t sss_error;
     unsigned int i;
-    debug_decl(sudo_sss_setdefs, SUDOERS_DEBUG_SSSD);
+    debug_decl(sudo_sss_getdefs, SUDOERS_DEBUG_SSSD);
 
     if (handle == NULL)
        debug_return_int(-1);
 
+    /* Free old defaults, if any. */
+    while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
+       TAILQ_REMOVE(&nss->defaults, def, entries);
+       free_default(def, &prev_binding);
+    }
+
     sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
 
-    if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
-                                     &sss_error, &handle->domainname,
-                                     &sss_result) != 0) {
+    /* NOTE: these are global defaults, user ID and name are not used. */
+    if (handle->fn_send_recv_defaults(sudo_user.pw->pw_uid,
+                                     sudo_user.pw->pw_name, &sss_error,
+                                     &handle->domainname, &sss_result) != 0) {
        sudo_debug_printf(SUDO_DEBUG_INFO,
            "handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
        debug_return_int(-1);
@@ -529,7 +602,7 @@ sudo_sss_setdefs(struct sudo_nss *nss)
         sudo_debug_printf(SUDO_DEBUG_DIAG,
            "Parsing cn=defaults, %d/%d", i, sss_result->num_rules);
         sss_rule = sss_result->rules + i;
-        if (!sudo_sss_parse_options(handle, sss_rule))
+        if (!sudo_sss_parse_options(handle, sss_rule, &nss->defaults))
            goto bad;
     }
 
@@ -541,217 +614,6 @@ bad:
     debug_return_int(-1);
 }
 
-static int
-sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
-{
-    struct sudo_sss_handle *handle = nss->handle;
-    debug_decl(sudo_sss_checkpw, SUDOERS_DEBUG_SSSD);
-
-    if (pw->pw_name != handle->pw->pw_name ||
-       pw->pw_uid  != handle->pw->pw_uid) {
-       sudo_debug_printf(SUDO_DEBUG_DIAG,
-           "Requested name or uid don't match the initial once, reinitializing...");
-       handle->pw = pw;
-
-       if (sudo_sss_setdefs(nss) != 0)
-           debug_return_int(-1);
-    }
-
-     debug_return_int(0);
-}
-
-static int
-sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule, int *group_matched)
-{
-    const char *host = handle->ipa_host ? handle->ipa_host : user_runhost;
-    const char *shost = handle->ipa_shost ? handle->ipa_shost : user_srunhost;
-    char *val, **val_array = NULL;
-    int ret = false, i;
-    debug_decl(sudo_sss_check_runas_user, SUDOERS_DEBUG_SSSD);
-
-    /* get the runas user from the entry */
-    i = handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array);
-    if (i == ENOENT) {
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "sudoRunAsUser: no result, trying sudoRunAs");
-       i = handle->fn_get_values(sss_rule, "sudoRunAs", &val_array);
-    }
-    switch (i) {
-    case 0:
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "sudoRunAsUser: no result.");
-        if (*group_matched == UNSPEC) {
-            /* We haven't check for sudoRunAsGroup yet, check now. */
-           i = handle->fn_get_values(sss_rule, "sudoRunAsGroup", &val_array);
-            if (i == 0) {
-                *group_matched = false;
-               handle->fn_free_values(val_array);
-            }
-        }
-       if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED))
-           debug_return_int(UNSPEC);
-       switch (*group_matched) {
-       case UNSPEC:
-           /*
-            * No runas user or group entries.  Match runas_default
-            * against what the user specified on the command line.
-            */
-           sudo_debug_printf(SUDO_DEBUG_INFO, "Matching against runas_default");
-           ret = userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
-           break;
-       case true:
-           /*
-            * No runas user entries but have a matching runas group entry.
-            * If trying to run as the invoking user, allow it.
-            */
-           sudo_debug_printf(SUDO_DEBUG_INFO, "Matching against user_name");
-           if (userpw_matches(user_name, runas_pw->pw_name, runas_pw))
-               ret = true;
-           break;
-       }
-       debug_return_int(ret);
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoRunAsUser): %d", i);
-       debug_return_int(false);
-    }
-
-    /*
-     * BUG:
-     *
-     * if runas is not specified on the command line, the only information
-     * as to which user to run as is in the runas_default option.  We should
-     * check to see if we have the local option present.  Unfortunately we
-     * don't parse these options until after this routine says yes or no.
-     * The query has already returned, so we could peek at the attribute
-     * values here though.
-     *
-     * For now just require users to always use -u option unless its set
-     * in the global defaults. This behaviour is no different than the global
-     * /etc/sudoers.
-     *
-     * Sigh - maybe add this feature later
-     */
-
-    /* walk through values returned, looking for a match */
-    for (i = 0; val_array[i] != NULL && !ret; ++i) {
-       val = val_array[i];
-
-       sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-
-       switch (val[0]) {
-       case '+':
-           sudo_debug_printf(SUDO_DEBUG_DEBUG, "netgr_");
-           if (netgr_matches(val, def_netgroup_tuple ? host : NULL,
-               def_netgroup_tuple ? shost : NULL, runas_pw->pw_name)) {
-               sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
-               ret = true;
-           }
-           break;
-       case '%':
-           sudo_debug_printf(SUDO_DEBUG_DEBUG, "usergr_");
-           if (usergr_matches(val, runas_pw->pw_name, runas_pw)) {
-               sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
-               ret = true;
-           }
-           break;
-       case '\0':
-           /* Empty RunAsUser means run as the invoking user. */
-           if (ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) &&
-               userpw_matches(user_name, runas_pw->pw_name, runas_pw))
-               ret = true;
-           break;
-       case 'A':
-           if (strcmp(val, "ALL") == 0) {
-               sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
-               ret = true;
-               break;
-           }
-           /* FALLTHROUGH */
-           sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
-       default:
-           if (userpw_matches(val, runas_pw->pw_name, runas_pw)) {
-               sudo_debug_printf(SUDO_DEBUG_DEBUG,
-                   "%s == %s (pw_name) => match", val, runas_pw->pw_name);
-               ret = true;
-           }
-           break;
-       }
-
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
-    }
-
-    handle->fn_free_values(val_array); /* cleanup */
-
-    debug_return_int(ret);
-}
-
-static int
-sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
-{
-    char **val_array = NULL;
-    char *val;
-    int ret = false, i;
-    debug_decl(sudo_sss_check_runas_group, SUDOERS_DEBUG_SSSD);
-
-    /* get the values from the entry */
-    i = handle->fn_get_values(rule, "sudoRunAsGroup", &val_array);
-    switch (i) {
-    case 0:
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "sudoRunAsGroup: no result.");
-       if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED)) {
-           if (runas_pw->pw_gid == runas_gr->gr_gid)
-               ret = true;     /* runas group matches passwd db */
-       }
-       debug_return_int(ret);
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoRunAsGroup): %d", i);
-       debug_return_int(false);
-    }
-
-    /* walk through values returned, looking for a match */
-    for (i = 0; val_array[i] != NULL; ++i) {
-       val = val_array[i];
-       sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-
-       if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
-           ret = true;
-
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
-    }
-
-    handle->fn_free_values(val_array);
-
-    debug_return_int(ret);
-}
-
-/*
- * Walk through search results and return true if we have a runas match,
- * else false.  RunAs info is optional.
- */
-static bool
-sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
-{
-    int user_matched = UNSPEC;
-    int group_matched = UNSPEC;
-    debug_decl(sudo_sss_check_runas, SUDOERS_DEBUG_SSSD);
-
-    if (rule == NULL)
-        debug_return_bool(false);
-
-    if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED))
-       group_matched = sudo_sss_check_runas_group(handle, rule);
-    user_matched = sudo_sss_check_runas_user(handle, rule, &group_matched);
-
-    debug_return_bool(group_matched != false && user_matched != false);
-}
-
 static bool
 sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
 {
@@ -867,6 +729,7 @@ sudo_sss_check_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
     debug_return_bool(ret);
 }
 
+/* XXX - insted of filtering result, include user and host in sudoers parse tree */
 static int
 sudo_sss_result_filterp(struct sudo_sss_handle *handle,
     struct sss_sudo_rule *rule, void *unused)
@@ -882,23 +745,20 @@ sudo_sss_result_filterp(struct sudo_sss_handle *handle,
 }
 
 static struct sss_sudo_result *
-sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
+sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw)
 {
     struct sudo_sss_handle *handle = nss->handle;
     struct sss_sudo_result *u_sss_result, *f_sss_result;
     uint32_t sss_error = 0, ret;
     debug_decl(sudo_sss_result_get, SUDOERS_DEBUG_SSSD);
 
-    if (sudo_sss_checkpw(nss, pw) != 0)
-       debug_return_ptr(NULL);
-
-    sudo_debug_printf(SUDO_DEBUG_DIAG, "  username=%s", handle->pw->pw_name);
+    sudo_debug_printf(SUDO_DEBUG_DIAG, "  username=%s", pw->pw_name);
     sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s",
        handle->domainname ? handle->domainname : "NULL");
 
     u_sss_result = f_sss_result = NULL;
 
-    ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
+    ret = handle->fn_send_recv(pw->pw_uid, pw->pw_name,
        handle->domainname, &sss_error, &u_sss_result);
 
     switch (ret) {
@@ -906,10 +766,6 @@ sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
        switch (sss_error) {
        case 0:
            if (u_sss_result != NULL) {
-               if (state != NULL) {
-                   sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
-                   *state |= SUDO_SSS_STATE_USERMATCH;
-               }
                sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
                    u_sss_result->num_rules);
            } else {
@@ -932,16 +788,11 @@ sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
        debug_return_ptr(NULL);
     }
 
+    /* XXX - insted of filtering result, include user and host in sudoers parse tree */
     f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
        sudo_sss_result_filterp, SUDO_SSS_FILTER_INCLUDE, NULL);
 
     if (f_sss_result != NULL) {
-       if (f_sss_result->num_rules > 0) {
-           if (state != NULL) {
-               sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
-               *state |= SUDO_SSS_STATE_HOSTMATCH;
-           }
-       }
        sudo_debug_printf(SUDO_DEBUG_DEBUG,
            "u_sss_result=(%p, %u) => f_sss_result=(%p, %u)", u_sss_result,
            u_sss_result->num_rules, f_sss_result, f_sss_result->num_rules);
@@ -956,132 +807,11 @@ sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
     debug_return_ptr(f_sss_result);
 }
 
-/*
- * Search for boolean "option" in sudoOption.
- * Returns true if found and allowed, false if negated, else UNSPEC.
- */
-static int
-sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
-    char *option)
-{
-    char *var, **val_array = NULL;
-    int i, ret = UNSPEC;
-    bool negated;
-    debug_decl(sudo_sss_check_bool, SUDOERS_DEBUG_SSSD);
-
-    if (rule == NULL)
-       debug_return_int(ret);
-
-    switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
-    case 0:
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       debug_return_int(ret);
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
-       debug_return_int(ret);
-    }
-
-    /* walk through options */
-    for (i = 0; val_array[i] != NULL; ++i) {
-       var = val_array[i];
-       sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
-
-       negated = sudo_ldap_is_negated(&var);
-       if (strcmp(var, option) == 0)
-           ret = negated ? false : true;
-    }
-
-    handle->fn_free_values(val_array);
-
-    debug_return_int(ret);
-}
-
-/*
- * Walk through search results and return true if we have a command match,
- * false if disallowed and UNSPEC if not matched.
- */
-static int
-sudo_sss_check_command(struct sudo_sss_handle *handle,
-    struct sss_sudo_rule *rule, int *setenv_implied)
-{
-    char **val_array = NULL, *val;
-    char *allowed_cmnd, *allowed_args;
-    int ret = UNSPEC;
-    bool negated;
-    unsigned int i;
-    struct sudo_digest digest, *allowed_digest = NULL;
-    debug_decl(sudo_sss_check_command, SUDOERS_DEBUG_SSSD);
-
-    if (rule == NULL)
-       debug_return_int(ret);
-
-    switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
-    case 0:
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       debug_return_int(ret);
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
-       debug_return_int(ret);
-    }
-
-    for (i = 0; val_array[i] != NULL && ret != false; ++i) {
-       val = val_array[i];
-
-       sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-
-       /* Match against ALL ? */
-       if (strcmp(val, "ALL") == 0) {
-           ret = true;
-           if (setenv_implied != NULL)
-               *setenv_implied = true;
-           sudo_debug_printf(SUDO_DEBUG_INFO,
-               "sssd/ldap sudoCommand '%s' ... MATCH!", val);
-           continue;
-       }
-
-        /* check for sha-2 digest */
-       allowed_digest = sudo_ldap_extract_digest(&val, &digest);
-
-       /* check for !command */
-       allowed_cmnd = val;
-       negated = sudo_ldap_is_negated(&allowed_cmnd);
-
-       /* split optional args away from command */
-       allowed_args = strchr(allowed_cmnd, ' ');
-       if (allowed_args)
-           *allowed_args++ = '\0';
-
-       /* check the command like normal */
-       if (command_matches(allowed_cmnd, allowed_args, allowed_digest)) {
-           /*
-            * If allowed (no bang) set ret but keep on checking.
-            * If disallowed (bang), exit loop.
-            */
-           ret = negated ? false : true;
-       }
-       if (allowed_args != NULL)
-           allowed_args[-1] = ' ';     /* restore val */
-
-       sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
-           val, ret == true ? "MATCH!" : "not");
-       if (allowed_digest != NULL)
-           free(allowed_digest->digest_str);
-    }
-
-    handle->fn_free_values(val_array); /* more cleanup */
-
-    debug_return_int(ret);
-}
-
 static bool
-sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
+sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule, struct defaults_list *defs)
 {
-    int i, op;
-    char *copy, *var, *val, *source = NULL;
+    int i;
+    char *source = NULL;
     bool ret = false;
     char **val_array = NULL;
     char **cn_array = NULL;
@@ -1101,312 +831,52 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul
        debug_return_bool(false);
     }
 
-    /* get the entry's cn for option error reporting */
+    /* Use sudoRole in place of file name in defaults. */
     if (handle->fn_get_values(rule, "cn", &cn_array) == 0) {
        if (cn_array[0] != NULL) {
-           if (asprintf(&source, "sudoRole %s", cn_array[0]) == -1) {
-               sudo_warnx(U_("%s: %s"), __func__,
-                   U_("unable to allocate memory"));
-               source = NULL;
-               goto done;
-           }
+           char *cp;
+           if (asprintf(&cp, "sudoRole %s", cn_array[0]) == -1)
+               goto oom;
+           source = rcstr_dup(cp);
+           free(cp);
+           if (source == NULL)
+               goto oom;
        }
        handle->fn_free_values(cn_array);
        cn_array = NULL;
     }
-
-    /* walk through options, early ones first */
-    for (i = 0; val_array[i] != NULL; i++) {
-       struct early_default *early;
-
-       if ((copy = strdup(val_array[i])) == NULL) {
-           sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-           goto done;
-       }
-       op = sudo_ldap_parse_option(copy, &var, &val);
-       early = is_early_default(var);
-       if (early != NULL) {
-           set_early_default(var, val, op,
-               source ? source : "sudoRole UNKNOWN", 0, false, early);
-       }
-       free(copy);
+    if (source == NULL) {
+       if ((source = rcstr_dup("sudoRole UNKNOWN")) == NULL)
+           goto oom;
     }
-    run_early_defaults();
 
-    /* walk through options again, skipping early ones */
+    /* Walk through options, appending to defs. */
     for (i = 0; val_array[i] != NULL; i++) {
-       if ((copy = strdup(val_array[i])) == NULL) {
-           sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-           goto done;
-       }
+       char *copy, *var, *val;
+       int op;
+
+       /* XXX - should not need to copy */
+       if ((copy = strdup(val_array[i])) == NULL)
+           goto oom;
        op = sudo_ldap_parse_option(copy, &var, &val);
-       if (is_early_default(var) == NULL) {
-           set_default(var, val, op,
-               source ? source : "sudoRole UNKNOWN", 0, false);
+       if (!sudo_ldap_add_default(var, val, op, source, defs)) {
+           free(copy);
+           goto oom;
        }
        free(copy);
     }
     ret = true;
+    goto done;
+
+oom:
+    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
 
 done:
-    free(source);
+    rcstr_delref(source);
     handle->fn_free_values(val_array);
     debug_return_bool(ret);
 }
 
-static int
-sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
-{
-    int rc, setenv_implied;
-
-    struct sudo_sss_handle *handle = nss->handle;
-    struct sss_sudo_result *sss_result = NULL;
-    struct sss_sudo_rule   *rule;
-    uint32_t i, state = 0;
-    debug_decl(sudo_sss_lookup, SUDOERS_DEBUG_SSSD);
-
-    /* Fetch list of sudoRole entries that match user and host. */
-    sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
-
-    /*
-     * The following queries are only determine whether or not a
-     * password is required, so the order of the entries doesn't matter.
-     */
-    if (pwflag) {
-       int doauth = UNSPEC;
-       int matched = UNSPEC;
-       enum def_tuple pwcheck =
-           (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-
-       sudo_debug_printf(SUDO_DEBUG_INFO, "perform search for pwflag %d", pwflag);
-       if (sss_result != NULL) {
-           for (i = 0; i < sss_result->num_rules; i++) {
-               rule = sss_result->rules + i;
-               if ((pwcheck == any && doauth != false) ||
-                   (pwcheck == all && doauth != true)) {
-                   doauth = !!sudo_sss_check_bool(handle, rule, "authenticate");
-               }
-               if (matched == true)
-                   continue;
-               /* Only check the command when listing another user. */
-               if (user_uid == 0 || list_pw == NULL ||
-                   user_uid == list_pw->pw_uid ||
-                   sudo_sss_check_command(handle, rule, NULL) == true) {
-                   matched = true;
-               }
-           }
-       }
-       if (matched == true || user_uid == 0) {
-           SET(ret, VALIDATE_SUCCESS);
-           CLR(ret, VALIDATE_FAILURE);
-           switch (pwcheck) {
-               case always:
-                   SET(ret, FLAG_CHECK_USER);
-                   break;
-               case all:
-               case any:
-                   if (doauth == false)
-                       SET(ret, FLAG_NOPASSWD);
-                   else
-                       CLR(ret, FLAG_NOPASSWD);
-                   break;
-               default:
-                   break;
-           }
-       }
-       goto done;
-    }
-
-    sudo_debug_printf(SUDO_DEBUG_DIAG,
-       "searching SSSD/LDAP for sudoers entries");
-
-    setenv_implied = false;
-    if (sss_result != NULL) {
-       for (i = 0; i < sss_result->num_rules; i++) {
-           rule = sss_result->rules + i;
-           if (!sudo_sss_check_runas(handle, rule))
-               continue;
-           rc = sudo_sss_check_command(handle, rule, &setenv_implied);
-           if (rc != UNSPEC) {
-               /* We have a match. */
-               sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
-                   rc == true ? "" : "NOT ");
-               if (rc == true) {
-                   sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
-                   /* Apply entry-specific options. */
-                   if (setenv_implied)
-                       def_setenv = true;
-                   if (sudo_sss_parse_options(handle, rule)) {
-#ifdef HAVE_SELINUX
-                       /* Set role/type if not specified on command line. */
-                       if (user_role == NULL)
-                           user_role = def_role;
-                       if (user_type == NULL)
-                           user_type = def_type;
-#endif /* HAVE_SELINUX */
-                       SET(ret, VALIDATE_SUCCESS);
-                       CLR(ret, VALIDATE_FAILURE);
-                   } else {
-                       SET(ret, VALIDATE_ERROR);
-                   }
-               } else {
-                   SET(ret, VALIDATE_FAILURE);
-                   CLR(ret, VALIDATE_SUCCESS);
-               }
-               break;
-           }
-       }
-    }
-done:
-    handle->fn_free_result(sss_result);
-
-    sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
-
-    if (!ISSET(ret, VALIDATE_SUCCESS)) {
-       /* No matching entries. */
-       if (pwflag && list_pw == NULL)
-           SET(ret, FLAG_NO_CHECK);
-    }
-
-    if (pwflag || ISSET(state, SUDO_SSS_STATE_USERMATCH))
-       CLR(ret, FLAG_NO_USER);
-    if (pwflag || ISSET(state, SUDO_SSS_STATE_HOSTMATCH))
-       CLR(ret, FLAG_NO_HOST);
-
-    sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
-       pwflag, ret);
-
-    debug_return_int(ret);
-}
-
-static int
-sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
-{
-    struct sudo_sss_handle *handle = nss->handle;
-    struct sss_sudo_result *sss_result = NULL;
-    struct sss_sudo_rule *rule;
-    unsigned int i;
-    bool found = false;
-    debug_decl(sudo_sss_display_cmnd, SUDOERS_DEBUG_SSSD);
-
-    if (handle == NULL)
-       debug_return_int(-1);
-    if (sudo_sss_checkpw(nss, pw) != 0)
-       debug_return_int(-1);
-
-    /*
-     * The sudo_sss_result_get() function returns all nodes that match
-     * the user and the host.
-     */
-    sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
-    sss_result = sudo_sss_result_get(nss, pw, NULL);
-
-    if (sss_result == NULL)
-       goto done;
-
-    for (i = 0; i < sss_result->num_rules; i++) {
-       rule = sss_result->rules + i;
-       if (!sudo_sss_check_runas(handle, rule))
-           continue;
-       if (sudo_sss_check_command(handle, rule, NULL) == true) {
-           found = true;
-           goto done;
-       }
-    }
-
-done:
-    if (found)
-       sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
-           safe_cmnd ? safe_cmnd : user_cmnd,
-           user_args ? " " : "", user_args ? user_args : "");
-
-    handle->fn_free_result(sss_result);
-
-    debug_return_int(!found);
-}
-
-static int
-sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    struct sudo_sss_handle *handle = nss->handle;
-    struct sss_sudo_rule *rule;
-    struct sss_sudo_result *sss_result = NULL;
-    uint32_t sss_error = 0;
-    char *prefix, **val_array = NULL;
-    unsigned int i, j;
-    int count = 0;
-    debug_decl(sudo_sss_display_defaults, SUDOERS_DEBUG_SSSD);
-
-    if (handle == NULL)
-       goto done;
-
-    if (handle->fn_send_recv_defaults(pw->pw_uid, pw->pw_name,
-                                   &sss_error, &handle->domainname,
-                                   &sss_result) != 0) {
-       sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_send_recv_defaults: !=0, sss_error=%u", sss_error);
-       goto done;
-    }
-
-    if (sss_error == ENOENT) {
-       sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
-       goto done;
-    } else if(sss_error != 0) {
-       sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
-       goto done;
-    }
-
-    handle->pw = pw;
-
-    for (i = 0; i < sss_result->num_rules; ++i) {
-       rule = sss_result->rules + i;
-
-       switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
-       case 0:
-           break;
-       case ENOENT:
-           sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-           continue;
-       default:
-           sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
-           continue;
-       }
-
-       if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
-           prefix = "    ";
-       else
-           prefix = ", ";
-
-       for (j = 0; val_array[j] != NULL; ++j) {
-           struct defaults d;
-
-           sudo_lbuf_append(lbuf, "%s", prefix);
-           d.op = sudo_ldap_parse_option(val_array[j], &d.var, &d.val);
-           sudoers_format_default(lbuf, &d);
-           prefix = ", ";
-           count++;
-       }
-
-       handle->fn_free_values(val_array);
-       val_array = NULL;
-    }
-
-    handle->fn_free_result(sss_result);
-done:
-    if (sudo_lbuf_error(lbuf))
-       debug_return_int(-1);
-    debug_return_int(count);
-}
-
-// ok
-static int
-sudo_sss_display_bound_defaults(struct sudo_nss *nss,
-    struct passwd *pw, struct sudo_lbuf *lbuf)
-{
-    debug_decl(sudo_sss_display_bound_defaults, SUDOERS_DEBUG_SSSD);
-    debug_return_int(0);
-}
-
 static char *
 val_array_iter(void **vp)
 {
@@ -1417,19 +887,14 @@ val_array_iter(void **vp)
     return *val_array;
 }
 
-static struct userspec_list *
-sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_result)
+static bool
+sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_result, struct userspec_list *sss_userspecs)
 {
-    struct userspec_list *sss_userspecs;
     struct userspec *us;
     struct member *m;
     unsigned int i;
     debug_decl(sss_to_sudoers, SUDOERS_DEBUG_SSSD)
 
-    if ((sss_userspecs = calloc(1, sizeof(*sss_userspecs))) == NULL)
-       goto oom;
-    TAILQ_INIT(sss_userspecs);
-
     /* We only have a single userspec */
     if ((us = calloc(1, sizeof(*us))) == NULL)
        goto oom;
@@ -1439,6 +904,7 @@ sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_resul
     TAILQ_INSERT_TAIL(sss_userspecs, us, entries);
 
     /* The user has already matched, use ALL as wildcard. */
+    /* XXX - remove filtering and include sudoUser and host in userspec */
     if ((m = calloc(1, sizeof(*m))) == NULL)
        goto oom;
     m->type = ALL;
@@ -1501,64 +967,14 @@ sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_resul
        TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
     }
 
-    debug_return_ptr(sss_userspecs);
+    debug_return_bool(true);
 
 oom:
     sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-    if (sss_userspecs != NULL) {
-       while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
-           TAILQ_REMOVE(sss_userspecs, us, entries);
-           free_userspec(us);
-       }
-       free(sss_userspecs);
-    }
-    debug_return_ptr(NULL);
-}
-
-static int
-sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
-    struct sudo_lbuf *lbuf)
-{
-    struct sudo_sss_handle *handle = nss->handle;
-    struct userspec_list *sss_userspecs = NULL;
-    struct sss_sudo_result *sss_result = NULL;
-    int ret = 0;
-    debug_decl(sudo_sss_display_privs, SUDOERS_DEBUG_SSSD);
-
-    if (handle == NULL)
-       debug_return_int(-1);
-    if (sudo_sss_checkpw(nss, pw) != 0)
-       debug_return_int(-1);
-
-    sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
-
-    sss_result = sudo_sss_result_get(nss, pw, NULL);
-
-    if (sss_result == NULL)
-       debug_return_int(ret);
-
-    /* Convert to sudoers parse tree. */
-    if ((sss_userspecs = sss_to_sudoers(handle, sss_result)) == NULL) {
-       ret = -1;
-       goto done;
-    }
-
-    /* Call common display code. */
-    ret = sudo_display_userspecs(sss_userspecs, pw, lbuf);
-
-done:
-    /* Cleanup */
-    handle->fn_free_result(sss_result);
-    if (sss_userspecs != NULL) {
-       struct userspec *us;
-       while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
-           TAILQ_REMOVE(sss_userspecs, us, entries);
-           free_userspec(us);
-       }
-       free(sss_userspecs);
+    while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
+       TAILQ_REMOVE(sss_userspecs, us, entries);
+       free_userspec(us);
     }
-    if (sudo_lbuf_error(lbuf))
-       debug_return_int(-1);
-    debug_return_int(ret);
+    debug_return_bool(false);
 }
 #endif /* HAVE_SSSD */
index aa4a2bde672f0d5365f365e12fc9d91d1b13f0ce..38639341e8ceb34c66173182069f38441122eb84 100644 (file)
@@ -20,8 +20,9 @@
 /* Iterators used by sudo_ldap_role_to_priv() to handle bervar ** or char ** */
 typedef char * (*sudo_ldap_iter_t)(void **);
 
-/* ldap_common.c */
+/* ldap_util.c */
 bool sudo_ldap_is_negated(char **valp);
+bool sudo_ldap_add_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
 int sudo_ldap_parse_option(char *optstr, char **varp, char **valp);
 struct privilege *sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, bool warnings, bool store_options, sudo_ldap_iter_t iter);
 struct sudo_digest *sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest);
index 355d12ca8a13e0bc2203121ab47618e181b86b4e..426434cb8b2236378bee3b13fdc3a9c33c38e10d 100644 (file)
@@ -43,6 +43,18 @@ extern struct sudo_nss sudo_nss_ldap;
 extern struct sudo_nss sudo_nss_sss;
 #endif
 
+static void
+sudo_nss_insert(struct sudo_nss_list *snl, struct sudo_nss *nss)
+{
+    debug_decl(sudo_nss_insert, SUDOERS_DEBUG_NSS)
+
+    TAILQ_INIT(&nss->userspecs);
+    TAILQ_INIT(&nss->defaults);
+    TAILQ_INSERT_TAIL(snl, nss, entries);
+
+    debug_return;
+}
+
 /* Make sure we have not already inserted the nss entry. */
 #define SUDO_NSS_CHECK_UNUSED(nss, tag)                                               \
     if (nss.entries.tqe_next != NULL || nss.entries.tqe_prev != NULL) {      \
@@ -91,18 +103,18 @@ sudo_read_nss(void)
        for ((cp = strtok_r(line + 8, " \t", &last)); cp != NULL; (cp = strtok_r(NULL, " \t", &last))) {
            if (strcasecmp(cp, "files") == 0 && !saw_files) {
                SUDO_NSS_CHECK_UNUSED(sudo_nss_file, "files");
-               TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+               sudo_nss_insert(&snl, &sudo_nss_file);
                got_match = saw_files = true;
 #ifdef HAVE_LDAP
            } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
                SUDO_NSS_CHECK_UNUSED(sudo_nss_ldap, "ldap");
-               TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
+               sudo_nss_insert(&snl, &sudo_nss_ldap);
                got_match = saw_ldap = true;
 #endif
 #ifdef HAVE_SSSD
            } else if (strcasecmp(cp, "sss") == 0 && !saw_sss) {
                SUDO_NSS_CHECK_UNUSED(sudo_nss_sss, "sss");
-               TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
+               sudo_nss_insert(&snl, &sudo_nss_sss);
                got_match = saw_sss = true;
 #endif
            } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
@@ -125,7 +137,7 @@ sudo_read_nss(void)
 nomatch:
     /* Default to files only if no matches */
     if (TAILQ_EMPTY(&snl))
-       TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+       sudo_nss_insert(&snl, &sudo_nss_file);
 
     debug_return_ptr(&snl);
 }
@@ -178,20 +190,20 @@ sudo_read_nss(void)
 
            if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
                (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
-               TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+               sudo_nss_insert(&snl, &sudo_nss_file);
                got_match = saw_files = true;
                ep = &cp[5];
 #ifdef HAVE_LDAP
            } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
                (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
-               TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
+               sudo_nss_insert(&snl, &sudo_nss_ldap);
                got_match = saw_ldap = true;
                ep = &cp[4];
 #endif
 #ifdef HAVE_SSSD
            } else if (!saw_sss && strncasecmp(cp, "sss", 3) == 0 &&
                (isspace((unsigned char)cp[3]) || cp[3] == '\0')) {
-               TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
+               sudo_nss_insert(&snl, &sudo_nss_sss);
                got_match = saw_sss = true;
                ep = &cp[3];
 #endif
@@ -218,7 +230,7 @@ sudo_read_nss(void)
 nomatch:
     /* Default to files only if no matches */
     if (TAILQ_EMPTY(&snl))
-       TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+       sudo_nss_insert(&snl, &sudo_nss_file);
 
     debug_return_ptr(&snl);
 }
@@ -235,12 +247,12 @@ sudo_read_nss(void)
     debug_decl(sudo_read_nss, SUDOERS_DEBUG_NSS)
 
 #  ifdef HAVE_SSSD
-    TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
+    sudo_nss_insert(&snl, &sudo_nss_sss);
 #  endif
 #  ifdef HAVE_LDAP
-    TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
+    sudo_nss_insert(&snl, &sudo_nss_ldap);
 #  endif
-    TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+    sudo_nss_insert(&snl, &sudo_nss_file);
 
     debug_return_ptr(&snl);
 }
@@ -249,132 +261,18 @@ sudo_read_nss(void)
 
 #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
 
-static int
-output(const char *buf)
+bool
+sudo_nss_can_continue(struct sudo_nss *nss, int match)
 {
-    struct sudo_conv_message msg;
-    struct sudo_conv_reply repl;
-    debug_decl(output, SUDOERS_DEBUG_NSS)
-
-    /* Call conversation function */
-    memset(&msg, 0, sizeof(msg));
-    msg.msg_type = SUDO_CONV_INFO_MSG;
-    msg.msg = buf;
-    memset(&repl, 0, sizeof(repl));
-    if (sudo_conv(1, &msg, &repl, NULL) == -1)
-       debug_return_int(0);
-    debug_return_int(strlen(buf));
-}
-
-/*
- * Print out privileges for the specified user.
- * Returns true on success or -1 on error.
- */
-int
-display_privs(struct sudo_nss_list *snl, struct passwd *pw)
-{
-    struct sudo_nss *nss;
-    struct sudo_lbuf defs, privs;
-    struct stat sb;
-    int cols, count, olen;
-    debug_decl(display_privs, SUDOERS_DEBUG_NSS)
-
-    cols = sudo_user.cols;
-    if (fstat(STDOUT_FILENO, &sb) == 0 && S_ISFIFO(sb.st_mode))
-       cols = 0;
-    sudo_lbuf_init(&defs, output, 4, NULL, cols);
-    sudo_lbuf_init(&privs, output, 8, NULL, cols);
-
-    /* Display defaults from all sources. */
-    sudo_lbuf_append(&defs, _("Matching Defaults entries for %s on %s:\n"),
-       pw->pw_name, user_srunhost);
-    count = 0;
-    TAILQ_FOREACH(nss, snl, entries) {
-       const int n = nss->display_defaults(nss, pw, &defs);
-       if (n == -1)
-           goto bad;
-       count += n;
-    }
-    if (count) {
-       sudo_lbuf_append(&defs, "\n\n");
-    } else {
-       /* Undo Defaults header. */
-       defs.len = 0;
-    }
-
-    /* Display Runas and Cmnd-specific defaults from all sources. */
-    olen = defs.len;
-    sudo_lbuf_append(&defs, _("Runas and Command-specific defaults for %s:\n"),
-       pw->pw_name);
-    count = 0;
-    TAILQ_FOREACH(nss, snl, entries) {
-       const int n = nss->display_bound_defaults(nss, pw, &defs);
-       if (n == -1)
-           goto bad;
-       count += n;
-    }
-    if (count) {
-       sudo_lbuf_append(&defs, "\n\n");
-    } else {
-       /* Undo Defaults header. */
-       defs.len = olen;
-    }
+    debug_decl(sudo_nss_should_continue, SUDOERS_DEBUG_NSS)
 
-    /* Display privileges from all sources. */
-    sudo_lbuf_append(&privs,
-       _("User %s may run the following commands on %s:\n"),
-       pw->pw_name, user_srunhost);
-    count = 0;
-    TAILQ_FOREACH(nss, snl, entries) {
-       const int n = nss->display_privs(nss, pw, &privs);
-       if (n == -1)
-           goto bad;
-       count += n;
-    }
-    if (count == 0) {
-       defs.len = 0;
-       privs.len = 0;
-       sudo_lbuf_append(&privs,
-           _("User %s is not allowed to run sudo on %s.\n"),
-           pw->pw_name, user_shost);
-    }
-    if (sudo_lbuf_error(&defs) || sudo_lbuf_error(&privs))
-       goto bad;
+    /* Handle [NOTFOUND=return] */
+    if (nss->ret_if_notfound && match == UNSPEC)
+       debug_return_bool(false);
 
-    sudo_lbuf_print(&defs);
-    sudo_lbuf_print(&privs);
+    /* Handle [SUCCESS=return] */
+    if (nss->ret_if_found && match != UNSPEC)
+       debug_return_bool(false);
 
-    sudo_lbuf_destroy(&defs);
-    sudo_lbuf_destroy(&privs);
-
-    debug_return_int(true);
-bad:
-    sudo_lbuf_destroy(&defs);
-    sudo_lbuf_destroy(&privs);
-
-    debug_return_int(-1);
-}
-
-/*
- * Check user_cmnd against sudoers and print the matching entry if the
- * command is allowed.
- * Returns true if the command is allowed, false if not or -1 on error.
- */
-int
-display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
-{
-    struct sudo_nss *nss;
-    debug_decl(display_cmnd, SUDOERS_DEBUG_NSS)
-
-    /* XXX - display_cmnd return value is backwards */
-    /* XXX - doesn't handle commands allowed by one backend denied by another. */
-    TAILQ_FOREACH(nss, snl, entries) {
-       switch (nss->display_cmnd(nss, pw)) {
-           case 0:
-               debug_return_int(true);
-           case -1:
-               debug_return_int(-1);
-       }
-    }
-    debug_return_int(false);
+    debug_return_bool(true);
 }
index 8569c9ba6d1f109d2cff434d1243ee328f068628..20909f57717c205d7f80bd2852b8ab296a4b6b97 100644 (file)
@@ -25,19 +25,18 @@ struct sudo_nss {
     int (*open)(struct sudo_nss *nss);
     int (*close)(struct sudo_nss *nss);
     int (*parse)(struct sudo_nss *nss);
-    int (*setdefs)(struct sudo_nss *nss);
-    int (*lookup)(struct sudo_nss *nss, int, int);
-    int (*display_cmnd)(struct sudo_nss *nss, struct passwd *);
-    int (*display_defaults)(struct sudo_nss *nss, struct passwd *, struct sudo_lbuf *);
-    int (*display_bound_defaults)(struct sudo_nss *nss, struct passwd *, struct sudo_lbuf *);
-    int (*display_privs)(struct sudo_nss *nss, struct passwd *, struct sudo_lbuf *);
+    int (*query)(struct sudo_nss *nss, struct passwd *pw);
+    int (*getdefs)(struct sudo_nss *nss);
     void *handle;
-    short ret_if_found;
-    short ret_if_notfound;
+    bool ret_if_found;
+    bool ret_if_notfound;
+    struct defaults_list defaults;
+    struct userspec_list userspecs;
 };
 
 TAILQ_HEAD(sudo_nss_list, sudo_nss);
 
 struct sudo_nss_list *sudo_read_nss(void);
+bool sudo_nss_can_continue(struct sudo_nss *nss, int match);
 
 #endif /* SUDOERS_NSS_H */
index 16ef7e1ae0fdca5dfcbb556363929522ae3f7a75..29ce411f5ad46128ebd57a9326a6729db4678ae4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996, 1998-2017 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 1993-1996, 1998-2018 Todd C. Miller <Todd.Miller@sudo.ws>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -59,6 +59,7 @@
 #include <ctype.h>
 
 #include "sudoers.h"
+#include "parse.h"
 #include "auth/sudo_auth.h"
 
 #ifndef HAVE_GETADDRINFO
@@ -189,11 +190,13 @@ sudoers_policy_init(void *info, char * const envp[])
      */
     sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
     sudo_warn_set_locale_func(sudoers_warn_setlocale);
+    init_parser(sudoers_file, false);
     TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
         if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
             sources++;
-            if (nss->setdefs(nss) != 0) {
-                log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
+           if (nss->getdefs(nss) != 0 || !update_defaults(&nss->defaults,
+               SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
+               log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
                    N_("problem with defaults entries"));
            }
         } else {
@@ -228,7 +231,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
     char *iolog_path = NULL;
     mode_t cmnd_umask = ACCESSPERMS;
     struct sudo_nss *nss;
-    int nopass = -1;
     int cmnd_status = -1, oldlocale, validated;
     int ret = -1;
     debug_decl(sudoers_policy_main, SUDOERS_DEBUG_PLUGIN)
@@ -307,54 +309,12 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
      * Check sudoers sources, using the locale specified in sudoers.
      */
     sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
-    validated = FLAG_NO_USER | FLAG_NO_HOST;
-    TAILQ_FOREACH(nss, snl, entries) {
-       validated = nss->lookup(nss, validated, pwflag);
-
-       /*
-        * The NOPASSWD tag needs special handling among all sources
-        * in -l or -v mode.
-        */
-       if (pwflag) {
-           enum def_tuple pwcheck =
-               (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-           switch (pwcheck) {
-           case all:
-               if (!ISSET(validated, FLAG_NOPASSWD))
-                   nopass = false;
-               else if (nopass == -1)
-                   nopass = true;
-               break;
-           case any:
-               if (ISSET(validated, FLAG_NOPASSWD))
-                   nopass = true;
-               break;
-           case never:
-               nopass = true;
-               break;
-           case always:
-               nopass = false;
-               break;
-           default:
-               break;
-           }
-       }
-
-       if (ISSET(validated, VALIDATE_ERROR)) {
-           /* The lookup function should have printed an error. */
-           goto done;
-       } else if (ISSET(validated, VALIDATE_SUCCESS)) {
-           /* Handle [SUCCESS=return] */
-           if (nss->ret_if_found)
-               break;
-       } else {
-           /* Handle [NOTFOUND=return] */
-           if (nss->ret_if_notfound)
-               break;
-       }
+    validated = sudoers_lookup(snl, sudo_user.pw, FLAG_NO_USER | FLAG_NO_HOST,
+       pwflag);
+    if (ISSET(validated, VALIDATE_ERROR)) {
+       /* The lookup function should have printed an error. */
+       goto done;
     }
-    if (pwflag && nopass == true)
-       def_authenticate = false;
 
     /* Restore user's locale. */
     sudoers_setlocale(oldlocale, NULL);
@@ -546,6 +506,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
     }
     if (def_group_plugin)
        group_plugin_unload();
+    init_parser(NULL, false);
 
     if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
        /* ret already set appropriately */
@@ -801,8 +762,9 @@ init_vars(char * const envp[])
 static int
 set_cmnd(void)
 {
-    int ret = FOUND;
+    struct sudo_nss *nss;
     char *path = user_path;
+    int ret = FOUND;
     debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN)
 
     /* Allocate user_stat for find_path() and match functions. */
@@ -890,9 +852,11 @@ set_cmnd(void)
     else
        user_base = user_cmnd;
 
-    if (!update_defaults(SETDEF_CMND, false)) {
-       log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
-           N_("problem with defaults entries"));
+    TAILQ_FOREACH(nss, snl, entries) {
+       if (!update_defaults(&nss->defaults, SETDEF_CMND, false)) {
+           log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
+               N_("problem with defaults entries"));
+       }
     }
 
     debug_return_int(ret);
index e0f3a39591176c4db0e6d300e7a77927ba6912ee..7b6f74fb6a5a031c6a433c89036a0e19ca16f6d3 100644 (file)
@@ -137,7 +137,6 @@ struct sudo_user {
 #define FLAG_NO_CHECK          0x080
 #define FLAG_NON_INTERACTIVE   0x100
 #define FLAG_BAD_PASSWORD      0x200
-#define FLAG_NOPASSWD          0x400
 
 /*
  * find_path()/set_cmnd() return values
@@ -300,10 +299,6 @@ void dump_auth_methods(void);
 /* getspwuid.c */
 char *sudo_getepw(const struct passwd *);
 
-/* sudo_nss.c */
-int display_privs(struct sudo_nss_list *, struct passwd *);
-int display_cmnd(struct sudo_nss_list *, struct passwd *);
-
 /* pwutil.c */
 typedef struct cache_item * (*sudo_make_pwitem_t)(uid_t uid, const char *user);
 typedef struct cache_item * (*sudo_make_gritem_t)(gid_t gid, const char *group);
index 7f54691492bc73dacc44196fed87d1a88f8761d0..556f4ae69693c1626332705dc11e69583768e855 100644 (file)
@@ -285,7 +285,7 @@ main(int argc, char *argv[])
        (void) fputs("Parses OK", stdout);
     }
 
-    if (!update_defaults(SETDEF_ALL, false))
+    if (!update_defaults(&defaults, SETDEF_ALL, false))
        (void) fputs(" (problem with defaults entries)", stdout);
     puts(".");
 
index a9963e7270d92983e180949e1282eb3f272e3943..dd9c03d670b0c821b338e4d7d501f59e748780fa 100644 (file)
@@ -246,7 +246,8 @@ main(int argc, char *argv[])
     init_parser(sudoers_file, quiet);
     sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
     (void) sudoersparse();
-    (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, quiet);
+    (void) update_defaults(&defaults, SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER,
+       quiet);
     sudoers_setlocale(oldlocale, NULL);
 
     editor = get_editor(&editor_argc, &editor_argv);
@@ -601,7 +602,8 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv,
        }
        fclose(sudoersin);
        if (!parse_error) {
-           (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true);
+           (void) update_defaults(&defaults,
+               SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true);
            check_defaults_and_aliases(strict, quiet);
        }
        sudoers_setlocale(oldlocale, NULL);
@@ -918,7 +920,8 @@ check_syntax(const char *sudoers_file, bool quiet, bool strict, bool oldperms)
            sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
     }
     if (!parse_error) {
-       (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true);
+       (void) update_defaults(&defaults,
+           SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true);
        check_defaults_and_aliases(strict, quiet);
     }
     sudoers_setlocale(oldlocale, NULL);