diff -up sudo-1.8.3p1/configure.in.sssd-support sudo-1.8.3p1/configure.in --- sudo-1.8.3p1/configure.in.sssd-support 2012-01-11 19:27:02.604019550 +0100 +++ sudo-1.8.3p1/configure.in 2012-01-12 16:28:48.031171923 +0100 @@ -275,6 +275,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."]) @@ -3157,6 +3173,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 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.3p1/plugins/sudoers/Makefile.in.sssd-support sudo-1.8.3p1/plugins/sudoers/Makefile.in --- sudo-1.8.3p1/plugins/sudoers/Makefile.in.sssd-support 2012-01-11 19:27:23.016032415 +0100 +++ sudo-1.8.3p1/plugins/sudoers/Makefile.in 2012-01-12 16:35:00.527406716 +0100 @@ -530,6 +530,10 @@ linux_audit.lo: $(srcdir)/linux_audit.c $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ $(incdir)/gettext.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_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ diff -up sudo-1.8.3p1/plugins/sudoers/sssd.c.sssd-support sudo-1.8.3p1/plugins/sudoers/sssd.c --- sudo-1.8.3p1/plugins/sudoers/sssd.c.sssd-support 2012-01-19 13:41:51.885154296 +0100 +++ sudo-1.8.3p1/plugins/sudoers/sssd.c 2012-02-07 12:22:37.641156963 +0100 @@ -0,0 +1,1157 @@ +/* + * Copyright (c) 2003-2011 Todd C. Miller + * Copyright (c) 2011 Daniel Kopecek + * + * 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 + +#include +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#include +#include +#include + +#include +#include + +#include "sudoers.h" +#include "parse.h" +#include "lbuf.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_sssd_open(struct sudo_nss *nss); +static int sudo_sssd_close(struct sudo_nss *nss); +static int sudo_sssd_parse(struct sudo_nss *nss); +static void sudo_sssd_parse_options(struct sss_rule *rule); +static int sudo_sssd_setdefs(struct sudo_nss *nss); +static int sudo_sssd_lookup(struct sudo_nss *nss, int ret, int pwflag); +static int sudo_sssd_display_cmnd(struct sudo_nss *nss, struct passwd *pw); +static int sudo_sssd_display_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf); + +static int sudo_sssd_display_bound_defaults(struct sudo_nss *nss, + struct passwd *pw, struct lbuf *lbuf); + +static int sudo_sssd_display_privs(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf); + + +static struct sss_result *sudo_sssd_result_get(struct sudo_nss *nss, + struct passwd *pw, + uint32_t *state); + +static void sudo_sssd_attrcpy(struct sss_attr *dst, const struct sss_attr *src) +{ + int i; + + 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]); + + return; +} + +static void sudo_sssd_rulecpy(struct sss_rule *dst, const struct sss_rule *src) +{ + int i; + + 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_attr) * dst->num_attrs); + + for (i = 0; i < dst->num_attrs; ++i) { + sudo_sssd_attrcpy(dst->attrs + i, + src->attrs + i); + } +} + +#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_result *sudo_sssd_filter_result(struct sss_result *in_res, int (*filterp)(struct sss_rule *, void *), int act, void *filterp_arg) +{ + struct sss_result *out_res; + int i, l, r; + + 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) + return NULL; + + DPRINTF(3, "emalloc: cnt=%d", in_res->num_rules); + + out_res = emalloc(sizeof(struct sss_result)); + out_res->rules = in_res->num_rules > 0 ? emalloc(sizeof(struct sss_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_sssd_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_rule) * l); + } + + out_res->num_rules = l; + + return out_res; +} + +struct sudo_sssd_handle { + char *username; + struct sss_result *result; + struct group_list *grlist; +}; + +struct sudo_nss sudo_nss_sssd = { + &sudo_nss_sssd, + NULL, + sudo_sssd_open, + sudo_sssd_close, + sudo_sssd_parse, + sudo_sssd_setdefs, + sudo_sssd_lookup, + sudo_sssd_display_cmnd, + sudo_sssd_display_defaults, + sudo_sssd_display_bound_defaults, + sudo_sssd_display_privs +}; + + +/* sudo_nss implementation */ +// ok +static int sudo_sssd_open(struct sudo_nss *nss) +{ + struct sudo_sssd_handle *handle; + + /* Create a handle container. */ + handle = emalloc(sizeof(struct sudo_sssd_handle)); + handle->result = NULL; + handle->username = NULL; + handle->grlist = NULL; + nss->handle = handle; + + DPRINTF(3, "handle=%p", handle); + + return 0; +} + +// ok +static int sudo_sssd_close(struct sudo_nss *nss) +{ + efree(nss->handle); + return 0; +} + +// ok +static int sudo_sssd_parse(struct sudo_nss *nss) +{ + return 0; +} + +static int sudo_sssd_setdefs(struct sudo_nss *nss) +{ + struct sudo_sssd_handle *handle = nss->handle; + + struct sss_result *sres; + struct sss_rule *rule; + uint32_t serr; + int i; + + if (handle == NULL) + return -1; + + DPRINTF(1, "Looking for cn=defaults"); + + if (sss_sudo_send_recv_defaults(&serr, &sres) != 0) { + DPRINTF(2, "sss_sudo_send_recv_defaults: != 0, serr=%u", serr); + return -1; + } + + for (i = 0; i < sres->num_rules; ++i) { + DPRINTF(1, "Parsing cn=defaults, %d/%d", i, sres->num_rules); + rule = sres->rules + i; + sudo_sssd_parse_options(rule); + } + + sss_sudo_free_result(sres); + + DPRINTF(1, "Looking for cn=defaults... end"); + + return 0; +} + +static int +sudo_sssd_check_runas_user(struct sss_rule *rule) +{ + char **v_arr = NULL; + char *val; + int ret = FALSE, i; + + if (!runas_pw) + return UNSPEC; + + + /* get the runas user from the entry */ + switch (sss_sudo_get_values(rule, "sudoRunAsUser", &v_arr)) + { + case 0: + break; + case ENOENT: + DPRINTF(2, "No result. Trying old style (sudoRunAs)"); + + /* try old style */ + switch (sss_sudo_get_values(rule, "sudoRunAs", &v_arr)) + { + 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"); + return UNSPEC; + } + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAsUser): != 0"); + return 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; v_arr[i] != NULL && !ret; ++i) { + val = v_arr[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(v_arr); /* cleanup */ + + return ret; +} + +static int +sudo_sssd_check_runas_group(struct sss_rule *rule) +{ + char **v_arr = NULL; + char *val; + int ret = FALSE, i; + + /* runas_gr is only set if the user specified the -g flag */ + if (!runas_gr) + return UNSPEC; + + /* get the values from the entry */ + switch (sss_sudo_get_values(rule, "sudoRunAsGroup", &v_arr)) + { + case 0: + break; + case ENOENT: + DPRINTF(2, "No result."); + return FALSE; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAsGroup): != 0"); + return UNSPEC; + } + + /* walk through values returned, looking for a match */ + for (i = 0; v_arr[i] != NULL; ++i) { + val = v_arr[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(v_arr); + + return ret; +} + +/* + * Walk through search results and return TRUE if we have a runas match, + * else FALSE. RunAs info is optional. + */ +static int +sudo_sssd_check_runas(struct sss_rule *rule) +{ + int ret; + + if (rule == NULL) + return FALSE; + + ret = sudo_sssd_check_runas_user(rule) != FALSE && + sudo_sssd_check_runas_group(rule) != FALSE; + + return ret; +} + +static int sudo_sssd_check_host(struct sss_rule *rule) +{ + char **v_arr, *val; + int ret = FALSE, i; + + if (rule == NULL) + return ret; + + /* get the values from the rule */ + switch (sss_sudo_get_values(rule, "sudoHost", &v_arr)) + { + case 0: + break; + case ENOENT: + DPRINTF(2, "No result."); + return FALSE; + default: + DPRINTF(2, "sss_sudo_get_values(sudoHost): != 0"); + return ret; + } + + /* walk through values */ + for (i = 0; v_arr[i] != NULL; ++i) { + val = v_arr[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(v_arr); + + return ret; +} + +static int sudo_sssd_result_filterp(struct sss_rule *rule, void *unused) +{ + (void)unused; + + if (sudo_sssd_check_host(rule)) + return 1; + else + return 0; +} + +static struct sss_result *sudo_sssd_result_get(struct sudo_nss *nss, + struct passwd *pw, + uint32_t *state) +{ + struct sudo_sssd_handle *handle = nss->handle; + struct sss_result *u_sres, *f_sres; + uint32_t serr = 0, ret; + + DPRINTF(1, "pw_name=%s", pw->pw_name); + + u_sres = f_sres = NULL; + + switch (ret = sss_sudo_send_recv(pw->pw_name, &serr, &u_sres)) + { + case 0: + switch (serr) { + case 0: + if (u_sres != NULL) { + if (state != NULL) { + DPRINTF(3, "state |= USERMATCH"); + *state |= _SUDO_SSS_STATE_USERMATCH; + } + DPRINTF(2, "Received %u rule(s)", u_sres->num_rules); + } else { + DPRINTF(2, "Internal error: u_sres == NULL && serr == 0"); + return NULL; + } + break; + case ENOENT: + DPRINTF(2, "No result."); + default: + DPRINTF(2, "serr=%u\n", serr); + return NULL; + } + break; + default: + DPRINTF(2, "sss_sudo_send_recv: != 0: ret=%d", ret); + return NULL; + } + + f_sres = sudo_sssd_filter_result(u_sres, sudo_sssd_result_filterp, _SUDO_SSS_FILTER_INCLUDE, NULL); + + if (f_sres != NULL) + if (f_sres->num_rules > 0) + if (state != NULL) { + DPRINTF(3, "state |= HOSTMATCH"); + *state |= _SUDO_SSS_STATE_HOSTMATCH; + } + + DPRINTF(3, "u_sres=(%p, %u) => f_sres=(%p, %u)", + u_sres, u_sres->num_rules, f_sres, f_sres->num_rules); + + sss_sudo_free_result(u_sres); + + /* Store everything in the sudo_nss handle. */ + handle->result = NULL; + + if (handle->username != NULL) { + DPRINTF(3, "Freeing previously stored username"); + efree(handle->username); + } + + handle->username = estrdup(pw->pw_name); + handle->grlist = user_group_list; + + return f_sres; +} + +/* + * Search for boolean "option" in sudoOption. + * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC. + */ +static int +sudo_sssd_check_bool(struct sss_rule *rule, char *option) +{ + char ch, *var, **v_arr = NULL; + int i, ret = UNSPEC; + + if (rule == NULL) + return ret; + + switch (sss_sudo_get_values(rule, "sudoOption", &v_arr)) + { + case 0: + break; + case ENOENT: + DPRINTF(2, "No result."); + return ret; + default: + DPRINTF(2, "sss_sudo_get_values: != 0"); + return ret; + } + + /* walk through options */ + for (i = 0; v_arr[i] != NULL; ++i) { + var = v_arr[i]; + DPRINTF(2, "sssd/ldap sudoOption: '%s'", var); + + if ((ch = *var) == '!') + var++; + if (strcmp(var, option) == 0) + ret = (ch != '!'); + } + + sss_sudo_free_values(v_arr); + + return 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_sssd_check_command(struct sss_rule *rule, int *setenv_implied) +{ + char **v_arr = NULL, *val; + char *allowed_cmnd, *allowed_args; + int i, foundbang, ret = UNSPEC; + + if (rule == NULL) + return ret; + + switch (sss_sudo_get_values(rule, "sudoCommand", &v_arr)) + { + case 0: + break; + case ENOENT: + DPRINTF(2, "No result."); + return ret; + default: + DPRINTF(2, "sss_sudo_get_values: != 0"); + return ret; + } + + for (i = 0; v_arr[i] != NULL && ret != FALSE; ++i) { + val = v_arr[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(v_arr); /* more cleanup */ + + return ret; +} + +static void +sudo_sssd_parse_options(struct sss_rule *rule) +{ + int i; + char op, *v, *val; + char **v_arr = NULL; + + if (rule == NULL) + return; + + switch (sss_sudo_get_values(rule, "sudoOption", &v_arr)) + { + case 0: + break; + case ENOENT: + DPRINTF(2, "No result."); + return; + default: + DPRINTF(2, "sss_sudo_get_values(sudoOption): != 0"); + return; + } + + /* walk through options */ + for (i = 0; v_arr[i] != NULL; i++) { + DPRINTF(2, "sssd/ldap sudoOption: '%s'", v_arr[i]); + v = estrdup(v_arr[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(v_arr); +} + +static int sudo_sssd_lookup(struct sudo_nss *nss, int ret, int pwflag) +{ + int rc, setenv_implied; + + struct sss_result *sres = NULL; + struct sss_rule *rule; + uint32_t i, state = 0; + + /* Fetch list of sudoRole entries that match user and host. */ + sres = sudo_sssd_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 (sres != NULL) { + for (i = 0; i < sres->num_rules; i++) { + rule = sres->rules + i; + if ((pwcheck == any && doauth != FALSE) || + (pwcheck == all && doauth == FALSE)) { + doauth = sudo_sssd_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_sssd_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 (sres != NULL) { + for (i = 0; i < sres->num_rules; i++) { + rule = sres->rules + i; + if (!sudo_sssd_check_runas(rule)) + continue; + rc = sudo_sssd_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_sssd_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_sssd_lookup(%d)=0x%02x", pwflag, ret); + + return ret; +} + +static int sudo_sssd_display_cmnd(struct sudo_nss *nss, struct passwd *pw) +{ + struct sudo_sssd_handle *handle = nss->handle; + struct sss_result *sres = NULL; + struct sss_rule *rule; + int i, found = FALSE; + + if (handle == NULL) + goto done; + + /* + * The sudo_sssd_result_get() function returns all nodes that match + * the user and the host. + */ + DPRINTF(1, "sssd/ldap search for command list"); + sres = sudo_sssd_result_get(nss, pw, NULL); + + if (sres == NULL) + goto done; + + for (i = 0; i < sres->num_rules; i++) { + rule = sres->rules + i; + if (sudo_sssd_check_command(rule, NULL) && + sudo_sssd_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 (sres != NULL) + sss_sudo_free_result(sres); + + return !found; +} + +static int sudo_sssd_display_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + struct sudo_sssd_handle *handle = nss->handle; + + struct sss_rule *rule; + struct sss_result *sres = NULL; + + uint32_t serr = 0; + + char *prefix, *val, **v_arr = NULL; + int count = 0, i, j; + + if (handle == NULL) + goto done; + + if (sss_sudo_send_recv_defaults(&serr, &sres) != 0) { + DPRINTF(2, "sss_sudo_send_recv_defaults: !=0, serr=%u", serr); + goto done; + } + + for (i = 0; i < sres->num_rules; ++i) { + rule = sres->rules + i; + + switch (sss_sudo_get_values(rule, "sudoOption", &v_arr)) + { + 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; v_arr[j] != NULL; ++j) { + val = v_arr[j]; + lbuf_append(lbuf, "%s%s", prefix, val); + prefix = ", "; + count++; + } + + sss_sudo_free_values(v_arr); + v_arr = NULL; + } + + sss_sudo_free_result(sres); +done: + return count; +} + +// ok +static int sudo_sssd_display_bound_defaults(struct sudo_nss *nss, + struct passwd *pw, struct lbuf *lbuf) +{ + return 0; +} + +static int sudo_sssd_display_entry_long(struct sss_rule *rule, struct lbuf *lbuf) +{ + char **v_arr = NULL; + int count = 0, i; + +#if 0 /* do we need this? */ + char *rdn; + /* extract the dn, only show the first rdn */ + rdn = sudo_ldap_get_first_rdn(ld, entry); + if (rdn != NULL) + lbuf_append(lbuf, _("\nLDAP Role: %s\n"), rdn); + else + lbuf_append(lbuf, _("\nLDAP Role: UNKNOWN\n")); + if (rdn) + ldap_memfree(rdn); +#endif + + /* get the RunAsUser Values from the entry */ + lbuf_append(lbuf, " RunAsUsers: "); + switch (sss_sudo_get_values(rule, "sudoRunAsUser", &v_arr)) + { + case 0: + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + break; + case ENOENT: + switch (sss_sudo_get_values(rule, "sudoRunAs", &v_arr)) + { + case 0: + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result."); + lbuf_append(lbuf, "%s", def_runas_default); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAs): != 0"); + return count; + } + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAsUser): != 0"); + return count; + } + lbuf_append(lbuf, "\n"); + + /* get the RunAsGroup Values from the entry */ + switch (sss_sudo_get_values(rule, "sudoRunAsGroup", &v_arr)) + { + case 0: + lbuf_append(lbuf, " RunAsGroups: "); + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + lbuf_append(lbuf, "\n"); + break; + case ENOENT: + DPRINTF(2, "No result."); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAsGroup): != 0"); + return count; + } + + + /* get the Option Values from the entry */ + switch (sss_sudo_get_values(rule, "sudoOption", &v_arr)) + { + case 0: + lbuf_append(lbuf, " Options: "); + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + lbuf_append(lbuf, "\n"); + break; + case ENOENT: + DPRINTF(2, "No result."); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoOption): != 0"); + return count; + } + + /* Get the command values from the entry. */ + switch (sss_sudo_get_values(rule, "sudoCommand", &v_arr)) { + case 0: + lbuf_append(lbuf, _(" Commands:\n")); + for (i = 0; v_arr[i] != NULL; ++i) { + lbuf_append(lbuf, "\t%s\n", v_arr[i]); + count++; + } + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result."); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoCommand): != 0"); + return count; + } + + return count; +} + +static int sudo_sssd_display_entry_short(struct sss_rule *rule, struct lbuf *lbuf) +{ + char **v_arr = NULL; + int count = 0, i; + + lbuf_append(lbuf, " ("); + + /* get the RunAsUser Values from the entry */ + switch (sss_sudo_get_values(rule, "sudoRunAsUser", &v_arr)) + { + case 0: + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result. Trying old style (sudoRunAs)."); + /* try old style */ + switch (sss_sudo_get_values(rule, "sudoRunAs", &v_arr)) + { + case 0: + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result."); + lbuf_append(lbuf, "%s", def_runas_default); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAs): != 0"); + return count; + } + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAsUser): != 0"); + return count; + } + + /* get the RunAsGroup Values from the entry */ + switch (sss_sudo_get_values(rule, "sudoRunAsGroup", &v_arr)) + { + case 0: + lbuf_append(lbuf, " : "); + for (i = 0; v_arr[i] != NULL; ++i) + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result."); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoRunAsGroup): != 0"); + return count; + } + + lbuf_append(lbuf, ") "); + + /* get the Option Values from the entry */ + switch (sss_sudo_get_values(rule, "sudoOption", &v_arr)) + { + case 0: + for (i = 0; v_arr[i] != NULL; ++i) { + char *cp = v_arr[i]; + if (*cp == '!') + cp++; + if (strcmp(cp, "authenticate") == 0) + lbuf_append(lbuf, v_arr[i][0] == '!' ? + "NOPASSWD: " : "PASSWD: "); + else if (strcmp(cp, "noexec") == 0) + lbuf_append(lbuf, v_arr[i][0] == '!' ? + "EXEC: " : "NOEXEC: "); + else if (strcmp(cp, "setenv") == 0) + lbuf_append(lbuf, v_arr[i][0] == '!' ? + "NOSETENV: " : "SETENV: "); + } + + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result."); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoOption): != 0"); + return count; + } + + /* get the Command Values from the entry */ + switch (sss_sudo_get_values(rule, "sudoCommand", &v_arr)) { + case 0: + for (i = 0; v_arr[i] != NULL; ++i) { + lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", v_arr[i]); + count++; + } + sss_sudo_free_values(v_arr); + break; + case ENOENT: + DPRINTF(2, "No result."); + break; + default: + DPRINTF(2, "sss_sudo_get_values(sudoCommand): != 0"); + return count; + } + lbuf_append(lbuf, "\n"); + + return count; +} + +static int sudo_sssd_display_privs(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + struct sss_result *sres = NULL; + struct sss_rule *rule; + unsigned int i, count = 0; + + DPRINTF(2, "sssd/ldap search for command list"); + + sres = sudo_sssd_result_get(nss, pw, NULL); + + if (sres == NULL) + return count; + + /* Display all matching entries. */ + for (i = 0; i < sres->num_rules; ++i) { + rule = sres->rules + i; + if (long_list) + count += sudo_sssd_display_entry_long(rule, lbuf); + else + count += sudo_sssd_display_entry_short(rule, lbuf); + } + + if (sres != NULL) + sss_sudo_free_result(sres); + + return count; +} diff -up sudo-1.8.3p1/plugins/sudoers/sudo_nss.c.sssd-support sudo-1.8.3p1/plugins/sudoers/sudo_nss.c --- sudo-1.8.3p1/plugins/sudoers/sudo_nss.c.sssd-support 2012-01-18 18:21:10.155151843 +0100 +++ sudo-1.8.3p1/plugins/sudoers/sudo_nss.c 2012-01-18 18:29:40.366473444 +0100 @@ -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_sssd; +#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. @@ -60,6 +63,7 @@ sudo_read_nss(void) char *cp; int saw_files = FALSE; int saw_ldap = FALSE; + int saw_sssd = FALSE; int got_match = FALSE; static struct sudo_nss_list snl; @@ -80,9 +84,16 @@ sudo_read_nss(void) if (strcasecmp(cp, "files") == 0 && !saw_files) { tq_append(&snl, &sudo_nss_file); got_match = TRUE; +#if defined(HAVE_LDAP) } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) { tq_append(&snl, &sudo_nss_ldap); got_match = TRUE; +#endif +#if defined(HAVE_SSSD) + } else if (strcasecmp(cp, "sss") == 0 && !saw_sssd) { + tq_append(&snl, &sudo_nss_sssd); + 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; @@ -105,7 +116,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) @@ -118,6 +129,7 @@ sudo_read_nss(void) char *cp, *ep; int saw_files = FALSE; int saw_ldap = FALSE; + int saw_sssd = FALSE; int got_match = FALSE; static struct sudo_nss_list snl; @@ -149,11 +161,20 @@ sudo_read_nss(void) tq_append(&snl, &sudo_nss_file); got_match = TRUE; ep = &cp[5]; +#if defined(HAVE_LDAP) } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 && (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { tq_append(&snl, &sudo_nss_ldap); got_match = TRUE; ep = &cp[4]; +#endif +#if defined(HAVE_SSSD) + } else if (!saw_sssd && strncasecmp(cp, "sss", 3) == 0 && + (isspace((unsigned char)cp[3]) || cp[3] == '\0')) { + tq_append(&snl, &sudo_nss_sssd); + got_match = TRUE; + ep = &cp[3]; +#endif } else { got_match = FALSE; }