Blob Blame History Raw
diff -up sudo-1.8.5/configure.in.sssd-support sudo-1.8.5/configure.in
--- sudo-1.8.5/configure.in.sssd-support	2012-05-17 10:30:40.796975447 +0200
+++ sudo-1.8.5/configure.in	2012-05-17 10:30:40.813975145 +0200
@@ -284,6 +284,22 @@ AC_ARG_WITH(linux-audit, [AS_HELP_STRING
 		;;
 esac])
 
+dnl
+dnl Handle SSSD support.
+dnl
+AC_ARG_WITH(sssd, [AS_HELP_STRING([--with-sssd], [enable SSSD support])],
+[case $with_sssd in
+    yes)
+		SUDO_LIBS="${SUDO_LIBS} `pkg-config libsss_sudo --libs`"
+		SUDOERS_LIBS="${SUDO_LIBS} `pkg-config libsss_sudo --libs`"
+		SUDOERS_OBJS="${SUDOERS_OBJS} sssd.lo"
+		AC_DEFINE(HAVE_SSSD)
+		;;
+    no)		;;
+    *)		AC_MSG_ERROR(["--with-sssd does not take an argument."])
+		;;
+esac])
+
 AC_ARG_WITH(incpath, [AS_HELP_STRING([--with-incpath], [additional places to look for include files])],
 [case $with_incpath in
     yes)	AC_MSG_ERROR(["must give --with-incpath an argument."])
@@ -3331,6 +3347,7 @@ AH_TEMPLATE(HAVE_LBER_H, [Define to 1 if
 AH_TEMPLATE(HAVE_LDAP, [Define to 1 if you use LDAP for sudoers.])
 AH_TEMPLATE(HAVE_LIBINTL_H, [Define to 1 if you have the <libintl.h> header file.])
 AH_TEMPLATE(HAVE_LINUX_AUDIT, [Define to 1 to enable Linux audit support.])
+AH_TEMPLATE(HAVE_SSSD, [Define to 1 to enable SSSD support.])
 AH_TEMPLATE(HAVE_OPIE, [Define to 1 if you use NRL OPIE.])
 AH_TEMPLATE(HAVE_PAM, [Define to 1 if you use PAM authentication.])
 AH_TEMPLATE(HAVE_PAM_LOGIN, [Define to 1 if you use a specific PAM session for sudo -i.])
diff -up sudo-1.8.5/plugins/sudoers/Makefile.in.sssd-support sudo-1.8.5/plugins/sudoers/Makefile.in
--- sudo-1.8.5/plugins/sudoers/Makefile.in.sssd-support	2012-05-15 18:22:02.000000000 +0200
+++ sudo-1.8.5/plugins/sudoers/Makefile.in	2012-05-17 10:30:40.815975110 +0200
@@ -574,6 +574,10 @@ linux_audit.lo: $(srcdir)/linux_audit.c
                 $(incdir)/gettext.h $(incdir)/sudo_debug.h \
                 $(srcdir)/linux_audit.h
 	$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/linux_audit.c
+sssd.lo: $(srcdir)/sssd.c $(top_builddir)/config.h \
+         $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \
+         $(incdir)/gettext.h
+	$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sssd.c
 logging.lo: $(srcdir)/logging.c $(top_builddir)/config.h $(srcdir)/sudoers.h \
             $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \
             $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \
diff -up sudo-1.8.5/plugins/sudoers/sssd.c.sssd-support sudo-1.8.5/plugins/sudoers/sssd.c
--- sudo-1.8.5/plugins/sudoers/sssd.c.sssd-support	2012-05-17 10:30:40.817975074 +0200
+++ sudo-1.8.5/plugins/sudoers/sssd.c	2012-05-17 10:58:10.775036464 +0200
@@ -0,0 +1,1194 @@
+/*
+ * Copyright (c) 2003-2011 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2011 Daniel Kopecek <dkopecek@redhat.com>
+ *
+ * This code is derived from software contributed by Aaron Spangler.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <sss_sudo.h>
+#include <errno.h>
+
+#include "sudoers.h"
+#include "parse.h"
+#include "lbuf.h"
+#include "sudo_debug.h"
+
+extern int debug_level;
+#define __sssd_debug debug_level
+
+#define	DPRINTF(level, fmt, ...) if (__sssd_debug >= (level)) warningx("%s:%d: "fmt, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
+
+/* sudo_nss implementation */
+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 void sudo_sss_parse_options(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 lbuf *lbuf);
+
+static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
+					    struct passwd *pw, struct lbuf *lbuf);
+
+static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
+				   struct lbuf *lbuf);
+
+
+static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
+					       struct passwd *pw,
+					       uint32_t *state);
+
+static void sudo_sss_attrcpy(struct sss_sudo_attr *dst, const struct sss_sudo_attr *src)
+{
+     int i;
+     debug_decl(sudo_sss_attrcpy, SUDO_DEBUG_LDAP)
+
+     DPRINTF(3, "dst=%p, src=%p", dst, src);
+     DPRINTF(2, "emalloc: cnt=%d", src->num_values);
+
+     dst->name = strdup(src->name);
+     dst->num_values = src->num_values;
+     dst->values = emalloc(sizeof(char *) * dst->num_values);
+
+     for (i = 0; i < dst->num_values; ++i)
+	  dst->values[i] = strdup(src->values[i]);
+
+     debug_return;
+}
+
+static void sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
+{
+     int i;
+     debug_decl(sudo_sss_rulecpy, SUDO_DEBUG_LDAP)
+     
+     DPRINTF(3, "dst=%p, src=%p", dst, src);
+     DPRINTF(2, "emalloc: cnt=%d", src->num_attrs);
+
+     dst->num_attrs = src->num_attrs;
+     dst->attrs = emalloc(sizeof(struct sss_sudo_attr) * dst->num_attrs);
+
+     for (i = 0; i < dst->num_attrs; ++i) {
+	  sudo_sss_attrcpy(dst->attrs + i,
+			    src->attrs + i);
+     }
+
+     debug_return;
+}
+
+#define _SUDO_SSS_FILTER_INCLUDE 0
+#define _SUDO_SSS_FILTER_EXCLUDE 1
+
+#define _SUDO_SSS_STATE_HOSTMATCH 0x01
+#define _SUDO_SSS_STATE_USERMATCH 0x02
+
+static struct sss_sudo_result *sudo_sss_filter_result(struct sss_sudo_result *in_res, int (*filterp)(struct sss_sudo_rule *, void *), int act, void *filterp_arg)
+{
+     struct sss_sudo_result *out_res;
+     int i, l, r;
+     debug_decl(sudo_sss_filter_result, SUDO_DEBUG_LDAP)
+
+     DPRINTF(3, "in_res=%p, count=%u, act=%s",
+	     in_res, in_res->num_rules, act == _SUDO_SSS_FILTER_EXCLUDE ? "EXCLUDE" : "INCLUDE");
+
+     if (in_res == NULL)
+       debug_return_ptr(NULL);
+
+     DPRINTF(3, "emalloc: cnt=%d", in_res->num_rules);
+
+     out_res = emalloc(sizeof(struct sss_sudo_result));
+     out_res->rules = in_res->num_rules > 0 ? emalloc(sizeof(struct sss_sudo_rule) * in_res->num_rules) : NULL;
+     out_res->num_rules = 0;
+
+     for (i = l = 0; i < in_res->num_rules; ++i) {
+	  r = filterp(in_res->rules + i, filterp_arg);
+
+	  if (( r && act == _SUDO_SSS_FILTER_INCLUDE) ||
+	      (!r && act == _SUDO_SSS_FILTER_EXCLUDE))
+	  {
+	       DPRINTF(3, "COPY (%s): %p[%u] => %p[%u] (= %p)",
+		       act == _SUDO_SSS_FILTER_EXCLUDE ? "not excluded" : "included",
+		       in_res->rules, i, out_res->rules, l, in_res->rules + i);
+
+	       sudo_sss_rulecpy(out_res->rules + l, in_res->rules + i);
+	       ++l;
+	  }
+     }
+
+     if (l < in_res->num_rules) {
+	  DPRINTF(3, "reallocating result: %p (count: %u -> %u)", out_res->rules, in_res->num_rules, l);
+	  out_res->rules = realloc(out_res->rules, sizeof(struct sss_sudo_rule) * l);
+     }
+
+     out_res->num_rules = l;
+
+     debug_return_ptr(out_res);
+}
+
+struct sudo_sss_handle {
+     char *domainname;
+     struct passwd *pw;
+};
+
+struct sudo_nss sudo_nss_sss = {
+    &sudo_nss_sss,
+    NULL,
+    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_nss implementation */
+// ok
+static int sudo_sss_open(struct sudo_nss *nss)
+{
+     struct sudo_sss_handle *handle;
+     debug_decl(sudo_sss_open, SUDO_DEBUG_LDAP);
+
+     /* Create a handle container. */
+     handle = emalloc(sizeof(struct sudo_sss_handle));
+     handle->domainname = NULL;
+     handle->pw = sudo_user.pw;
+     nss->handle = handle;
+
+     DPRINTF(3, "handle=%p", handle);
+
+     debug_return_int(0);
+}
+
+// ok
+static int sudo_sss_close(struct sudo_nss *nss)
+{
+     debug_decl(sudo_sss_close, SUDO_DEBUG_LDAP);
+     efree(nss->handle);
+     debug_return_int(0);
+}
+
+// ok
+static int sudo_sss_parse(struct sudo_nss *nss)
+{
+     debug_decl(sudo_sss_parse, SUDO_DEBUG_LDAP);
+     debug_return_int(0);
+}
+
+static int sudo_sss_setdefs(struct sudo_nss *nss)
+{
+     struct sudo_sss_handle *handle = nss->handle;
+
+     struct sss_sudo_result *sss_result;
+     struct sss_sudo_rule   *sss_rule;
+     uint32_t sss_error;
+     int i;
+     debug_decl(sudo_sss_setdefs, SUDO_DEBUG_LDAP);
+
+     if (handle == NULL)
+	  debug_return_int(-1);
+
+     DPRINTF(1, "Looking for cn=defaults");
+
+     if (sss_sudo_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
+				     &sss_error, &handle->domainname,
+				     &sss_result) != 0)
+     {
+	  DPRINTF(2, "sss_sudo_send_recv_defaults: != 0, sss_error=%u", sss_error);
+	  debug_return_int(-1);
+     }
+
+     for (i = 0; i < sss_result->num_rules; ++i) {
+	  DPRINTF(1, "Parsing cn=defaults, %d/%d", i, sss_result->num_rules);
+	  sss_rule = sss_result->rules + i;
+	  sudo_sss_parse_options(sss_rule);
+     }
+
+     sss_sudo_free_result(sss_result);
+     debug_return_int(0);
+}
+
+static int sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
+{
+     struct sudo_sss_handle *handle = nss->handle;
+     debug_decl(sudo_sss_checkpw, SUDO_DEBUG_LDAP);
+
+     if (pw->pw_name != handle->pw->pw_name ||
+	 pw->pw_uid  != handle->pw->pw_uid)
+     {
+	  DPRINTF(1, "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 sss_sudo_rule *sss_rule)
+{
+     char **val_array = NULL;
+     char *val;
+     int ret = false, i;
+     debug_decl(sudo_sss_check_runas_user, SUDO_DEBUG_LDAP);
+
+     if (!runas_pw)
+	  debug_return_int(UNSPEC);
+
+     /* get the runas user from the entry */
+     switch (sss_sudo_get_values(sss_rule, "sudoRunAsUser", &val_array)) 
+     {
+     case 0:
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result. Trying old style (sudoRunAs)");
+
+	  /* try old style */
+	  switch (sss_sudo_get_values(sss_rule, "sudoRunAs", &val_array))
+	  {
+	  case 0:
+	       break;
+	  case ENOENT:
+	       DPRINTF(2, "No result. Matching against runas_default");
+	       /*
+		* If there are no runas entries, match runas_default against
+		* what the user specified on the command line.
+		*/
+	       return !strcasecmp(runas_pw->pw_name, def_runas_default);
+	  default:
+	       DPRINTF(2, "sss_sudo_get_values(sudoRunAs): != 0");
+	       debug_return_int(UNSPEC);
+	  }
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoRunAsUser): != 0");
+	  debug_return_int(UNSPEC);
+     }
+
+     /*
+      * 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];
+
+	  DPRINTF(3, "val[%d]=%s", i, val);
+
+	  switch (val[0]) {
+	  case '+':
+	       DPRINTF(3, "netgr_");
+	       if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) {
+		    DPRINTF(3, "=> match");
+		    ret = true;
+	       }
+	       break;
+	  case '%':
+	       DPRINTF(3, "usergr_");
+	       if (usergr_matches(val, runas_pw->pw_name, runas_pw)) {
+		    DPRINTF(3, "=> match");
+		    ret = true;
+	       }
+	       break;
+	  case 'A':
+	       if (strcmp(val, "ALL") == 0) {
+		    DPRINTF(3, "ALL => match");
+		    ret = true;
+		    break;
+	       }
+	       /* FALLTHROUGH */
+	       DPRINTF(3, "FALLTHROUGH");
+	  default:
+	       if (strcasecmp(val, runas_pw->pw_name) == 0) {
+		    DPRINTF(3, "%s == %s (pw_name) => match", val, runas_pw->pw_name);
+		    ret = true;
+	       }
+	       break;
+	  }
+
+	  DPRINTF(2, "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
+     }
+
+     sss_sudo_free_values(val_array); /* cleanup */
+
+     debug_return_int(ret);
+}
+
+static int
+sudo_sss_check_runas_group(struct sss_sudo_rule *rule)
+{
+     char **val_array = NULL;
+     char *val;
+     int ret = false, i;
+     debug_decl(sudo_sss_check_runas_group, SUDO_DEBUG_LDAP);
+
+     /* runas_gr is only set if the user specified the -g flag */
+     if (!runas_gr)
+	  debug_return_int(UNSPEC);
+
+     /* get the values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoRunAsGroup", &val_array))
+     {
+     case 0:
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  debug_return_int(false);
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoRunAsGroup): != 0");
+	  debug_return_int(UNSPEC);
+     }
+
+     /* walk through values returned, looking for a match */
+     for (i = 0; val_array[i] != NULL; ++i) {
+	  val = val_array[i];
+	  DPRINTF(3, "val[%d]=%s", i, val);
+
+	  if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
+	       ret = true;
+
+	  DPRINTF(2, "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
+     }
+
+     sss_sudo_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 int
+sudo_sss_check_runas(struct sss_sudo_rule *rule)
+{
+    int ret;
+    debug_decl(sudo_sss_check_runas, SUDO_DEBUG_LDAP);
+
+    if (rule == NULL)
+	 debug_return_int(false);
+
+    ret = sudo_sss_check_runas_user(rule) != false &&
+	 sudo_sss_check_runas_group(rule) != false;
+
+    debug_return_int(ret);
+}
+
+static int sudo_sss_check_host(struct sss_sudo_rule *rule)
+{
+    char **val_array, *val;
+    int ret = false, i;
+    debug_decl(sudo_sss_check_host, SUDO_DEBUG_LDAP);
+
+    if (rule == NULL)
+	 debug_return_int(ret);
+
+    /* get the values from the rule */
+    switch (sss_sudo_get_values(rule, "sudoHost", &val_array))
+    {
+    case 0:
+	 break;
+    case ENOENT:
+	 DPRINTF(2, "No result.");
+	 debug_return_int(false);
+    default:
+	 DPRINTF(2, "sss_sudo_get_values(sudoHost): != 0");
+	 debug_return_int(ret);
+    }
+
+    /* walk through values */
+    for (i = 0; val_array[i] != NULL; ++i) {
+	 val = val_array[i];
+	 DPRINTF(3, "val[%d]=%s", i, val);
+
+	 /* match any or address or netgroup or hostname */
+	 if (!strcmp(val, "ALL") || addr_matches(val) ||
+	     netgr_matches(val, user_host, user_shost, NULL) ||
+	     hostname_matches(user_shost, user_host, val))
+	      ret = true;
+
+	 DPRINTF(2, "sssd/ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
+    }
+
+    sss_sudo_free_values(val_array);
+
+    debug_return_int(ret);
+}
+
+static int sudo_sss_result_filterp(struct sss_sudo_rule *rule, void *unused)
+{
+     (void)unused;
+     debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_LDAP);
+
+     if (sudo_sss_check_host(rule))
+	  debug_return_int(1);
+     else
+	  debug_return_int(0);
+}
+
+static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
+{
+     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, SUDO_DEBUG_LDAP);
+
+     if (sudo_sss_checkpw(nss, pw) != 0)
+	  debug_return_ptr(NULL);
+
+     DPRINTF(1, "  username=%s", handle->pw->pw_name);
+     DPRINTF(1, "domainname=%s", handle->domainname);
+
+     u_sss_result = f_sss_result = NULL;
+
+     switch (ret = sss_sudo_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
+				      handle->domainname, &sss_error, &u_sss_result))
+     {
+     case 0:
+	  switch (sss_error) {
+	  case 0:
+	       if (u_sss_result != NULL) {
+		    if (state != NULL) {
+			 DPRINTF(3, "state |= USERMATCH");
+			 *state |= _SUDO_SSS_STATE_USERMATCH;
+		    }
+		    DPRINTF(2, "Received %u rule(s)", u_sss_result->num_rules);
+	       } else {
+		    DPRINTF(2, "Internal error: u_sss_result == NULL && sss_error == 0");
+		    debug_return_ptr(NULL);
+	       }
+	       break;
+	  case ENOENT:
+	       DPRINTF(2, "No result.");
+	  default:
+	       DPRINTF(2, "sss_error=%u\n", sss_error);
+	       debug_return_ptr(NULL);
+	  }
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_send_recv: != 0: ret=%d", ret);
+	  debug_return_ptr(NULL);
+     }
+
+     f_sss_result = sudo_sss_filter_result(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) {
+		    DPRINTF(3, "state |= HOSTMATCH");
+		    *state |= _SUDO_SSS_STATE_HOSTMATCH;
+	       }
+
+     DPRINTF(3, "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);
+
+     sss_sudo_free_result(u_sss_result);
+
+     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 sss_sudo_rule *rule, char *option)
+{
+     char ch, *var, **val_array = NULL;
+     int i, ret = UNSPEC;
+     debug_decl(sudo_sss_check_bool, SUDO_DEBUG_LDAP);
+
+     if (rule == NULL)
+	  debug_return_int(ret);
+
+     switch (sss_sudo_get_values(rule, "sudoOption", &val_array))
+     {
+     case 0:
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  debug_return_int(ret);
+     default:
+	  DPRINTF(2, "sss_sudo_get_values: != 0");
+	  debug_return_int(ret);
+     }
+
+     /* walk through options */
+     for (i = 0; val_array[i] != NULL; ++i) {
+	  var = val_array[i];
+	  DPRINTF(2, "sssd/ldap sudoOption: '%s'", var);
+
+	  if ((ch = *var) == '!')
+	       var++;
+	  if (strcmp(var, option) == 0)
+	       ret = (ch != '!');
+     }
+
+     sss_sudo_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 sss_sudo_rule *rule, int *setenv_implied)
+{
+     char **val_array = NULL, *val;
+     char *allowed_cmnd, *allowed_args;
+     int i, foundbang, ret = UNSPEC;
+     debug_decl(sudo_sss_check_command, SUDO_DEBUG_LDAP);
+
+     if (rule == NULL)
+	  debug_return_int(ret);
+
+     switch (sss_sudo_get_values(rule, "sudoCommand", &val_array))
+     {
+     case 0:
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  debug_return_int(ret);
+     default:
+	  DPRINTF(2, "sss_sudo_get_values: != 0");
+	  debug_return_int(ret);
+     }
+
+     for (i = 0; val_array[i] != NULL && ret != false; ++i) {
+	  val = val_array[i];
+
+	  DPRINTF(3, "val[%d]=%s", i, val);
+
+	  /* Match against ALL ? */
+	  if (!strcmp(val, "ALL")) {
+	       ret = true;
+	       if (setenv_implied != NULL)
+		    *setenv_implied = true;
+	       DPRINTF(2, "sssd/ldap sudoCommand '%s' ... MATCH!", val);
+	       continue;
+	  }
+
+	  /* check for !command */
+	  if (*val == '!') {
+	       foundbang = true;
+	       allowed_cmnd = estrdup(1 + val);	/* !command */
+	  } else {
+	       foundbang = false;
+	       allowed_cmnd = estrdup(val);	/* command */
+	  }
+
+	  /* 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)) {
+	       /*
+		* If allowed (no bang) set ret but keep on checking.
+		* If disallowed (bang), exit loop.
+		*/
+	       ret = foundbang ? false : true;
+	  }
+
+	  DPRINTF(2, "sssd/ldap sudoCommand '%s' ... %s", val, ret == true ? "MATCH!" : "not");
+	  efree(allowed_cmnd);	/* cleanup */
+     }
+
+     sss_sudo_free_values(val_array); /* more cleanup */
+
+     debug_return_int(ret);
+}
+
+static void
+sudo_sss_parse_options(struct sss_sudo_rule *rule)
+{
+     int i;
+     char op, *v, *val;
+     char **val_array = NULL;
+     debug_decl(sudo_sss_parse_options, SUDO_DEBUG_LDAP);
+
+     if (rule == NULL)
+	  debug_return;
+
+     switch (sss_sudo_get_values(rule, "sudoOption", &val_array))
+     {
+     case 0:
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  debug_return;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoOption): != 0");
+	  debug_return;
+     }
+
+     /* walk through options */
+     for (i = 0; val_array[i] != NULL; i++) {
+	  DPRINTF(2, "sssd/ldap sudoOption: '%s'", val_array[i]);
+	  v = estrdup(val_array[i]);
+
+	  /* check for equals sign past first char */
+	  val = strchr(v, '=');
+	  if (val > v) {
+	       *val++ = '\0';	/* split on = and truncate var */
+	       op = *(val - 2);	/* peek for += or -= cases */
+	       if (op == '+' || op == '-') {
+		    *(val - 2) = '\0';	/* found, remove extra char */
+		    /* case var+=val or var-=val */
+		    set_default(v, val, (int) op);
+	       } else {
+		    /* case var=val */
+		    set_default(v, val, true);
+	       }
+	  } else if (*v == '!') {
+	       /* case !var Boolean False */
+	       set_default(v + 1, NULL, false);
+	  } else {
+	       /* case var Boolean True */
+	       set_default(v, NULL, true);
+	  }
+	  efree(v);
+     }
+
+     sss_sudo_free_values(val_array);
+     debug_return;
+}
+
+static int sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
+{
+    int rc, setenv_implied;
+
+    struct sss_sudo_result *sss_result = NULL;
+    struct sss_sudo_rule   *rule;
+    uint32_t i, state = 0;
+    debug_decl(sudo_sss_lookup, SUDO_DEBUG_LDAP);
+
+    /* 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;
+
+	DPRINTF(2, "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 == false)) {
+		       doauth = sudo_sss_check_bool(rule, "authenticate");
+		  }
+		  /* 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(rule, NULL)) {
+		       matched = true;
+		       break;
+		  }
+	     }
+	}
+	if (matched || user_uid == 0) {
+	    SET(ret, VALIDATE_OK);
+	    CLR(ret, VALIDATE_NOT_OK);
+	    if (def_authenticate) {
+		switch (pwcheck) {
+		    case always:
+			SET(ret, FLAG_CHECK_USER);
+			break;
+		    case all:
+		    case any:
+			if (doauth == false)
+			    def_authenticate = false;
+			break;
+		    case never:
+			def_authenticate = false;
+			break;
+		    default:
+			break;
+		}
+	    }
+	}
+	goto done;
+    }
+
+    DPRINTF(1, "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(rule))
+		   continue;
+	      rc = sudo_sss_check_command(rule, &setenv_implied);
+	      if (rc != UNSPEC) {
+		   /* We have a match. */
+		   DPRINTF(1, "Command %sallowed", rc == true ? "" : "NOT ");
+		   if (rc == true) {
+			DPRINTF(3, "SSSD rule: %p", rule);
+			/* Apply entry-specific options. */
+			if (setenv_implied)
+			     def_setenv = true;
+			sudo_sss_parse_options(rule);
+#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_OK);
+			CLR(ret, VALIDATE_NOT_OK);
+		   } else {
+			SET(ret, VALIDATE_NOT_OK);
+			CLR(ret, VALIDATE_OK);
+		   }
+		   break;
+	      }
+	 }
+    }
+done:
+    DPRINTF(1, "Done with LDAP searches");
+
+    if (!ISSET(ret, VALIDATE_OK)) {
+	/* No matching entries. */
+	if (pwflag && list_pw == NULL)
+	    SET(ret, FLAG_NO_CHECK);
+    }
+
+    if (state & _SUDO_SSS_STATE_USERMATCH)
+	 CLR(ret, FLAG_NO_USER);
+    if (state & _SUDO_SSS_STATE_HOSTMATCH)
+	 CLR(ret, FLAG_NO_HOST);
+
+    DPRINTF(3, "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;
+     int i, found = false;
+     debug_decl(sudo_sss_display_cmnd, SUDO_DEBUG_LDAP);
+
+     if (handle == NULL)
+	  goto done;
+
+     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.
+      */
+     DPRINTF(1, "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_command(rule, NULL) &&
+	      sudo_sss_check_runas(rule)) {
+	       found = true;
+	       goto done;
+	  }
+     }
+
+done:
+     if (found)
+	  printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
+		 user_args ? " " : "", user_args ? user_args : "");
+
+     if (sss_result != NULL)
+	  sss_sudo_free_result(sss_result);
+
+     debug_return_int(!found);
+}
+
+static int sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
+				      struct 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, **val_array = NULL;
+     int count = 0, i, j;
+
+     debug_decl(sudo_sss_display_defaults, SUDO_DEBUG_LDAP);
+
+     if (handle == NULL)
+	  goto done;
+
+     if (sss_sudo_send_recv_defaults(pw->pw_uid, pw->pw_name,
+				     &sss_error, &handle->domainname,
+				     &sss_result) != 0)
+     {
+	  DPRINTF(2, "sss_sudo_send_recv_defaults: !=0, sss_error=%u", sss_error);
+	  goto done;
+     }
+
+     handle->pw = pw;
+
+     for (i = 0; i < sss_result->num_rules; ++i) {
+	  rule = sss_result->rules + i;
+
+	  switch (sss_sudo_get_values(rule, "sudoOption", &val_array))
+	  {
+	  case 0:
+	       break;
+	  case ENOENT:
+	       DPRINTF(2, "No result.");
+	       continue;
+	  default:
+	       DPRINTF(2, "sss_sudo_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) {
+	       val = val_array[j];
+	       lbuf_append(lbuf, "%s%s", prefix, val);
+	       prefix = ", ";
+	       count++;
+	  }
+	  
+	  sss_sudo_free_values(val_array);
+	  val_array = NULL;
+     }
+
+     sss_sudo_free_result(sss_result);
+done:
+     debug_return_int(count);
+}
+
+// ok
+static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
+					    struct passwd *pw, struct lbuf *lbuf)
+{
+     debug_decl(sudo_sss_display_bound_defaults, SUDO_DEBUG_LDAP);
+     debug_return_int(0);
+}
+
+static int sudo_sss_display_entry_long(struct sss_sudo_rule *rule, struct lbuf *lbuf)
+{
+     char **val_array = NULL;
+     int count = 0, i;
+     debug_decl(sudo_sss_display_entry_long, SUDO_DEBUG_LDAP);
+
+     /* get the RunAsUser Values from the entry */
+     lbuf_append(lbuf, "    RunAsUsers: ");
+     switch (sss_sudo_get_values(rule, "sudoRunAsUser", &val_array))
+     {
+     case 0:
+	  for (i = 0; val_array[i] != NULL; ++i)
+	       lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	  sss_sudo_free_values(val_array);
+	  break;
+     case ENOENT:
+	  switch (sss_sudo_get_values(rule, "sudoRunAs", &val_array))
+	  {
+	  case 0:
+	       for (i = 0; val_array[i] != NULL; ++i)
+		    lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	       sss_sudo_free_values(val_array);
+	       break;
+	  case ENOENT:
+	       DPRINTF(2, "No result.");
+	       lbuf_append(lbuf, "%s", def_runas_default);
+	       break;
+	  default:
+	       DPRINTF(2, "sss_sudo_get_values(sudoRunAs): != 0");
+	       debug_return_int(count);
+	  }
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoRunAsUser): != 0");
+	  debug_return_int(count);
+     }
+     lbuf_append(lbuf, "\n");
+
+     /* get the RunAsGroup Values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoRunAsGroup", &val_array))
+     {
+     case 0:
+	  lbuf_append(lbuf, "    RunAsGroups: ");
+	  for (i = 0; val_array[i] != NULL; ++i)
+	       lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	  sss_sudo_free_values(val_array);
+	  lbuf_append(lbuf, "\n");
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoRunAsGroup): != 0");
+	  debug_return_int(count);
+     }
+
+     /* get the Option Values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoOption", &val_array))
+     {
+     case 0:
+	  lbuf_append(lbuf, "    Options: ");
+	  for (i = 0; val_array[i] != NULL; ++i)
+	       lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	  sss_sudo_free_values(val_array);
+	  lbuf_append(lbuf, "\n");
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoOption): != 0");
+	  debug_return_int(count);
+     }
+
+     /* Get the command values from the entry. */
+     switch (sss_sudo_get_values(rule, "sudoCommand", &val_array)) {
+     case 0:
+	  lbuf_append(lbuf, _("    Commands:\n"));
+	  for (i = 0; val_array[i] != NULL; ++i) {
+	       lbuf_append(lbuf, "\t%s\n", val_array[i]);
+	       count++;
+	  }
+	  sss_sudo_free_values(val_array);
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoCommand): != 0");
+	  debug_return_int(count);
+     }
+
+     debug_return_int(count);
+}
+
+static int sudo_sss_display_entry_short(struct sss_sudo_rule *rule, struct lbuf *lbuf)
+{
+     char **val_array = NULL;
+     int count = 0, i;
+     debug_decl(sudo_sss_display_entry_short, SUDO_DEBUG_LDAP);
+
+     lbuf_append(lbuf, "    (");
+
+     /* get the RunAsUser Values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoRunAsUser", &val_array))
+     {
+     case 0:
+	  for (i = 0; val_array[i] != NULL; ++i)
+	       lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	  sss_sudo_free_values(val_array);
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result. Trying old style (sudoRunAs).");
+	  /* try old style */
+	  switch (sss_sudo_get_values(rule, "sudoRunAs", &val_array))
+	  {
+	  case 0:
+	       for (i = 0; val_array[i] != NULL; ++i)
+		    lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	       sss_sudo_free_values(val_array);
+	       break;
+	  case ENOENT:
+	       DPRINTF(2, "No result.");
+	       lbuf_append(lbuf, "%s", def_runas_default);
+	       break;
+	  default:
+	       DPRINTF(2, "sss_sudo_get_values(sudoRunAs): != 0");
+	       debug_return_int(count);
+	  }
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoRunAsUser): != 0");
+	  debug_return_int(count);
+     }
+
+     /* get the RunAsGroup Values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoRunAsGroup", &val_array))
+     {
+     case 0:
+	  lbuf_append(lbuf, " : ");
+	  for (i = 0; val_array[i] != NULL; ++i)
+	       lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	  sss_sudo_free_values(val_array);
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoRunAsGroup): != 0");
+	  debug_return_int(count);
+     }
+
+     lbuf_append(lbuf, ") ");
+
+     /* get the Option Values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoOption", &val_array))
+     {
+     case 0:
+	  for (i = 0; val_array[i] != NULL; ++i) {
+	       char *cp = val_array[i];
+	       if (*cp == '!')
+		    cp++;
+	       if (strcmp(cp, "authenticate") == 0)
+		    lbuf_append(lbuf, val_array[i][0] == '!' ?
+				"NOPASSWD: " : "PASSWD: ");
+	       else if (strcmp(cp, "noexec") == 0)
+		    lbuf_append(lbuf, val_array[i][0] == '!' ?
+				"EXEC: " : "NOEXEC: ");
+	       else if (strcmp(cp, "setenv") == 0)
+		    lbuf_append(lbuf, val_array[i][0] == '!' ?
+				"NOSETENV: " : "SETENV: ");
+	  }
+
+	  sss_sudo_free_values(val_array);
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoOption): != 0");
+	  debug_return_int(count);
+     }
+
+     /* get the Command Values from the entry */
+     switch (sss_sudo_get_values(rule, "sudoCommand", &val_array)) {
+     case 0:
+	  for (i = 0; val_array[i] != NULL; ++i) {
+	       lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
+	       count++;
+	  }
+	  sss_sudo_free_values(val_array);
+	  break;
+     case ENOENT:
+	  DPRINTF(2, "No result.");
+	  break;
+     default:
+	  DPRINTF(2, "sss_sudo_get_values(sudoCommand): != 0");
+	  debug_return_int(count);
+     }
+     lbuf_append(lbuf, "\n");
+
+     debug_return_int(count);
+}
+
+static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
+				   struct lbuf *lbuf)
+{
+     struct sudo_sss_handle *handle = nss->handle;
+
+     struct sss_sudo_result *sss_result = NULL;
+     struct sss_sudo_rule *rule;
+     unsigned int i, count = 0;
+     debug_decl(sudo_sss_display_privs, SUDO_DEBUG_LDAP);
+
+     if (handle == NULL)
+	  debug_return_int(-1);
+     if (sudo_sss_checkpw(nss, pw) != 0)
+	  debug_return_int(-1);
+
+     DPRINTF(2, "sssd/ldap search for command list");
+
+     sss_result = sudo_sss_result_get(nss, pw, NULL);
+
+     if (sss_result == NULL)
+	  debug_return_int(count);
+
+     /* Display all matching entries. */
+     for (i = 0; i < sss_result->num_rules; ++i) {
+	  rule = sss_result->rules + i;
+	  if (long_list)
+	       count += sudo_sss_display_entry_long(rule, lbuf);
+	  else
+	       count += sudo_sss_display_entry_short(rule, lbuf);
+     }
+
+     if (sss_result != NULL)
+	  sss_sudo_free_result(sss_result);
+
+     debug_return_int(count);
+}
diff -up sudo-1.8.5/plugins/sudoers/sudo_nss.c.sssd-support sudo-1.8.5/plugins/sudoers/sudo_nss.c
--- sudo-1.8.5/plugins/sudoers/sudo_nss.c.sssd-support	2012-03-12 19:02:14.000000000 +0100
+++ sudo-1.8.5/plugins/sudoers/sudo_nss.c	2012-05-17 10:30:40.819975039 +0200
@@ -47,8 +47,11 @@ extern struct sudo_nss sudo_nss_file;
 #ifdef HAVE_LDAP
 extern struct sudo_nss sudo_nss_ldap;
 #endif
