From d4159888614139b8a003f5472be8696112ac8d5a Mon Sep 17 00:00:00 2001 From: Daniel Kopecek Date: Feb 07 2012 11:25:11 +0000 Subject: added SSSD support --- diff --git a/sudo-1.8.3p1-sssd-support.patch b/sudo-1.8.3p1-sssd-support.patch new file mode 100644 index 0000000..ee1b68a --- /dev/null +++ b/sudo-1.8.3p1-sssd-support.patch @@ -0,0 +1,1288 @@ +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; + } diff --git a/sudo.spec b/sudo.spec index 9724ad1..16ee6cf 100644 --- a/sudo.spec +++ b/sudo.spec @@ -1,7 +1,7 @@ Summary: Allows restricted root access for specified users Name: sudo Version: 1.8.3p1 -Release: 3%{?dist} +Release: 4%{?dist} License: ISC Group: Applications/System URL: http://www.courtesan.com/sudo/ @@ -20,6 +20,7 @@ BuildRequires: audit-libs-devel libcap-devel BuildRequires: libselinux-devel BuildRequires: sendmail BuildRequires: gettext +BuildRequires: libsss_sudo-devel # don't strip Patch1: sudo-1.6.7p5-strip.patch @@ -31,6 +32,8 @@ Patch3: sudo-1.7.4p3-m4path.patch Patch4: sudo-1.8.3-pipelist.patch # CVE-2012-0809 Patch5: sudo-1.8.3p1-CVE-2012-0809.patch +# SSSD support +Patch6: sudo-1.8.3p1-sssd-support.patch %description Sudo (superuser do) allows a system administrator to give certain @@ -60,6 +63,7 @@ plugins that use %{name}. %patch3 -p1 -b .m4path %patch4 -p1 -b .pipelist %patch5 -p1 -b .CVE-2012-0809 +%patch6 -p1 -b .sssd-support # Remove execute permission on this script so we don't pull in perl deps chmod -x plugins/sudoers/sudoers2ldif @@ -91,7 +95,8 @@ export CFLAGS="$RPM_OPT_FLAGS $F_PIE" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" --with-ldap \ --with-selinux \ --with-passprompt="[sudo] password for %p: " \ - --with-linux-audit + --with-linux-audit \ + --with-sssd # --without-kerb5 \ # --without-kerb4 make @@ -170,6 +175,9 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sudo_plugin.8* %changelog +* Tue Feb 7 2012 Daniel Kopecek - 1.8.3p1-4 +- added SSSD support + * Thu Jan 26 2012 Daniel Kopecek - 1.8.3p1-3 - added patch for CVE-2012-0809