+#ifdef HAVE_SSSD
+extern struct sudo_nss sudo_nss_sss;
+#endif
 
-#if defined(HAVE_LDAP) && defined(_PATH_NSSWITCH_CONF)
+#if (defined(HAVE_SSSD) || defined(HAVE_LDAP)) && defined(_PATH_NSSWITCH_CONF)
 /*
  * Read in /etc/nsswitch.conf
  * Returns a tail queue of matches.
@@ -58,6 +61,9 @@ sudo_read_nss(void)
 {
     FILE *fp;
     char *cp;
+#if defined(HAVE_SSSD)
+    bool saw_sss = false;
+#endif
     bool saw_files = false;
     bool saw_ldap = false;
     bool got_match = false;
@@ -84,6 +90,11 @@ sudo_read_nss(void)
 	    } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
 		tq_append(&snl, &sudo_nss_ldap);
 		got_match = true;
+#if defined(HAVE_SSSD)
+	    } else if (strcasecmp(cp, "sss") == 0 && !saw_sss) {
+		tq_append(&snl, &sudo_nss_sss);
+		got_match = true;
+#endif
 	    } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
 		/* NOTFOUND affects the most recent entry */
 		tq_last(&snl)->ret_if_notfound = true;
@@ -106,7 +117,7 @@ nomatch:
 
 #else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
 
-# if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF)
+# if (defined(HAVE_SSSD) || defined(HAVE_LDAP)) && defined(_PATH_NETSVC_CONF)
 
 /*
  * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
@@ -117,6 +128,9 @@ sudo_read_nss(void)
 {
     FILE *fp;
     char *cp, *ep;
+#if defined(HAVE_SSSD)
+    bool saw_sss = false;
+#endif
     bool saw_files = false;
     bool saw_ldap = false;
     bool got_match = false;
@@ -156,6 +170,13 @@ sudo_read_nss(void)
 		tq_append(&snl, &sudo_nss_ldap);
 		got_match = true;
 		ep = &cp[4];
+#if defined(HAVE_SSSD)
+	    } else if (!saw_sss && strncasecmp(cp, "sss", 3) == 0 &&
+		(isspace((unsigned char)cp[3]) || cp[3] == '\0')) {
+		tq_append(&snl, &sudo_nss_sss);
+		got_match = true;
+		ep = &cp[3];
+#endif
 	    } else {
 		got_match = false;
 	    }
@@ -195,6 +216,9 @@ sudo_read_nss(void)
     static struct sudo_nss_list snl;
     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
 
+#  ifdef HAVE_SSSD
+    tq_append(&snl, &sudo_nss_sss);
+#  endif
 #  ifdef HAVE_LDAP
     tq_append(&snl, &sudo_nss_ldap);
 #  endif