diff --git a/.gitignore b/.gitignore
index c3932a8..5032c1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/sssd-1.11.2.tar.gz
+SOURCES/sssd-1.12.2.tar.gz
diff --git a/.sssd.metadata b/.sssd.metadata
index dc0ee00..1ccf4e7 100644
--- a/.sssd.metadata
+++ b/.sssd.metadata
@@ -1 +1 @@
-c1a747f6b8cb5fd37bec8e759eb5ef033b067973 SOURCES/sssd-1.11.2.tar.gz
+c7969eeb880fdd79cead88504c313fa042ca524a SOURCES/sssd-1.12.2.tar.gz
diff --git a/SOURCES/0001-SYSDB-Skip-malformed-netgroup-attribute.patch b/SOURCES/0001-SYSDB-Skip-malformed-netgroup-attribute.patch
deleted file mode 100644
index a240448..0000000
--- a/SOURCES/0001-SYSDB-Skip-malformed-netgroup-attribute.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From d0eeff900d721a0e147b3513d075dbb64b002dc1 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 12 Nov 2013 14:39:27 +0100
-Subject: [PATCH 1/6] SYSDB: Skip malformed netgroup attribute.
-
-It was not easy find out why netgroup could not be covert into result entries.
-Problem was that nisNetgroupTriple contained unexpected string "(,user01)"
-This patch will ignore only malformed attribute and processing of netgroup
-will not fail.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2137
----
- src/db/sysdb_search.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index 8dfaf1f2ada22db5e70ebe18bee1ee299e4767dd..d15fc73ce2272bff53650ae9dd0dbdad99a849e6 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -728,7 +728,11 @@ errno_t sysdb_netgr_to_entries(TALLOC_CTX *mem_ctx,
-                                         &tmp_entry[c]->value.triple.username,
-                                         &tmp_entry[c]->value.triple.domainname);
-                     if (ret != EOK) {
--                        goto done;
-+                        DEBUG(SSSDBG_IMPORTANT_INFO,
-+                              ("Cannot split netgroup triple [%s], "
-+                               "this attribute will be skipped \n",
-+                               triple_str));
-+                        continue;
-                     }
- 
-                     c++;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0001-util-Move-semanage-related-functions-to-src-util.patch b/SOURCES/0001-util-Move-semanage-related-functions-to-src-util.patch
new file mode 100644
index 0000000..f87ee45
--- /dev/null
+++ b/SOURCES/0001-util-Move-semanage-related-functions-to-src-util.patch
@@ -0,0 +1,590 @@
+From 40dac78bce81ebf65ccbcd4f346de9e91d3da58b Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 24 Sep 2014 15:50:04 +0200
+Subject: [PATCH 01/22] util: Move semanage related functions to src/util
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+These functions will be reused by IPA provider.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am                                  |  37 ++-
+ src/tests/dlopen-tests.c                     |   1 +
+ src/tools/selinux.c                          | 334 ---------------------------
+ src/tools/tools_util.h                       |   2 -
+ src/{tools/selinux.c => util/sss_semanage.c} |  61 +----
+ src/util/util.h                              |   4 +
+ 6 files changed, 35 insertions(+), 404 deletions(-)
+ copy src/{tools/selinux.c => util/sss_semanage.c} (87%)
+
+diff --git a/Makefile.am b/Makefile.am
+index 6a8124b5ad30f9e54a0325dc574a96c91ec4e805..49acdb107cb45410493dfabe30a2ea4553a23669 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -476,10 +476,6 @@ if BUILD_SELINUX
+     PYTHON_BINDINGS_LIBS += $(SELINUX_LIBS)
+     TOOLS_LIBS += $(SELINUX_LIBS)
+ endif
+-if BUILD_SEMANAGE
+-    PYTHON_BINDINGS_LIBS += $(SEMANAGE_LIBS)
+-    TOOLS_LIBS += $(SEMANAGE_LIBS)
+-endif
+ 
+ dist_noinst_HEADERS = \
+     src/monitor/monitor.h \
+@@ -728,11 +724,26 @@ libsss_util_la_SOURCES += \
+ endif
+ libsss_util_la_LDFLAGS = -avoid-version
+ 
++pkglib_LTLIBRARIES += libsss_semanage.la
++libsss_semanage_la_SOURCES = \
++    src/util/sss_semanage.c \
++    $(NULL)
++libsss_semanage_la_LIBADD = \
++    libsss_debug.la \
++    $(NULL)
++if BUILD_SEMANAGE
++libsss_semanage_la_LIBADD += $(SEMANAGE_LIBS)
++endif
++
++libsss_semanage_la_LDFLAGS = \
++    -avoid-version
++
+ SSSD_INTERNAL_LTLIBS = \
+     libsss_util.la \
+     libsss_crypt.la \
+     libsss_debug.la \
+-    libsss_child.la
++    libsss_child.la \
++    $(NULL)
+ 
+ if BUILD_IFP
+ if BUILD_CONFIG_LIB
+@@ -1065,7 +1076,9 @@ sss_useradd_SOURCES = \
+     $(SSSD_TOOLS_OBJ)
+ sss_useradd_LDADD = \
+     $(TOOLS_LIBS) \
+-    $(SSSD_INTERNAL_LTLIBS)
++    $(SSSD_INTERNAL_LTLIBS) \
++    libsss_semanage.la \
++    $(NULL)
+ 
+ sss_userdel_SOURCES = \
+     src/tools/sss_userdel.c \
+@@ -1073,7 +1086,9 @@ sss_userdel_SOURCES = \
+ sss_userdel_LDADD = \
+     $(TOOLS_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+-    $(CLIENT_LIBS)
++    $(CLIENT_LIBS) \
++    libsss_semanage.la \
++    $(NULL)
+ sss_userdel_CFLAGS = \
+     $(AM_CFLAGS)
+ 
+@@ -1099,7 +1114,9 @@ sss_usermod_SOURCES = \
+ sss_usermod_LDADD = \
+     $(TOOLS_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+-    $(CLIENT_LIBS)
++    $(CLIENT_LIBS) \
++    libsss_semanage.la \
++    $(NULL)
+ sss_usermod_CFLAGS = $(AM_CFLAGS)
+ 
+ sss_groupmod_SOURCES = \
+@@ -2372,7 +2389,9 @@ libsss_ipa_la_LIBADD = \
+     libsss_ldap_common.la \
+     libsss_krb5_common.la \
+     libipa_hbac.la \
+-    libsss_idmap.la
++    libsss_idmap.la \
++    libsss_semanage.la \
++    $(NULL)
+ libsss_ipa_la_LDFLAGS = \
+     -avoid-version \
+     -module
+diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c
+index 1dd80c49cf3e91e214ac6ffb2df1f98268571831..7e56d652461155045023fddeb988f4f4ba017277 100644
+--- a/src/tests/dlopen-tests.c
++++ b/src/tests/dlopen-tests.c
+@@ -38,6 +38,7 @@ struct so {
+     const char *libs[6];
+ } so[] = {
+     { "libsss_debug.so", { LIBPFX"libsss_debug.so", NULL } },
++    { "libsss_semanage.so", { LIBPFX"libsss_semanage.so", NULL } },
+     { "libipa_hbac.so", { LIBPFX"libipa_hbac.so", NULL } },
+     { "libsss_idmap.so", { LIBPFX"libsss_idmap.so", NULL } },
+     { "libsss_nss_idmap.so", { LIBPFX"libsss_nss_idmap.so", NULL } },
+diff --git a/src/tools/selinux.c b/src/tools/selinux.c
+index 1f87d40f99440b15ed71be9c225003b2860c5003..5e9c458f93340fcb4264eced7964a6cfecadc9e6 100644
+--- a/src/tools/selinux.c
++++ b/src/tools/selinux.c
+@@ -27,16 +27,8 @@
+ #include <selinux/selinux.h>
+ #endif
+ 
+-#ifdef HAVE_SEMANAGE
+-#include <semanage/semanage.h>
+-#endif
+-
+ #include "tools/tools_util.h"
+ 
+-#ifndef DEFAULT_SERANGE
+-#define DEFAULT_SERANGE "s0"
+-#endif
+-
+ #ifdef HAVE_SELINUX
+ /*
+  * selinux_file_context - Set the security context before any file or
+@@ -89,329 +81,3 @@ int reset_selinux_file_context(void)
+     return EOK;
+ }
+ #endif  /* HAVE_SELINUX */
+-
+-#ifdef HAVE_SEMANAGE
+-/* turn libselinux messages into SSSD DEBUG() calls */
+-static void sss_semanage_error_callback(void *varg,
+-                                        semanage_handle_t *handle,
+-                                        const char *fmt, ...)
+-{
+-    int level = SSSDBG_INVALID;
+-    int ret;
+-    char * message = NULL;
+-    va_list ap;
+-
+-    switch (semanage_msg_get_level(handle)) {
+-        case SEMANAGE_MSG_ERR:
+-            level = SSSDBG_CRIT_FAILURE;
+-            break;
+-        case SEMANAGE_MSG_WARN:
+-            level = SSSDBG_MINOR_FAILURE;
+-            break;
+-        case SEMANAGE_MSG_INFO:
+-            level = SSSDBG_TRACE_FUNC;
+-            break;
+-    }
+-
+-    va_start(ap, fmt);
+-    ret = vasprintf(&message, fmt, ap);
+-    va_end(ap);
+-    if (ret < 0) {
+-        /* ENOMEM */
+-        return;
+-    }
+-
+-    if (DEBUG_IS_SET(level))
+-        debug_fn(__FILE__, __LINE__, "libsemanage", level, "%s\n", message);
+-    free(message);
+-}
+-
+-static semanage_handle_t *sss_semanage_init(void)
+-{
+-    int ret;
+-    semanage_handle_t *handle = NULL;
+-
+-    handle = semanage_handle_create();
+-    if (!handle) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n");
+-        return NULL;
+-    }
+-
+-    semanage_msg_set_callback(handle,
+-                              sss_semanage_error_callback,
+-                              NULL);
+-
+-    ret = semanage_is_managed(handle);
+-    if (ret != 1) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "SELinux policy not managed\n");
+-        goto fail;
+-    }
+-
+-    ret = semanage_access_check(handle);
+-    if (ret < SEMANAGE_CAN_READ) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n");
+-        goto fail;
+-    }
+-
+-    ret = semanage_connect(handle);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Cannot estabilish SELinux management connection\n");
+-        goto fail;
+-    }
+-
+-    ret = semanage_begin_transaction(handle);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot begin SELinux transaction\n");
+-        goto fail;
+-    }
+-
+-    return handle;
+-fail:
+-    semanage_handle_destroy(handle);
+-    return NULL;
+-}
+-
+-static int sss_semanage_user_add(semanage_handle_t *handle,
+-                                 semanage_seuser_key_t *key,
+-                                 const char *login_name,
+-                                 const char *seuser_name)
+-{
+-    int ret;
+-    semanage_seuser_t *seuser = NULL;
+-
+-    ret = semanage_seuser_create(handle, &seuser);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Cannot create SELinux login mapping for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_set_name(handle, seuser, login_name);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Could not set name for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not set serange for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_set_sename(handle, seuser, seuser_name);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not set SELinux user for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_modify_local(handle, key, seuser);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not add login mapping for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-done:
+-    semanage_seuser_free(seuser);
+-    return ret;
+-}
+-
+-static int sss_semanage_user_mod(semanage_handle_t *handle,
+-                                 semanage_seuser_key_t *key,
+-                                 const char *login_name,
+-                                 const char *seuser_name)
+-{
+-    int ret;
+-    semanage_seuser_t *seuser = NULL;
+-
+-    semanage_seuser_query(handle, key, &seuser);
+-    if (seuser == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not query seuser for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not set serange for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_set_sename(handle, seuser, seuser_name);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Could not set sename for %s\n", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_modify_local(handle, key, seuser);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              ("Could not modify login mapping for %s\n"), login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-done:
+-    semanage_seuser_free(seuser);
+-    return ret;
+-}
+-
+-int set_seuser(const char *login_name, const char *seuser_name)
+-{
+-    semanage_handle_t *handle = NULL;
+-    semanage_seuser_key_t *key = NULL;
+-    int ret;
+-    int seuser_exists = 0;
+-
+-    if (seuser_name == NULL) {
+-        /* don't care, just let system pick the defaults */
+-        return EOK;
+-    }
+-
+-    handle = sss_semanage_init();
+-    if (!handle) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_key_create(handle, login_name, &key);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux user key\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_exists(handle, key, &seuser_exists);
+-    if (ret < 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot verify the SELinux user\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    if (seuser_exists) {
+-        ret = sss_semanage_user_mod(handle, key, login_name, seuser_name);
+-        if (ret != 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot modify SELinux user mapping\n");
+-            ret = EIO;
+-            goto done;
+-        }
+-    } else {
+-        ret = sss_semanage_user_add(handle, key, login_name, seuser_name);
+-        if (ret != 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add SELinux user mapping\n");
+-            ret = EIO;
+-            goto done;
+-        }
+-    }
+-
+-    ret = semanage_commit(handle);
+-    if (ret < 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot commit SELinux transaction\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-done:
+-    semanage_seuser_key_free(key);
+-    semanage_handle_destroy(handle);
+-    return ret;
+-}
+-
+-int del_seuser(const char *login_name)
+-{
+-    semanage_handle_t *handle = NULL;
+-    semanage_seuser_key_t *key = NULL;
+-    int ret;
+-    int exists = 0;
+-
+-    handle = sss_semanage_init();
+-    if (!handle) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_key_create(handle, login_name, &key);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux user key\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_exists(handle, key, &exists);
+-    if (ret < 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot verify the SELinux user\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    if (!exists) {
+-        DEBUG(SSSDBG_FUNC_DATA,
+-              "Login mapping for %s is not defined, OK if default mapping "
+-                  "was used\n", login_name);
+-        ret = EOK;  /* probably default mapping */
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_exists_local(handle, key, &exists);
+-    if (ret < 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot verify the SELinux user\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    if (!exists) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Login mapping for %s is defined in policy, "
+-                  "cannot be deleted", login_name);
+-        ret = ENOENT;
+-        goto done;
+-    }
+-
+-    ret = semanage_seuser_del_local(handle, key);
+-    if (ret != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not delete login mapping for %s", login_name);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = semanage_commit(handle);
+-    if (ret < 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot commit SELinux transaction\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-done:
+-    semanage_handle_destroy(handle);
+-    return ret;
+-}
+-
+-#else /* HAVE_SEMANAGE */
+-int set_seuser(const char *login_name, const char *seuser_name)
+-{
+-    return EOK;
+-}
+-
+-int del_seuser(const char *login_name)
+-{
+-    return EOK;
+-}
+-#endif  /* HAVE_SEMANAGE */
+diff --git a/src/tools/tools_util.h b/src/tools/tools_util.h
+index 87fe752eac49ef85d77043fe0a8c459bc4f5a74c..c5990b012892a25b315d744a056861e7b2130410 100644
+--- a/src/tools/tools_util.h
++++ b/src/tools/tools_util.h
+@@ -123,7 +123,5 @@ int copy_tree(const char *src_root, const char *dst_root,
+ /* from selinux.c */
+ int selinux_file_context(const char *dst_name);
+ int reset_selinux_file_context(void);
+-int set_seuser(const char *login_name, const char *seuser_name);
+-int del_seuser(const char *login_name);
+ 
+ #endif  /* __TOOLS_UTIL_H__ */
+diff --git a/src/tools/selinux.c b/src/util/sss_semanage.c
+similarity index 87%
+copy from src/tools/selinux.c
+copy to src/util/sss_semanage.c
+index 1f87d40f99440b15ed71be9c225003b2860c5003..dbef3b3437f9ac51021f30b510b9c15cd34e297a 100644
+--- a/src/tools/selinux.c
++++ b/src/util/sss_semanage.c
+@@ -1,7 +1,7 @@
+ /*
+    SSSD
+ 
+-   selinux.c
++   sss_semanage.c
+ 
+    Copyright (C) Jakub Hrozek <jhrozek@redhat.com>        2010
+ 
+@@ -23,73 +23,16 @@
+ 
+ #include <stdio.h>
+ 
+-#ifdef HAVE_SELINUX
+-#include <selinux/selinux.h>
+-#endif
+-
+ #ifdef HAVE_SEMANAGE
+ #include <semanage/semanage.h>
+ #endif
+ 
+-#include "tools/tools_util.h"
++#include "util/util.h"
+ 
+ #ifndef DEFAULT_SERANGE
+ #define DEFAULT_SERANGE "s0"
+ #endif
+ 
+-#ifdef HAVE_SELINUX
+-/*
+- * selinux_file_context - Set the security context before any file or
+- *                        directory creation.
+- *
+- *  selinux_file_context () should be called before any creation of file,
+- *  symlink, directory, ...
+- *
+- *  Callers may have to Reset SELinux to create files with default
+- *  contexts:
+- *      reset_selinux_file_context();
+- */
+-int selinux_file_context(const char *dst_name)
+-{
+-    security_context_t scontext = NULL;
+-
+-    if (is_selinux_enabled() == 1) {
+-        /* Get the default security context for this file */
+-        if (matchpathcon(dst_name, 0, &scontext) < 0) {
+-            if (security_getenforce () != 0) {
+-                return 1;
+-            }
+-        }
+-        /* Set the security context for the next created file */
+-        if (setfscreatecon(scontext) < 0) {
+-            if (security_getenforce() != 0) {
+-                return 1;
+-            }
+-        }
+-        freecon(scontext);
+-    }
+-
+-    return 0;
+-}
+-
+-int reset_selinux_file_context(void)
+-{
+-    setfscreatecon(NULL);
+-    return EOK;
+-}
+-
+-#else   /* HAVE_SELINUX */
+-int selinux_file_context(const char *dst_name)
+-{
+-    return EOK;
+-}
+-
+-int reset_selinux_file_context(void)
+-{
+-    return EOK;
+-}
+-#endif  /* HAVE_SELINUX */
+-
+ #ifdef HAVE_SEMANAGE
+ /* turn libselinux messages into SSSD DEBUG() calls */
+ static void sss_semanage_error_callback(void *varg,
+diff --git a/src/util/util.h b/src/util/util.h
+index 0ac9b0104ca941b52bb37720dd16d2bbc9fbb9f8..b43ce6f5092e9920609826bead483976fef2f9b1 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -591,4 +591,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+                      struct sss_creds **saved_creds);
+ errno_t restore_creds(struct sss_creds *saved_creds);
+ 
++/* from sss_semanage.c */
++int set_seuser(const char *login_name, const char *seuser_name);
++int del_seuser(const char *login_name);
++
+ #endif /* __SSSD_UTIL_H__ */
+-- 
+1.9.3
+
diff --git a/SOURCES/0002-monitor-Specific-error-message-for-missing-sssd.conf.patch b/SOURCES/0002-monitor-Specific-error-message-for-missing-sssd.conf.patch
deleted file mode 100644
index ea4a22b..0000000
--- a/SOURCES/0002-monitor-Specific-error-message-for-missing-sssd.conf.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From 08134dde5a6c8b23cf40ec8f0020cd553af2667e Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <pavel.reichl@redhat.com>
-Date: Tue, 19 Nov 2013 11:24:31 +0000
-Subject: [PATCH 2/6] monitor: Specific error message for missing sssd.conf
-
-Specific error message is logged for missing sssd.conf file. New sssd specific
-error value is introduced for this case.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2156
----
- src/confdb/confdb_setup.c | 9 +++++++--
- src/monitor/monitor.c     | 8 +++++++-
- src/util/util_errors.c    | 1 +
- src/util/util_errors.h    | 1 +
- 4 files changed, 16 insertions(+), 3 deletions(-)
-
-diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
-index b13553eaa560bb83ecf7a53b32ab116f38f7f480..2a34e4f7a3e5f9aa37760036520f5274e9289b70 100644
---- a/src/confdb/confdb_setup.c
-+++ b/src/confdb/confdb_setup.c
-@@ -155,8 +155,13 @@ int confdb_init_db(const char *config_file, struct confdb_ctx *cdb)
-     /* Open config file */
-     ret = sss_ini_config_file_open(init_data, config_file);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to open configuration file.\n"));
--        ret = EIO;
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              ("sss_ini_config_file_open failed: %s [%d]\n", strerror(ret),
-+               ret));
-+        if (ret == ENOENT) {
-+            /* sss specific error denoting missing configuration file */
-+            ret = ERR_MISSING_CONF;
-+        }
-         goto done;
-     }
- 
-diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
-index 3d8ba26285b6a8fc60ccb695f8b10ae1714ac918..09f530d2643b45fc31fb4dbe3cb69f2abc5510af 100644
---- a/src/monitor/monitor.c
-+++ b/src/monitor/monitor.c
-@@ -1614,7 +1614,7 @@ static errno_t load_configuration(TALLOC_CTX *mem_ctx,
-     ret = confdb_init_db(config_file, ctx->cdb);
-     if (ret != EOK) {
-         DEBUG(0, ("ConfDB initialization has failed [%s]\n",
--              strerror(ret)));
-+              sss_strerror(ret)));
-         goto done;
-     }
- 
-@@ -2789,6 +2789,12 @@ int main(int argc, const char *argv[])
-     ret = load_configuration(tmp_ctx, config_file, &monitor);
-     if (ret != EOK) {
-         switch (ret) {
-+        case ERR_MISSING_CONF:
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  ("Configuration file: %s does not exist.\n", config_file));
-+            sss_log(SSS_LOG_ALERT,
-+                    "Configuration file: %s does not exist.\n", config_file);
-+            break;
-         case EPERM:
-         case EACCES:
-             DEBUG(SSSDBG_CRIT_FAILURE,
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index b3d10f97b0567ca21ca08a3f2d326ea401c28aff..114c8b04fd354b166d14e526a3bab6a6c0c05951 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -50,6 +50,7 @@ struct err_string error_to_str[] = {
-     { "Dynamic DNS update not possible while offline" }, /* ERR_DYNDNS_OFFLINE */
-     { "Entry not found" }, /* ERR_NOT_FOUND */
-     { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */
-+    { "Missing configuration file" }, /* ERR_MISSING_CONF */
- };
- 
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index 685607c5bb1b4e7c37152c876518a2b1c69c18d6..bca45f392b0357c3f1c848768358cb1d47514715 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -72,6 +72,7 @@ enum sssd_errors {
-     ERR_DYNDNS_OFFLINE,
-     ERR_NOT_FOUND,
-     ERR_DOMAIN_NOT_FOUND,
-+    ERR_MISSING_CONF,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0002-sss_semanage-Add-mlsrange-parameter-to-set_seuser.patch b/SOURCES/0002-sss_semanage-Add-mlsrange-parameter-to-set_seuser.patch
new file mode 100644
index 0000000..c6f920d
--- /dev/null
+++ b/SOURCES/0002-sss_semanage-Add-mlsrange-parameter-to-set_seuser.patch
@@ -0,0 +1,153 @@
+From 214c04af59ea09589743b88943a7ba0adac64a7a Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 24 Sep 2014 16:03:04 +0200
+Subject: [PATCH 02/22] sss_semanage: Add mlsrange parameter to set_seuser
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+mlsrange parameter will be needed in IPA provider
+and probably at some point in the tools as well.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tools/sss_useradd.c |  2 +-
+ src/tools/sss_usermod.c |  2 +-
+ src/util/sss_semanage.c | 25 ++++++++++++++++---------
+ src/util/util.h         |  3 ++-
+ 4 files changed, 20 insertions(+), 12 deletions(-)
+
+diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c
+index 59439401e225d752ea9a82fdb33900bf44699e18..8521b83011b42c9e2acca4136f154acb3919440c 100644
+--- a/src/tools/sss_useradd.c
++++ b/src/tools/sss_useradd.c
+@@ -205,7 +205,7 @@ int main(int argc, const char **argv)
+ 
+     /* Set SELinux login context - must be done after transaction is done
+      * b/c libselinux calls getpwnam */
+-    ret = set_seuser(tctx->octx->name, pc_selinux_user);
++    ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL);
+     if (ret != EOK) {
+         ERROR("Cannot set SELinux login context\n");
+         ret = EXIT_FAILURE;
+diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c
+index 9683c6e9e7c2bf389563515162a3772ee73987ed..55e94394766f5f46bb3c14c231186f2d79d6b6ab 100644
+--- a/src/tools/sss_usermod.c
++++ b/src/tools/sss_usermod.c
+@@ -300,7 +300,7 @@ int main(int argc, const char **argv)
+ 
+     /* Set SELinux login context - must be done after transaction is done
+      * b/c libselinux calls getpwnam */
+-    ret = set_seuser(tctx->octx->name, pc_selinux_user);
++    ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL);
+     if (ret != EOK) {
+         ERROR("Cannot set SELinux login context\n");
+         ret = EXIT_FAILURE;
+diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
+index dbef3b3437f9ac51021f30b510b9c15cd34e297a..3c566553f2085a696f79c5ee35ec6015824d56a6 100644
+--- a/src/util/sss_semanage.c
++++ b/src/util/sss_semanage.c
+@@ -22,7 +22,6 @@
+ #include "config.h"
+ 
+ #include <stdio.h>
+-
+ #ifdef HAVE_SEMANAGE
+ #include <semanage/semanage.h>
+ #endif
+@@ -118,7 +117,8 @@ fail:
+ static int sss_semanage_user_add(semanage_handle_t *handle,
+                                  semanage_seuser_key_t *key,
+                                  const char *login_name,
+-                                 const char *seuser_name)
++                                 const char *seuser_name,
++                                 const char *mls)
+ {
+     int ret;
+     semanage_seuser_t *seuser = NULL;
+@@ -138,7 +138,8 @@ static int sss_semanage_user_add(semanage_handle_t *handle,
+         goto done;
+     }
+ 
+-    ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
++    ret = semanage_seuser_set_mlsrange(handle, seuser,
++                                       mls ? mls : DEFAULT_SERANGE);
+     if (ret != 0) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Could not set serange for %s\n", login_name);
+@@ -171,7 +172,8 @@ done:
+ static int sss_semanage_user_mod(semanage_handle_t *handle,
+                                  semanage_seuser_key_t *key,
+                                  const char *login_name,
+-                                 const char *seuser_name)
++                                 const char *seuser_name,
++                                 const char *mls)
+ {
+     int ret;
+     semanage_seuser_t *seuser = NULL;
+@@ -184,7 +186,8 @@ static int sss_semanage_user_mod(semanage_handle_t *handle,
+         goto done;
+     }
+ 
+-    ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
++    ret = semanage_seuser_set_mlsrange(handle, seuser,
++                                       mls ? mls : DEFAULT_SERANGE);
+     if (ret != 0) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Could not set serange for %s\n", login_name);
+@@ -213,7 +216,8 @@ done:
+     return ret;
+ }
+ 
+-int set_seuser(const char *login_name, const char *seuser_name)
++int set_seuser(const char *login_name, const char *seuser_name,
++               const char *mls)
+ {
+     semanage_handle_t *handle = NULL;
+     semanage_seuser_key_t *key = NULL;
+@@ -247,14 +251,16 @@ int set_seuser(const char *login_name, const char *seuser_name)
+     }
+ 
+     if (seuser_exists) {
+-        ret = sss_semanage_user_mod(handle, key, login_name, seuser_name);
++        ret = sss_semanage_user_mod(handle, key, login_name, seuser_name,
++                                    mls);
+         if (ret != 0) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Cannot modify SELinux user mapping\n");
+             ret = EIO;
+             goto done;
+         }
+     } else {
+-        ret = sss_semanage_user_add(handle, key, login_name, seuser_name);
++        ret = sss_semanage_user_add(handle, key, login_name, seuser_name,
++                                    mls);
+         if (ret != 0) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add SELinux user mapping\n");
+             ret = EIO;
+@@ -348,7 +354,8 @@ done:
+ }
+ 
+ #else /* HAVE_SEMANAGE */
+-int set_seuser(const char *login_name, const char *seuser_name)
++int set_seuser(const char *login_name, const char *seuser_name,
++               const char *mls)
+ {
+     return EOK;
+ }
+diff --git a/src/util/util.h b/src/util/util.h
+index b43ce6f5092e9920609826bead483976fef2f9b1..0af4db3fec723ef372f7c1acde0e3f9f013f90e0 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -592,7 +592,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+ errno_t restore_creds(struct sss_creds *saved_creds);
+ 
+ /* from sss_semanage.c */
+-int set_seuser(const char *login_name, const char *seuser_name);
++int set_seuser(const char *login_name, const char *seuser_name,
++               const char *mlsrange);
+ int del_seuser(const char *login_name);
+ 
+ #endif /* __SSSD_UTIL_H__ */
+-- 
+1.9.3
+
diff --git a/SOURCES/0003-AD-Fix-a-typo-in-the-man-page.patch b/SOURCES/0003-AD-Fix-a-typo-in-the-man-page.patch
deleted file mode 100644
index 9baeeb9..0000000
--- a/SOURCES/0003-AD-Fix-a-typo-in-the-man-page.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From ebb9c8acfb2423a2474cbbc52794d41975478dcf Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 18 Nov 2013 11:05:04 +0100
-Subject: [PATCH 3/6] AD: Fix a typo in the man page
-
-https://fedorahosted.org/sssd/ticket/2154
----
- src/man/sssd-ad.5.xml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 3dcf2c7390e89cacec202f49c559eccf03800450..e31f87a96a14907c64166e53da443ad735c6e85e 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -175,7 +175,7 @@ ldap_id_mapping = False
-                             This option specifies LDAP access control
-                             filter that the user must match in order
-                             to be allowed access. Please note that the
--                            <quote>access_filter</quote> option must be
-+                            <quote>access_provider</quote> option must be
-                             explicitly set to <quote>ad</quote> in order
-                             for this option to have an effect.
-                         </para>
--- 
-1.8.4.2
-
diff --git a/SOURCES/0003-IPA-Use-set_seuser-instead-of-writing-selinux-login-.patch b/SOURCES/0003-IPA-Use-set_seuser-instead-of-writing-selinux-login-.patch
new file mode 100644
index 0000000..83341fe
--- /dev/null
+++ b/SOURCES/0003-IPA-Use-set_seuser-instead-of-writing-selinux-login-.patch
@@ -0,0 +1,277 @@
+From 7d5eda445b127f4fdb5ff2f680792d46aa82439b Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 24 Sep 2014 16:51:55 +0200
+Subject: [PATCH 03/22] IPA: Use set_seuser instead of writing selinux login
+ file
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Remove the write/remove_selinux login file functions
+and use set_seuser instead.
+
+This patch will require change in selinux policy.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ipa/ipa_selinux.c | 184 +++++++++++-----------------------------
+ 1 file changed, 49 insertions(+), 135 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
+index 5b65a7b04cb0d55b10de47c4ea306b6d4470dfe9..7db1c6ed2981e4c4a85d892171bbfa60b006980e 100644
+--- a/src/providers/ipa/ipa_selinux.c
++++ b/src/providers/ipa/ipa_selinux.c
+@@ -652,10 +652,10 @@ done:
+     return ret;
+ }
+ 
+-static errno_t write_selinux_login_file(const char *orig_name,
+-                                        struct sss_domain_info *dom,
+-                                        char *string);
+-static errno_t remove_selinux_login_file(const char *username);
++static errno_t
++set_seuser_helper(const char *orig_name, struct sss_domain_info *dom,
++                  const char *seuser_mls_string);
++
+ 
+ /* Choose best selinux user based on given order and write
+  * the user to selinux login file. */
+@@ -666,9 +666,9 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
+                                   const char *default_user)
+ {
+     TALLOC_CTX *tmp_ctx;
+-    char *file_content = NULL;
++    char *seuser_mls_str = NULL;
+     const char *tmp_str;
+-    errno_t ret, err;
++    errno_t ret;
+     int i, j;
+ 
+     tmp_ctx = talloc_new(NULL);
+@@ -679,8 +679,8 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
+ 
+     /* If no maps match, we'll use the default SELinux user from the
+      * config */
+-    file_content = talloc_strdup(tmp_ctx, default_user);
+-    if (file_content == NULL) {
++    seuser_mls_str = talloc_strdup(tmp_ctx, default_user);
++    if (seuser_mls_str == NULL) {
+         ret = ENOMEM;
+         goto done;
+     }
+@@ -702,12 +702,12 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
+             tmp_str = sss_selinux_map_get_seuser(usermaps[j]);
+ 
+             if (tmp_str && !strcasecmp(tmp_str, mo_ctx->order_array[i])) {
+-                /* If file_content contained something, overwrite it.
++                /* If seuser_mls_str contained something, overwrite it.
+                  * This record has higher priority.
+                  */
+-                talloc_zfree(file_content);
+-                file_content = talloc_strdup(tmp_ctx, tmp_str);
+-                if (file_content == NULL) {
++                talloc_zfree(seuser_mls_str);
++                seuser_mls_str = talloc_strdup(tmp_ctx, tmp_str);
++                if (seuser_mls_str == NULL) {
+                     ret = ENOMEM;
+                     goto done;
+                 }
+@@ -716,44 +716,48 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
+         }
+     }
+ 
+-    ret = write_selinux_login_file(pd->user, user_domain, file_content);
++    ret = set_seuser_helper(pd->user, user_domain, seuser_mls_str);
+ done:
+-    if (!file_content) {
+-        err = remove_selinux_login_file(pd->user);
+-        /* Don't overwrite original error condition if there was one */
+-        if (ret == EOK) ret = err;
+-    }
+     talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
+-static errno_t write_selinux_login_file(const char *orig_name,
+-                                        struct sss_domain_info *dom,
+-                                        char *string)
++static errno_t
++set_seuser_helper(const char *orig_name, struct sss_domain_info *dom,
++                  const char *seuser_mls_string)
+ {
+-    char *path = NULL;
+-    char *tmp_path = NULL;
+-    ssize_t written;
+-    size_t len;
+-    int fd = -1;
+-    mode_t oldmask;
++    errno_t ret;
++    char *seuser;
++    char *mls_range;
++    char *ptr;
++    char *username;
++    char *username_final;
+     TALLOC_CTX *tmp_ctx;
+-    char *full_string = NULL;
+-    int enforce;
+-    errno_t ret = EOK;
+-    const char *username;
+-
+-    len = strlen(string);
+-    if (len == 0) {
+-        return EINVAL;
+-    }
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+         return ENOMEM;
+     }
+ 
++    /* Split seuser and mls_range */
++    seuser = talloc_strdup(tmp_ctx, seuser_mls_string);
++    if (seuser == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ptr = seuser;
++    while (*ptr != ':' && *ptr != '\0') {
++        ptr++;
++    }
++    if (*ptr == '\0') {
++        /* No mls_range specified */
++        mls_range = NULL;
++    } else {
++        *ptr = '\0'; /* split */
++        mls_range = ptr + 1;
++    }
++
+     /* pam_selinux needs the username in the same format getpwnam() would
+      * return it
+      */
+@@ -763,113 +767,23 @@ static errno_t write_selinux_login_file(const char *orig_name,
+         goto done;
+     }
+ 
+-    path = selogin_path(tmp_ctx, username);
+-    if (path == NULL) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    tmp_path = talloc_asprintf(tmp_ctx, "%sXXXXXX", path);
+-    if (tmp_path == NULL) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    oldmask = umask(022);
+-    fd = mkstemp(tmp_path);
+-    ret = errno;
+-    umask(oldmask);
+-    if (fd < 0) {
+-        if (ret == ENOENT) {
+-            /* if selinux is disabled and selogin dir does not exist,
+-             * just ignore the error */
+-            if (selinux_getenforcemode(&enforce) == 0 && enforce == -1) {
+-                ret = EOK;
+-                goto done;
+-            }
+-
+-            /* continue if we can't get enforce mode or selinux is enabled */
++    if (dom->fqnames) {
++        username_final = talloc_asprintf(tmp_ctx, dom->names->fq_fmt,
++                                         username, dom->name);
++        if (username_final == NULL) {
++            ret = ENOMEM;
++            goto done;
+         }
+-
+-        DEBUG(SSSDBG_OP_FAILURE, "unable to create temp file [%s] "
+-              "for SELinux data [%d]: %s\n", tmp_path, ret, strerror(ret));
+-        goto done;
+-    }
+-
+-    full_string = talloc_asprintf(tmp_ctx, "%s:%s", ALL_SERVICES, string);
+-    if (full_string == NULL) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    len = strlen(full_string);
+-
+-    errno = 0;
+-    written = sss_atomic_write_s(fd, full_string, len);
+-    if (written == -1) {
+-        ret = errno;
+-        DEBUG(SSSDBG_OP_FAILURE, "writing to SELinux data file %s"
+-                                  "failed [%d]: %s", tmp_path, ret,
+-                                  strerror(ret));
+-        goto done;
+-    }
+-
+-    if (written != len) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Expected to write %zd bytes, wrote %zu",
+-                                  written, len);
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    errno = 0;
+-    if (rename(tmp_path, path) < 0) {
+-        ret = errno;
+     } else {
+-        ret = EOK;
++        username_final = username;
+     }
+-    close(fd);
+-    fd = -1;
+ 
++    ret = set_seuser(username_final, seuser, mls_range);
+ done:
+-    if (fd != -1) {
+-        close(fd);
+-        if (unlink(tmp_path) < 0) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove file [%s]",
+-                                         tmp_path);
+-        }
+-    }
+-
+     talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
+-static errno_t remove_selinux_login_file(const char *username)
+-{
+-    char *path;
+-    errno_t ret;
+-
+-    path = selogin_path(NULL, username);
+-    if (!path) return ENOMEM;
+-
+-    errno = 0;
+-    ret = unlink(path);
+-    if (ret < 0) {
+-        ret = errno;
+-        if (ret == ENOENT) {
+-            /* Just return success if the file was not there */
+-            ret = EOK;
+-        } else {
+-            DEBUG(SSSDBG_OP_FAILURE,
+-                  "Could not remove login file %s [%d]: %s\n",
+-                   path, ret, strerror(ret));
+-        }
+-    }
+-
+-    talloc_free(path);
+-    return ret;
+-}
+-
+-
+ /* A more generic request to gather all SELinux and HBAC rules. Updates
+  * cache if necessary
+  */
+-- 
+1.9.3
+
diff --git a/SOURCES/0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch b/SOURCES/0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch
deleted file mode 100644
index 10ffd1a..0000000
--- a/SOURCES/0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 44d60762a2ffe45b2dadf05634eefb2af2e3ce14 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 18 Nov 2013 16:38:34 +0100
-Subject: [PATCH 4/6] LDAP: Initialize user count for AD matching rule
-
-https://fedorahosted.org/sssd/ticket/2157
-
-If AD matching rule was selected, but the group was empty, the SSSD
-accessed random data. Initializing count to zero prevents that.
----
- src/providers/ldap/sdap_async_groups.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 7a8f3e2a5c83c5b320497a76c363a90620315dcf..9f7e3e55d0234e9aa7b9e59456044587bcad88ef 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -1828,7 +1828,7 @@ static void sdap_ad_match_rule_members_process(struct tevent_req *subreq)
-     struct sysdb_attrs *group = state->groups[0];
-     struct ldb_message_element *member_el;
-     struct ldb_message_element *orig_dn_el;
--    size_t count;
-+    size_t count = 0;
-     size_t i;
-     hash_table_t *ghosts;
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0004-SSSD-Add-the-options-to-specify-a-UID-and-GID-to-run.patch b/SOURCES/0004-SSSD-Add-the-options-to-specify-a-UID-and-GID-to-run.patch
new file mode 100644
index 0000000..31302d7
--- /dev/null
+++ b/SOURCES/0004-SSSD-Add-the-options-to-specify-a-UID-and-GID-to-run.patch
@@ -0,0 +1,366 @@
+From b967aefd1c7463ecad93f63d67c77446584cc829 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 6 Oct 2014 16:28:13 +0200
+Subject: [PATCH 04/22] SSSD: Add the options to specify a UID and GID to run
+ as
+
+Adds new command line options --uid and --gid to all SSSD servers,
+making it possible to switch to another user ID if needed.
+
+So far all code still runs as root.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ Makefile.am                       | 7 +++++--
+ src/monitor/monitor.c             | 3 ++-
+ src/providers/data_provider_be.c  | 5 ++++-
+ src/providers/proxy/proxy_child.c | 5 ++++-
+ src/responder/autofs/autofssrv.c  | 6 +++++-
+ src/responder/ifp/ifpsrv.c        | 6 +++++-
+ src/responder/nss/nsssrv.c        | 5 ++++-
+ src/responder/pac/pacsrv.c        | 5 ++++-
+ src/responder/pam/pamsrv.c        | 5 ++++-
+ src/responder/ssh/sshsrv.c        | 5 ++++-
+ src/responder/sudo/sudosrv.c      | 6 +++++-
+ src/util/server.c                 | 8 ++++++++
+ src/util/util.h                   | 7 +++++++
+ 13 files changed, 61 insertions(+), 12 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 49acdb107cb45410493dfabe30a2ea4553a23669..b949c9c24070026570de970b545918a7eb279c6d 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -706,14 +706,17 @@ libsss_util_la_SOURCES = \
+     src/util/util_sss_idmap.c \
+     src/util/well_known_sids.c \
+     src/util/string_utils.c \
++    src/util/become_user.c \
+     $(NULL)
+ libsss_util_la_CFLAGS = \
+     $(AM_CFLAGS) \
+-    $(SYSTEMD_LOGIN_CFLAGS)
++    $(SYSTEMD_LOGIN_CFLAGS) \
++    $(NULL)
+ libsss_util_la_LIBADD = \
+     $(SSSD_LIBS) \
+     $(SYSTEMD_LOGIN_LIBS) \
+-    $(UNICODE_LIBS)
++    $(UNICODE_LIBS) \
++    $(NULL)
+ if BUILD_SUDO
+     libsss_util_la_SOURCES += src/db/sysdb_sudo.c
+ endif
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 624e45026b01842ab81d8c37d50751977185d20c..edd1c2dfc674d8a7ca9d069d6499c0dcc959f210 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -2855,7 +2855,8 @@ int main(int argc, const char *argv[])
+     ret = close(STDIN_FILENO);
+     if (ret != EOK) return 6;
+ 
+-    ret = server_setup(MONITOR_NAME, flags, monitor->conf_path, &main_ctx);
++    ret = server_setup(MONITOR_NAME, flags, 0, 0,
++                       monitor->conf_path, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     monitor->is_daemon = !opt_interactive;
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index e7f345f922361b60775e149c1b28f45cf16ed00e..18b50214b0795709d583d5891bf4f6fd220bcb11 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -2804,10 +2804,13 @@ int main(int argc, const char *argv[])
+     struct main_context *main_ctx;
+     char *confdb_path;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         {"domain", 0, POPT_ARG_STRING, &be_domain, 0,
+          _("Domain of the information provider (mandatory)"), NULL },
+         POPT_TABLEEND
+@@ -2847,7 +2850,7 @@ int main(int argc, const char *argv[])
+     confdb_path = talloc_asprintf(NULL, CONFDB_DOMAIN_PATH_TMPL, be_domain);
+     if (!confdb_path) return 2;
+ 
+-    ret = server_setup(srv_name, 0, confdb_path, &main_ctx);
++    ret = server_setup(srv_name, 0, 0, 0, confdb_path, &main_ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up mainloop [%d]\n", ret);
+         return 2;
+diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c
+index 6bee1c7f63c4bb5b33f11601c2be32df05206756..e261b2f588a89a27ed6fe78f7fc5cfa053b49833 100644
+--- a/src/providers/proxy/proxy_child.c
++++ b/src/providers/proxy/proxy_child.c
+@@ -504,10 +504,13 @@ int main(int argc, const char *argv[])
+     int ret;
+     long id;
+     char *pam_target = NULL;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         {"domain", 0, POPT_ARG_STRING, &domain, 0,
+          _("Domain of the information provider (mandatory)"), NULL },
+         {"id", 0, POPT_ARG_LONG, &id, 0,
+@@ -557,7 +560,7 @@ int main(int argc, const char *argv[])
+     conf_entry = talloc_asprintf(NULL, CONFDB_DOMAIN_PATH_TMPL, domain);
+     if (!conf_entry) return 2;
+ 
+-    ret = server_setup(srv_name, 0, conf_entry, &main_ctx);
++    ret = server_setup(srv_name, 0, 0, 0, conf_entry, &main_ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up mainloop [%d]\n", ret);
+         return 2;
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index bd5aa135a3fb64a020e74a9dd39fa1b67dc76533..931cf018bfe15b37bf8e5f93a21c7ab61d238c18 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -207,10 +207,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -235,7 +238,8 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_autofs";
+ 
+-    ret = server_setup("sssd[autofs]", 0, CONFDB_AUTOFS_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[autofs]", 0, 0, 0,
++                       CONFDB_AUTOFS_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) {
+         return 2;
+     }
+diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
+index 4af836543d3945603d22099b7ab98a90588bce35..8d8fe885abb8ef53ee7f49e763ba78c4dda9a983 100644
+--- a/src/responder/ifp/ifpsrv.c
++++ b/src/responder/ifp/ifpsrv.c
+@@ -441,10 +441,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -469,7 +472,8 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_ifp";
+ 
+-    ret = server_setup("sssd[ifp]", 0, CONFDB_IFP_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[ifp]", 0, 0, 0,
++                       CONFDB_IFP_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index 84a6b7fedd096a7d4159b7ac6670820c1d8fd941..420fd3d316959a67737f23e9a8b3d1c797583ea3 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -537,10 +537,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -565,7 +568,7 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_nss";
+ 
+-    ret = server_setup("sssd[nss]", 0, CONFDB_NSS_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[nss]", 0, 0, 0, CONFDB_NSS_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
+index 47a9d1a68fbf1615277af41cef297b4955e7f7c3..b76691de829b4f40937a07ea83825a606950aa1e 100644
+--- a/src/responder/pac/pacsrv.c
++++ b/src/responder/pac/pacsrv.c
+@@ -216,10 +216,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -244,7 +247,7 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_pac";
+ 
+-    ret = server_setup("sssd[pac]", 0, CONFDB_PAC_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[pac]", 0, 0, 0, CONFDB_PAC_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index 428b252acb56406291e3cac5d2a13e6f6b581c36..91b395080820b27f5d57341e59dd739e674be31a 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -316,10 +316,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -344,7 +347,7 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_pam";
+ 
+-    ret = server_setup("sssd[pam]", 0, CONFDB_PAM_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[pam]", 0, 0, 0, CONFDB_PAM_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index 8aa603d79dddb327606f02d9e7ddf2b18a98e700..1328d1746b9e2d6474d6c2f8ce2825be463ca3e7 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -184,10 +184,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -212,7 +215,7 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_ssh";
+ 
+-    ret = server_setup("sssd[ssh]", 0, CONFDB_SSH_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[ssh]", 0, 0, 0, CONFDB_SSH_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) {
+         return 2;
+     }
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index 8a197159b23abde45953b65121ff2e3fc3f2f67a..30752c9dacdc390b24fe837c0630333b5e171448 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -164,10 +164,13 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     struct main_context *main_ctx;
+     int ret;
++    uid_t uid;
++    gid_t gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         SSSD_MAIN_OPTS
++        SSSD_SERVER_OPTS(uid, gid)
+         POPT_TABLEEND
+     };
+ 
+@@ -192,7 +195,8 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_sudo";
+ 
+-    ret = server_setup("sssd[sudo]", 0, CONFDB_SUDO_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[sudo]", 0, 0, 0, CONFDB_SUDO_CONF_ENTRY,
++                       &main_ctx);
+     if (ret != EOK) {
+         return 2;
+     }
+diff --git a/src/util/server.c b/src/util/server.c
+index 51934f8ba287d6f6e395231ed893753e10b4c9b0..3a84dee0cee06cb98c94a1d57209c2bcf7c4340a 100644
+--- a/src/util/server.c
++++ b/src/util/server.c
+@@ -412,6 +412,7 @@ errno_t server_common_rotate_logs(struct confdb_ctx *confdb,
+ }
+ 
+ int server_setup(const char *name, int flags,
++                 uid_t uid, gid_t gid,
+                  const char *conf_entry,
+                  struct main_context **main_ctx)
+ {
+@@ -426,6 +427,13 @@ int server_setup(const char *name, int flags,
+     struct tevent_signal *tes;
+     struct logrotate_ctx *lctx;
+ 
++    ret = become_user(uid, gid);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FUNC_DATA,
++              "Cannot become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid);
++        return ret;
++    }
++
+     debug_prg_name = strdup(name);
+     if (!debug_prg_name) {
+         return ENOMEM;
+diff --git a/src/util/util.h b/src/util/util.h
+index 0af4db3fec723ef372f7c1acde0e3f9f013f90e0..cc5588c183006a03525e0540524c28bd9eb4dc57 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -175,6 +175,12 @@ errno_t set_debug_file_from_fd(const int fd);
+ 
+ #define SSSD_MAIN_OPTS SSSD_DEBUG_OPTS
+ 
++#define SSSD_SERVER_OPTS(uid, gid) \
++        {"uid", 0, POPT_ARG_INT, &uid, 0, \
++          _("The user ID to run the server as"), NULL}, \
++        {"gid", 0, POPT_ARG_INT, &gid, 0, \
++          _("The group ID to run the server as"), NULL},
++
+ #define FLAGS_NONE 0x0000
+ #define FLAGS_DAEMON 0x0001
+ #define FLAGS_INTERACTIVE 0x0002
+@@ -242,6 +248,7 @@ errno_t server_common_rotate_logs(struct confdb_ctx *confdb,
+ int die_if_parent_died(void);
+ int pidfile(const char *path, const char *name);
+ int server_setup(const char *name, int flags,
++                 uid_t uid, gid_t gid,
+                  const char *conf_entry,
+                  struct main_context **main_ctx);
+ void server_loop(struct main_context *main_ctx);
+-- 
+1.9.3
+
diff --git a/SOURCES/0005-SSSD-Chown-the-log-files.patch b/SOURCES/0005-SSSD-Chown-the-log-files.patch
new file mode 100644
index 0000000..f1f2b37
--- /dev/null
+++ b/SOURCES/0005-SSSD-Chown-the-log-files.patch
@@ -0,0 +1,93 @@
+From 9f4f7549998e4047063fc12561068893b2100d59 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 Oct 2014 13:59:49 +0200
+Subject: [PATCH 05/22] SSSD: Chown the log files
+
+We need to chown the log files before dropping root to make sure they
+are usable by the SSSD user. Unfortunately, we can't just rely on
+passing the fd opened by root, because we need to be also able to rotate
+the log files.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/util/debug.c  | 33 +++++++++++++++++++++++++++++++++
+ src/util/server.c |  6 ++++++
+ src/util/util.h   |  1 +
+ 3 files changed, 40 insertions(+)
+
+diff --git a/src/util/debug.c b/src/util/debug.c
+index a99d5403a238f125010b9b309355b30f9f528c44..41375709170abe33b0c7fd90e3b1244299ed0241 100644
+--- a/src/util/debug.c
++++ b/src/util/debug.c
+@@ -297,6 +297,39 @@ void ldb_debug_messages(void *context, enum ldb_debug_level level,
+     free(message);
+ }
+ 
++/* In cases SSSD used to run as the root user, but runs as the SSSD user now,
++ * we need to chown the log files
++ */
++int chown_debug_file(const char *filename,
++                     uid_t uid, gid_t gid)
++{
++    char *logpath;
++    const char *log_file;
++    errno_t ret;
++
++    if (filename == NULL) {
++        log_file = debug_log_file;
++    } else {
++        log_file = filename;
++    }
++
++    ret = asprintf(&logpath, "%s/%s.log", LOG_PATH, log_file);
++    if (ret == -1) {
++        return ENOMEM;
++    }
++
++    ret = chown(logpath, uid, gid);
++    free(logpath);
++    if (ret != 0) {
++        ret = errno;
++        DEBUG(SSSDBG_FATAL_FAILURE, "chown failed for [%s]: [%d]\n",
++              log_file, ret);
++        return ret;
++    }
++
++    return EOK;
++}
++
+ int open_debug_file_ex(const char *filename, FILE **filep, bool want_cloexec)
+ {
+     FILE *f = NULL;
+diff --git a/src/util/server.c b/src/util/server.c
+index 3a84dee0cee06cb98c94a1d57209c2bcf7c4340a..a908470cdcf2cb85a6742e44905ae12d136c83d5 100644
+--- a/src/util/server.c
++++ b/src/util/server.c
+@@ -427,6 +427,12 @@ int server_setup(const char *name, int flags,
+     struct tevent_signal *tes;
+     struct logrotate_ctx *lctx;
+ 
++    ret = chown_debug_file(NULL, uid, gid);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot chown the debug files, debugging might not work!\n");
++    }
++
+     ret = become_user(uid, gid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FUNC_DATA,
+diff --git a/src/util/util.h b/src/util/util.h
+index cc5588c183006a03525e0540524c28bd9eb4dc57..df83aac7d53ccadb806e8a1be90f0e45abb829ae 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -218,6 +218,7 @@ errno_t set_debug_file_from_fd(const int fd);
+ /* From debug.c */
+ void ldb_debug_messages(void *context, enum ldb_debug_level level,
+                         const char *fmt, va_list ap);
++int chown_debug_file(const char *filename, uid_t uid, gid_t gid);
+ int open_debug_file_ex(const char *filename, FILE **filep, bool want_cloexec);
+ int open_debug_file(void);
+ int rotate_debug_files(void);
+-- 
+1.9.3
+
diff --git a/SOURCES/0005-SSSD-Improved-domain-detection.patch b/SOURCES/0005-SSSD-Improved-domain-detection.patch
deleted file mode 100644
index 7ae4898..0000000
--- a/SOURCES/0005-SSSD-Improved-domain-detection.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-From 3cf1217a277d1103a8956e33fc0a8464227e2dd2 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <pavel.reichl@redhat.com>
-Date: Thu, 14 Nov 2013 21:34:51 +0000
-Subject: [PATCH 5/6] SSSD: Improved domain detection
-
-A bit more elegant way of detection of what domain the group member belongs to
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2132
----
- src/providers/ldap/ldap_common.c | 39 ++++++++++++++++++++++++++++-----------
- src/util/sss_ldap.c              | 28 +++++++++++++++++++++++-----
- src/util/sss_ldap.h              |  6 ++++++
- 3 files changed, 57 insertions(+), 16 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
-index facf102edc792c75a563a276f3ea9f3acc3052b4..35ea81360b4ec61eca6b952cd86fc93a6eda17dc 100644
---- a/src/providers/ldap/ldap_common.c
-+++ b/src/providers/ldap/ldap_common.c
-@@ -68,23 +68,40 @@ sdap_domain_get_by_dn(struct sdap_options *opts,
-                       const char *dn)
- {
-     struct sdap_domain *sditer = NULL;
--    char *dc = NULL;
-+    struct sdap_domain *sdmatch = NULL;
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    int match_len;
-+    int best_match_len = 0;
- 
--    dc = strstr(dn, "dc=");
--    if (dc == NULL) {
--        dc = strstr(dn, "DC=");
--        if (dc == NULL) {
--            return NULL;
--        }
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return NULL;
-     }
- 
-     DLIST_FOR_EACH(sditer, opts->sdom) {
--        if (strcasecmp(sditer->basedn, dc) == 0) {
--            return sditer;
-+        if (sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, sditer->search_bases,
-+                                            NULL, &match_len)
-+            || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn,
-+                   sditer->user_search_bases, NULL, &match_len)
-+            || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn,
-+                   sditer->group_search_bases, NULL, &match_len)
-+            || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn,
-+                   sditer->netgroup_search_bases, NULL, &match_len)
-+            || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn,
-+                   sditer->sudo_search_bases, NULL, &match_len)
-+            || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn,
-+                   sditer->service_search_bases, NULL, &match_len)
-+            || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn,
-+                   sditer->autofs_search_bases, NULL, &match_len)) {
-+            if (best_match_len < match_len) {
-+                /*this is a longer match*/
-+                best_match_len = match_len;
-+                sdmatch = sditer;
-+            }
-         }
-     }
--
--    return NULL;
-+    talloc_free(tmp_ctx);
-+    return sdmatch;
- }
- 
- errno_t
-diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
-index 6d7b0907ca2fa48d9cff5257ab6bbba0ae7dd5c6..e1a05e8f60afb692ac95c99a443febac72a31187 100644
---- a/src/util/sss_ldap.c
-+++ b/src/util/sss_ldap.c
-@@ -470,10 +470,13 @@ int sss_ldap_init_recv(struct tevent_req *req, LDAP **ldap, int *sd)
-  * _filter will contain combined filters from all possible search bases
-  * or NULL if it should be empty
-  */
--bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
--                                 const char *dn,
--                                 struct sdap_search_base **search_bases,
--                                 char **_filter)
-+
-+
-+bool sss_ldap_dn_in_search_bases_len(TALLOC_CTX *mem_ctx,
-+                                     const char *dn,
-+                                     struct sdap_search_base **search_bases,
-+                                     char **_filter,
-+                                     int *_match_len)
- {
-     struct sdap_search_base *base;
-     int basedn_len, dn_len;
-@@ -484,6 +487,7 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
-     bool backslash_found = false;
-     char *filter = NULL;
-     bool ret = false;
-+    int match_len;
- 
-     if (dn == NULL) {
-         DEBUG(SSSDBG_FUNC_DATA, ("dn is NULL\n"));
-@@ -511,6 +515,7 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
-         if (!base_confirmed) {
-             continue;
-         }
-+        match_len = basedn_len;
- 
-         switch (base->scope) {
-         case LDAP_SCOPE_BASE:
-@@ -558,6 +563,9 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
-          *  Append filter otherwise.
-          */
-         ret = true;
-+        if (_match_len) {
-+            *_match_len = match_len;
-+        }
- 
-         if (base->filter == NULL || _filter == NULL) {
-             goto done;
-@@ -575,7 +583,8 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
-         if (filter != NULL) {
-             *_filter = talloc_asprintf(mem_ctx, "(|%s)", filter);
-             if (*_filter == NULL) {
--                DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf_append() failed\n"));
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      ("talloc_asprintf_append() failed\n"));
-                 ret = false;
-                 goto done;
-             }
-@@ -589,6 +598,15 @@ done:
-     return ret;
- }
- 
-+bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
-+                                 const char *dn,
-+                                 struct sdap_search_base **search_bases,
-+                                 char **_filter)
-+{
-+    return sss_ldap_dn_in_search_bases_len(mem_ctx, dn, search_bases, _filter,
-+                                           NULL);
-+}
-+
- char *sss_ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t flags)
- {
-     char hex[9]; /* 4 bytes in hex + terminating zero */
-diff --git a/src/util/sss_ldap.h b/src/util/sss_ldap.h
-index e5c30eb2115d422ef5a52cc5cd75c85be8fbe2d7..f298b2fbb30cf1532f8e94504ffb83ef73880b81 100644
---- a/src/util/sss_ldap.h
-+++ b/src/util/sss_ldap.h
-@@ -74,6 +74,12 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx,
-                                  struct sdap_search_base **search_bases,
-                                  char **_filter);
- 
-+bool sss_ldap_dn_in_search_bases_len(TALLOC_CTX *mem_ctx,
-+                                     const char *dn,
-+                                     struct sdap_search_base **search_bases,
-+                                     char **_filter,
-+                                     int *_match_len);
-+
- char *sss_ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t flags);
- 
- #endif /* __SSS_LDAP_H__ */
--- 
-1.8.4.2
-
diff --git a/SOURCES/0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch b/SOURCES/0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch
deleted file mode 100644
index e0555b3..0000000
--- a/SOURCES/0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch
+++ /dev/null
@@ -1,260 +0,0 @@
-From 94c85df2d7ded82f2939d8fe29821e4c78ff000d Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <pavel.reichl@redhat.com>
-Date: Thu, 14 Nov 2013 21:52:26 +0000
-Subject: [PATCH 6/6] SSSD: Unit test - sss_ldap_dn_in_search_bases
-
-Unit test testing detection of the right domain when processing group with members from several domains
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2132
----
- Makefile.am                          |  27 ++++-
- src/tests/cmocka/test_search_bases.c | 191 +++++++++++++++++++++++++++++++++++
- 2 files changed, 217 insertions(+), 1 deletion(-)
- create mode 100644 src/tests/cmocka/test_search_bases.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 2ba1ec0fd94e3292f05de0139d607b3626b5c6f7..583ccdb499306268640bfb894f673c42945e19ff 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -151,7 +151,8 @@ if HAVE_CMOCKA
-         fqnames-tests \
-         test_sss_idmap \
-         test_utils \
--        ad_access_filter_tests
-+        ad_access_filter_tests \
-+        test_search_bases
- endif
- 
- check_PROGRAMS = \
-@@ -1367,6 +1368,30 @@ test_utils_LDADD = \
-     $(SSSD_INTERNAL_LTLIBS) \
-     libsss_test_common.la
- 
-+test_search_bases_SOURCES = \
-+    $(sssd_be_SOURCES) \
-+    src/util/sss_ldap.c \
-+    src/util/sss_krb5.c \
-+    src/util/find_uid.c \
-+    src/util/user_info_msg.c \
-+    src/tests/cmocka/test_search_bases.c
-+test_search_bases_CFLAGS = \
-+    $(AM_CFLAGS) \
-+    -DUNIT_TESTING
-+test_search_bases_LDADD = \
-+    $(PAM_LIBS) \
-+    $(CMOCKA_LIBS) \
-+    $(POPT_LIBS) \
-+    $(SSSD_LIBS) \
-+    $(CARES_LIBS) \
-+    $(KRB5_LIBS) \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    $(SYSTEMD_LOGIN_LIBS) \
-+    libsss_ldap_common.la \
-+    libsss_idmap.la \
-+    libsss_krb5_common.la \
-+    libsss_test_common.la
-+
- ad_access_filter_tests_SOURCES = \
-     $(sssd_be_SOURCES) \
-     src/util/sss_ldap.c \
-diff --git a/src/tests/cmocka/test_search_bases.c b/src/tests/cmocka/test_search_bases.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..e03ef3662685d92335bce4a7023e1ac7e64432c8
---- /dev/null
-+++ b/src/tests/cmocka/test_search_bases.c
-@@ -0,0 +1,191 @@
-+/*
-+    Authors:
-+        Pavel Reichl <preichl@redhat.com>
-+
-+    Copyright (C) 2013 Red Hat
-+
-+    SSSD tests - Search bases
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include <stdarg.h>
-+#include <stdlib.h>
-+#include <stddef.h>
-+#include <setjmp.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <cmocka.h>
-+#include <ldap.h>
-+
-+#include "util/find_uid.h"
-+#include "util/sss_ldap.h"
-+#include "tests/common.h"
-+#include "providers/ldap/ldap_common.h"
-+#include "providers/ldap/sdap.h"
-+#include "dhash.h"
-+#include "tests/common_check.h"
-+
-+enum sss_test_get_by_dn {
-+    DN_NOT_IN_DOMS, /* dn is not in any domain           */
-+    DN_IN_DOM1,     /* dn is in the domain based on dns  */
-+    DN_IN_DOM2,     /* dn is in the domain based on dns2 */
-+};
-+
-+static struct sdap_search_base** generate_bases(TALLOC_CTX *mem_ctx,
-+                                                const char** dns, size_t n)
-+{
-+    struct sdap_search_base **search_bases;
-+    errno_t err;
-+    int i;
-+
-+    search_bases = talloc_array(mem_ctx, struct sdap_search_base *, n + 1);
-+    assert_non_null(search_bases);
-+
-+    for (i=0; i < n; ++i) {
-+        err = sdap_create_search_base(mem_ctx, dns[i], LDAP_SCOPE_SUBTREE,
-+                                      NULL, &search_bases[i]);
-+        if (err != EOK) {
-+            fprintf(stderr, "Failed to create search base\n");
-+        }
-+        assert_int_equal(err, EOK);
-+    }
-+    search_bases[n] = NULL;
-+    return search_bases;
-+}
-+
-+static bool do_test_search_bases(const char* dn, const char** dns, size_t n)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct sdap_search_base **search_bases;
-+    bool ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    assert_non_null(tmp_ctx);
-+
-+    search_bases = generate_bases(tmp_ctx, dns, n);
-+    check_leaks_push(tmp_ctx);
-+    ret = sss_ldap_dn_in_search_bases(tmp_ctx, dn, search_bases, NULL);
-+    assert_true(check_leaks_pop(tmp_ctx) == true);
-+
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+void test_search_bases_fail(void **state)
-+{
-+    const char *dn = "cn=user, dc=sub, dc=ad, dc=pb";
-+    const char *dns[] = {"dc=example, dc=com", "dc=subdom, dc=ad, dc=pb"};
-+    bool ret;
-+
-+    ret = do_test_search_bases(dn, dns, 2);
-+    assert_false(ret);
-+}
-+
-+void test_search_bases_success(void **state)
-+{
-+    const char *dn = "cn=user, dc=sub, dc=ad, dc=pb";
-+    const char *dns[] = {"", "dc=ad, dc=pb", "dc=sub, dc=ad, dc=pb"};
-+    bool ret;
-+
-+    ret = do_test_search_bases(dn, dns, 3);
-+    assert_true(ret);
-+}
-+
-+static void do_test_get_by_dn(const char *dn, const char **dns, size_t n,
-+                              const char **dns2, size_t n2, int expected_result)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct sdap_options *opts;
-+    struct sdap_domain *sdom;
-+    struct sdap_domain *sdom2;
-+    struct sdap_domain *res_sdom;
-+    struct sdap_search_base **search_bases;
-+    struct sdap_search_base **search_bases2;
-+    tmp_ctx = talloc_new(NULL);
-+    assert_non_null(tmp_ctx);
-+
-+    search_bases = generate_bases(tmp_ctx, dns, n);
-+    search_bases2 = generate_bases(tmp_ctx, dns2, n2);
-+    sdom = talloc_zero(tmp_ctx, struct sdap_domain);
-+    assert_non_null(sdom);
-+    sdom2 = talloc_zero(tmp_ctx, struct sdap_domain);
-+    assert_non_null(sdom2);
-+
-+    sdom->search_bases = search_bases;
-+    sdom->next = sdom2;
-+    sdom->prev = NULL;
-+    sdom2->search_bases = search_bases2;
-+    sdom2->next = NULL;
-+    sdom2->prev = sdom;
-+
-+    opts = talloc(tmp_ctx, struct sdap_options);
-+    assert_non_null(opts);
-+    opts->sdom = sdom;
-+    res_sdom = sdap_domain_get_by_dn(opts, dn);
-+
-+    switch (expected_result) {
-+    case DN_NOT_IN_DOMS:
-+        assert_null(res_sdom);
-+        break;
-+    case DN_IN_DOM1:
-+        assert_true(res_sdom == sdom);
-+        break;
-+    case DN_IN_DOM2:
-+        assert_true(res_sdom == sdom2);
-+        break;
-+    }
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_get_by_dn(void **state)
-+{
-+    const char *dn = "cn=user, dc=sub, dc=ad, dc=pb";
-+    const char *dns[] = {"dc=ad, dc=pb"};
-+    const char *dns2[] = {"dc=sub, dc=ad, dc=pb"};
-+
-+    do_test_get_by_dn(dn, dns, 1, dns2, 1, DN_IN_DOM2);
-+}
-+
-+void test_get_by_dn2(void **state)
-+{
-+    const char *dn = "cn=user, dc=ad, dc=com";
-+    const char *dns[] = {"dc=ad, dc=com"};
-+    const char *dns2[] = {"dc=sub, dc=ad, dc=pb"};
-+
-+    do_test_get_by_dn(dn, dns, 1, dns2, 1, DN_IN_DOM1);
-+}
-+
-+void test_get_by_dn_fail(void **state)
-+{
-+    const char *dn = "cn=user, dc=sub, dc=example, dc=com";
-+    const char *dns[] = {"dc=ad, dc=pb"};
-+    const char *dns2[] = {"dc=sub, dc=ad, dc=pb"};
-+
-+    do_test_get_by_dn(dn, dns, 1, dns2, 1, DN_NOT_IN_DOMS);
-+}
-+
-+int main(void)
-+{
-+    const UnitTest tests[] = {
-+        unit_test(test_search_bases_fail),
-+        unit_test(test_search_bases_success),
-+        unit_test(test_get_by_dn_fail),
-+        unit_test(test_get_by_dn),
-+        unit_test(test_get_by_dn2)
-+     };
-+
-+    return run_tests(tests);
-+}
--- 
-1.8.4.2
-
diff --git a/SOURCES/0006-UTIL-Use-a-custom-PID_PATH-and-DB_PATH-when-unit-tes.patch b/SOURCES/0006-UTIL-Use-a-custom-PID_PATH-and-DB_PATH-when-unit-tes.patch
new file mode 100644
index 0000000..23fb933
--- /dev/null
+++ b/SOURCES/0006-UTIL-Use-a-custom-PID_PATH-and-DB_PATH-when-unit-tes.patch
@@ -0,0 +1,80 @@
+From a2fbe2b9de23e91835c10153d048c1b0c5ec7fee Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 3 Oct 2014 16:09:38 +0200
+Subject: [PATCH 06/22] UTIL: Use a custom PID_PATH and DB_PATH when unit
+ testing server.c
+
+server.c used hardcoded PID_PATH and DB_PATH from config.h. Normally,
+this path resides in a system directory (like /var/) and should not be
+written to by tests. In order to specify a different one for tests, we
+need to conditionalize normal builds and unit test builds.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/util/server.c | 35 +++++++++++++++++++++++++++++++----
+ 1 file changed, 31 insertions(+), 4 deletions(-)
+
+diff --git a/src/util/server.c b/src/util/server.c
+index a908470cdcf2cb85a6742e44905ae12d136c83d5..03f4b9588e6c5322d9b68b8cac90128bcb5cfcb6 100644
+--- a/src/util/server.c
++++ b/src/util/server.c
+@@ -411,6 +411,32 @@ errno_t server_common_rotate_logs(struct confdb_ctx *confdb,
+     return EOK;
+ }
+ 
++static const char *get_db_path(void)
++{
++#ifdef UNIT_TESTING
++#ifdef TEST_DB_PATH
++    return TEST_DB_PATH;
++#else
++    #error "TEST_DB_PATH must be defined when unit testing server.c!"
++#endif /* TEST_DB_PATH */
++#else
++    return DB_PATH;
++#endif /* UNIT_TESTING */
++}
++
++static const char *get_pid_path(void)
++{
++#ifdef UNIT_TESTING
++#ifdef TEST_PID_PATH
++    return TEST_PID_PATH;
++#else
++    #error "TEST_PID_PATH must be defined when unit testing server.c!"
++#endif /* TEST_PID_PATH */
++#else
++    return PID_PATH;
++#endif
++}
++
+ int server_setup(const char *name, int flags,
+                  uid_t uid, gid_t gid,
+                  const char *conf_entry,
+@@ -468,10 +494,10 @@ int server_setup(const char *name, int flags,
+     }
+ 
+     if (flags & FLAGS_PID_FILE) {
+-        ret = pidfile(PID_PATH, name);
++        ret = pidfile(get_pid_path(), name);
+         if (ret != EOK) {
+-            DEBUG(SSSDBG_FATAL_FAILURE, "Error creating pidfile: %s/%s! "
+-                  "(%d [%s])\n", PID_PATH, name, ret, strerror(ret));
++            DEBUG(SSSDBG_FATAL_FAILURE, "Error creating pidfile: %s/%s.pid! "
++                  "(%d [%s])\n", get_pid_path(), name, ret, strerror(ret));
+             return ret;
+         }
+     }
+@@ -513,7 +539,8 @@ int server_setup(const char *name, int flags,
+     ctx->parent_pid = getppid();
+     ctx->event_ctx = event_ctx;
+ 
+-    conf_db = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
++    conf_db = talloc_asprintf(ctx, "%s/%s",
++                              get_db_path(), CONFDB_FILE);
+     if (conf_db == NULL) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, aborting!\n");
+         return ENOMEM;
+-- 
+1.9.3
+
diff --git a/SOURCES/0007-TESTS-Unit-tests-can-use-confdb-without-using-sysdb.patch b/SOURCES/0007-TESTS-Unit-tests-can-use-confdb-without-using-sysdb.patch
new file mode 100644
index 0000000..baf9afa
--- /dev/null
+++ b/SOURCES/0007-TESTS-Unit-tests-can-use-confdb-without-using-sysdb.patch
@@ -0,0 +1,85 @@
+From 9dd73e9ad92b2905271cd5466ac237c829f1a608 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 3 Oct 2014 16:11:08 +0200
+Subject: [PATCH 07/22] TESTS: Unit tests can use confdb without using sysdb
+
+Previously, if a test used the utility functions for setting up a test,
+it had to use both sysdb and confdb. Some unit tests only need to use of
+of them, for example the unit tests for the server module only need
+confdb.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/tests/common_dom.c | 52 +++++++++++++++++++++++++++-----------------------
+ 1 file changed, 28 insertions(+), 24 deletions(-)
+
+diff --git a/src/tests/common_dom.c b/src/tests/common_dom.c
+index b96db8d9084fea9ec07be88d9c5f72c6885d8f09..bc69c5a093e17fc56e42ccedd998ab6434d85003 100644
+--- a/src/tests/common_dom.c
++++ b/src/tests/common_dom.c
+@@ -159,34 +159,38 @@ void test_dom_suite_cleanup(const char *tests_path,
+         return;
+     }
+ 
+-    conf_db = talloc_asprintf(tmp_ctx, "%s/%s", tests_path, confdb_path);
+-    if (!conf_db) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not construct conf_db path\n");
+-        goto done;
+-    }
++    if (confdb_path != NULL) {
++        conf_db = talloc_asprintf(tmp_ctx, "%s/%s", tests_path, confdb_path);
++        if (!conf_db) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                "Could not construct conf_db path\n");
++            goto done;
++        }
+ 
+-    errno = 0;
+-    ret = unlink(conf_db);
+-    if (ret != 0 && errno != ENOENT) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not delete the test config ldb file (%d) (%s)\n",
+-               errno, strerror(errno));
++        errno = 0;
++        ret = unlink(conf_db);
++        if (ret != 0 && errno != ENOENT) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                "Could not delete the test config ldb file (%d) (%s)\n",
++                errno, strerror(errno));
++        }
+     }
+ 
+-    sys_db = talloc_asprintf(tmp_ctx, "%s/%s", tests_path, sysdb_path);
+-    if (!sys_db) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not construct sys_db path\n");
+-        goto done;
+-    }
++    if (sysdb_path != NULL) {
++        sys_db = talloc_asprintf(tmp_ctx, "%s/%s", tests_path, sysdb_path);
++        if (!sys_db) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                "Could not construct sys_db path\n");
++            goto done;
++        }
+ 
+-    errno = 0;
+-    ret = unlink(sys_db);
+-    if (ret != 0 && errno != ENOENT) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not delete the test ldb file (%d) (%s)\n",
+-               errno, strerror(errno));
++        errno = 0;
++        ret = unlink(sys_db);
++        if (ret != 0 && errno != ENOENT) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                "Could not delete the test ldb file (%d) (%s)\n",
++                errno, strerror(errno));
++        }
+     }
+ 
+     errno = 0;
+-- 
+1.9.3
+
diff --git a/SOURCES/0007-do-not-use-default_domain_suffix-with-autofs.patch b/SOURCES/0007-do-not-use-default_domain_suffix-with-autofs.patch
deleted file mode 100644
index d10d47d..0000000
--- a/SOURCES/0007-do-not-use-default_domain_suffix-with-autofs.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From b7c339c616e88c0e8db5c5a653dacdedf19a147a Mon Sep 17 00:00:00 2001
-From: Aron Parsons <parsonsa@bit-sys.com>
-Date: Wed, 6 Nov 2013 15:18:54 +0000
-Subject: [PATCH 7/7] do not use default_domain_suffix with autofs
-
----
- src/responder/autofs/autofssrv_cmd.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
-index e9168ea8f85cbaf9e934b44838d17360024a2bc1..4c5bda01d4abd967e8cd8260904f34546b898d99 100644
---- a/src/responder/autofs/autofssrv_cmd.c
-+++ b/src/responder/autofs/autofssrv_cmd.c
-@@ -435,7 +435,7 @@ setautomntent_send(TALLOC_CTX *mem_ctx,
-     state->dctx = dctx;
- 
-     ret = sss_parse_name_for_domains(state, client->rctx->domains,
--                                     client->rctx->default_domain, rawname,
-+                                     NULL, rawname,
-                                      &domname, &state->mapname);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE,
--- 
-1.8.4.2
-
diff --git a/SOURCES/0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch b/SOURCES/0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch
deleted file mode 100644
index c51c590..0000000
--- a/SOURCES/0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From bd24c6f485ac1421053167eabd6e5e963829403b Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 25 Nov 2013 13:43:30 +0100
-Subject: [PATCH 8/9] SYSDB: Sanitize filter before sysdb_search_groups
-
-sysdb_delete_user fails with EIO if user does not exist and contains
-backslashes.
-ldb could not parse filter (&(objectclass=group)(ghost=usr\\\\001)),
-because ghost value was not sanitized
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2163
----
- src/db/sysdb_ops.c      | 9 ++++++++-
- src/tests/sysdb-tests.c | 5 +++++
- 2 files changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 094c27b7f478e0a53a3b6666c727e86eb36a249e..eb88cd256d0c2e45e1528e8a867e42354215cc7f 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -2539,6 +2539,7 @@ int sysdb_delete_user(struct sysdb_ctx *sysdb,
-     struct ldb_message *msg;
-     int ret;
-     int i;
-+    char *sanitized_name;
- 
-     tmp_ctx = talloc_new(NULL);
-     if (!tmp_ctx) {
-@@ -2578,7 +2579,13 @@ int sysdb_delete_user(struct sysdb_ctx *sysdb,
-         }
-     } else if (ret == ENOENT && name != NULL) {
-         /* Perhaps a ghost user? */
--        filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_GHOST, name);
-+        ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
-+        if (ret != EOK) {
-+            goto fail;
-+        }
-+
-+        filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
-+                                          SYSDB_GHOST, sanitized_name);
-         if (filter == NULL) {
-             ret = ENOMEM;
-             goto fail;
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index 1c28526e06df012b8749e1540e70a27948c17ab2..bf964fd76d33bbceac6c1846db7a5011db1375f5 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -3998,6 +3998,11 @@ START_TEST(test_odd_characters)
-     fail_unless(ret == EOK, "sysdb_delete_user error [%d][%s]",
-                             ret, strerror(ret));
- 
-+    /* Delete non existing User */
-+    ret = sysdb_delete_user(test_ctx->sysdb, test_ctx->domain,
-+                            odd_username, 10000);
-+    fail_unless(ret == ENOENT, "sysdb_delete_user error [%d][%s]",
-+                               ret, strerror(ret));
- 
-     /* Delete Group */
-     ret = sysdb_delete_group(test_ctx->sysdb, test_ctx->domain,
--- 
-1.8.4.2
-
diff --git a/SOURCES/0008-TESTS-Add-std-gnu99-to-cwrap-tests-CFLAGS.patch b/SOURCES/0008-TESTS-Add-std-gnu99-to-cwrap-tests-CFLAGS.patch
new file mode 100644
index 0000000..f3bf0c4
--- /dev/null
+++ b/SOURCES/0008-TESTS-Add-std-gnu99-to-cwrap-tests-CFLAGS.patch
@@ -0,0 +1,33 @@
+From b4c6efddae7159a08ece5b2d94aabf7a629c0455 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Tue, 14 Oct 2014 18:02:47 +0100
+Subject: [PATCH 08/22] TESTS: Add -std=gnu99 to cwrap tests CFLAGS
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+../../../../src/tests/cwrap/../../../src/util/domain_info_utils.c: In function ‘subdomain_enumerates’:
+../../../../src/tests/cwrap/../../../src/util/domain_info_utils.c:77:9: error: ‘for’ loop initial declarations are only allowed in C99 mode
+         for (int i=0; parent->sd_enumerate[i]; i++) {
+         ^
+../../../../src/tests/cwrap/../../../src/util/domain_info_utils.c:77:9: note: use option -std=c99 or -std=gnu99 to compile your code
+make[3]: *** [../../../src/util/server_tests-domain_info_utils.o] Error 1
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/tests/cwrap/Makefile.am | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 34aec92c197a60c47067c72df9c8f3644e1a3c45..96b9a52435d9e80bea3ec132cc86c3e6abd0adf2 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -1,4 +1,5 @@
+ AM_CPPFLAGS = \
++    -std=gnu99 \
+     -Wall \
+     -I$(top_srcdir)/src \
+     -I. \
+-- 
+1.9.3
+
diff --git a/SOURCES/0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch b/SOURCES/0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch
deleted file mode 100644
index ac80bac..0000000
--- a/SOURCES/0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch
+++ /dev/null
@@ -1,85 +0,0 @@
-From 0a509d518dd5d17e32e3a4c34b319a38210ba17b Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 25 Nov 2013 16:01:59 +0100
-Subject: [PATCH 9/9] SYSDB: Sanitize filter before removing ghost attrs
-
-sysdb_add_user fails with EIO if enumeration is disabled and user contains
-backslashes.
-We try to remove ghost attributes from groups with disabled enumeration,
-but unsanitized filter is used to find ghost attributes
-"(|(ghost=usr\\\\002)" and ldb cannot parse this filter.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2163
----
- src/db/sysdb_ops.c      |  9 ++++++++-
- src/tests/sysdb-tests.c | 19 +++++++++++++++++++
- 2 files changed, 27 insertions(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index eb88cd256d0c2e45e1528e8a867e42354215cc7f..890bf1eb3cc5fc0b6eb6f7a145aee6d87945cd8d 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -1091,6 +1091,7 @@ sysdb_remove_ghostattr_from_groups(struct sysdb_ctx *sysdb,
-     struct ldb_dn *tmpdn;
-     const char *group_attrs[] = {SYSDB_NAME, SYSDB_GHOST, SYSDB_ORIG_MEMBER, NULL};
-     const char *userdn;
-+    char *sanitized_name;
-     char *filter;
-     errno_t ret = EOK;
-     size_t group_count = 0;
-@@ -1101,7 +1102,13 @@ sysdb_remove_ghostattr_from_groups(struct sysdb_ctx *sysdb,
-         return ENOENT;
-     }
- 
--    filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)", SYSDB_GHOST, name);
-+    ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)",
-+                                      SYSDB_GHOST, sanitized_name);
-     if (!filter) {
-         ret = ENOMEM;
-         goto done;
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index bf964fd76d33bbceac6c1846db7a5011db1375f5..ddbf6f28fd5024945fedcb3c6e2122948c4f1459 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -3900,6 +3900,8 @@ START_TEST(test_odd_characters)
-     struct ldb_message *msg;
-     const struct ldb_val *val;
-     const char odd_username[] = "*(odd)\\user,name";
-+    const char odd_username_orig_dn[] =
-+        "\\2a\\28odd\\29\\5cuser,name,cn=users,dc=example,dc=com";
-     const char odd_groupname[] = "*(odd\\*)\\group,name";
-     const char odd_netgroupname[] = "*(odd\\*)\\netgroup,name";
-     const char *received_user;
-@@ -4010,6 +4012,23 @@ START_TEST(test_odd_characters)
-     fail_unless(ret == EOK, "sysdb_delete_group error [%d][%s]",
-                             ret, strerror(ret));
- 
-+    /* Add */
-+    ret = sysdb_add_user(test_ctx->sysdb,
-+                         test_ctx->domain,
-+                         odd_username,
-+                         10000, 0,
-+                         "","","",
-+                         odd_username_orig_dn,
-+                         NULL, 5400, 0);
-+    fail_unless(ret == EOK, "sysdb_add_user error [%d][%s]",
-+                            ret, strerror(ret));
-+
-+    /* Delete User */
-+    ret = sysdb_delete_user(test_ctx->sysdb, test_ctx->domain,
-+                            odd_username, 10000);
-+    fail_unless(ret == EOK, "sysdb_delete_user error [%d][%s]",
-+                            ret, strerror(ret));
-+
-     /* ===== Netgroups ===== */
-     /* Add */
-     ret = sysdb_add_netgroup(test_ctx->sysdb, test_ctx->domain,
--- 
-1.8.4.2
-
diff --git a/SOURCES/0009-TESTS-Unit-tests-for-server_setup.patch b/SOURCES/0009-TESTS-Unit-tests-for-server_setup.patch
new file mode 100644
index 0000000..384197a
--- /dev/null
+++ b/SOURCES/0009-TESTS-Unit-tests-for-server_setup.patch
@@ -0,0 +1,322 @@
+From dd8c2ad0efbd6bb4d1f942ce45e3b87d5ecb83b7 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 3 Oct 2014 16:12:01 +0200
+Subject: [PATCH 09/22] TESTS: Unit tests for server_setup
+
+We changed server_setup, so we must make sure the function continues to
+work as expected.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/tests/cwrap/Makefile.am   |  63 ++++++++++++-
+ src/tests/cwrap/test_server.c | 204 ++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 266 insertions(+), 1 deletion(-)
+ create mode 100644 src/tests/cwrap/test_server.c
+
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 96b9a52435d9e80bea3ec132cc86c3e6abd0adf2..28d60e7f5bc346543f51740ec4b2781a99a48909 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -3,7 +3,10 @@ AM_CPPFLAGS = \
+     -Wall \
+     -I$(top_srcdir)/src \
+     -I. \
++    -DLOCALEDIR=\"$(localedir)\" \
++    -DVARDIR=\"$(localstatedir)\" \
+     $(DBUS_CFLAGS) \
++    $(GLIB2_CFLAGS) \
+     $(NULL)
+ 
+ TESTS_ENVIRONMENT = \
+@@ -16,6 +19,20 @@ dist_noinst_SCRIPTS = \
+     cwrap_test_setup.sh \
+     $(NULL)
+ 
++SSSD_LIBS = \
++    $(TALLOC_LIBS) \
++    $(TEVENT_LIBS) \
++    $(POPT_LIBS) \
++    $(LDB_LIBS) \
++    $(DBUS_LIBS) \
++    $(PCRE_LIBS) \
++    $(INI_CONFIG_LIBS) \
++    $(COLLECTION_LIBS) \
++    $(DHASH_LIBS) \
++    $(SSS_CRYPT_LIBS) \
++    $(OPENLDAP_LIBS) \
++    $(TDB_LIBS)
++
+ dist_noinst_DATA = \
+     group \
+     passwd \
+@@ -25,7 +42,10 @@ check_PROGRAMS =
+ if HAVE_CMOCKA
+ if HAVE_NSS_WRAPPER
+ if HAVE_UID_WRAPPER
+-check_PROGRAMS += become_user-tests
++check_PROGRAMS = \
++	become_user-tests \
++	server-tests \
++	$(NULL)
+ endif # HAVE_UID_WRAPPER
+ endif # HAVE_NSS_WRAPPER
+ endif # HAVE_CMOCKA
+@@ -45,4 +65,45 @@ become_user_tests_LDADD = \
+     $(abs_top_builddir)/libsss_test_common.la \
+     $(NULL)
+ 
++server_tests_SOURCES = \
++    test_server.c \
++    ../../../src/util/server.c \
++    ../../../src/util/become_user.c \
++    ../../../src/util/backup_file.c \
++    ../../../src/util/domain_info_utils.c \
++    ../../../src/util/atomic_io.c \
++    ../../../src/util/signal.c \
++    ../../../src/util/util.c \
++    ../../../src/util/strtonum.c \
++    ../../../src/util/util_errors.c \
++    ../../../src/util/safe-format-string.c \
++    ../../../src/util/sss_tc_utf8.c \
++    ../../../src/util/sss_utf8.c \
++    ../../../src/util/usertools.c \
++    ../../../src/confdb/confdb.c \
++    ../../../src/db/sysdb.c \
++    ../../../src/db/sysdb_upgrade.c \
++    ../../../src/db/sysdb_ops.c \
++    ../../../src/db/sysdb_search.c \
++    ../../../src/db/sysdb_autofs.c \
++    ../../../src/db/sysdb_services.c \
++    ../../../src/db/sysdb_views.c \
++    $(NULL)
++server_tests_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(LIBCAPNG_CFLAGS) \
++    -DTEST_DB_PATH=\"server_tests\" \
++    -DTEST_PID_PATH=\"server_tests\" \
++    -DUNIT_TESTING \
++    $(NULL)
++server_tests_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(LIBCAPNG_LIBS) \
++    $(UNICODE_LIBS) \
++    $(SSSD_LIBS) \
++    $(abs_top_builddir)/libsss_debug.la \
++    $(abs_top_builddir)/libsss_crypt.la \
++    $(abs_top_builddir)/libsss_test_common.la \
++    $(NULL)
++
+ tests: $(check_PROGRAMS)
+diff --git a/src/tests/cwrap/test_server.c b/src/tests/cwrap/test_server.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..26ecfee1e189b6a474ae52fdbfff6b8922b3f0d7
+--- /dev/null
++++ b/src/tests/cwrap/test_server.c
+@@ -0,0 +1,204 @@
++/*
++    Authors:
++        Jakub Hrozek <jhrozek@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    SSSD tests: Server instantiation
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <popt.h>
++#include "util/util.h"
++#include "tests/cmocka/common_mock.h"
++
++static void wait_for_fg_server(pid_t pid)
++{
++    pid_t wpid;
++    int status;
++
++    assert_int_not_equal(pid, -1);
++
++    wpid = waitpid(pid, &status, 0);
++    assert_int_equal(wpid, pid);
++    assert_true(WIFEXITED(status));
++    assert_int_equal(WEXITSTATUS(status), 0);
++}
++
++static void wait_for_bg_server(const char *pidfile)
++{
++    int fd;
++    long tmp;
++    char buf[16];
++    pid_t pid;
++    int ret;
++    int count;
++
++    count = 0;
++    do {
++        struct stat sb;
++
++        count++;
++        if (count > 100) {
++            break;
++        }
++
++        ret = stat(pidfile, &sb);
++        usleep(50);
++    } while (ret != 0);
++
++    /* read the pidfile */
++    fd = open(pidfile, O_RDONLY);
++    assert_false(fd < 0);
++
++    ret = read(fd, buf, sizeof(buf));
++    close(fd);
++    assert_false(ret <= 0);
++
++    buf[sizeof(buf) - 1] = '\0';
++
++    tmp = strtol(buf, NULL, 10);
++    assert_false(tmp == 0 || tmp > 0xFFFF || errno == ERANGE);
++
++    pid = (pid_t) (tmp & 0xFFFF);
++
++    /* Make sure the daemon goes away! */
++    ret = kill(pid, SIGTERM);
++    fprintf(stderr, "killing %u\n", pid);
++    assert_true(ret == 0);
++
++    unlink(pidfile);
++}
++
++void test_run_as_root_fg(void **state)
++{
++    int ret;
++    struct main_context *main_ctx;
++    pid_t pid;
++
++    /* Must root as root, real or fake */
++    assert_int_equal(geteuid(), 0);
++
++    pid = fork();
++    if (pid == 0) {
++        ret = server_setup(__FUNCTION__, 0, 0, 0,
++                           __FUNCTION__, &main_ctx);
++        assert_int_equal(ret, 0);
++        exit(0);
++    }
++    wait_for_fg_server(pid);
++}
++
++void test_run_as_sssd_fg(void **state)
++{
++    int ret;
++    struct main_context *main_ctx;
++    struct passwd *sssd;
++    pid_t pid;
++
++    /* Must root as root, real or fake */
++    assert_int_equal(geteuid(), 0);
++
++    sssd = getpwnam("sssd");
++    assert_non_null(sssd);
++
++    pid = fork();
++    if (pid == 0) {
++        ret = server_setup(__FUNCTION__, 0, sssd->pw_uid, sssd->pw_gid,
++                           __FUNCTION__, &main_ctx);
++        assert_int_equal(ret, 0);
++        exit(0);
++    }
++    wait_for_fg_server(pid);
++}
++
++void test_run_as_root_daemon(void **state)
++{
++    int ret;
++    struct main_context *main_ctx;
++    pid_t pid;
++    char *pidfile;
++
++    /* Must root as root, real or fake */
++    assert_int_equal(geteuid(), 0);
++
++    pidfile = talloc_asprintf(NULL, "%s/%s.pid", TEST_PID_PATH, __FUNCTION__);
++
++    /* Make sure there are no leftovers */
++    unlink(pidfile);
++
++    pid = fork();
++    if (pid == 0) {
++        ret = server_setup(__FUNCTION__, FLAGS_PID_FILE,
++                           0, 0, __FUNCTION__, &main_ctx);
++        assert_int_equal(ret, 0);
++
++        server_loop(main_ctx);
++        exit(0);
++    }
++
++    wait_for_bg_server(pidfile);
++    talloc_free(pidfile);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    int rv;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test(test_run_as_root_fg),
++        unit_test(test_run_as_sssd_fg),
++        unit_test(test_run_as_root_daemon),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    /* Even though normally the tests should clean up after themselves
++     * they might not after a failed run. Remove the old db to be sure */
++    tests_set_cwd();
++    test_dom_suite_cleanup(TEST_DB_PATH, CONFDB_FILE, NULL);
++    test_dom_suite_setup(TEST_DB_PATH);
++
++    rv = run_tests(tests);
++    test_dom_suite_cleanup(TEST_DB_PATH, CONFDB_FILE, NULL);
++
++    return rv;
++}
+-- 
+1.9.3
+
diff --git a/SOURCES/0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch b/SOURCES/0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch
deleted file mode 100644
index 3d4f47b..0000000
--- a/SOURCES/0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch
+++ /dev/null
@@ -1,301 +0,0 @@
-From 26f41ed62ab74d628764702a1522cedd22b55599 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 1 Oct 2013 17:44:07 +0200
-Subject: [PATCH 10/11] LDAP: Split out a request to search for a user w/o
- saving
-
-Related:
-https://fedorahosted.org/sssd/ticket/2077
-
-Certain situations require that a user entry is downloaded for further
-inpection, but not saved to the sysdb right away. This patch splits the
-previously monolithic request into one that just downloads the data and
-one that uses the new one to download and save the user.
----
- src/providers/ldap/sdap_async.h       |  16 ++++
- src/providers/ldap/sdap_async_users.c | 162 +++++++++++++++++++++++++++-------
- 2 files changed, 146 insertions(+), 32 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index c8031c9a9d527a6d808f1ddce096de23850ebfd6..dbf572cdc82b100ba9c26b4853f05db1ba5fa4ed 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -58,6 +58,22 @@ errno_t sdap_connect_host_recv(TALLOC_CTX *mem_ctx,
-                                struct tevent_req *req,
-                                struct sdap_handle **_sh);
- 
-+/* Search users in LDAP, return them as attrs */
-+struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
-+                                         struct tevent_context *ev,
-+                                         struct sss_domain_info *dom,
-+                                         struct sdap_options *opts,
-+                                         struct sdap_search_base **search_bases,
-+                                         struct sdap_handle *sh,
-+                                         const char **attrs,
-+                                         const char *filter,
-+                                         int timeout,
-+                                         bool enumeration);
-+int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req,
-+                          char **higher_usn, struct sysdb_attrs ***users,
-+                          size_t *count);
-+
-+/* Search users in LDAP using the request above, save them to cache */
- struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
-                                        struct tevent_context *ev,
-                                        struct sss_domain_info *dom,
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index 9cfe217482580d4a11ad4ace2f688f42ca55d7b3..7f0b2eea0b5ee909bcf148236c7fc43863fe8c13 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -579,15 +579,15 @@ done:
- 
- /* ==Search-Users-with-filter============================================= */
- 
--struct sdap_get_users_state {
-+struct sdap_search_user_state {
-     struct tevent_context *ev;
-     struct sdap_options *opts;
-     struct sdap_handle *sh;
-     struct sss_domain_info *dom;
--    struct sysdb_ctx *sysdb;
-+
-     const char **attrs;
-     const char *base_filter;
--    char *filter;
-+    const char *filter;
-     int timeout;
-     bool enumeration;
- 
-@@ -599,33 +599,31 @@ struct sdap_get_users_state {
-     struct sdap_search_base **search_bases;
- };
- 
--static errno_t sdap_get_users_next_base(struct tevent_req *req);
--static void sdap_get_users_process(struct tevent_req *subreq);
-+static errno_t sdap_search_user_next_base(struct tevent_req *req);
-+static void sdap_search_user_process(struct tevent_req *subreq);
- 
--struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
--                                       struct tevent_context *ev,
--                                       struct sss_domain_info *dom,
--                                       struct sysdb_ctx *sysdb,
--                                       struct sdap_options *opts,
--                                       struct sdap_search_base **search_bases,
--                                       struct sdap_handle *sh,
--                                       const char **attrs,
--                                       const char *filter,
--                                       int timeout,
--                                       bool enumeration)
-+struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
-+                                         struct tevent_context *ev,
-+                                         struct sss_domain_info *dom,
-+                                         struct sdap_options *opts,
-+                                         struct sdap_search_base **search_bases,
-+                                         struct sdap_handle *sh,
-+                                         const char **attrs,
-+                                         const char *filter,
-+                                         int timeout,
-+                                         bool enumeration)
- {
-     errno_t ret;
-     struct tevent_req *req;
--    struct sdap_get_users_state *state;
-+    struct sdap_search_user_state *state;
- 
--    req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
--    if (!req) return NULL;
-+    req = tevent_req_create(memctx, &state, struct sdap_search_user_state);
-+    if (req == NULL) return NULL;
- 
-     state->ev = ev;
-     state->opts = opts;
-     state->dom = dom;
-     state->sh = sh;
--    state->sysdb = sysdb;
-     state->attrs = attrs;
-     state->higher_usn = NULL;
-     state->users =  NULL;
-@@ -643,7 +641,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
-         goto done;
-     }
- 
--    ret = sdap_get_users_next_base(req);
-+    ret = sdap_search_user_next_base(req);
- 
- done:
-     if (ret != EOK) {
-@@ -654,18 +652,18 @@ done:
-     return req;
- }
- 
--static errno_t sdap_get_users_next_base(struct tevent_req *req)
-+static errno_t sdap_search_user_next_base(struct tevent_req *req)
- {
-     struct tevent_req *subreq;
--    struct sdap_get_users_state *state;
-+    struct sdap_search_user_state *state;
- 
--    state = tevent_req_data(req, struct sdap_get_users_state);
-+    state = tevent_req_data(req, struct sdap_search_user_state);
- 
-     talloc_zfree(state->filter);
-     state->filter = sdap_get_id_specific_filter(state,
-                         state->base_filter,
-                         state->search_bases[state->base_iter]->filter);
--    if (!state->filter) {
-+    if (state->filter == NULL) {
-         return ENOMEM;
-     }
- 
-@@ -681,20 +679,20 @@ static errno_t sdap_get_users_next_base(struct tevent_req *req)
-             state->opts->user_map, SDAP_OPTS_USER,
-             state->timeout,
-             state->enumeration); /* If we're enumerating, we need paging */
--    if (!subreq) {
-+    if (subreq == NULL) {
-         return ENOMEM;
-     }
--    tevent_req_set_callback(subreq, sdap_get_users_process, req);
-+    tevent_req_set_callback(subreq, sdap_search_user_process, req);
- 
-     return EOK;
- }
- 
--static void sdap_get_users_process(struct tevent_req *subreq)
-+static void sdap_search_user_process(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct sdap_get_users_state *state = tevent_req_data(req,
--                                            struct sdap_get_users_state);
-+    struct sdap_search_user_state *state = tevent_req_data(req,
-+                                            struct sdap_search_user_state);
-     int ret;
-     size_t count, i;
-     struct sysdb_attrs **users;
-@@ -744,7 +742,7 @@ static void sdap_get_users_process(struct tevent_req *subreq)
-         state->base_iter++;
-         if (state->search_bases[state->base_iter]) {
-             /* There are more search bases to try */
--            ret = sdap_get_users_next_base(req);
-+            ret = sdap_search_user_next_base(req);
-             if (ret != EOK) {
-                 tevent_req_error(req, ret);
-             }
-@@ -760,12 +758,112 @@ static void sdap_get_users_process(struct tevent_req *subreq)
-         return;
-     }
- 
-+    DEBUG(SSSDBG_TRACE_ALL, ("Retrieved total %zu users\n", state->count));
-+    tevent_req_done(req);
-+}
-+
-+
-+int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req,
-+                          char **higher_usn, struct sysdb_attrs ***users,
-+                          size_t *count)
-+{
-+    struct sdap_search_user_state *state = tevent_req_data(req,
-+                                            struct sdap_search_user_state);
-+
-+    if (higher_usn) {
-+        *higher_usn = talloc_steal(memctx, state->higher_usn);
-+    }
-+
-+    if (users) {
-+        *users = talloc_steal(memctx, state->users);
-+    }
-+
-+    if (count) {
-+        *count = state->count;
-+    }
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-+
-+/* ==Search-And-Save-Users-with-filter============================================= */
-+struct sdap_get_users_state {
-+    struct sysdb_ctx *sysdb;
-+    struct sdap_options *opts;
-+    struct sss_domain_info *dom;
-+
-+    char *higher_usn;
-+    struct sysdb_attrs **users;
-+    size_t count;
-+};
-+
-+static void sdap_get_users_done(struct tevent_req *subreq);
-+
-+struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
-+                                       struct tevent_context *ev,
-+                                       struct sss_domain_info *dom,
-+                                       struct sysdb_ctx *sysdb,
-+                                       struct sdap_options *opts,
-+                                       struct sdap_search_base **search_bases,
-+                                       struct sdap_handle *sh,
-+                                       const char **attrs,
-+                                       const char *filter,
-+                                       int timeout,
-+                                       bool enumeration)
-+{
-+    errno_t ret;
-+    struct tevent_req *req;
-+    struct tevent_req *subreq;
-+    struct sdap_get_users_state *state;
-+
-+    req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
-+    if (!req) return NULL;
-+
-+    state->sysdb = sysdb;
-+    state->opts = opts;
-+    state->dom = dom;
-+
-+    subreq = sdap_search_user_send(state, ev, dom, opts, search_bases,
-+                                   sh, attrs, filter, timeout, enumeration);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    tevent_req_set_callback(subreq, sdap_get_users_done, req);
-+
-+    ret = EOK;
-+done:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        tevent_req_post(req, ev);
-+    }
-+
-+    return req;
-+}
-+
-+static void sdap_get_users_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_get_users_state *state = tevent_req_data(req,
-+                                            struct sdap_get_users_state);
-+    int ret;
-+
-+    ret = sdap_search_user_recv(state, subreq, &state->higher_usn,
-+                                &state->users, &state->count);
-+    if (ret) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Failed to retrieve users\n"));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-     ret = sdap_save_users(state, state->sysdb,
-                           state->dom, state->opts,
-                           state->users, state->count,
-                           &state->higher_usn);
-     if (ret) {
--        DEBUG(2, ("Failed to store users.\n"));
-+        DEBUG(SSSDBG_OP_FAILURE, ("Failed to store users.\n"));
-         tevent_req_error(req, ret);
-         return;
-     }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0010-RPM-Package-the-libsss_semanage.so-library.patch b/SOURCES/0010-RPM-Package-the-libsss_semanage.so-library.patch
new file mode 100644
index 0000000..1e8e2b6
--- /dev/null
+++ b/SOURCES/0010-RPM-Package-the-libsss_semanage.so-library.patch
@@ -0,0 +1,28 @@
+From e1daa56df4c15874ae60c4bf4f2422d39d3a1654 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 Oct 2014 22:22:09 +0200
+Subject: [PATCH 10/22] RPM: Package the libsss_semanage.so library
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ contrib/sssd.spec.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index 529304205274ad39e4281e3d298222420d5eb439..74f7e950518841ec3cbd6e3fb4edf2eb873c7704 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -589,6 +589,7 @@ rm -rf $RPM_BUILD_ROOT
+ %{_libdir}/%{name}/libsss_debug.so
+ %{_libdir}/%{name}/libsss_ldap_common.so
+ %{_libdir}/%{name}/libsss_util.so
++%{_libdir}/%{name}/libsss_semanage.so
+ 
+ # 3rd party application libraries
+ %{_libdir}/sssd/modules/libsss_autofs.so
+-- 
+1.9.3
+
diff --git a/SOURCES/0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch b/SOURCES/0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch
deleted file mode 100644
index 11481f6..0000000
--- a/SOURCES/0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch
+++ /dev/null
@@ -1,269 +0,0 @@
-From 8285fdca515e103eed41625a444de6fe72c5daa7 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 1 Oct 2013 17:44:55 +0200
-Subject: [PATCH 11/11] LDAP: Search for original DN during auth if it's
- missing
-
-Resolves: https://fedorahosted.org/sssd/ticket/2077
-
-If during the LDAP authentication we find out that the originalDN to
-bind as is missing (because the ID module is not LDAP based), we can try
-to look up the user from LDAP without saving him just in order to
-receive the originalDN.
----
- src/providers/ldap/ldap_auth.c | 210 +++++++++++++++++++++++++++++++++++++----
- 1 file changed, 194 insertions(+), 16 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index f9bab4b2b72a061c88fbf18d3f8401b673f79619..ddaeb09c8ae06812855a1daec2fc3399eb4be361 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -343,6 +343,146 @@ shadow_fail:
- }
- 
- /* ==Get-User-DN========================================================== */
-+struct get_user_dn_state {
-+    const char *username;
-+
-+    char *orig_dn;
-+};
-+
-+static void get_user_dn_done(struct tevent_req *subreq);
-+
-+static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
-+                                           struct tevent_context *ev,
-+                                           struct sss_domain_info *domain,
-+                                           struct sdap_handle *sh,
-+                                           struct sdap_options *opts,
-+                                           const char *username)
-+{
-+    struct tevent_req *req;
-+    struct tevent_req *subreq;
-+    struct get_user_dn_state *state;
-+    char *clean_name;
-+    char *filter;
-+    const char **attrs;
-+    errno_t ret;
-+
-+    req = tevent_req_create(memctx, &state, struct get_user_dn_state);
-+    if (!req) return NULL;
-+
-+    state->username = username;
-+
-+    ret = sss_filter_sanitize(state, username, &clean_name);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
-+                             opts->user_map[SDAP_AT_USER_NAME].name,
-+                             clean_name,
-+                             opts->user_map[SDAP_OC_USER].name);
-+    talloc_zfree(clean_name);
-+    if (filter == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Failed to build the base filter\n"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    /* We're mostly interested in the DN anyway */
-+    attrs = talloc_array(state, const char *, 3);
-+    if (attrs == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    attrs[0] = "objectclass";
-+    attrs[1] = opts->user_map[SDAP_AT_USER_NAME].name;
-+    attrs[2] = NULL;
-+
-+    subreq = sdap_search_user_send(state, ev, domain, opts,
-+                                   opts->sdom->user_search_bases,
-+                                   sh, attrs, filter,
-+                                   dp_opt_get_int(opts->basic,
-+                                                  SDAP_SEARCH_TIMEOUT),
-+                                   false);
-+    if (!subreq) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    tevent_req_set_callback(subreq, get_user_dn_done, req);
-+    return req;
-+
-+done:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+    return req;
-+}
-+
-+static void get_user_dn_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct get_user_dn_state *state = tevent_req_data(req,
-+                                                    struct get_user_dn_state);
-+    struct ldb_message_element *el;
-+    struct sysdb_attrs **users;
-+    size_t count;
-+
-+    ret = sdap_search_user_recv(state, subreq, NULL, &users, &count);
-+    talloc_zfree(subreq);
-+    if (ret && ret != ENOENT) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Failed to retrieve users\n"));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    if (count == 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("No such user\n"));
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    } else if (count > 1) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Multiple users matched\n"));
-+        tevent_req_error(req, EIO);
-+        return;
-+    }
-+
-+    /* exactly one user. Get the originalDN */
-+    ret = sysdb_attrs_get_el_ext(users[0], SYSDB_ORIG_DN, false, &el);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("originalDN is not available for [%s].\n", state->username));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    state->orig_dn = talloc_strdup(state, (const char *) el->values[0].data);
-+    if (state->orig_dn == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL, ("Found originalDN [%s] for [%s]\n",
-+          state->orig_dn, state->username));
-+    tevent_req_done(req);
-+}
-+
-+static int get_user_dn_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req,
-+                            char **orig_dn)
-+{
-+    struct get_user_dn_state *state = tevent_req_data(req,
-+                                                    struct get_user_dn_state);
-+
-+    if (orig_dn) {
-+        *orig_dn = talloc_move(mem_ctx, &state->orig_dn);
-+    }
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
- 
- static int get_user_dn(TALLOC_CTX *memctx,
-                        struct sysdb_ctx *sysdb,
-@@ -391,25 +531,20 @@ static int get_user_dn(TALLOC_CTX *memctx,
- 
-     switch (res->count) {
-     case 0:
--        /* FIXME: not in cache, needs a true search */
--        ret = ENOENT;
-+        /* No such user entry? Look it up */
-+        ret = EAGAIN;
-         break;
- 
-     case 1:
-         dn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_ORIG_DN, NULL);
--        if (dn) {
--            dn = talloc_strdup(tmpctx, dn);
--        } else {
--            /* TODO: try to search ldap server ? */
--
--            /* FIXME: remove once we store originalDN on every call
--             * NOTE: this is wrong, works only with some DITs */
--            dn = talloc_asprintf(tmpctx, "%s=%s,%s",
--                                 opts->user_map[SDAP_AT_USER_NAME].name,
--                                 username,
--                                 dp_opt_get_string(opts->basic,
--                                                   SDAP_USER_SEARCH_BASE));
-+        if (dn == NULL) {
-+            /* The user entry has no original DN. This is the case when the ID
-+             * provider is not LDAP-based (proxy perhaps) */
-+            ret = EAGAIN;
-+            break;
-         }
-+
-+        dn = talloc_strdup(tmpctx, dn);
-         if (!dn) {
-             ret = ENOMEM;
-             break;
-@@ -466,6 +601,8 @@ struct auth_state {
- };
- 
- static struct tevent_req *auth_get_server(struct tevent_req *req);
-+static void auth_get_dn_done(struct tevent_req *subreq);
-+static void auth_do_bind(struct tevent_req *req);
- static void auth_resolve_done(struct tevent_req *subreq);
- static void auth_connect_done(struct tevent_req *subreq);
- static void auth_bind_user_done(struct tevent_req *subreq);
-@@ -610,11 +747,52 @@ static void auth_connect_done(struct tevent_req *subreq)
-     ret = get_user_dn(state, state->ctx->be->domain->sysdb, state->ctx->be->domain,
-                       state->ctx->opts, state->username, &state->dn,
-                       &state->pw_expire_type, &state->pw_expire_data);
--    if (ret) {
--        tevent_req_error(req, ret);
-+    if (ret == EOK) {
-+        /* All required user data was pre-cached during an identity lookup.
-+         * We can proceed with the bind */
-+        auth_do_bind(req);
-+        return;
-+    } else if (ret == EAGAIN) {
-+        /* The cached user entry was missing the bind DN. Need to look
-+         * it up based on user name in order to perform the bind */
-+        subreq = get_user_dn_send(req, state->ev, state->ctx->be->domain,
-+                                  state->sh, state->ctx->opts, state->username);
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+        tevent_req_set_callback(subreq, auth_get_dn_done, req);
-+        return;
-+    }
-+
-+    tevent_req_error(req, ret);
-+    return;
-+}
-+
-+static void auth_get_dn_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct auth_state *state = tevent_req_data(req, struct auth_state);
-+    errno_t ret;
-+
-+    ret = get_user_dn_recv(state, subreq, &state->dn);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ERR_ACCOUNT_UNKNOWN);
-         return;
-     }
- 
-+    /* The DN was found with an LDAP lookup
-+     * We can proceed with the bind */
-+    return auth_do_bind(req);
-+}
-+
-+static void auth_do_bind(struct tevent_req *req)
-+{
-+    struct auth_state *state = tevent_req_data(req, struct auth_state);
-+    struct tevent_req *subreq;
-+
-     subreq = sdap_auth_send(state, state->ev, state->sh,
-                             NULL, NULL, state->dn,
-                             state->authtok);
--- 
-1.8.4.2
-
diff --git a/SOURCES/0011-ipa-fix-issues-with-older-servers-not-supporting-vie.patch b/SOURCES/0011-ipa-fix-issues-with-older-servers-not-supporting-vie.patch
new file mode 100644
index 0000000..4e95f7f
--- /dev/null
+++ b/SOURCES/0011-ipa-fix-issues-with-older-servers-not-supporting-vie.patch
@@ -0,0 +1,97 @@
+From d384cf52b5753c2409625eca906474b95edcbe9d Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 22 Oct 2014 10:03:09 +0200
+Subject: [PATCH 11/22] ipa: fix issues with older servers not supporting views
+
+Older FreeIPA servers which do not know about the ipaAssignedIDView
+attribute will return an error during the LDAP dereference request
+because SSSD marks LDAP extensions as critical. In this case we keep the
+view name empty and skip override lookups.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c    | 14 +++++++++++++-
+ src/providers/ipa/ipa_subdomains_id.c |  4 +++-
+ src/providers/ipa/ipa_views.c         | 17 ++++++++++++-----
+ 3 files changed, 28 insertions(+), 7 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index bedc0f1a50e8a35ea65de45247b1814c9abc0bcd..eb172fdfc05ac4e482174f01d89ad28db1498fc1 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -1002,7 +1002,19 @@ static void ipa_get_view_name_done(struct tevent_req *req)
+     ret = sdap_deref_search_with_filter_recv(req, ctx, &reply_count, &reply);
+     talloc_zfree(req);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "get_view_name request failed.\n");
++        if (ret == EOPNOTSUPP) {
++            DEBUG(SSSDBG_TRACE_FUNC, "get_view_name request failed, looks " \
++                                     "like server does not support views.\n");
++            ret = ipa_check_master(ctx);
++            if (ret == EAGAIN) {
++                return;
++            } else if (ret != EOK) {
++                goto done;
++            }
++
++        } else {
++            DEBUG(SSSDBG_OP_FAILURE, "get_view_name request failed.\n");
++        }
+         goto done;
+     }
+ 
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 36f8b239249e5f0146610cfab148be20c39c66c2..b67006ce6e0b4bf9c794016c1dfc923ac6da3624 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -106,11 +106,13 @@ struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
+      * have to check first if the request matches an override in the given
+      * view. But there are cases where this can be skipped and the AD object
+      * can be searched directly:
++     * - if no view is defined, i.e. the server does not supprt views yet
+      * - searches by SID: because we do not override the SID
+      * - if the responder does not send the EXTRA_INPUT_MAYBE_WITH_VIEW flags,
+      *   because in this case the entry was found in the cache and the
+      *   original value is used for the search (e.g. during cache updates) */
+-    if (state->ar->filter_type == BE_FILTER_SECID
++    if (state->ipa_ctx->view_name == NULL
++            || state->ar->filter_type == BE_FILTER_SECID
+             || (!state->ipa_server_mode
+                 && state->ar->extra_value != NULL
+                 && strcmp(state->ar->extra_value,
+diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
+index 33dbf7b1c17f188924ee7b50a77ab699f03392be..2eb77216ab9759d8b1d66fbdf0b2e90cd07a4604 100644
+--- a/src/providers/ipa/ipa_views.c
++++ b/src/providers/ipa/ipa_views.c
+@@ -208,16 +208,23 @@ struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
+     state->sdap_id_ctx = sdap_id_ctx;
+     state->ipa_options = ipa_options;
+     state->ipa_realm = ipa_realm;
+-    if (strcmp(view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
+-        state->ipa_view_name = IPA_DEFAULT_VIEW_NAME;
+-    } else {
+-        state->ipa_view_name = view_name;
+-    }
+     state->ar = ar;
+     state->dp_error = -1;
+     state->override_attrs = NULL;
+     state->filter = NULL;
+ 
++    if (view_name == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL, "View not defined, nothing to do.\n");
++        ret = EOK;
++        goto done;
++    }
++
++    if (strcmp(view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
++        state->ipa_view_name = IPA_DEFAULT_VIEW_NAME;
++    } else {
++        state->ipa_view_name = view_name;
++    }
++
+     state->sdap_op = sdap_id_op_create(state,
+                                        state->sdap_id_ctx->conn->conn_cache);
+     if (state->sdap_op == NULL) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch b/SOURCES/0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch
deleted file mode 100644
index 7c99b36..0000000
--- a/SOURCES/0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 5eea6f1e7a43bdd63a1530fb9c68ef292f431f4f Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 13 Nov 2013 08:32:23 +0100
-Subject: [PATCH 12/12] LDAP: Prevent from using uninitialized sdap_options
-
-ldap_get_options can fail in time of ldap back end initialisation
-and then sssd try to release uninitialised sdap_options.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2147
----
- src/providers/ldap/ldap_init.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
-index 17874b1325d3e5bf2eded62c6f022364b84a5c2a..15615b2891f2e3104c11e8610c081adcd1d1ee8e 100644
---- a/src/providers/ldap/ldap_init.c
-+++ b/src/providers/ldap/ldap_init.c
-@@ -94,7 +94,7 @@ int sssm_ldap_id_init(struct be_ctx *bectx,
-     const char *dns_service_name;
-     const char *sasl_mech;
-     struct sdap_service *sdap_service;
--    struct sdap_options *opts;
-+    struct sdap_options *opts = NULL;
-     int ret;
- 
-     /* If we're already set up, just return that */
--- 
-1.8.4.2
-
diff --git a/SOURCES/0012-ipa-improve-error-reporting-for-extdom-LDAP-exop.patch b/SOURCES/0012-ipa-improve-error-reporting-for-extdom-LDAP-exop.patch
new file mode 100644
index 0000000..8120e60
--- /dev/null
+++ b/SOURCES/0012-ipa-improve-error-reporting-for-extdom-LDAP-exop.patch
@@ -0,0 +1,48 @@
+From de830a6c4b032ec21c2aad9f7b56fd80fe09817b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 20 Oct 2014 17:09:34 +0200
+Subject: [PATCH 12/22] ipa: improve error reporting for extdom LDAP exop
+
+This patch fixes a typo when calling ldap_parse_result() which prevented
+the server-side error message to be used and adds a hint that more
+information might be available on the server side.
+
+Fixes: https://fedorahosted.org/sssd/ticket/2456
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 96528816a520b633f1f1caa975dee9b9515621c3..bd5c00b6a48018f8f904aaa03e8162425651b37a 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -133,7 +133,7 @@ static void ipa_s2n_exop_done(struct sdap_op *op,
+     }
+ 
+     ret = ldap_parse_result(state->sh->ldap, reply->msg,
+-                            &result, &errmsg, NULL, NULL,
++                            &result, NULL, &errmsg, NULL,
+                             NULL, 0);
+     if (ret != LDAP_SUCCESS) {
+         DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed (%d)\n",
+@@ -142,10 +142,13 @@ static void ipa_s2n_exop_done(struct sdap_op *op,
+         goto done;
+     }
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC, "ldap_extended_operation result: %s(%d), %s\n",
+-            sss_ldap_err2string(result), result, errmsg);
++    DEBUG(result == LDAP_SUCCESS ? SSSDBG_TRACE_FUNC : SSSDBG_OP_FAILURE,
++          "ldap_extended_operation result: %s(%d), %s.\n",
++          sss_ldap_err2string(result), result, errmsg);
+ 
+     if (result != LDAP_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldap_extended_operation failed, " \
++                                 "server logs might contain more details.\n");
+         ret = ERR_NETWORK_IO;
+         goto done;
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0013-BUILD-Fix-automake-warning.patch b/SOURCES/0013-BUILD-Fix-automake-warning.patch
new file mode 100644
index 0000000..7c93e71
--- /dev/null
+++ b/SOURCES/0013-BUILD-Fix-automake-warning.patch
@@ -0,0 +1,39 @@
+From 37d4520aea8d02701edc7a2c4d1407430b22860c Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 21 Oct 2014 19:31:24 +0200
+Subject: [PATCH 13/22] BUILD: Fix automake warning
+
+src/tests/cwrap/Makefile.am:45: warning: check_PROGRAMS was already
+        defined in condition TRUE, which includes condition HAVE_CMOCKA
+         and HAVE_NSS_WRAPPER and HAVE_UID_WRAPPER ...
+src/tests/cwrap/Makefile.am:41: ... 'check_PROGRAMS' previously defined here
+
+This patch also replace '\t' with spaces
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/tests/cwrap/Makefile.am | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 28d60e7f5bc346543f51740ec4b2781a99a48909..d1f0e9e1b999814d8081af36f82e94f638452da4 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -42,10 +42,10 @@ check_PROGRAMS =
+ if HAVE_CMOCKA
+ if HAVE_NSS_WRAPPER
+ if HAVE_UID_WRAPPER
+-check_PROGRAMS = \
+-	become_user-tests \
+-	server-tests \
+-	$(NULL)
++check_PROGRAMS += \
++    become_user-tests \
++    server-tests \
++    $(NULL)
+ endif # HAVE_UID_WRAPPER
+ endif # HAVE_NSS_WRAPPER
+ endif # HAVE_CMOCKA
+-- 
+1.9.3
+
diff --git a/SOURCES/0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch b/SOURCES/0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch
deleted file mode 100644
index bc5a348..0000000
--- a/SOURCES/0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 8751aace6de14f3782765a89555b65e991f340a0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Dec 2013 15:25:25 +0100
-Subject: [PATCH 13/15] SUBDOMAINS: Reuse cached results if DP is offline
-
-If Data Provider was unable to refresh the subdomain list, the
-sss_domain_info->subdomains list was NULL. Which meant that no DP
-request matched any known domain and hence offline authentication was
-not working correctly.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2168
----
- src/providers/ad/ad_subdomains.c   | 7 +++++++
- src/providers/ipa/ipa_subdomains.c | 8 ++++++--
- 2 files changed, 13 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 9911dfe0f4fda6749fa6dd3f15b1c04a36964ca4..18414523096ba0e53261415551eea57b4b2758b2 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -650,5 +650,12 @@ int ad_subdom_init(struct be_ctx *be_ctx,
-         return EFAULT;
-     }
- 
-+    ret = sysdb_update_subdomains(be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. "
-+              "Users from trusted domains might not be resolved correctly\n"));
-+        /* Ignore this error and try to discover the subdomains later */
-+    }
-+
-     return EOK;
- }
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 4f7627eddb9c54d68e45be876157057f3c30b422..416e21913be8e991c9f496ff2b54f238b602f304 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -809,8 +809,6 @@ static void ipa_subdomains_get_conn_done(struct tevent_req *req)
-             DEBUG(SSSDBG_MINOR_FAILURE,
-                   ("No IPA server is available, cannot get the "
-                    "subdomain list while offline\n"));
--
--/* FIXME: return saved results ?? */
-         } else {
-             DEBUG(SSSDBG_OP_FAILURE,
-                   ("Failed to connect to IPA server: [%d](%s)\n",
-@@ -1291,6 +1289,12 @@ int ipa_subdom_init(struct be_ctx *be_ctx,
-         DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom offline callback"));
-     }
- 
-+    ret = sysdb_update_subdomains(be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. "
-+              "Users from trusted domains might not be resolved correctly\n"));
-+    }
-+
-     return EOK;
- }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0014-failover-check-dns_domain-if-primary-servers-lookup-.patch b/SOURCES/0014-failover-check-dns_domain-if-primary-servers-lookup-.patch
deleted file mode 100644
index 3da0806..0000000
--- a/SOURCES/0014-failover-check-dns_domain-if-primary-servers-lookup-.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 0926cec5b98218131ac822e1684f9bce7aa0072c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 5 Dec 2013 13:19:16 +0100
-Subject: [PATCH 14/15] failover: check dns_domain if primary servers lookup
- failed
-
-If primary servers lookup failed, dns_domain is not set.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2173
----
- src/providers/fail_over_srv.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/fail_over_srv.c b/src/providers/fail_over_srv.c
-index 543516ef19e288556e39e61b400a628c94e2817b..c27416899e30b3cf8b3c0496adb08089f4b2c11d 100644
---- a/src/providers/fail_over_srv.c
-+++ b/src/providers/fail_over_srv.c
-@@ -302,13 +302,17 @@ static void fo_discover_servers_primary_done(struct tevent_req *subreq)
-     }
- 
-     if (state->backup_domain == NULL) {
-+        /* if there is no backup domain, we are done */
-         DEBUG(SSSDBG_TRACE_FUNC, ("No backup domain specified\n"));
-         goto done;
-     }
- 
--    if (strcasecmp(state->dns_domain, state->backup_domain) == 0) {
--        /* primary domain was unreachable, we will use servers from backup
--         * domain as primary */
-+    if (state->dns_domain != NULL
-+            && strcasecmp(state->dns_domain, state->backup_domain) == 0) {
-+        /* If there was no error and dns_domain is the same as backup domain,
-+         * it means that we were unable to resolve SRV in primary domain, but
-+         * SRV from backup domain was resolved and those servers are considered
-+         * to be primary. We are done. */
-         state->backup_servers = NULL;
-         state->num_backup_servers = 0;
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0014-test_server-Fix-waiting-for-background-process.patch b/SOURCES/0014-test_server-Fix-waiting-for-background-process.patch
new file mode 100644
index 0000000..f4b8270
--- /dev/null
+++ b/SOURCES/0014-test_server-Fix-waiting-for-background-process.patch
@@ -0,0 +1,48 @@
+From 74774cb436fc62d258d9642254f3029397062864 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 21 Oct 2014 20:29:15 +0200
+Subject: [PATCH 14/22] test_server: Fix waiting for background process
+
+A waiting loop for background process was very fast (just 5 milliseconds)
+It caused problem when test was executed with valgrind.
+The maximum time was increased to 10 seconds.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/tests/cwrap/test_server.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/src/tests/cwrap/test_server.c b/src/tests/cwrap/test_server.c
+index 26ecfee1e189b6a474ae52fdbfff6b8922b3f0d7..d0aeac47d0b067fdbc3399037c0a74f150337a23 100644
+--- a/src/tests/cwrap/test_server.c
++++ b/src/tests/cwrap/test_server.c
+@@ -55,12 +55,13 @@ static void wait_for_bg_server(const char *pidfile)
+         struct stat sb;
+ 
+         count++;
+-        if (count > 100) {
++        if (count > 200) {
++            fail();
+             break;
+         }
+ 
+         ret = stat(pidfile, &sb);
+-        usleep(50);
++        usleep(50000);
+     } while (ret != 0);
+ 
+     /* read the pidfile */
+@@ -198,7 +199,9 @@ int main(int argc, const char *argv[])
+     test_dom_suite_setup(TEST_DB_PATH);
+ 
+     rv = run_tests(tests);
+-    test_dom_suite_cleanup(TEST_DB_PATH, CONFDB_FILE, NULL);
++    if (rv != 0) {
++        test_dom_suite_cleanup(TEST_DB_PATH, CONFDB_FILE, NULL);
++    }
+ 
+     return rv;
+ }
+-- 
+1.9.3
+
diff --git a/SOURCES/0015-NSS-Set-packet-length-for-initgroups.patch b/SOURCES/0015-NSS-Set-packet-length-for-initgroups.patch
deleted file mode 100644
index b122626..0000000
--- a/SOURCES/0015-NSS-Set-packet-length-for-initgroups.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 644f0b89c61b8a912514df550633f179c654240a Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 5 Nov 2013 17:58:36 +0100
-Subject: [PATCH 15/15] NSS: Set packet length for initgroups
-
-Some groups could be skipped, but packet length was not trimmed.
-This is a reason why valgrind reported access to uninitialised bytes.
-Actually, it isn't a problem, because the first uint32 in body is number of
-sended gids.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2138
----
- src/responder/nss/nsssrv_cmd.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index ada2b64df88d6a03a5c36a76076da447faa573c9..07f31188074bf45664969fb33388edb475e53b96 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -3558,6 +3558,13 @@ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res)
- 
-     ((uint32_t *)body)[0] = num-skipped; /* num results */
-     ((uint32_t *)body)[1] = 0; /* reserved */
-+    blen = (2 + bindex) * sizeof(uint32_t);
-+    ret = sss_packet_set_size(packet, blen);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Could not set packet size to value:%zu\n", blen));
-+        return ret;
-+    }
- 
-     return EOK;
- }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0015-ipa_subdomains_handler_master_done-initialize-reply_.patch b/SOURCES/0015-ipa_subdomains_handler_master_done-initialize-reply_.patch
new file mode 100644
index 0000000..5115210
--- /dev/null
+++ b/SOURCES/0015-ipa_subdomains_handler_master_done-initialize-reply_.patch
@@ -0,0 +1,31 @@
+From cb7813503506729a5595e23c575619bd89250dfd Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 14 Oct 2014 16:52:04 +0200
+Subject: [PATCH 15/22] ipa_subdomains_handler_master_done: initialize
+ reply_count
+
+This patch should mainly silence a false-positive Coverity warning but
+since further processing depends on this variable I think it is a good
+idea anyways.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index eb172fdfc05ac4e482174f01d89ad28db1498fc1..c61c1c666908ec23f8a92e5568222e55ec47be0a 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -1276,7 +1276,7 @@ static void ipa_subdomains_handler_master_done(struct tevent_req *req)
+ {
+     errno_t ret;
+     int dp_error = DP_ERR_FATAL;
+-    size_t reply_count;
++    size_t reply_count = 0;
+     struct sysdb_attrs **reply = NULL;
+     struct ipa_subdomains_req_ctx *ctx;
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0016-Fix-debug-messages-trailing.patch b/SOURCES/0016-Fix-debug-messages-trailing.patch
new file mode 100644
index 0000000..1812d97
--- /dev/null
+++ b/SOURCES/0016-Fix-debug-messages-trailing.patch
@@ -0,0 +1,37 @@
+From e66b32e80303ae40afb282f6e52962303a23e5f5 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Tue, 21 Oct 2014 13:41:17 +0100
+Subject: [PATCH 16/22] Fix debug messages - trailing '.'
+
+Fix debug messages where '\n' was wrongly followed by '.'.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/db/sysdb_views.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 926cd847c8dd8ddc33c0b517642a11bbe78059b5..a42aa96ed3e0cd7c877ff0c42887ef3f03ef5e0e 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -721,7 +721,7 @@ static errno_t sysdb_search_override_by_name(TALLOC_CTX *mem_ctx,
+         goto done;
+     } else if (override_res->count > 1) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Found more than one override for name [%s]\n.", name);
++              "Found more than one override for name [%s].\n", name);
+         ret = EINVAL;
+         goto done;
+     }
+@@ -878,7 +878,7 @@ static errno_t sysdb_search_override_by_id(TALLOC_CTX *mem_ctx,
+         goto done;
+     } else if (override_res->count > 1) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Found more than one override for id [%lu]\n.", id);
++              "Found more than one override for id [%lu].\n", id);
+         ret = EINVAL;
+         goto done;
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch b/SOURCES/0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch
deleted file mode 100644
index 698ba3e..0000000
--- a/SOURCES/0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 81aa563090c33bafbf22f1cde586b77ed526c25f Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 27 Nov 2013 10:22:59 +0100
-Subject: [PATCH 16/17] NSS: Fix memory leak in sss_setnetgrent
-
-struct nss_cmd_ctx was not released in function nss_cmd_setnetgrent_done
-and it wasn't used in the other function, because getnetgrent creates its own
-nss_cmd_ctx context. struct nss_cmd_ctx was released after closing client
-because it was allocated under client context. Memory leak is apparent with
-long living clients.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2170
----
- src/responder/nss/nsssrv_netgroup.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
-index a1c41968db0becbc42a1c501b666d9aec5241b5f..18e8579372fa39a1b3a60076948bc12bc008fb80 100644
---- a/src/responder/nss/nsssrv_netgroup.c
-+++ b/src/responder/nss/nsssrv_netgroup.c
-@@ -687,7 +687,7 @@ static void nss_cmd_setnetgrent_done(struct tevent_req *req)
-             ((uint32_t *)body)[1] = 0; /* reserved */
-         }
- 
--        sss_cmd_done(cmdctx->cctx, NULL);
-+        sss_cmd_done(cmdctx->cctx, cmdctx);
-         return;
-     }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0017-AD-use-LDAP-for-group-lookups.patch b/SOURCES/0017-AD-use-LDAP-for-group-lookups.patch
deleted file mode 100644
index be1d3cf..0000000
--- a/SOURCES/0017-AD-use-LDAP-for-group-lookups.patch
+++ /dev/null
@@ -1,253 +0,0 @@
-From 0324d31d0479e5de0d3aac05bf5fb922d84f84c4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 9 Dec 2013 11:45:28 +0100
-Subject: [PATCH 17/17] AD: use LDAP for group lookups
-
-The group memberships cannot be reliable retrieved from the Global
-Catalog. By default the memberOf attribute is not replicated to the GC
-at all and the member attribute is copied from the local LDAP instance
-to the GC running on the same host, but is only replicated to other GC
-instances for groups with universal scope. Additionally the tokenGroups
-attribute contains invalid SIDs when used with the GC for users from a
-different domains than the GC belongs to.
-
-As a result the requests which tries to resolve group-memberships of a
-AD user have to go to a LDAP server from the domain of the user.
-
-Fixes https://fedorahosted.org/sssd/ticket/2161 and
-https://fedorahosted.org/sssd/ticket/2148 as a side-effect.
----
- src/providers/ad/ad_id.c         |  20 +++++-
- src/providers/ad/ad_subdomains.c | 133 ++++++++++++++++++++++++++++++++++++++-
- src/providers/ldap/sdap.h        |   2 +
- 3 files changed, 152 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 87b69c66892ebfa48a1067c63006f3e3bd2e7444..dadb50da92cac87d3162bddb44395dad7d2abbc4 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -188,6 +188,8 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-               struct sss_domain_info *dom, struct be_acct_req *ar)
- {
-     struct sdap_id_conn_ctx **clist;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *subdom_id_ctx;
- 
-     /* LDAP, GC, sentinel */
-     clist = talloc_zero_array(breq, struct sdap_id_conn_ctx *, 3);
-@@ -197,8 +199,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-     case BE_REQ_USER: /* user */
-     case BE_REQ_BY_SECID:   /* by SID */
-     case BE_REQ_USER_AND_GROUP: /* get SID */
--    case BE_REQ_GROUP: /* group */
--    case BE_REQ_INITGROUPS: /* init groups for user */
-         /* Always try GC first */
-         clist[0] = ad_ctx->gc_ctx;
-         if (IS_SUBDOMAIN(dom) == true) {
-@@ -216,6 +216,22 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-         clist[1] = ad_ctx->ldap_ctx;
-         break;
- 
-+    case BE_REQ_GROUP: /* group */
-+    case BE_REQ_INITGROUPS: /* init groups for user */
-+        if (IS_SUBDOMAIN(dom)) {
-+            sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom);
-+            if (sdom == NULL || sdom->pvt == NULL) {
-+                DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n",
-+                                            dom->name));
-+                return NULL;
-+            }
-+            subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
-+            clist[0] = subdom_id_ctx->ldap_ctx;
-+        } else {
-+            clist[0] = ad_ctx->ldap_ctx;
-+        }
-+        break;
-+
-     default:
-         clist[0] = ad_ctx->ldap_ctx;
-         break;
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 18414523096ba0e53261415551eea57b4b2758b2..28c5eafb395b70e8f3630a43b67c61810683fe7c 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -25,6 +25,7 @@
- #include "providers/ldap/sdap_async.h"
- #include "providers/ad/ad_subdomains.h"
- #include "providers/ad/ad_domain_info.h"
-+#include "providers/ad/ad_srv.h"
- #include "providers/ldap/sdap_idmap.h"
- #include "util/util_sss_idmap.h"
- #include <ctype.h>
-@@ -68,6 +69,7 @@ struct ad_subdomains_ctx {
- 
-     time_t last_refreshed;
-     struct tevent_timer *timer_event;
-+    struct ad_id_ctx *ad_id_ctx;
- };
- 
- struct ad_subdomains_req_ctx {
-@@ -86,10 +88,138 @@ struct ad_subdomains_req_ctx {
- };
- 
- static errno_t
-+ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
-+                     struct ad_id_ctx *id_ctx,
-+                     struct sss_domain_info *subdom,
-+                     struct ad_id_ctx **_subdom_id_ctx)
-+{
-+    struct ad_options *ad_options;
-+    struct ad_id_ctx *ad_id_ctx;
-+    const char *gc_service_name;
-+    struct ad_srv_plugin_ctx *srv_ctx;
-+    char *ad_domain;
-+    struct sdap_domain *sdom;
-+    errno_t ret;
-+    const char *realm;
-+    const char *hostname;
-+
-+    realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM);
-+    hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME);
-+    if (realm == NULL || hostname == NULL) {
-+        DEBUG(SSSDBG_CONF_SETTINGS, ("Missing realm or hostname.\n"));
-+        return EINVAL;
-+    }
-+
-+    ad_options = ad_create_default_options(id_ctx, realm, hostname);
-+    if (ad_options == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD options\n"));
-+        talloc_free(ad_options);
-+        return ENOMEM;
-+    }
-+
-+    ad_domain = subdom->name;
-+
-+    ret = dp_opt_set_string(ad_options->basic, AD_DOMAIN, ad_domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot set AD domain\n"));
-+        talloc_free(ad_options);
-+        return ret;
-+    }
-+
-+    gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
-+    if (gc_service_name == NULL) {
-+        talloc_free(ad_options);
-+        return ENOMEM;
-+    }
-+
-+    ret = ad_failover_init(ad_options, be_ctx, NULL, NULL, realm,
-+                           subdom->name, gc_service_name,
-+                           subdom->name, &ad_options->service);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD failover\n"));
-+        talloc_free(ad_options);
-+        return ret;
-+    }
-+
-+    ad_id_ctx = ad_id_ctx_init(ad_options, be_ctx);
-+    if (ad_id_ctx == NULL) {
-+        talloc_free(ad_options);
-+        return ENOMEM;
-+    }
-+    ad_id_ctx->sdap_id_ctx->opts = ad_options->id;
-+    ad_options->id_ctx = ad_id_ctx;
-+
-+    /* use AD plugin */
-+    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
-+                                     default_host_dbs,
-+                                     ad_id_ctx->ad_options->id,
-+                                     hostname,
-+                                     ad_domain);
-+    if (srv_ctx == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, ("Out of memory?\n"));
-+        return ENOMEM;
-+    }
-+    be_fo_set_srv_lookup_plugin(be_ctx, ad_srv_plugin_send,
-+                                ad_srv_plugin_recv, srv_ctx, "AD");
-+
-+    ret = sdap_domain_subdom_add(ad_id_ctx->sdap_id_ctx,
-+                                 ad_id_ctx->sdap_id_ctx->opts->sdom,
-+                                 subdom->parent);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize sdap domain\n"));
-+        talloc_free(ad_options);
-+        return ret;
-+    }
-+
-+    sdom = sdap_domain_get(ad_id_ctx->sdap_id_ctx->opts, subdom);
-+    if (sdom == NULL) {
-+        return EFAULT;
-+    }
-+
-+    ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx,
-+                              ad_id_ctx->ldap_ctx, sdom,
-+                              ldap_enumeration_send,
-+                              ldap_enumeration_recv);
-+    if (ret != EOK) {
-+        talloc_free(ad_options);
-+        return ret;
-+    }
-+
-+    /* Set up the ID mapping object */
-+    ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
-+        id_ctx->sdap_id_ctx->opts->idmap_ctx;
-+
-+    *_subdom_id_ctx = ad_id_ctx;
-+    return EOK;
-+}
-+
-+static errno_t
- ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
-                       struct sss_domain_info *parent)
- {
--    return sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
-+    int ret;
-+    struct sdap_domain *sditer;
-+    struct ad_id_ctx *subdom_id_ctx;
-+
-+    ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_domain_subdom_add failed.\n"));
-+        return ret;
-+    }
-+
-+    DLIST_FOR_EACH(sditer, ctx->sdom) {
-+        if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
-+            ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
-+                                       sditer->dom, &subdom_id_ctx);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, ("ad_subdom_ad_ctx_new failed.\n"));
-+            } else {
-+                sditer->pvt = subdom_id_ctx;
-+            }
-+        }
-+    }
-+
-+    return EOK;
- }
- 
- static errno_t
-@@ -630,6 +760,7 @@ int ad_subdom_init(struct be_ctx *be_ctx,
-         DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
-         return ENOMEM;
-     }
-+    ctx->ad_id_ctx = id_ctx;
-     *ops = &ad_subdomains_ops;
-     *pvt_data = ctx;
- 
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index c53471b9bd6d9b18f37a8bf4089c8700d4a1163d..fa641730bb78b6a96c0b9640af7612b876f56533 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -394,6 +394,8 @@ struct sdap_domain {
-     struct timeval last_enum;
-     /* cleanup loop timer */
-     struct timeval last_purge;
-+
-+    void *pvt;
- };
- 
- struct sdap_options {
--- 
-1.8.4.2
-
diff --git a/SOURCES/0017-IPA-Handle-NULL-members-in-process_members.patch b/SOURCES/0017-IPA-Handle-NULL-members-in-process_members.patch
new file mode 100644
index 0000000..1cdf793
--- /dev/null
+++ b/SOURCES/0017-IPA-Handle-NULL-members-in-process_members.patch
@@ -0,0 +1,40 @@
+From 8eaafce7331a787bb2ae242eebe92ce8da342ca2 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 14 Oct 2014 14:15:25 +0200
+Subject: [PATCH 17/22] IPA: Handle NULL members in process_members()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index bd5c00b6a48018f8f904aaa03e8162425651b37a..2c31120b196353df52c87ef5b924a80bda134a17 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1196,6 +1196,11 @@ static errno_t process_members(struct sss_domain_info *domain,
+     struct sss_domain_info *obj_domain;
+     struct sss_domain_info *parent_domain;
+ 
++    if (members == NULL) {
++        DEBUG(SSSDBG_TRACE_INTERNAL, "No members\n");
++        return EOK;
++    }
++
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+@@ -1731,6 +1736,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                     goto done;
+                 }
+             }
++            DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", name);
+ 
+             ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
+             if (ret != EOK) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0018-SPEC-Print-testsuite-log-for-failed-test.patch b/SOURCES/0018-SPEC-Print-testsuite-log-for-failed-test.patch
new file mode 100644
index 0000000..47f2cdc
--- /dev/null
+++ b/SOURCES/0018-SPEC-Print-testsuite-log-for-failed-test.patch
@@ -0,0 +1,32 @@
+From 5662219fbd76c297b7137c1648fdb25e51777c92 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Thu, 16 Oct 2014 19:55:55 +0200
+Subject: [PATCH 18/22] SPEC: Print testsuite log for failed test
+
+Starting from Automake 1.13, the parallel testsuite harness has been made
+the default one; this harness is quite silent.
+
+VERBOSE=yes will displays the logs of the non-passed tests (i.e., only
+of the failed or skipped ones, or of the ones that passed unexpectedly).
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ contrib/sssd.spec.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index 74f7e950518841ec3cbd6e3fb4edf2eb873c7704..e5de4c44c4b4982f6819af363fdb8a32930f6137 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -467,7 +467,7 @@ make %{?_smp_mflags} docs
+ 
+ %check
+ export CK_TIMEOUT_MULTIPLIER=10
+-make %{?_smp_mflags} check
++make %{?_smp_mflags} check VERBOSE=yes
+ unset CK_TIMEOUT_MULTIPLIER
+ 
+ %install
+-- 
+1.9.3
+
diff --git a/SOURCES/0018-idmap-add-API-to-free-allocated-SIDs.patch b/SOURCES/0018-idmap-add-API-to-free-allocated-SIDs.patch
deleted file mode 100644
index 02df2e8..0000000
--- a/SOURCES/0018-idmap-add-API-to-free-allocated-SIDs.patch
+++ /dev/null
@@ -1,119 +0,0 @@
-From 16c8b0e7a0ac40b078f98c9f8025d39a59dca9bb Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 1 Nov 2013 12:23:23 +0100
-Subject: [PATCH 18/31] idmap: add API to free allocated SIDs
-
----
- src/lib/idmap/sss_idmap.c | 36 +++++++++++++++++++++++++++++++++++
- src/lib/idmap/sss_idmap.h | 48 +++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 84 insertions(+)
-
-diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
-index 9278e10d2bee37b741a87cd84d666d8a5b7bb671..3f1e7a58f390a3c10999251e2155ef513ba69bd7 100644
---- a/src/lib/idmap/sss_idmap.c
-+++ b/src/lib/idmap/sss_idmap.c
-@@ -246,6 +246,42 @@ enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx)
-     return IDMAP_SUCCESS;
- }
- 
-+static enum idmap_error_code sss_idmap_free_ptr(struct sss_idmap_ctx *ctx,
-+                                                void *ptr)
-+{
-+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
-+
-+    if (ptr != NULL) {
-+        ctx->free_func(ptr, ctx->alloc_pvt);
-+    }
-+
-+    return IDMAP_SUCCESS;
-+}
-+
-+enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx,
-+                                         char *sid)
-+{
-+    return sss_idmap_free_ptr(ctx, sid);
-+}
-+
-+enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx,
-+                                             struct sss_dom_sid *dom_sid)
-+{
-+    return sss_idmap_free_ptr(ctx, dom_sid);
-+}
-+
-+enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx,
-+                                             struct dom_sid *smb_sid)
-+{
-+    return sss_idmap_free_ptr(ctx, smb_sid);
-+}
-+
-+enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx,
-+                                             uint8_t *bin_sid)
-+{
-+    return sss_idmap_free_ptr(ctx, bin_sid);
-+}
-+
- enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
-                                                 const char *dom_sid,
-                                                 id_t *slice_num,
-diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
-index 4101fb9a5e0982c6ba0560decd299a0ed9e722b6..1e1c9a5cfe490301d0e633db808589f1bc0ef857 100644
---- a/src/lib/idmap/sss_idmap.h
-+++ b/src/lib/idmap/sss_idmap.h
-@@ -504,6 +504,54 @@ enum idmap_error_code sss_idmap_unix_to_bin_sid(struct sss_idmap_ctx *ctx,
- enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx);
- 
- /**
-+ * @brief Free mapped SID.
-+ *
-+ * @param[in] ctx         Idmap context
-+ * @param[in] sid         SID to be freed.
-+ *
-+ * @return
-+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
-+ */
-+enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx,
-+                                         char *sid);
-+
-+/**
-+ * @brief Free mapped domain SID.
-+ *
-+ * @param[in] ctx         Idmap context
-+ * @param[in] dom_sid     Domain SID to be freed.
-+ *
-+ * @return
-+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
-+ */
-+enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx,
-+                                             struct sss_dom_sid *dom_sid);
-+
-+/**
-+ * @brief Free mapped Samba SID.
-+ *
-+ * @param[in] ctx         Idmap context
-+ * @param[in] smb_sid     Samba SID to be freed.
-+ *
-+ * @return
-+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
-+ */
-+enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx,
-+                                             struct dom_sid *smb_sid);
-+
-+/**
-+ * @brief Free mapped binary SID.
-+ *
-+ * @param[in] ctx         Idmap context
-+ * @param[in] smb_sid     Binary SID to be freed.
-+ *
-+ * @return
-+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
-+ */
-+enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx,
-+                                             uint8_t *bin_sid);
-+
-+/**
-  * @brief Translate error code to a string
-  *
-  * @param[in] err  Idmap error code
--- 
-1.8.4.2
-
diff --git a/SOURCES/0019-MAN-PAGE-modified-sssd-ldap.5.xml-for-sssd-ticket-24.patch b/SOURCES/0019-MAN-PAGE-modified-sssd-ldap.5.xml-for-sssd-ticket-24.patch
new file mode 100644
index 0000000..c611e9b
--- /dev/null
+++ b/SOURCES/0019-MAN-PAGE-modified-sssd-ldap.5.xml-for-sssd-ticket-24.patch
@@ -0,0 +1,72 @@
+From ad51468ac53ff073efeaf28733b596004433721d Mon Sep 17 00:00:00 2001
+From: Dan Lavu <dlavu@redhat.com>
+Date: Mon, 13 Oct 2014 15:06:53 -0400
+Subject: [PATCH 19/22] MAN PAGE: modified sssd-ldap.5.xml for sssd ticket
+ #2451
+
+https://fedorahosted.org/sssd/ticket/2451
+
+Added a configuration example at the bottom for
+'ldap_access_order = lockout'. Also added a line
+to note that 'ldap_access_provider = ldap' must
+be specified for this feature to work.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/man/sssd-ldap.5.xml | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index a21ffc12986c4af10f4c0a5950eb43b88dac9d47..9a9410b415a7419ee303aea6ec2f9f3d41509647 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1449,7 +1449,7 @@
+                     <listitem>
+                         <para>
+                             Specifies acceptable cipher suites.  Typically this
+-                            is a colon sperated list.  See 
++                            is a colon sperated list.  See
+                             <citerefentry><refentrytitle>ldap.conf</refentrytitle>
+                             <manvolnum>5</manvolnum></citerefentry> for format.
+                         </para>
+@@ -1922,6 +1922,9 @@ ldap_access_filter = (employeeType=admin)
+                             attribute 'pwdAccountLockedTime' is present and has
+                             value of '000001010000Z'. Please see the option
+                             ldap_pwdlockout_dn.
++
++                            Please note that 'access_provider = ldap' must
++                            be set for this feature to work.
+                         </para>
+                         <para>
+                             <emphasis>expire</emphasis>: use
+@@ -2491,6 +2494,27 @@ ldap_access_filter = (employeeType=admin)
+ </programlisting>
+         </para>
+     </refsect1>
++    <refsect1 id='ldap_access_filter_example'>
++        <title>LDAP ACCESS FILTER EXAMPLE</title>
++        <para>
++            The following example assumes that SSSD is correctly
++            configured and to use the ldap_access_order=lockout.
++        </para>
++        <para>
++<programlisting>
++    [domain/LDAP]
++    id_provider = ldap
++    auth_provider = ldap
++    access_provider = ldap
++    ldap_access_order = lockout
++    ldap_pwdlockout_dn = cn=ppolicy,ou=policies,dc=mydomain,dc=org
++    ldap_uri = ldap://ldap.mydomain.org
++    ldap_search_base = dc=mydomain,dc=org
++    ldap_tls_reqcert = demand
++    cache_credentials = true
++</programlisting>
++        </para>
++    </refsect1>
+ 
+     <refsect1 id='notes'>
+         <title>NOTES</title>
+-- 
+1.9.3
+
diff --git a/SOURCES/0019-free-idmapped-SIDs-correctly.patch b/SOURCES/0019-free-idmapped-SIDs-correctly.patch
deleted file mode 100644
index 241ae14..0000000
--- a/SOURCES/0019-free-idmapped-SIDs-correctly.patch
+++ /dev/null
@@ -1,205 +0,0 @@
-From 9fad27b40eff82bcdffa61cafcc54e2d7750faee Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 1 Nov 2013 12:27:59 +0100
-Subject: [PATCH 19/31] free idmapped SIDs correctly
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2133
----
- src/providers/ad/ad_id.c                      |  3 +--
- src/providers/ad/ad_subdomains.c              |  2 ++
- src/providers/ldap/ldap_id.c                  |  4 ++--
- src/providers/ldap/sdap_async_initgroups_ad.c |  2 ++
- src/responder/pac/pacsrv_cmd.c                |  2 ++
- src/responder/pac/pacsrv_utils.c              |  4 ++--
- src/tests/cmocka/test_sss_idmap.c             |  2 ++
- src/tests/sss_idmap-tests.c                   | 14 +++++++-------
- 8 files changed, 20 insertions(+), 13 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index dadb50da92cac87d3162bddb44395dad7d2abbc4..19bc65825be21c6419db1e92db642be0a14b97a8 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -307,8 +307,7 @@ static errno_t ad_account_can_shortcut(struct be_ctx *be_ctx,
- 
- done:
-     if (sid != NULL) {
--        /* FIXME: use library function when #2133 is fixed */
--        talloc_free(sid);
-+        sss_idmap_free_sid(idmap_ctx->map, sid);
-     }
- 
-     if (ret == EOK) {
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 28c5eafb395b70e8f3630a43b67c61810683fe7c..dd692fb699ddf14bcf8f9926383e82da77c494e0 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -302,7 +302,9 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
- 
-     ret = EOK;
- done:
-+    sss_idmap_free_sid(ctx->sdap_id_ctx->opts->idmap_ctx->map, sid_str);
-     talloc_free(tmp_ctx);
-+
-     return ret;
- }
- 
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index fad1585331b7f0240770d2dc5a2e89788d2ad4da..793bc99ebcec883be7db3fc9dd56fa511d8ba3bb 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -139,7 +139,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
- 
-             attr_name = ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name;
-             ret = sss_filter_sanitize(state, sid, &clean_name);
--            talloc_zfree(sid);
-+            sss_idmap_free_sid(ctx->opts->idmap_ctx->map, sid);
-             if (ret != EOK) {
-                 goto fail;
-             }
-@@ -509,7 +509,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
- 
-             attr_name = ctx->opts->group_map[SDAP_AT_GROUP_OBJECTSID].name;
-             ret = sss_filter_sanitize(state, sid, &clean_name);
--            talloc_zfree(sid);
-+            sss_idmap_free_sid(ctx->opts->idmap_ctx->map, sid);
-             if (ret != EOK) {
-                 goto fail;
-             }
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index a0841a799bdbb1ad4de856d1715c88588b3b4da9..aa72c8876ba93eefc6230537801c50ab04e591ce 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -594,6 +594,8 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
-     in_transaction = false;
- 
- done:
-+    sss_idmap_free_sid(state->opts->idmap_ctx->map, sid_str);
-+
-     if (in_transaction) {
-         sret = sysdb_transaction_cancel(state->sysdb);
-         DEBUG(SSSDBG_FATAL_FAILURE,
-diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
-index f6e8abaf580a43417f3ea09929feccf19e5b0f29..144f5f5847e7ead490d59bae0e2fe49722eb9b69 100644
---- a/src/responder/pac/pacsrv_cmd.c
-+++ b/src/responder/pac/pacsrv_cmd.c
-@@ -161,6 +161,8 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx)
-         goto done;
-     }
- 
-+    talloc_steal(pr_ctx, pr_ctx->user_dom_sid_str);
-+
-     ret = responder_get_domain_by_id(cctx->rctx, pr_ctx->user_dom_sid_str,
-                                      &pr_ctx->dom);
-     if (ret == EAGAIN || ret == ENOENT) {
-diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
-index 05b53edee2ada79abf8bd04a6032314b68541d8e..30055a1345b7d943e6adf822438263c92e53b51a 100644
---- a/src/responder/pac/pacsrv_utils.c
-+++ b/src/responder/pac/pacsrv_utils.c
-@@ -264,14 +264,14 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-             goto done;
-         }
- 
--        talloc_zfree(sid_str);
-+        sss_idmap_free_sid(pac_ctx->idmap_ctx, sid_str);
-     }
- 
-     ret = EOK;
- 
- done:
-     talloc_free(sid_str);
--    talloc_free(user_dom_sid_str);
-+    sss_idmap_free_sid(pac_ctx->idmap_ctx, user_dom_sid_str);
- 
-     if (ret == EOK) {
-         *_sid_table = sid_table;
-diff --git a/src/tests/cmocka/test_sss_idmap.c b/src/tests/cmocka/test_sss_idmap.c
-index 53ed35a97863f8f52b82bec64d6dfb192891b0fe..019b4618ef0e14e87cb86d64989e8f5ca9dfdfd8 100644
---- a/src/tests/cmocka/test_sss_idmap.c
-+++ b/src/tests/cmocka/test_sss_idmap.c
-@@ -251,6 +251,7 @@ void test_map_id(void **state)
-     err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, id, &sid);
-     assert_int_equal(err, IDMAP_SUCCESS);
-     assert_string_equal(sid, TEST_DOM_SID"-0");
-+    sss_idmap_free_sid(test_ctx->idmap_ctx, sid);
- 
-     err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx,
-                                 TEST_DOM_SID"-"TEST_OFFSET_STR, &id);
-@@ -260,6 +261,7 @@ void test_map_id(void **state)
-     err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, id, &sid);
-     assert_int_equal(err, IDMAP_SUCCESS);
-     assert_string_equal(sid, TEST_DOM_SID"-"TEST_OFFSET_STR);
-+    sss_idmap_free_sid(test_ctx->idmap_ctx, sid);
- }
- 
- void test_map_id_external(void **state)
-diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c
-index 65e61351ddcf52deffe9c8abf38497cd9183c448..b2de0e70f794414587080587af1fd4a06d5ae854 100644
---- a/src/tests/sss_idmap-tests.c
-+++ b/src/tests/sss_idmap-tests.c
-@@ -280,7 +280,7 @@ START_TEST(idmap_test_uid2sid)
-                 "sss_idmap_unix_to_sid returned wrong SID, "
-                 "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid);
- 
--    talloc_free(sid);
-+    sss_idmap_free_sid(idmap_ctx, sid);
- }
- END_TEST
- 
-@@ -304,7 +304,7 @@ START_TEST(idmap_test_uid2dom_sid)
-                 "sss_idmap_unix_to_dom_sid returned wrong SID, "
-                 "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid);
- 
--    talloc_free(sid);
-+    sss_idmap_free_sid(idmap_ctx, sid);
-     talloc_free(dom_sid);
- }
- END_TEST
-@@ -330,7 +330,7 @@ START_TEST(idmap_test_uid2bin_sid)
-                 "sss_idmap_unix_to_bin_sid returned wrong SID, "
-                 "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid);
- 
--    talloc_free(sid);
-+    sss_idmap_free_sid(idmap_ctx, sid);
-     talloc_free(bin_sid);
- }
- END_TEST
-@@ -385,7 +385,7 @@ START_TEST(idmap_test_sid2dom_sid)
-                 "SID strings do not match.");
- 
-     talloc_free(dom_sid);
--    talloc_free(new_sid);
-+    sss_idmap_free_sid(idmap_ctx, new_sid);
- }
- END_TEST
- 
-@@ -418,7 +418,7 @@ START_TEST(idmap_test_large_and_too_large_sid)
-                 "did not return IDMAP_SID_INVALID");
- 
-     talloc_free(dom_sid);
--    talloc_free(new_sid);
-+    sss_idmap_free_sid(idmap_ctx, new_sid);
- }
- END_TEST
- 
-@@ -454,7 +454,7 @@ START_TEST(idmap_test_bin_sid2sid)
-                                             "expected [%s], get [%s]",
-                                             test_sid, sid);
- 
--    talloc_free(sid);
-+    sss_idmap_free_sid(idmap_ctx, sid);
- }
- END_TEST
- 
-@@ -528,7 +528,7 @@ START_TEST(idmap_test_smb_sid2sid)
-                                             "expected [%s], get [%s]",
-                                             test_sid, sid);
- 
--    talloc_free(sid);
-+    sss_idmap_free_sid(idmap_ctx, sid);
- }
- END_TEST
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0020-NSS-Possibility-to-use-any-shells-in-allowed_shells.patch b/SOURCES/0020-NSS-Possibility-to-use-any-shells-in-allowed_shells.patch
new file mode 100644
index 0000000..9007059
--- /dev/null
+++ b/SOURCES/0020-NSS-Possibility-to-use-any-shells-in-allowed_shells.patch
@@ -0,0 +1,71 @@
+From 96f96e74926f48ae5a023af9bed36ba813a7d024 Mon Sep 17 00:00:00 2001
+From: Denis Kutin <dekutin@ya.ru>
+Date: Sat, 16 Nov 2013 16:48:21 +0400
+Subject: [PATCH 20/22] NSS: Possibility to use any shells in 'allowed_shells'
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2219
+
+Signed-off-by: Pavel Reichl <preichl@redhat.com>
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/man/sssd.conf.5.xml        | 10 ++++++++++
+ src/responder/nss/nsssrv_cmd.c | 19 +++++++++++++------
+ 2 files changed, 23 insertions(+), 6 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index d5734166144a7c3ce7e62914558f8e69121bf774..77690432b841221328d65403830cf4a1ac12dba0 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -617,6 +617,16 @@ fallback_homedir = /home/%u
+                             is used.
+                         </para>
+                         <para>
++                            The wildcard (*) can be used to allow any shell.
++                        </para>
++                        <para>
++                            The (*) is useful if you want to use
++                            shell_fallback in case that user's shell is not
++                            in <quote>/etc/shells</quote> and maintaining list
++                            of all allowed shells in allowed_shells would be
++                            to much overhead.
++                        </para>
++                        <para>
+                             An empty string for shell is passed as-is to libc.
+                         </para>
+                         <para>
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 616f83dda58b11bb7b715e1eb6a2c43e91d2d9da..4ec99c153b25db26d482eec8da6ca52487967abc 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -284,12 +284,19 @@ static const char *get_shell_override(TALLOC_CTX *mem_ctx,
+     }
+ 
+     if (nctx->allowed_shells) {
+-        for (i=0; nctx->allowed_shells[i]; i++) {
+-            if (strcmp(nctx->allowed_shells[i], user_shell) == 0) {
+-                DEBUG(SSSDBG_FUNC_DATA,
+-                      "The shell '%s' is allowed but does not exist. "
+-                        "Using fallback\n", user_shell);
+-                return talloc_strdup(mem_ctx, nctx->shell_fallback);
++        if (strcmp(nctx->allowed_shells[0], "*") == 0) {
++            DEBUG(SSSDBG_FUNC_DATA,
++                  "The shell '%s' is allowed but does not exist. "
++                  "Using fallback\n", user_shell);
++            return talloc_strdup(mem_ctx, nctx->shell_fallback);
++        } else {
++            for (i=0; nctx->allowed_shells[i]; i++) {
++                if (strcmp(nctx->allowed_shells[i], user_shell) == 0) {
++                    DEBUG(SSSDBG_FUNC_DATA,
++                          "The shell '%s' is allowed but does not exist. "
++                          "Using fallback\n", user_shell);
++                    return talloc_strdup(mem_ctx, nctx->shell_fallback);
++                }
+             }
+         }
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0020-free-idmapped-dom-SIDs-correctly.patch b/SOURCES/0020-free-idmapped-dom-SIDs-correctly.patch
deleted file mode 100644
index 8632643..0000000
--- a/SOURCES/0020-free-idmapped-dom-SIDs-correctly.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 8894f5214c20e530c15a7481ed0b84e533cef519 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 1 Nov 2013 13:17:17 +0100
-Subject: [PATCH 20/31] free idmapped dom SIDs correctly
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2133
----
- src/tests/sss_idmap-tests.c | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c
-index b2de0e70f794414587080587af1fd4a06d5ae854..c43e326b1f49ac74c387c76e58f2f32efdce40ff 100644
---- a/src/tests/sss_idmap-tests.c
-+++ b/src/tests/sss_idmap-tests.c
-@@ -261,7 +261,7 @@ START_TEST(idmap_test_dom_sid2uid)
-                 "sss_idmap_dom_sid_to_unix returned wrong id, "
-                 "got [%d], expected [%d].", id, 1000 + IDMAP_RANGE_MIN);
- 
--    talloc_free(dom_sid);
-+    sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
- }
- END_TEST
- 
-@@ -305,7 +305,7 @@ START_TEST(idmap_test_uid2dom_sid)
-                 "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid);
- 
-     sss_idmap_free_sid(idmap_ctx, sid);
--    talloc_free(dom_sid);
-+    sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
- }
- END_TEST
- 
-@@ -358,7 +358,7 @@ START_TEST(idmap_test_bin_sid2dom_sid)
-     fail_unless(memcmp(test_bin_sid, new_bin_sid, test_bin_sid_length) == 0,
-                 "Binary SIDs do not match.");
- 
--    talloc_free(dom_sid);
-+    sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
-     talloc_free(new_bin_sid);
- }
- END_TEST
-@@ -384,7 +384,7 @@ START_TEST(idmap_test_sid2dom_sid)
-     fail_unless(strcmp("S-1-5-21-1-2-3-1000", new_sid) == 0,
-                 "SID strings do not match.");
- 
--    talloc_free(dom_sid);
-+    sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
-     sss_idmap_free_sid(idmap_ctx, new_sid);
- }
- END_TEST
-@@ -417,7 +417,7 @@ START_TEST(idmap_test_large_and_too_large_sid)
-                 "Trying to convert  a SID with a too large component "
-                 "did not return IDMAP_SID_INVALID");
- 
--    talloc_free(dom_sid);
-+    sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
-     sss_idmap_free_sid(idmap_ctx, new_sid);
- }
- END_TEST
-@@ -475,7 +475,7 @@ START_TEST(idmap_test_smb_sid2dom_sid)
-     fail_unless(memcmp(&test_smb_sid, new_smb_sid, sizeof(struct dom_sid)) == 0,
-                 "Samba dom_sid-s do not match.");
- 
--    talloc_free(dom_sid);
-+    sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
-     talloc_free(new_smb_sid);
- }
- END_TEST
--- 
-1.8.4.2
-
diff --git a/SOURCES/0021-GPO-Terminate-request-on-error.patch b/SOURCES/0021-GPO-Terminate-request-on-error.patch
new file mode 100644
index 0000000..c087e3e
--- /dev/null
+++ b/SOURCES/0021-GPO-Terminate-request-on-error.patch
@@ -0,0 +1,31 @@
+From f979db8ea926cd51093a0f2406ddfc49540b392e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 Oct 2014 16:18:02 +0200
+Subject: [PATCH 21/22] GPO: Terminate request on error
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/providers/ad/ad_gpo.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 3f5df75c5a9de53eac11ffcf785e929cf9b3165e..4dfbd4b6943b477bd93fdd730dfa5b1c5828a10a 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3954,11 +3954,13 @@ static void gpo_cse_done(struct tevent_req *subreq)
+               "ad_gpo_parse_gpo_child_response failed: [%d][%s]\n",
+               ret, strerror(ret));
+         tevent_req_error(req, ret);
++        return;
+     } else if (child_result != 0){
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Error in gpo_child: [%d][%s]\n",
+               child_result, strerror(child_result));
+         tevent_req_error(req, child_result);
++        return;
+     }
+ 
+     now = time(NULL);
+-- 
+1.9.3
+
diff --git a/SOURCES/0021-free-idmapped-smb-SIDs-correctly.patch b/SOURCES/0021-free-idmapped-smb-SIDs-correctly.patch
deleted file mode 100644
index 5566418..0000000
--- a/SOURCES/0021-free-idmapped-smb-SIDs-correctly.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 6b44bc4465b954183f8a52fbb05da6b63b17f0d1 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Mon, 4 Nov 2013 11:59:28 +0100
-Subject: [PATCH 21/31] free idmapped smb SIDs correctly
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2133
----
- src/tests/sss_idmap-tests.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c
-index c43e326b1f49ac74c387c76e58f2f32efdce40ff..888be82248045058093d6943ef73742d8812eac3 100644
---- a/src/tests/sss_idmap-tests.c
-+++ b/src/tests/sss_idmap-tests.c
-@@ -476,7 +476,7 @@ START_TEST(idmap_test_smb_sid2dom_sid)
-                 "Samba dom_sid-s do not match.");
- 
-     sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
--    talloc_free(new_smb_sid);
-+    sss_idmap_free_smb_sid(idmap_ctx, new_smb_sid);
- }
- END_TEST
- 
-@@ -512,7 +512,7 @@ START_TEST(idmap_test_bin_sid2smb_sid)
-     fail_unless(memcmp(&test_smb_sid, smb_sid, sizeof(struct dom_sid)) == 0,
-                  "Samba dom_sid structs do not match.");
- 
--    talloc_free(smb_sid);
-+    sss_idmap_free_smb_sid(idmap_ctx, smb_sid);
- }
- END_TEST
- 
-@@ -543,7 +543,7 @@ START_TEST(idmap_test_sid2smb_sid)
-     fail_unless(memcmp(&test_smb_sid, smb_sid, sizeof(struct dom_sid)) == 0,
-                  "Samba dom_sid structs do not match.");
- 
--    talloc_free(smb_sid);
-+    sss_idmap_free_smb_sid(idmap_ctx, smb_sid);
- }
- END_TEST
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0022-free-idmapped-binary-SIDs-correctly.patch b/SOURCES/0022-free-idmapped-binary-SIDs-correctly.patch
deleted file mode 100644
index 6ad0fd2..0000000
--- a/SOURCES/0022-free-idmapped-binary-SIDs-correctly.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From ccb2fe6ee1397b3c3d413d6c546cb88701958de3 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 7 Nov 2013 11:09:48 +0100
-Subject: [PATCH 22/31] free idmapped binary SIDs correctly
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2133
----
- src/responder/nss/nsssrv_cmd.c |  2 +-
- src/tests/sss_idmap-tests.c    | 10 +++++-----
- 2 files changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index 07f31188074bf45664969fb33388edb475e53b96..550017c0e4385a7147ed5ef83da2c37cb97c8092 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -4341,7 +4341,7 @@ static int nss_cmd_getbysid(enum sss_cli_command cmd, struct cli_ctx *cctx)
-     /* If the body isn't a SID, fail */
-     err = sss_idmap_sid_to_bin_sid(nctx->idmap_ctx, sid_str,
-                                    &bin_sid, &bin_sid_length);
--    talloc_free(bin_sid);
-+    sss_idmap_free_bin_sid(nctx->idmap_ctx, bin_sid);
-     if (err != IDMAP_SUCCESS) {
-         DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_sid_to_bin_sid failed for [%s].\n",
-                                   body));
-diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c
-index 888be82248045058093d6943ef73742d8812eac3..f5ec68383679bfc685467bd625c86b8d6f474d48 100644
---- a/src/tests/sss_idmap-tests.c
-+++ b/src/tests/sss_idmap-tests.c
-@@ -242,7 +242,7 @@ START_TEST(idmap_test_bin_sid2uid)
-                 "sss_idmap_bin_sid_to_unix returned wrong id, "
-                 "got [%d], expected [%d].", id, 1000 + IDMAP_RANGE_MIN);
- 
--    talloc_free(bin_sid);
-+    sss_idmap_free_bin_sid(idmap_ctx, bin_sid);
- }
- END_TEST
- 
-@@ -331,7 +331,7 @@ START_TEST(idmap_test_uid2bin_sid)
-                 "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid);
- 
-     sss_idmap_free_sid(idmap_ctx, sid);
--    talloc_free(bin_sid);
-+    sss_idmap_free_bin_sid(idmap_ctx, bin_sid);
- }
- END_TEST
- 
-@@ -359,7 +359,7 @@ START_TEST(idmap_test_bin_sid2dom_sid)
-                 "Binary SIDs do not match.");
- 
-     sss_idmap_free_dom_sid(idmap_ctx, dom_sid);
--    talloc_free(new_bin_sid);
-+    sss_idmap_free_bin_sid(idmap_ctx, new_bin_sid);
- }
- END_TEST
- 
-@@ -437,7 +437,7 @@ START_TEST(idmap_test_sid2bin_sid)
-     fail_unless(memcmp(bin_sid, test_bin_sid, test_bin_sid_length) == 0,
-                 "Binary SIDs do not match");
- 
--    talloc_free(bin_sid);
-+    sss_idmap_free_bin_sid(idmap_ctx, bin_sid);
- }
- END_TEST
- 
-@@ -496,7 +496,7 @@ START_TEST(idmap_test_smb_sid2bin_sid)
-     fail_unless(memcmp(bin_sid, test_bin_sid, test_bin_sid_length) == 0,
-                 "Binary SIDs do not match.");
- 
--    talloc_free(bin_sid);
-+    sss_idmap_free_bin_sid(idmap_ctx, bin_sid);
- }
- END_TEST
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0022-pyhbac-pysss-fix-reference-leaks.patch b/SOURCES/0022-pyhbac-pysss-fix-reference-leaks.patch
new file mode 100644
index 0000000..180d730
--- /dev/null
+++ b/SOURCES/0022-pyhbac-pysss-fix-reference-leaks.patch
@@ -0,0 +1,122 @@
+From b615258d6df8ad867cee99bdccffff05127fbc92 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Mon, 29 Sep 2014 16:40:53 +0100
+Subject: [PATCH 22/22] pyhbac,pysss: fix reference leaks
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/1195
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/python/pyhbac.c | 22 +++++++++++++---------
+ src/python/pysss.c  | 10 +++++++---
+ 2 files changed, 20 insertions(+), 12 deletions(-)
+
+diff --git a/src/python/pyhbac.c b/src/python/pyhbac.c
+index e9dce9b01b78401516b5c21141be8007b4a94aec..dd345a6eb4db8ac6104251d5b9c8f11a160e280d 100644
+--- a/src/python/pyhbac.c
++++ b/src/python/pyhbac.c
+@@ -139,14 +139,17 @@ sequence_as_string_list(PyObject *seq, const char *paramname)
+ 
+         utf_item = get_utf8_string(item, p);
+         if (utf_item == NULL) {
++            Py_DECREF(item);
+             return NULL;
+         }
+ 
+         ret[i] = py_strdup(PyString_AsString(utf_item));
+         Py_DECREF(utf_item);
+         if (!ret[i]) {
++            Py_DECREF(item);
+             return NULL;
+         }
++        Py_DECREF(item);
+     }
+ 
+     ret[i] = NULL;
+@@ -242,10 +245,7 @@ str_concat_sequence(PyObject *seq, const char *delim)
+         if (item == NULL) goto fail;
+ 
+         part = PyString_AsString(item);
+-        if (part == NULL) {
+-            Py_DECREF(item);
+-            goto fail;
+-        }
++        if (part == NULL) goto fail;
+ 
+         if (s) {
+             s = py_strcat_realloc(s, delim);
+@@ -260,7 +260,9 @@ str_concat_sequence(PyObject *seq, const char *delim)
+     }
+ 
+     return s;
++
+ fail:
++    Py_XDECREF(item);
+     PyMem_Free(s);
+     return NULL;
+ }
+@@ -269,11 +271,13 @@ fail:
+ static void
+ set_hbac_exception(PyObject *exc, struct hbac_info *error)
+ {
+-    PyErr_SetObject(exc,
+-                    Py_BuildValue(sss_py_const_p(char, "(i,s)"),
+-                                  error->code,
+-                                  error->rule_name ? \
+-                                        error->rule_name : "no rule"));
++    PyObject *obj;
++
++    obj = Py_BuildValue(sss_py_const_p(char, "(i,s)"), error->code,
++                        error->rule_name ? error->rule_name : "no rule");
++
++    PyErr_SetObject(exc, obj);
++    Py_XDECREF(obj);
+ }
+ 
+ /* ==================== HBAC Rule Element ========================*/
+diff --git a/src/python/pysss.c b/src/python/pysss.c
+index 8f98f081c9600b74f5953faef40cb40b30388319..9e899f1399553a950e41e157612a7360de4c07b5 100644
+--- a/src/python/pysss.c
++++ b/src/python/pysss.c
+@@ -850,7 +850,7 @@ static PyObject *PySssLocalObject_new(PyTypeObject *type,
+     if (confdb_path == NULL) {
+         talloc_free(mem_ctx);
+         PyErr_NoMemory();
+-        return NULL;
++        goto fail;
+     }
+ 
+     /* Connect to the conf db */
+@@ -859,7 +859,7 @@ static PyObject *PySssLocalObject_new(PyTypeObject *type,
+         talloc_free(mem_ctx);
+         PyErr_SetSssErrorWithMessage(ret,
+                 "Could not initialize connection to the confdb\n");
+-        return NULL;
++        goto fail;
+     }
+ 
+     ret = sssd_domain_init(self->mem_ctx, self->confdb, "local",
+@@ -868,7 +868,7 @@ static PyObject *PySssLocalObject_new(PyTypeObject *type,
+         talloc_free(mem_ctx);
+         PyErr_SetSssErrorWithMessage(ret,
+                 "Could not initialize connection to the sysdb\n");
+-        return NULL;
++        goto fail;
+     }
+     self->sysdb = self->local->sysdb;
+ 
+@@ -876,6 +876,10 @@ static PyObject *PySssLocalObject_new(PyTypeObject *type,
+     self->unlock = DO_UNLOCK;
+ 
+     return (PyObject *) self;
++
++fail:
++    Py_DECREF(self);
++    return NULL;
+ }
+ 
+ /*
+-- 
+1.9.3
+
diff --git a/SOURCES/0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch b/SOURCES/0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch
deleted file mode 100644
index 4839823..0000000
--- a/SOURCES/0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 456d952eecf2f068feafd2fff8bec8df84eba8ca Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 7 Nov 2013 12:00:43 +0100
-Subject: [PATCH 23/31] Initialize sid_str to NULL to avoid freeing random data
-
-If any function before failed, sss_idmap_free_sid() might have been
-called with random data.
----
- src/providers/ad/ad_subdomains.c              | 2 +-
- src/providers/ldap/sdap_async_initgroups_ad.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index dd692fb699ddf14bcf8f9926383e82da77c494e0..100fb13e99f7bf4b3946b1f5c5f9c626674bfb46 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -234,7 +234,7 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
-     errno_t ret;
-     enum idmap_error_code err;
-     struct ldb_message_element *el;
--    char *sid_str;
-+    char *sid_str = NULL;
-     uint32_t trust_type;
-     bool mpg;
- 
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index aa72c8876ba93eefc6230537801c50ab04e591ce..e58d93fb2da36febd6074381882192ba9e204e86 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -361,7 +361,7 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
-     size_t user_count, group_count, i;
-     TALLOC_CTX *tmp_ctx;
-     bool in_transaction = false;
--    char *sid_str;
-+    char *sid_str = NULL;
-     gid_t gid;
-     time_t now;
-     struct sss_domain_info *group_domain;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0023-UTIL-Add-a-function-to-convert-id_t-from-a-number-or.patch b/SOURCES/0023-UTIL-Add-a-function-to-convert-id_t-from-a-number-or.patch
new file mode 100644
index 0000000..5bdce3c
--- /dev/null
+++ b/SOURCES/0023-UTIL-Add-a-function-to-convert-id_t-from-a-number-or.patch
@@ -0,0 +1,518 @@
+From bb0970825fa8702d8b5dea94d9fc97c1041db338 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 23 Sep 2014 16:27:23 +0200
+Subject: [PATCH 23/46] UTIL: Add a function to convert id_t from a number or a
+ name
+
+We need a custom function that would convert a numeric or string input
+into uid_t. The function will be used to drop privileges in servers and
+also in the PAC and IFP responders.
+
+Includes a unit test to test all code that changed as well as a fix for
+a misnamed attribute in the csv_to_uid_list function synopsis.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 5eda23c28c582b43b2a0a165b1750f3875c0fa84)
+---
+ src/responder/common/responder.h        |   2 +-
+ src/responder/common/responder_common.c |  17 ++--
+ src/tests/cwrap/Makefile.am             |  54 ++++++++++++
+ src/tests/cwrap/passwd                  |   3 +-
+ src/tests/cwrap/test_responder_common.c | 144 ++++++++++++++++++++++++++++++++
+ src/tests/cwrap/test_usertools.c        | 106 +++++++++++++++++++++++
+ src/util/usertools.c                    |  44 ++++++++++
+ src/util/util.c                         |   1 +
+ src/util/util.h                         |   2 +
+ 9 files changed, 360 insertions(+), 13 deletions(-)
+ create mode 100644 src/tests/cwrap/test_responder_common.c
+ create mode 100644 src/tests/cwrap/test_usertools.c
+
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index 3674d13f2303d0ce248f765a638aaa83d0c16cf3..97552ec472c5baa285b41cc48b51149f3ef6adb5 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -308,7 +308,7 @@ errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
+                                   struct tevent_context *ev,
+                                   struct resp_ctx *rctx);
+ 
+-errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *cvs_string,
++errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
+                                 bool allow_sss_loop,
+                                 size_t *_uid_count, uid_t **_uids);
+ 
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index b7331ac8ab1de51839937d117968e92062af76d7..0ec2372e8d08f1002b303b5edc6897f17cee9699 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -159,7 +159,7 @@ errno_t check_allowed_uids(uid_t uid, size_t allowed_uids_count,
+     return EACCES;
+ }
+ 
+-errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *cvs_string,
++errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
+                                 bool allow_sss_loop,
+                                 size_t *_uid_count, uid_t **_uids)
+ {
+@@ -169,9 +169,8 @@ errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *cvs_string,
+     int list_size;
+     uid_t *uids = NULL;
+     char *endptr;
+-    struct passwd *pwd;
+ 
+-    ret = split_on_separator(mem_ctx, cvs_string, ',', true, false,
++    ret = split_on_separator(mem_ctx, csv_string, ',', true, false,
+                              &list, &list_size);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed [%d][%s].\n",
+@@ -211,17 +210,13 @@ errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *cvs_string,
+                 goto done;
+             }
+ 
+-            errno = 0;
+-            pwd = getpwnam(list[c]);
+-            if (pwd == NULL) {
++            ret = sss_user_by_name_or_uid(list[c], &uids[c], NULL);
++            if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is neither a valid "
+-                                          "UID nor a user name which cloud be "
+-                                          "resolved by getpwnam().\n", list[c]);
+-                ret = EINVAL;
++                                         "UID nor a user name which could be "
++                                         "resolved by getpwnam().\n", list[c]);
+                 goto done;
+             }
+-
+-            uids[c] = pwd->pw_uid;
+         }
+     }
+ 
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index d1f0e9e1b999814d8081af36f82e94f638452da4..02be67387110c0a440b647c35bba0c10e89e699d 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -45,6 +45,8 @@ if HAVE_UID_WRAPPER
+ check_PROGRAMS += \
+     become_user-tests \
+     server-tests \
++    usertools-tests \
++    responder_common-tests \
+     $(NULL)
+ endif # HAVE_UID_WRAPPER
+ endif # HAVE_NSS_WRAPPER
+@@ -106,4 +108,56 @@ server_tests_LDADD = \
+     $(abs_top_builddir)/libsss_test_common.la \
+     $(NULL)
+ 
++usertools_tests_SOURCES = \
++    test_usertools.c \
++    ../../../src/util/domain_info_utils.c \
++    ../../../src/util/safe-format-string.c \
++    ../../../src/util/usertools.c \
++    ../../../src/util/strtonum.c \
++    ../../../src/util/backup_file.c \
++    ../../../src/util/atomic_io.c \
++    ../../../src/util/util.c \
++    ../../../src/util/util_errors.c \
++    ../../../src/util/sss_tc_utf8.c \
++    ../../../src/util/sss_utf8.c \
++    ../../../src/confdb/confdb.c \
++    ../../../src/db/sysdb.c \
++    ../../../src/db/sysdb_upgrade.c \
++    ../../../src/db/sysdb_autofs.c \
++    ../../../src/db/sysdb_search.c \
++    ../../../src/db/sysdb_services.c \
++    ../../../src/db/sysdb_ops.c \
++    ../../../src/db/sysdb_views.c \
++    $(NULL)
++usertools_tests_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
++usertools_tests_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(UNICODE_LIBS) \
++    $(SSSD_LIBS) \
++    $(abs_top_builddir)/libsss_debug.la \
++    $(abs_top_builddir)/libsss_crypt.la \
++    $(abs_top_builddir)/libsss_test_common.la \
++    $(NULL)
++
++responder_common_tests_SOURCES =\
++    test_responder_common.c \
++    ../../../src/responder/common/responder_common.c \
++    ../../../src/responder/common/responder_packet.c \
++    ../../../src/responder/common/responder_cmd.c \
++    $(NULL)
++responder_common_tests_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
++responder_common_tests_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(UNICODE_LIBS) \
++    $(SSSD_LIBS) \
++    $(abs_top_builddir)/libsss_debug.la \
++    $(abs_top_builddir)/libsss_crypt.la \
++    $(abs_top_builddir)/libsss_util.la \
++    $(abs_top_builddir)/libsss_test_common.la \
++    $(NULL)
++
+ tests: $(check_PROGRAMS)
+diff --git a/src/tests/cwrap/passwd b/src/tests/cwrap/passwd
+index aa0a97db5259172c0b4ab47c7c2346fa5c2aa88e..862ccfe03e40d43c60c56b0c50f328f494d7e6b9 100644
+--- a/src/tests/cwrap/passwd
++++ b/src/tests/cwrap/passwd
+@@ -1 +1,2 @@
+-sssd:x:123:123:sssd unprivileged user:/:/sbin/nologin
++sssd:x:123:456:sssd unprivileged user:/:/sbin/nologin
++foobar:x:10001:10001:User for SSSD testing:/home/foobar:/bin/bash
+diff --git a/src/tests/cwrap/test_responder_common.c b/src/tests/cwrap/test_responder_common.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..23dcf753f184cdecaf39c73c6e9be0e23e6df968
+--- /dev/null
++++ b/src/tests/cwrap/test_responder_common.c
+@@ -0,0 +1,144 @@
++/*
++    Authors:
++        Jakub Hrozek <jhrozek@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    SSSD tests: User utilities
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <popt.h>
++#include "util/util.h"
++#include "responder/common/responder.h"
++#include "tests/cmocka/common_mock.h"
++
++/* Just to satisfy dependencies */
++struct cli_protocol_version *register_cli_protocol_version(void)
++{
++    static struct cli_protocol_version responder_test_cli_protocol_version[] = {
++        {0, NULL, NULL}
++    };
++
++    return responder_test_cli_protocol_version;
++}
++
++void test_uid_csv_to_uid_list(void **state)
++{
++    TALLOC_CTX *tmp_ctx;
++    errno_t ret;
++    size_t count;
++    uid_t *list;
++
++    tmp_ctx = talloc_new(global_talloc_context);
++    assert_non_null(tmp_ctx);
++
++    check_leaks_push(tmp_ctx);
++
++    ret = csv_string_to_uid_array(tmp_ctx, "1, 2, 3", false, &count, &list);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(count, 3);
++    assert_int_equal(list[0], 1);
++    assert_int_equal(list[1], 2);
++    assert_int_equal(list[2], 3);
++
++    talloc_free(list);
++    check_leaks_pop(tmp_ctx);
++    talloc_free(tmp_ctx);
++}
++
++void test_name_csv_to_uid_list(void **state)
++{
++    TALLOC_CTX *tmp_ctx;
++    errno_t ret;
++    size_t count;
++    uid_t *list;
++
++    tmp_ctx = talloc_new(global_talloc_context);
++    assert_non_null(tmp_ctx);
++
++    check_leaks_push(tmp_ctx);
++
++    ret = csv_string_to_uid_array(tmp_ctx, "sssd, foobar", true, &count, &list);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(count, 2);
++    assert_int_equal(list[0], 123);
++    assert_int_equal(list[1], 10001);
++
++    talloc_free(list);
++    check_leaks_pop(tmp_ctx);
++    talloc_free(tmp_ctx);
++}
++
++void test_csv_to_uid_list_neg(void **state)
++{
++    TALLOC_CTX *tmp_ctx;
++    errno_t ret;
++    size_t count;
++    uid_t *list = NULL;
++
++    tmp_ctx = talloc_new(global_talloc_context);
++    assert_non_null(tmp_ctx);
++
++    check_leaks_push(tmp_ctx);
++
++    ret = csv_string_to_uid_array(tmp_ctx, "nosuchuser", true, &count, &list);
++    assert_int_not_equal(ret, EOK);
++
++    check_leaks_pop(tmp_ctx);
++    talloc_free(tmp_ctx);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test(test_uid_csv_to_uid_list),
++        unit_test(test_name_csv_to_uid_list),
++        unit_test(test_csv_to_uid_list_neg),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    tests_set_cwd();
++
++    return run_tests(tests);
++}
+diff --git a/src/tests/cwrap/test_usertools.c b/src/tests/cwrap/test_usertools.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..6423059456a06f0c8f8ebdd803641b7207e862fd
+--- /dev/null
++++ b/src/tests/cwrap/test_usertools.c
+@@ -0,0 +1,106 @@
++/*
++    Authors:
++        Jakub Hrozek <jhrozek@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    SSSD tests: User utilities
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <popt.h>
++#include "util/util.h"
++#include "tests/cmocka/common_mock.h"
++
++void test_get_user_num(void **state)
++{
++    uid_t uid;
++    gid_t gid;
++    errno_t ret;
++
++    ret = sss_user_by_name_or_uid("123", &uid, &gid);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(uid, 123);
++    assert_int_equal(gid, 456);
++}
++
++void test_get_user_str(void **state)
++{
++    uid_t uid;
++    gid_t gid;
++    errno_t ret;
++
++    ret = sss_user_by_name_or_uid("sssd", &uid, &gid);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(uid, 123);
++    assert_int_equal(gid, 456);
++}
++
++void test_get_user_nullparm(void **state)
++{
++    uid_t uid;
++    gid_t gid;
++    errno_t ret;
++
++    ret = sss_user_by_name_or_uid("sssd", &uid, NULL);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(uid, 123);
++
++    ret = sss_user_by_name_or_uid("sssd", NULL, &gid);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(gid, 456);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test(test_get_user_num),
++        unit_test(test_get_user_str),
++        unit_test(test_get_user_nullparm),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    tests_set_cwd();
++
++    return run_tests(tests);
++}
+diff --git a/src/util/usertools.c b/src/util/usertools.c
+index 809b42d67c7b1cdfa0729c3a7e835fab37297596..a0b914e2fe8f65a71015944e63cb2d2813345d84 100644
+--- a/src/util/usertools.c
++++ b/src/util/usertools.c
+@@ -23,8 +23,11 @@
+ #include <pcre.h>
+ #include <errno.h>
+ #include <talloc.h>
++#include <pwd.h>
++#include <grp.h>
+ 
+ #include "confdb/confdb.h"
++#include "util/strtonum.h"
+ #include "util/util.h"
+ #include "util/safe-format-string.h"
+ #include "responder/common/responder.h"
+@@ -659,3 +662,44 @@ sss_get_domain_name(TALLOC_CTX *mem_ctx,
+ 
+     return user_name;
+ }
++
++errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid)
++{
++    uid_t uid;
++    errno_t ret;
++    char *endptr;
++    struct passwd *pwd;
++
++    /* Try if it's an ID first */
++    errno = 0;
++    uid = strtouint32(input, &endptr, 10);
++    if (errno != 0 || *endptr != '\0') {
++        ret = errno;
++        if (ret == ERANGE) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "UID [%s] is out of range.\n", input);
++            return ret;
++        }
++
++        /* Nope, maybe a username? */
++        pwd = getpwnam(input);
++    } else {
++        pwd = getpwuid(uid);
++    }
++
++    if (pwd == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "[%s] is neither a valid UID nor a user name which could be "
++              "resolved by getpwnam().\n", input);
++        return EINVAL;
++    }
++
++    if (_uid) {
++        *_uid = pwd->pw_uid;
++    }
++
++    if (_gid) {
++        *_gid = pwd->pw_gid;
++    }
++    return EOK;
++}
+diff --git a/src/util/util.c b/src/util/util.c
+index 7f80771ecd9868feaf43e34cbd61e44dd8ae5f3a..d78d37d975e6591bca6ac3f2fa36b5b9f4659a29 100644
+--- a/src/util/util.c
++++ b/src/util/util.c
+@@ -21,6 +21,7 @@
+ #include <ctype.h>
+ #include <netdb.h>
+ #include <poll.h>
++#include <sys/types.h>
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+ #include <talloc.h>
+diff --git a/src/util/util.h b/src/util/util.h
+index df83aac7d53ccadb806e8a1be90f0e45abb829ae..69074c93c1640a1e4a7e590b7f9feb6cc04804a4 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -404,6 +404,8 @@ bool check_ipv6_addr(struct in6_addr *addr, uint8_t check);
+ 
+ const char * const * get_known_services(void);
+ 
++errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid);
++
+ int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,
+                        const char sep, bool trim, bool skip_empty,
+                        char ***_list, int *size);
+-- 
+1.9.3
+
diff --git a/SOURCES/0024-BUILD-Add-a-config-option-for-sssd-user-own-private-.patch b/SOURCES/0024-BUILD-Add-a-config-option-for-sssd-user-own-private-.patch
new file mode 100644
index 0000000..b75f699
--- /dev/null
+++ b/SOURCES/0024-BUILD-Add-a-config-option-for-sssd-user-own-private-.patch
@@ -0,0 +1,116 @@
+From f504126d3d54b5b1b5467b59616255ef4c46d1be Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 1 Oct 2014 14:47:09 +0200
+Subject: [PATCH 24/46] BUILD: Add a config option for sssd user, own private
+ directories as the user
+
+Adds a new configure-time option that lets you select the user to run
+SSSD as. The default is 'root' for backwards compatibility.
+
+The directories the deamon stores its private data at are also created
+as owned by this user during install time.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit bc13c352ba9c2877f1e9bc62e55ad60fc000a55d)
+---
+ Makefile.am        | 23 +++++++++++++++++------
+ configure.ac       |  1 +
+ src/conf_macros.m4 | 19 +++++++++++++++++++
+ 3 files changed, 37 insertions(+), 6 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index b949c9c24070026570de970b545918a7eb279c6d..61bf5cf957d4024b67f48cf42f5735b5fa368945 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -78,6 +78,14 @@ sudolibdir = @sudolibpath@
+ UNICODE_LIBS=@UNICODE_LIBS@
+ 
+ MKDIR_P = @MKDIR_P@
++INSTALL = @INSTALL@
++
++SSSD_USER = @SSSD_USER@
++
++INSTALL_USER_DIR_FLAGS = -d
++if SSSD_USER
++INSTALL_USER_DIR_FLAGS += -o $(SSSD_USER) -g $(SSSD_USER)
++endif
+ 
+ AM_CFLAGS =
+ if WANT_AUX_INFO
+@@ -2740,24 +2748,27 @@ installsssddirs::
+     $(DESTDIR)$(bindir) \
+     $(DESTDIR)$(sbindir) \
+     $(DESTDIR)$(mandir) \
++    $(DESTDIR)$(pidpath) \
+     $(DESTDIR)$(pluginpath) \
+     $(DESTDIR)$(libdir)/ldb \
+     $(DESTDIR)$(dbuspolicydir) \
+     $(DESTDIR)$(dbusservicedir) \
+-    $(DESTDIR)$(pipepath)/private \
+     $(DESTDIR)$(sssdlibdir) \
+     $(DESTDIR)$(pkglibdir) \
+-    $(DESTDIR)$(sssdconfdir) \
+     $(DESTDIR)$(sssddatadir) \
++    $(DESTDIR)$(sudolibdir) \
++    $(DESTDIR)$(autofslibdir) \
++    $(NULL); \
++	$(INSTALL) $(INSTALL_USER_DIR_FLAGS) \
+     $(DESTDIR)$(dbpath) \
+     $(DESTDIR)$(mcpath) \
+-    $(DESTDIR)$(pidpath) \
+-    $(DESTDIR)$(logpath) \
++    $(DESTDIR)$(pipepath) \
++    $(DESTDIR)$(pipepath)/private \
+     $(DESTDIR)$(pubconfpath) \
+     $(DESTDIR)$(pubconfpath)/krb5.include.d \
+     $(DESTDIR)$(gpocachepath) \
+-    $(DESTDIR)$(sudolibdir) \
+-    $(DESTDIR)$(autofslibdir) \
++    $(DESTDIR)$(sssdconfdir) \
++    $(DESTDIR)$(logpath) \
+     $(NULL)
+ 
+ if HAVE_DOXYGEN
+diff --git a/configure.ac b/configure.ac
+index e6745cb454624d1d62e1a827c2fbf557f6502ae9..e5ec204ad9671d15deb1830c60168e066a66f198 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -137,6 +137,7 @@ WITH_SAMBA
+ WITH_NFS
+ WITH_NFS_LIB_PATH
+ WITH_LIBWBCLIENT
++WITH_SSSD_USER
+ 
+ m4_include([src/external/pkg.m4])
+ m4_include([src/external/libpopt.m4])
+diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
+index 4aa58138c85db9266fd3f1765fc357b3fd104941..fbee81f56e484b618379f7c987ecee50ae48917e 100644
+--- a/src/conf_macros.m4
++++ b/src/conf_macros.m4
+@@ -737,3 +737,22 @@ AC_DEFUN([WITH_NFS_LIB_PATH],
+     fi
+     AC_SUBST(nfslibpath)
+   ])
++
++AC_DEFUN([WITH_SSSD_USER],
++  [ AC_ARG_WITH([sssd-user],
++                [AS_HELP_STRING([--with-sssd-user=<user>],
++                                [User for running SSSD (root)]
++                               )
++                ]
++               )
++
++    SSSD_USER=root
++
++    if test x"$with_sssd_user" != x; then
++        SSSD_USER=$with_sssd_user
++    fi
++
++    AC_SUBST(SSSD_USER)
++    AC_DEFINE_UNQUOTED(SSSD_USER, "$SSSD_USER", ["The default user to run SSSD as"])
++    AM_CONDITIONAL([SSSD_USER], [test x"$with_sssd_user" != x])
++  ])
+-- 
+1.9.3
+
diff --git a/SOURCES/0024-ad-refactor-tokengroups-initgroups.patch b/SOURCES/0024-ad-refactor-tokengroups-initgroups.patch
deleted file mode 100644
index cd4ad74..0000000
--- a/SOURCES/0024-ad-refactor-tokengroups-initgroups.patch
+++ /dev/null
@@ -1,749 +0,0 @@
-From 8b581624e18d6f232d3174ed112d032bb6deffba Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 12 Nov 2013 13:52:40 +0100
-Subject: [PATCH 24/31] ad: refactor tokengroups initgroups
-
-sdap_get_ad_tokengroups_initgroups is split into more parts so
-it can be reused later.
----
- src/providers/ldap/sdap_async.h               |  20 +-
- src/providers/ldap/sdap_async_initgroups.c    |  16 +-
- src/providers/ldap/sdap_async_initgroups_ad.c | 552 ++++++++++++++++----------
- 3 files changed, 357 insertions(+), 231 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index dbf572cdc82b100ba9c26b4853f05db1ba5fa4ed..67623454e675f648259c089acca59258f386ecdb 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -294,17 +294,17 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req);
- 
- 
- struct tevent_req *
--sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
--                                        struct tevent_context *ev,
--                                        struct sdap_options *opts,
--                                        struct sysdb_ctx *sysdb,
--                                        struct sss_domain_info *domain,
--                                        struct sdap_handle *sh,
--                                        const char *name,
--                                        const char *orig_dn,
--                                        int timeout);
-+sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-+                                    struct tevent_context *ev,
-+                                    struct sdap_options *opts,
-+                                    struct sysdb_ctx *sysdb,
-+                                    struct sss_domain_info *domain,
-+                                    struct sdap_handle *sh,
-+                                    const char *name,
-+                                    const char *orig_dn,
-+                                    int timeout);
- 
- errno_t
--sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req);
-+sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req);
- 
- #endif /* _SDAP_ASYNC_H_ */
-diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
-index c16d484950e06c8474cc38db45b978b624473056..7d5cd2e7cbd86e2eb9774dfee1b8e31edec57b88 100644
---- a/src/providers/ldap/sdap_async_initgroups.c
-+++ b/src/providers/ldap/sdap_async_initgroups.c
-@@ -2857,13 +2857,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
-             /* Take advantage of AD's tokenGroups mechanism to look up all
-              * parent groups in a single request.
-              */
--            subreq = sdap_get_ad_tokengroups_initgroups_send(state, state->ev,
--                                                             state->opts,
--                                                             state->sysdb,
--                                                             state->dom,
--                                                             state->sh,
--                                                             cname, orig_dn,
--                                                             state->timeout);
-+            subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev,
-+                                                         state->opts,
-+                                                         state->sysdb,
-+                                                         state->dom,
-+                                                         state->sh,
-+                                                         cname, orig_dn,
-+                                                         state->timeout);
-         } else if (state->opts->support_matching_rule
-                     && dp_opt_get_bool(state->opts->basic,
-                                        SDAP_AD_MATCHING_RULE_INITGROUPS)) {
-@@ -2952,7 +2952,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
-     case SDAP_SCHEMA_AD:
-         if (state->use_id_mapping
-                 && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
--            ret = sdap_get_ad_tokengroups_initgroups_recv(subreq);
-+            ret = sdap_ad_tokengroups_initgroups_recv(subreq);
-         }
-         else if (state->opts->support_matching_rule
-                 && dp_opt_get_bool(state->opts->basic,
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index e58d93fb2da36febd6074381882192ba9e204e86..7ba155338a358681c1bd201bee1c75f67afb4650 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -298,96 +298,87 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req)
-     return EOK;
- }
- 
--struct sdap_ad_tokengroups_initgr_state {
-+struct sdap_get_ad_tokengroups_state {
-     struct tevent_context *ev;
--    struct sdap_options *opts;
--    struct sysdb_ctx *sysdb;
--    struct sss_domain_info *domain;
--    struct sdap_handle *sh;
-+    struct sss_idmap_ctx *idmap_ctx;
-     const char *username;
-+
-+    char **sids;
-+    size_t num_sids;
- };
- 
--static void
--sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *req);
-+static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq);
- 
--struct tevent_req *
--sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
--                                        struct tevent_context *ev,
--                                        struct sdap_options *opts,
--                                        struct sysdb_ctx *sysdb,
--                                        struct sss_domain_info *domain,
--                                        struct sdap_handle *sh,
--                                        const char *name,
--                                        const char *orig_dn,
--                                        int timeout)
-+static struct tevent_req *
-+sdap_get_ad_tokengroups_send(TALLOC_CTX *mem_ctx,
-+                             struct tevent_context *ev,
-+                             struct sdap_options *opts,
-+                             struct sdap_handle *sh,
-+                             const char *name,
-+                             const char *orig_dn,
-+                             int timeout)
- {
--    struct tevent_req *req;
--    struct tevent_req *subreq;
--    struct sdap_ad_tokengroups_initgr_state *state;
-+    struct sdap_get_ad_tokengroups_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct tevent_req *subreq = NULL;
-     const char *attrs[] = {AD_TOKENGROUPS_ATTR, NULL};
-+    errno_t ret;
- 
-     req = tevent_req_create(mem_ctx, &state,
--                            struct sdap_ad_tokengroups_initgr_state);
--    if (!req) return NULL;
-+                            struct sdap_get_ad_tokengroups_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
-+        return NULL;
-+    }
- 
-+    state->idmap_ctx = opts->idmap_ctx->map;
-     state->ev = ev;
--    state->opts = opts;
--    state->sysdb = sysdb;
--    state->domain = domain;
--    state->sh = sh;
--    state->username = name;
-+    state->username = talloc_strdup(state, name);
-+    if (state->username == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    subreq = sdap_get_generic_send(state, state->ev, opts, sh, orig_dn,
-+                                   LDAP_SCOPE_BASE, NULL, attrs,
-+                                   NULL, 0, timeout, false);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    tevent_req_set_callback(subreq, sdap_get_ad_tokengroups_done, req);
-+
-+    return req;
- 
--    subreq = sdap_get_generic_send(
--            state, state->ev, state->opts, state->sh,
--            orig_dn, LDAP_SCOPE_BASE, NULL, attrs,
--            NULL, 0, timeout, false);
--    if (!subreq) {
--        tevent_req_error(req, ENOMEM);
--        tevent_req_post(req, ev);
--        return req;
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-     }
-+    tevent_req_post(req, ev);
- 
--    tevent_req_set_callback(subreq,
--                            sdap_get_ad_tokengroups_initgroups_lookup_done,
--                            req);
-     return req;
- }
- 
--static void
--sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
-+static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq)
- {
--    errno_t ret, sret;
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    struct sdap_get_ad_tokengroups_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct sysdb_attrs **users = NULL;
-+    struct ldb_message_element *el = NULL;
-     enum idmap_error_code err;
--    size_t user_count, group_count, i;
--    TALLOC_CTX *tmp_ctx;
--    bool in_transaction = false;
-     char *sid_str = NULL;
--    gid_t gid;
--    time_t now;
--    struct sss_domain_info *group_domain;
--    struct sysdb_attrs **users;
--    struct ldb_message_element *el;
--    struct ldb_message *msg;
--    struct ldb_dn *group_ldb_dn;
--    const char *group_str_dn;
--    char **ldap_grouplist;
--    char **sysdb_grouplist;
--    char **add_groups;
--    char **del_groups;
--    const char *attrs[] = { SYSDB_NAME, NULL };
--    const char *group_name;
--    struct tevent_req *req =
--            tevent_req_callback_data(subreq, struct tevent_req);
--    struct sdap_ad_tokengroups_initgr_state *state =
--            tevent_req_data(req, struct sdap_ad_tokengroups_initgr_state);
-+    size_t num_users;
-+    size_t i;
-+    errno_t ret;
- 
--    tmp_ctx = talloc_new(NULL);
--    if (!tmp_ctx) {
--        ret = ENOMEM;
--        goto done;
--    }
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct sdap_get_ad_tokengroups_state);
- 
--    ret = sdap_get_generic_recv(subreq, tmp_ctx, &user_count, &users);
-+    ret = sdap_get_generic_recv(subreq, tmp_ctx, &num_users, &users);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
-@@ -395,226 +386,361 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
-         goto done;
-     }
- 
--    if (user_count != 1) {
-+    if (num_users != 1) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
-               ("More than one result on a base search!\n"));
-         ret = EINVAL;
-         goto done;
-     }
- 
--    /* Get the list of group SIDs */
--    ret = sysdb_attrs_get_el_ext(users[0], AD_TOKENGROUPS_ATTR,
--                                 false, &el);
--    if (ret != EOK) {
--        if (ret == ENOENT) {
--            DEBUG(SSSDBG_TRACE_LIBS,
--                  ("No tokenGroups entries for [%s]\n",
--                   state->username));
--            /* No groups in LDAP. We need to ensure that the
--             * sysdb matches.
--             */
--            el = talloc_zero(tmp_ctx, struct ldb_message_element);
--            if (!el) {
--                ret = ENOMEM;
--                goto done;
--            }
--            el->num_values = 0;
-+    /* get the list of sids from tokengroups */
-+    ret = sysdb_attrs_get_el_ext(users[0], AD_TOKENGROUPS_ATTR, false, &el);
-+    if (ret == ENOENT) {
-+        DEBUG(SSSDBG_TRACE_LIBS, ("No tokenGroups entries for [%s]\n",
-+                                  state->username));
- 
--            /* This will skip the group-processing loop below
--             * and proceed to removing any sysdb groups.
--             */
--        } else {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Could not read tokenGroups attribute: [%s]\n",
--                   strerror(ret)));
--            goto done;
--        }
-+        state->sids = NULL;
-+        state->num_sids = 0;
-+        ret = EOK;
-+        goto done;
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not read tokenGroups attribute: "
-+                                     "[%s]\n", strerror(ret)));
-+        goto done;
-     }
- 
--    /* Process the groups */
--    now = time(NULL);
--
--    ret = sysdb_transaction_start(state->sysdb);
--    if (ret != EOK) goto done;
--    in_transaction = true;
--
--    ldap_grouplist = talloc_array(tmp_ctx, char *, el->num_values + 1);
--    if (!ldap_grouplist) {
-+    state->num_sids = 0;
-+    state->sids = talloc_zero_array(state, char*, el->num_values);
-+    if (state->sids == NULL) {
-         ret = ENOMEM;
-         goto done;
-     }
--    group_count = 0;
- 
-+    /* convert binary sid to string */
-     for (i = 0; i < el->num_values; i++) {
--        /* Get the SID and convert it to a GID */
--
--        err = sss_idmap_bin_sid_to_sid(state->opts->idmap_ctx->map,
--                                        el->values[i].data,
--                                        el->values[i].length,
--                                        &sid_str);
-+        err = sss_idmap_bin_sid_to_sid(state->idmap_ctx, el->values[i].data,
-+                                       el->values[i].length, &sid_str);
-         if (err != IDMAP_SUCCESS) {
-             DEBUG(SSSDBG_MINOR_FAILURE,
-                   ("Could not convert binary SID to string: [%s]. Skipping\n",
-                    idmap_error_string(err)));
-             continue;
-         }
--        DEBUG(SSSDBG_TRACE_LIBS,
--              ("Processing membership SID [%s]\n",
--               sid_str));
--        ret = sdap_idmap_sid_to_unix(state->opts->idmap_ctx, sid_str,
--                                     &gid);
-+
-+        state->sids[i] = talloc_move(state->sids, &sid_str);
-+        state->num_sids++;
-+    }
-+
-+    /* shrink array to final number of elements */
-+    state->sids = talloc_realloc(state, state->sids, char*, state->num_sids);
-+    if (state->sids == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+}
-+
-+static errno_t sdap_get_ad_tokengroups_recv(TALLOC_CTX *mem_ctx,
-+                                            struct tevent_req *req,
-+                                            size_t *_num_sids,
-+                                            char ***_sids)
-+{
-+    struct sdap_get_ad_tokengroups_state *state = NULL;
-+    state = tevent_req_data(req, struct sdap_get_ad_tokengroups_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    if (_num_sids != NULL) {
-+        *_num_sids = state->num_sids;
-+    }
-+
-+    if (_sids != NULL) {
-+        *_sids = talloc_steal(mem_ctx, state->sids);
-+    }
-+
-+    return EOK;
-+}
-+
-+static errno_t
-+sdap_ad_tokengroups_update_members(TALLOC_CTX *mem_ctx,
-+                                   const char *username,
-+                                   struct sysdb_ctx *sysdb,
-+                                   struct sss_domain_info *domain,
-+                                   char **ldap_groups)
-+{
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    char **sysdb_groups = NULL;
-+    char **add_groups = NULL;
-+    char **del_groups = NULL;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
-+        return ENOMEM;
-+    }
-+
-+    /* Get the current sysdb group list for this user so we can update it. */
-+    ret = get_sysdb_grouplist_dn(tmp_ctx, sysdb, domain,
-+                                 username, &sysdb_groups);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not get the list of groups for "
-+              "[%s] in the sysdb: [%s]\n", username, strerror(ret)));
-+        goto done;
-+    }
-+
-+    /* Find the differences between the sysdb and LDAP lists.
-+     * Groups in the sysdb only must be removed. */
-+    ret = diff_string_lists(tmp_ctx, ldap_groups, sysdb_groups,
-+                            &add_groups, &del_groups, NULL);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_LIBS, ("Updating memberships for [%s]\n", username));
-+
-+    ret = sysdb_update_members_dn(domain->sysdb, domain, username,
-+                                  SYSDB_MEMBER_USER,
-+                                  (const char *const *) add_groups,
-+                                  (const char *const *) del_groups);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n",
-+                                     ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+struct sdap_ad_tokengroups_initgroups_state {
-+    struct sdap_idmap_ctx *idmap_ctx;
-+    struct sysdb_ctx *sysdb;
-+    struct sss_domain_info *domain;
-+    const char *username;
-+};
-+
-+static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq);
-+
-+struct tevent_req *
-+sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-+                                    struct tevent_context *ev,
-+                                    struct sdap_options *opts,
-+                                    struct sysdb_ctx *sysdb,
-+                                    struct sss_domain_info *domain,
-+                                    struct sdap_handle *sh,
-+                                    const char *name,
-+                                    const char *orig_dn,
-+                                    int timeout)
-+{
-+    struct sdap_ad_tokengroups_initgroups_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct tevent_req *subreq = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct sdap_ad_tokengroups_initgroups_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
-+        return NULL;
-+    }
-+
-+    state->idmap_ctx = opts->idmap_ctx;
-+    state->sysdb = sysdb;
-+    state->domain = domain;
-+    state->username = talloc_strdup(state, name);
-+    if (state->username == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn,
-+                                          timeout);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_done, req);
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+
-+    return req;
-+}
-+
-+static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
-+{
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    struct sdap_ad_tokengroups_initgroups_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    struct ldb_message *msg = NULL;
-+    const char *attrs[] = {SYSDB_NAME, NULL};
-+    const char *name = NULL;
-+    const char *sid = NULL;
-+    char **sids = NULL;
-+    size_t num_sids;
-+    size_t i;
-+    time_t now;
-+    gid_t gid;
-+    char **groups = NULL;
-+    size_t num_groups;
-+    errno_t ret, sret;
-+    bool in_transaction;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
-+
-+    ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to acquire tokengroups [%d]: %s\n",
-+                                    ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    num_groups = 0;
-+    groups = talloc_zero_array(tmp_ctx, char*, num_sids + 1);
-+    if (groups == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    now = time(NULL);
-+    ret = sysdb_transaction_start(state->sysdb);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+    in_transaction = true;
-+
-+    for (i = 0; i < num_sids; i++) {
-+        sid = sids[i];
-+        DEBUG(SSSDBG_TRACE_LIBS, ("Processing membership SID [%s]\n", sid));
-+
-+        ret = sdap_idmap_sid_to_unix(state->idmap_ctx, sid, &gid);
-         if (ret == ENOTSUP) {
-             DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n"));
-             ret = EOK;
-             continue;
-         } else if (ret != EOK) {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Could not convert SID to GID: [%s]. Skipping\n",
--                   strerror(ret)));
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Could not convert SID to GID: [%s]. "
-+                                         "Skipping\n", strerror(ret)));
-             continue;
-         }
- 
--        group_domain = find_subdomain_by_sid(get_domains_head(state->domain),
--                                                              sid_str);
--        if (group_domain == NULL) {
--            DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n",
--                                         sid_str));
-+        domain = find_subdomain_by_sid(get_domains_head(state->domain), sid);
-+        if (domain == NULL) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n", sid));
-             continue;
-         }
- 
--        DEBUG(SSSDBG_TRACE_LIBS,
--              ("Processing membership GID [%"SPRIgid"]\n", gid));
-+        DEBUG(SSSDBG_TRACE_LIBS, ("SID [%s] maps to GID [%"SPRIgid"]\n",
-+                                  sid, gid));
- 
-         /* Check whether this GID already exists in the sysdb */
--        ret = sysdb_search_group_by_gid(tmp_ctx, group_domain->sysdb,
--                                        group_domain, gid, attrs, &msg);
-+        ret = sysdb_search_group_by_gid(tmp_ctx, domain->sysdb, domain,
-+                                        gid, attrs, &msg);
-         if (ret == EOK) {
--            group_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
--            if (!group_name) {
-+            name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+            if (name == NULL) {
-                 DEBUG(SSSDBG_MINOR_FAILURE,
-                       ("Could not retrieve group name from sysdb\n"));
-                 ret = EINVAL;
-                 goto done;
-             }
-         } else if (ret == ENOENT) {
--            /* This is a new group. For now, we will store it
--             * under the name of its SID. When a direct lookup of
--             * the group or its GID occurs, it will replace this
--             * temporary entry.
--             */
--
--            group_name = sid_str;
--            ret = sysdb_add_incomplete_group(group_domain->sysdb,
--                                             group_domain,
--                                             group_name, gid,
--                                             NULL, sid_str, false, now);
-+            /* This is a new group. For now, we will store it under the name
-+             * of its SID. When a direct lookup of the group or its GID occurs,
-+             * it will replace this temporary entry. */
-+            name = sid;
-+            ret = sysdb_add_incomplete_group(domain->sysdb, domain, name, gid,
-+                                             NULL, sid, false, now);
-             if (ret != EOK) {
--                DEBUG(SSSDBG_MINOR_FAILURE,
--                      ("Could not create incomplete group: [%s]\n",
--                       strerror(ret)));
-+                DEBUG(SSSDBG_MINOR_FAILURE, ("Could not create incomplete "
-+                                             "group: [%s]\n", strerror(ret)));
-                 goto done;
-             }
-         } else {
-             /* Unexpected error */
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Could not look up group in sysdb: [%s]\n",
--                   strerror(ret)));
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Could not look up group in sysdb: "
-+                                         "[%s]\n", strerror(ret)));
-             goto done;
-         }
- 
--        group_ldb_dn = sysdb_group_dn(group_domain->sysdb, tmp_ctx,
--                                      group_domain, group_name);
--        if (group_ldb_dn == NULL) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("sysdb_group_dn() failed\n"));
-+        groups[num_groups] = sysdb_group_strdn(tmp_ctx, domain->name, name);
-+        if (groups[num_groups] == NULL) {
-             ret = ENOMEM;
-             goto done;
-         }
--
--        group_str_dn = ldb_dn_get_linearized(group_ldb_dn);
--        if (group_str_dn == NULL) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("ldb_dn_get_linearized() failed\n"));
--            ret = EINVAL;
--            goto done;
--        }
--
--        ldap_grouplist[group_count] =
--                talloc_strdup(ldap_grouplist, group_str_dn);
--        if (!ldap_grouplist[group_count]) {
--            ret = ENOMEM;
--            goto done;
--        }
--
--        talloc_zfree(group_ldb_dn); /* also frees group_str_dn */
--        group_str_dn = NULL;
--
--        group_count++;
--    }
--    ldap_grouplist[group_count] = NULL;
--
--    /* Get the current sysdb group list for this user
--     * so we can update it.
--     */
--    ret = get_sysdb_grouplist_dn(state, state->sysdb, state->domain,
--                                 state->username, &sysdb_grouplist);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_MINOR_FAILURE,
--              ("Could not get the list of groups for [%s] in the sysdb: "
--               "[%s]\n",
--               state->username, strerror(ret)));
--        goto done;
-+        num_groups++;
-     }
- 
--    /* Find the differences between the sysdb and LDAP lists
--     * Groups in the sysdb only must be removed.
--     */
--    ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
--                            &add_groups, &del_groups, NULL);
--    if (ret != EOK) goto done;
-+    groups[num_groups] = NULL;
- 
--    DEBUG(SSSDBG_TRACE_LIBS,
--          ("Updating memberships for [%s]\n", state->username));
--    ret = sysdb_update_members_dn(state->sysdb, state->domain,
--                                  state->username, SYSDB_MEMBER_USER,
--                                  (const char *const *) add_groups,
--                                  (const char *const *) del_groups);
-+    ret = sdap_ad_tokengroups_update_members(state, state->username,
-+                                             state->sysdb, state->domain,
-+                                             groups);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_MINOR_FAILURE,
--              ("Membership update failed [%d]: %s\n",
--               ret, strerror(ret)));
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n",
-+                                     ret, strerror(ret)));
-         goto done;
-     }
- 
-     ret = sysdb_transaction_commit(state->sysdb);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              ("Could not commit transaction! [%s]\n",
--               strerror(ret)));
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Could not commit transaction! [%s]\n",
-+                                    strerror(ret)));
-         goto done;
-     }
-     in_transaction = false;
- 
- done:
--    sss_idmap_free_sid(state->opts->idmap_ctx->map, sid_str);
-+    talloc_free(tmp_ctx);
- 
-     if (in_transaction) {
-         sret = sysdb_transaction_cancel(state->sysdb);
--        DEBUG(SSSDBG_FATAL_FAILURE,
--              ("Could not cancel transaction! [%s]\n",
--               strerror(sret)));
-+        DEBUG(SSSDBG_FATAL_FAILURE, ("Could not cancel transaction! [%s]\n",
-+                                     strerror(sret)));
-     }
- 
--    if (ret == EOK) {
--        tevent_req_done(req);
--    } else {
-+    if (ret != EOK) {
-         tevent_req_error(req, ret);
-+        return;
-     }
--    talloc_free(tmp_ctx);
--    return;
-+
-+    tevent_req_done(req);
- }
- 
--errno_t
--sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req)
-+errno_t sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req)
- {
-     TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-     return EOK;
- }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0025-RPM-Change-file-ownership-to-sssd.sssd.patch b/SOURCES/0025-RPM-Change-file-ownership-to-sssd.sssd.patch
new file mode 100644
index 0000000..ff8be93
--- /dev/null
+++ b/SOURCES/0025-RPM-Change-file-ownership-to-sssd.sssd.patch
@@ -0,0 +1,67 @@
+From d140aa913a0aad28b151c79f4c6f7ff5d8fee6c9 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 5 Aug 2014 13:53:20 +0200
+Subject: [PATCH 25/46] RPM: Change file ownership to sssd.sssd
+
+Adds a private SSSD user in the %pre section of SSSD specfile. Also
+changes the ownership of SSSD private directories to sssd.sssd.
+
+Does not change the configure time default, so SSSD will still run as
+root. The file and directory ownership does not widen, because the
+directories are still only accessible by the private user (whose shell
+is /sbin/nologin) and of course the root user.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit fa24dabfd480e1ce346009336c7979ab59520c44)
+---
+ contrib/sssd.spec.in | 26 +++++++++++++++-----------
+ 1 file changed, 15 insertions(+), 11 deletions(-)
+
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index e5de4c44c4b4982f6819af363fdb8a32930f6137..db3bbcb09d6b27ca785f511ce6414fbeaaf445c6 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -604,17 +604,17 @@ rm -rf $RPM_BUILD_ROOT
+ 
+ %dir %{sssdstatedir}
+ %dir %{_localstatedir}/cache/krb5rcache
+-%attr(700,root,root) %dir %{dbpath}
+-%attr(755,root,root) %dir %{mcpath}
+-%ghost %attr(0644,root,root) %verify(not md5 size mtime) %{mcpath}/passwd
+-%ghost %attr(0644,root,root) %verify(not md5 size mtime) %{mcpath}/group
+-%attr(755,root,root) %dir %{pipepath}
+-%attr(755,root,root) %dir %{pubconfpath}
+-%attr(755,root,root) %dir %{gpocachepath}
+-%attr(700,root,root) %dir %{pipepath}/private
+-%attr(750,root,root) %dir %{_var}/log/%{name}
+-%attr(711,root,root) %dir %{_sysconfdir}/sssd
+-%ghost %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
++%attr(700,sssd,sssd) %dir %{dbpath}
++%attr(755,sssd,sssd) %dir %{mcpath}
++%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd
++%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
++%attr(755,sssd,sssd) %dir %{pipepath}
++%attr(755,sssd,sssd) %dir %{pubconfpath}
++%attr(755,sssd,sssd) %dir %{gpocachepath}
++%attr(700,sssd,sssd) %dir %{pipepath}/private
++%attr(750,sssd,sssd) %dir %{_var}/log/%{name}
++%attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd
++%ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
+ %if (0%{?use_systemd} == 1)
+ %attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d
+ %config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf
+@@ -803,6 +803,10 @@ rm -rf $RPM_BUILD_ROOT
+ %{_libdir}/%{name}/modules/libwbclient.so
+ %{_libdir}/pkgconfig/wbclient_sssd.pc
+ 
++%pre common
++getent group sssd >/dev/null || groupadd -r sssd
++getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
++
+ %if (0%{?use_systemd} == 1)
+ # systemd
+ %post common
+-- 
+1.9.3
+
diff --git a/SOURCES/0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch b/SOURCES/0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch
deleted file mode 100644
index 50f54c9..0000000
--- a/SOURCES/0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch
+++ /dev/null
@@ -1,677 +0,0 @@
-From 6385798f807d370fe6685653e337f65bf59f21bc Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 12 Nov 2013 13:51:34 +0100
-Subject: [PATCH 25/31] ad: use tokengroups even when id mapping is disabled
-
-https://fedorahosted.org/sssd/ticket/1568
----
- src/providers/ldap/sdap_async.h               |   4 +-
- src/providers/ldap/sdap_async_initgroups.c    |  10 +-
- src/providers/ldap/sdap_async_initgroups_ad.c | 537 +++++++++++++++++++++++++-
- 3 files changed, 525 insertions(+), 26 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index 67623454e675f648259c089acca59258f386ecdb..f47437553a2d35dac90d86209848e840a237c3fb 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -296,13 +296,15 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req);
- struct tevent_req *
- sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-                                     struct tevent_context *ev,
-+                                    struct sdap_id_ctx *id_ctx,
-                                     struct sdap_options *opts,
-                                     struct sysdb_ctx *sysdb,
-                                     struct sss_domain_info *domain,
-                                     struct sdap_handle *sh,
-                                     const char *name,
-                                     const char *orig_dn,
--                                    int timeout);
-+                                    int timeout,
-+                                    bool use_id_mapping);
- 
- errno_t
- sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req);
-diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
-index 7d5cd2e7cbd86e2eb9774dfee1b8e31edec57b88..1b865af0a113222b3c9c11e9401718abad577fd7 100644
---- a/src/providers/ldap/sdap_async_initgroups.c
-+++ b/src/providers/ldap/sdap_async_initgroups.c
-@@ -2852,18 +2852,19 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
-             return;
-         }
- 
--        if (state->use_id_mapping
--                && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
-+        if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
-             /* Take advantage of AD's tokenGroups mechanism to look up all
-              * parent groups in a single request.
-              */
-             subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev,
-+                                                         state->id_ctx,
-                                                          state->opts,
-                                                          state->sysdb,
-                                                          state->dom,
-                                                          state->sh,
-                                                          cname, orig_dn,
--                                                         state->timeout);
-+                                                         state->timeout,
-+                                                         state->use_id_mapping);
-         } else if (state->opts->support_matching_rule
-                     && dp_opt_get_bool(state->opts->basic,
-                                        SDAP_AD_MATCHING_RULE_INITGROUPS)) {
-@@ -2950,8 +2951,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
- 
-     case SDAP_SCHEMA_RFC2307BIS:
-     case SDAP_SCHEMA_AD:
--        if (state->use_id_mapping
--                && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
-+        if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
-             ret = sdap_ad_tokengroups_initgroups_recv(subreq);
-         }
-         else if (state->opts->support_matching_rule
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index 7ba155338a358681c1bd201bee1c75f67afb4650..8e0506831cb189415b62efaa378d3dc7ec350cde 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -525,33 +525,180 @@ done:
-     return ret;
- }
- 
--struct sdap_ad_tokengroups_initgroups_state {
-+struct sdap_ad_resolve_sids_state {
-+    struct tevent_context *ev;
-+    struct sdap_id_ctx *id_ctx;
-+    struct sdap_options *opts;
-+    struct sss_domain_info *domain;
-+    char **sids;
-+
-+    const char *current_sid;
-+    int index;
-+};
-+
-+static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req);
-+static void sdap_ad_resolve_sids_done(struct tevent_req *subreq);
-+
-+static struct tevent_req *
-+sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx,
-+                          struct tevent_context *ev,
-+                          struct sdap_id_ctx *id_ctx,
-+                          struct sdap_options *opts,
-+                          struct sss_domain_info *domain,
-+                          char **sids)
-+{
-+    struct sdap_ad_resolve_sids_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct sdap_ad_resolve_sids_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
-+        return NULL;
-+    }
-+
-+    state->ev = ev;
-+    state->id_ctx = id_ctx;
-+    state->opts = opts;
-+    state->domain = get_domains_head(domain);
-+    state->sids = sids;
-+    state->index = 0;
-+
-+    if (state->sids == NULL) {
-+        ret = EOK;
-+        goto immediately;
-+    }
-+
-+    ret = sdap_ad_resolve_sids_step(req);
-+    if (ret != EAGAIN) {
-+        goto immediately;
-+    }
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+
-+    return req;
-+}
-+
-+static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req)
-+{
-+    struct sdap_ad_resolve_sids_state *state = NULL;
-+    struct tevent_req *subreq = NULL;
-+    struct sdap_domain *sdap_domain = NULL;
-+    struct sss_domain_info *domain = NULL;
-+
-+    state = tevent_req_data(req, struct sdap_ad_resolve_sids_state);
-+
-+    do {
-+        state->current_sid = state->sids[state->index];
-+        if (state->current_sid == NULL) {
-+            return EOK;
-+        }
-+        state->index++;
-+
-+        domain = find_subdomain_by_sid(state->domain, state->current_sid);
-+        if (domain == NULL) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("SID %s does not belong to any known "
-+                                         "domain\n", state->current_sid));
-+        }
-+    } while (domain == NULL);
-+
-+    sdap_domain = sdap_domain_get(state->opts, domain);
-+    if (sdap_domain == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("SDAP domain does not exist?\n"));
-+        return ERR_INTERNAL;
-+    }
-+
-+    subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain,
-+                             state->id_ctx->conn, state->current_sid,
-+                             BE_FILTER_SECID, BE_ATTR_CORE, false);
-+    if (subreq == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    tevent_req_set_callback(subreq, sdap_ad_resolve_sids_done, req);
-+
-+    return EAGAIN;
-+}
-+
-+static void sdap_ad_resolve_sids_done(struct tevent_req *subreq)
-+{
-+    struct sdap_ad_resolve_sids_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    int dp_error;
-+    int sdap_error;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct sdap_ad_resolve_sids_state);
-+
-+    ret = groups_get_recv(subreq, &dp_error, &sdap_error);
-+    talloc_zfree(subreq);
-+    if (ret != EOK || sdap_error != EOK || dp_error != DP_ERR_OK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to resolve SID %s [dp_error: %d, "
-+              "sdap_error: %d, ret: %d]: %s\n", state->current_sid, dp_error,
-+              sdap_error, ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    ret = sdap_ad_resolve_sids_step(req);
-+    if (ret == EAGAIN) {
-+        /* continue with next SID */
-+        return;
-+    }
-+
-+done:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+}
-+
-+static errno_t sdap_ad_resolve_sids_recv(struct tevent_req *req)
-+{
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-+
-+
-+struct sdap_ad_tokengroups_initgr_mapping_state {
-     struct sdap_idmap_ctx *idmap_ctx;
-     struct sysdb_ctx *sysdb;
-     struct sss_domain_info *domain;
-     const char *username;
- };
- 
--static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq);
-+static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq);
- 
--struct tevent_req *
--sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
--                                    struct tevent_context *ev,
--                                    struct sdap_options *opts,
--                                    struct sysdb_ctx *sysdb,
--                                    struct sss_domain_info *domain,
--                                    struct sdap_handle *sh,
--                                    const char *name,
--                                    const char *orig_dn,
--                                    int timeout)
-+static struct tevent_req *
-+sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx,
-+                                        struct tevent_context *ev,
-+                                        struct sdap_options *opts,
-+                                        struct sysdb_ctx *sysdb,
-+                                        struct sss_domain_info *domain,
-+                                        struct sdap_handle *sh,
-+                                        const char *name,
-+                                        const char *orig_dn,
-+                                        int timeout)
- {
--    struct sdap_ad_tokengroups_initgroups_state *state = NULL;
-+    struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL;
-     struct tevent_req *req = NULL;
-     struct tevent_req *subreq = NULL;
-     errno_t ret;
- 
-     req = tevent_req_create(mem_ctx, &state,
--                            struct sdap_ad_tokengroups_initgroups_state);
-+                            struct sdap_ad_tokengroups_initgr_mapping_state);
-     if (req == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
-         return NULL;
-@@ -573,7 +720,8 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-         goto immediately;
-     }
- 
--    tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_done, req);
-+    tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_done,
-+                            req);
- 
-     return req;
- 
-@@ -588,10 +736,10 @@ immediately:
-     return req;
- }
- 
--static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
-+static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq)
- {
-     TALLOC_CTX *tmp_ctx = NULL;
--    struct sdap_ad_tokengroups_initgroups_state *state = NULL;
-+    struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL;
-     struct tevent_req *req = NULL;
-     struct sss_domain_info *domain = NULL;
-     struct ldb_message *msg = NULL;
-@@ -599,14 +747,14 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
-     const char *name = NULL;
-     const char *sid = NULL;
-     char **sids = NULL;
--    size_t num_sids;
-+    size_t num_sids = 0;
-     size_t i;
-     time_t now;
-     gid_t gid;
-     char **groups = NULL;
-     size_t num_groups;
-     errno_t ret, sret;
--    bool in_transaction;
-+    bool in_transaction = false;
- 
-     tmp_ctx = talloc_new(NULL);
-     if (tmp_ctx == NULL) {
-@@ -616,7 +764,7 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
-     }
- 
-     req = tevent_req_callback_data(subreq, struct tevent_req);
--    state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
-+    state = tevent_req_data(req, struct sdap_ad_tokengroups_initgr_mapping_state);
- 
-     ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids);
-     talloc_zfree(subreq);
-@@ -738,6 +886,355 @@ done:
-     tevent_req_done(req);
- }
- 
-+static int sdap_ad_tokengroups_initgr_mapping_recv(struct tevent_req *req)
-+{
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-+
-+struct sdap_ad_tokengroups_initgr_posix_state {
-+    struct tevent_context *ev;
-+    struct sdap_id_ctx *id_ctx;
-+    struct sdap_options *opts;
-+    struct sysdb_ctx *sysdb;
-+    struct sss_domain_info *domain;
-+    const char *username;
-+};
-+
-+static void
-+sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq);
-+
-+static void
-+sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq);
-+
-+static struct tevent_req *
-+sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx,
-+                                      struct tevent_context *ev,
-+                                      struct sdap_id_ctx *id_ctx,
-+                                      struct sdap_options *opts,
-+                                      struct sysdb_ctx *sysdb,
-+                                      struct sss_domain_info *domain,
-+                                      struct sdap_handle *sh,
-+                                      const char *name,
-+                                      const char *orig_dn,
-+                                      int timeout)
-+{
-+    struct sdap_ad_tokengroups_initgr_posix_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct tevent_req *subreq = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct sdap_ad_tokengroups_initgr_posix_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
-+        return NULL;
-+    }
-+
-+    state->ev = ev;
-+    state->id_ctx = id_ctx;
-+    state->opts = opts;
-+    state->sysdb = sysdb;
-+    state->domain = domain;
-+    state->username = talloc_strdup(state, name);
-+    if (state->username == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn,
-+                                          timeout);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_done,
-+                            req);
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+
-+    return req;
-+}
-+
-+static void
-+sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq)
-+{
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    struct sdap_ad_tokengroups_initgr_posix_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    struct ldb_message *msg = NULL;
-+    const char *attrs[] = {SYSDB_NAME, SYSDB_POSIX, NULL};
-+    const char *is_posix = NULL;
-+    const char *name = NULL;
-+    char *sid = NULL;
-+    char **sids = NULL;
-+    size_t num_sids = 0;
-+    char **valid_groups = NULL;
-+    size_t num_valid_groups;
-+    char **missing_sids = NULL;
-+    size_t num_missing_sids;
-+    size_t i;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req,
-+                            struct sdap_ad_tokengroups_initgr_posix_state);
-+
-+    ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to acquire tokengroups [%d]: %s\n",
-+                                    ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    num_valid_groups = 0;
-+    valid_groups = talloc_zero_array(tmp_ctx, char*, num_sids + 1);
-+    if (valid_groups == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    num_missing_sids = 0;
-+    missing_sids = talloc_zero_array(tmp_ctx, char*, num_sids + 1);
-+    if (missing_sids == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    /* For each SID check if it is already present in the cache. If yes, we
-+     * will get name of the group and update the membership. Otherwise we need
-+     * to remember the SID and download missing groups one by one. */
-+    for (i = 0; i < num_sids; i++) {
-+        sid = sids[i];
-+        DEBUG(SSSDBG_TRACE_LIBS, ("Processing membership SID [%s]\n", sid));
-+
-+        domain = find_subdomain_by_sid(get_domains_head(state->domain), sid);
-+        if (domain == NULL) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n", sid));
-+            continue;
-+        }
-+
-+        ret = sysdb_search_group_by_sid_str(tmp_ctx, domain->sysdb, domain,
-+                                            sid, attrs, &msg);
-+        if (ret == EOK) {
-+            is_posix = ldb_msg_find_attr_as_string(msg, SYSDB_POSIX, NULL);
-+            if (is_posix != NULL && strcmp(is_posix, "FALSE") == 0) {
-+                /* skip non-posix group */
-+                continue;
-+            }
-+
-+            /* we will update membership of this group */
-+            name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+            if (name == NULL) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      ("Could not retrieve group name from sysdb\n"));
-+                ret = EINVAL;
-+                goto done;
-+            }
-+
-+            valid_groups[num_valid_groups] = sysdb_group_strdn(tmp_ctx,
-+                                                               domain->name,
-+                                                               name);
-+            if (valid_groups[num_valid_groups] == NULL) {
-+                ret = ENOMEM;
-+                goto done;
-+            }
-+            num_valid_groups++;
-+        } else if (ret == ENOENT) {
-+            /* we need to download this group */
-+            missing_sids[num_missing_sids] = talloc_steal(missing_sids, sid);
-+            num_missing_sids++;
-+
-+            DEBUG(SSSDBG_TRACE_FUNC, ("Missing SID %s will be downloaded\n",
-+                                      sid));
-+        } else {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Could not look up group in sysdb: "
-+                                         "[%s]\n", strerror(ret)));
-+            goto done;
-+        }
-+    }
-+
-+    valid_groups[num_valid_groups] = NULL;
-+    missing_sids[num_missing_sids] = NULL;
-+
-+    /* update membership of existing groups */
-+    ret = sdap_ad_tokengroups_update_members(state, state->username,
-+                                             state->sysdb, state->domain,
-+                                             valid_groups);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n",
-+                                     ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    /* download missing SIDs */
-+    missing_sids = talloc_steal(state, missing_sids);
-+    subreq = sdap_ad_resolve_sids_send(state, state->ev, state->id_ctx,
-+                                       state->opts, state->domain,
-+                                       missing_sids);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_sids_done,
-+                            req);
-+
-+    return;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+}
-+
-+static void
-+sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+
-+    ret = sdap_ad_resolve_sids_recv(subreq);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to resolve missing SIDs "
-+                                    "[%d]: %s\n", ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+done:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+}
-+
-+static errno_t sdap_ad_tokengroups_initgr_posix_recv(struct tevent_req *req)
-+{
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-+
-+struct sdap_ad_tokengroups_initgroups_state {
-+    bool use_id_mapping;
-+};
-+
-+static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq);
-+
-+struct tevent_req *
-+sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-+                                    struct tevent_context *ev,
-+                                    struct sdap_id_ctx *id_ctx,
-+                                    struct sdap_options *opts,
-+                                    struct sysdb_ctx *sysdb,
-+                                    struct sss_domain_info *domain,
-+                                    struct sdap_handle *sh,
-+                                    const char *name,
-+                                    const char *orig_dn,
-+                                    int timeout,
-+                                    bool use_id_mapping)
-+{
-+    struct sdap_ad_tokengroups_initgroups_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    struct tevent_req *subreq = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct sdap_ad_tokengroups_initgroups_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
-+        return NULL;
-+    }
-+
-+    state->use_id_mapping = use_id_mapping;
-+
-+    if (state->use_id_mapping) {
-+        subreq = sdap_ad_tokengroups_initgr_mapping_send(state, ev, opts,
-+                                                         sysdb, domain, sh,
-+                                                         name, orig_dn,
-+                                                         timeout);
-+    } else {
-+        subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, opts,
-+                                                       sysdb, domain, sh,
-+                                                       name, orig_dn,
-+                                                       timeout);
-+    }
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_done, req);
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+
-+    return req;
-+}
-+
-+static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
-+{
-+    struct sdap_ad_tokengroups_initgroups_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
-+
-+    if (state->use_id_mapping) {
-+        ret = sdap_ad_tokengroups_initgr_mapping_recv(subreq);
-+    } else {
-+        ret = sdap_ad_tokengroups_initgr_posix_recv(subreq);
-+    }
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+done:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+}
-+
- errno_t sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req)
- {
-     TEVENT_REQ_RETURN_ON_ERROR(req);
--- 
-1.8.4.2
-
diff --git a/SOURCES/0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch b/SOURCES/0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch
deleted file mode 100644
index a0be4bd..0000000
--- a/SOURCES/0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch
+++ /dev/null
@@ -1,309 +0,0 @@
-From 8d55e0fffd29184d44cb49eaab2ca3a4226e0123 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 10 Dec 2013 10:14:28 +0100
-Subject: [PATCH 26/31] AD: filter domain local groups for trusted/sub domains
-
-In Active Directory groups with a domain local scope should only be used
-inside of the specific domain. Since SSSD read the group memberships
-from LDAP server of the user's domain the domain local groups are
-included in the LDAP result. Those groups should be filtered out if the
-domain is a sub/trusted domain, i.e. is not the domain the client
-running SSSD is joined to.
-
-The groups will still be in the cache but marked as non-POSIX groups and
-no GID will be assigned.
-
-Fixes https://fedorahosted.org/sssd/ticket/2178
----
- src/providers/ldap/sdap.h                     |   8 ++
- src/providers/ldap/sdap_async_groups.c        | 160 ++++++++++++++++----------
- src/providers/ldap/sdap_async_initgroups_ad.c |   6 +-
- src/providers/ldap/sdap_async_nested_groups.c |  28 ++++-
- 4 files changed, 138 insertions(+), 64 deletions(-)
-
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index fa641730bb78b6a96c0b9640af7612b876f56533..a7ea94eb810a96b61862bd8cc6fcd800c3e8e0cb 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -137,6 +137,14 @@ struct sdap_ppolicy_data {
- #define SDAP_AD_USN "uSNChanged"
- #define SDAP_AD_LAST_USN "highestCommittedUSN"
- 
-+#define SDAP_AD_GROUP_TYPE_BUILTIN      0x00000001
-+#define SDAP_AD_GROUP_TYPE_GLOBAL       0x00000002
-+#define SDAP_AD_GROUP_TYPE_DOMAIN_LOCAL 0x00000004
-+#define SDAP_AD_GROUP_TYPE_UNIVERSAL    0x00000008
-+#define SDAP_AD_GROUP_TYPE_APP_BASIC    0x00000010
-+#define SDAP_AD_GROUP_TYPE_APP_QUERY    0x00000020
-+#define SDAP_AD_GROUP_TYPE_SECURITY     0x80000000
-+
- enum sdap_basic_opt {
-     SDAP_URI = 0,
-     SDAP_BACKUP_URI,
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 9f7e3e55d0234e9aa7b9e59456044587bcad88ef..33648c5da367c908d085a71a9a9017cb294bb300 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -451,6 +451,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
-     bool posix_group;
-     bool use_id_mapping;
-     char *sid_str;
-+    int32_t ad_group_type;
- 
-     tmpctx = talloc_new(NULL);
-     if (!tmpctx) {
-@@ -503,74 +504,113 @@ static int sdap_save_group(TALLOC_CTX *memctx,
-     }
-     DEBUG(SSSDBG_TRACE_FUNC, ("Processing group %s\n", group_name));
- 
--    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
--                                                               dom->name,
--                                                               sid_str);
--    if (use_id_mapping) {
--        posix_group = true;
--
--        if (sid_str == NULL) {
--            DEBUG(SSSDBG_MINOR_FAILURE, ("SID not available, cannot map a " \
--                                         "unix ID to group [%s].\n", group_name));
--            ret = ENOENT;
-+    posix_group = true;
-+    if (opts->schema_type == SDAP_SCHEMA_AD) {
-+        ret = sysdb_attrs_get_int32_t(attrs, SYSDB_GROUP_TYPE, &ad_group_type);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_int32_t failed.\n"));
-             goto done;
-         }
- 
--        DEBUG(SSSDBG_TRACE_LIBS,
--              ("Mapping group [%s] objectSID [%s] to unix ID\n",
--               group_name, sid_str));
--
--        /* Convert the SID into a UNIX group ID */
--        ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &gid);
--        if (ret == ENOTSUP) {
--            /* ENOTSUP is returned if built-in SID was provided
--             * => do not store the group, but return EOK */
--            DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n"));
--            ret = EOK;
--            goto done;
--        } else if (ret != EOK) {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Could not convert SID string: [%s]\n",
--                   strerror(ret)));
--            goto done;
-+        DEBUG(SSSDBG_TRACE_ALL, ("AD group [%s] has type flags %#x.",
-+                                 group_name, ad_group_type));
-+        /* Only security groups from AD are considered for POSIX groups.
-+         * Additionally only global and universal group are taken to account
-+         * for trusted domains. */
-+        if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY)
-+                || (IS_SUBDOMAIN(dom)
-+                    && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL)
-+                        || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) {
-+            posix_group = false;
-+            gid = 0;
-+            DEBUG(SSSDBG_TRACE_FUNC, ("Filtering AD group [%s].\n",
-+                                      group_name));
-+            ret = sysdb_attrs_add_uint32(group_attrs,
-+                                         opts->group_map[SDAP_AT_GROUP_GID].sys_name, 0);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      ("Failed to add a GID to non-posix group!\n"));
-+                return ret;
-+            }
-+            ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      ("Error: Failed to mark group as non-posix!\n"));
-+                return ret;
-+            }
-         }
-+    }
- 
--        /* Store the GID in the ldap_attrs so it doesn't get
--         * treated as a missing attribute from LDAP and removed.
--         */
--        ret = sdap_replace_id(attrs, SYSDB_GIDNUM, gid);
--        if (ret) {
--            DEBUG(SSSDBG_OP_FAILURE, ("Cannot set the id-mapped GID\n"));
--            goto done;
--        }
--    } else {
--        ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group);
--        if (ret == ENOENT) {
-+    if (posix_group) {
-+        use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
-+                                                                   dom->name,
-+                                                                   sid_str);
-+        if (use_id_mapping) {
-             posix_group = true;
--        } else if (ret != EOK) {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Error reading posix attribute: [%s]\n",
--                   strerror(ret)));
--            goto done;
--        }
- 
--        DEBUG(8, ("This is%s a posix group\n", (posix_group)?"":" not"));
--        ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Error setting posix attribute: [%s]\n",
--                   strerror(ret)));
--            goto done;
--        }
-+            if (sid_str == NULL) {
-+                DEBUG(SSSDBG_MINOR_FAILURE, ("SID not available, cannot map a " \
-+                                             "unix ID to group [%s].\n", group_name));
-+                ret = ENOENT;
-+                goto done;
-+            }
- 
--        ret = sysdb_attrs_get_uint32_t(attrs,
--                                       opts->group_map[SDAP_AT_GROUP_GID].sys_name,
--                                       &gid);
--        if (ret != EOK) {
--            DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
--                      group_name, dom->name));
--            ret = EINVAL;
--            goto done;
-+            DEBUG(SSSDBG_TRACE_LIBS,
-+                  ("Mapping group [%s] objectSID [%s] to unix ID\n",
-+                   group_name, sid_str));
-+
-+            /* Convert the SID into a UNIX group ID */
-+            ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &gid);
-+            if (ret == ENOTSUP) {
-+                /* ENOTSUP is returned if built-in SID was provided
-+                 * => do not store the group, but return EOK */
-+                DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n"));
-+                ret = EOK;
-+                goto done;
-+            } else if (ret != EOK) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      ("Could not convert SID string: [%s]\n",
-+                       strerror(ret)));
-+                goto done;
-+            }
-+
-+            /* Store the GID in the ldap_attrs so it doesn't get
-+             * treated as a missing attribute from LDAP and removed.
-+             */
-+            ret = sdap_replace_id(attrs, SYSDB_GIDNUM, gid);
-+            if (ret) {
-+                DEBUG(SSSDBG_OP_FAILURE, ("Cannot set the id-mapped GID\n"));
-+                goto done;
-+            }
-+        } else {
-+            ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group);
-+            if (ret == ENOENT) {
-+                posix_group = true;
-+            } else if (ret != EOK) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      ("Error reading posix attribute: [%s]\n",
-+                       strerror(ret)));
-+                goto done;
-+            }
-+
-+            DEBUG(8, ("This is%s a posix group\n", (posix_group)?"":" not"));
-+            ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      ("Error setting posix attribute: [%s]\n",
-+                       strerror(ret)));
-+                goto done;
-+            }
-+
-+            ret = sysdb_attrs_get_uint32_t(attrs,
-+                                           opts->group_map[SDAP_AT_GROUP_GID].sys_name,
-+                                           &gid);
-+            if (ret != EOK) {
-+                DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
-+                          group_name, dom->name));
-+                ret = EINVAL;
-+                goto done;
-+            }
-         }
-     }
- 
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index 8e0506831cb189415b62efaa378d3dc7ec350cde..f1bf77e8614c30b214118140e380c23c40c1195b 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -1145,6 +1145,7 @@ static errno_t sdap_ad_tokengroups_initgr_posix_recv(struct tevent_req *req)
- 
- struct sdap_ad_tokengroups_initgroups_state {
-     bool use_id_mapping;
-+    struct sss_domain_info *domain;
- };
- 
- static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq);
-@@ -1175,8 +1176,9 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-     }
- 
-     state->use_id_mapping = use_id_mapping;
-+    state->domain = domain;
- 
--    if (state->use_id_mapping) {
-+    if (state->use_id_mapping && !IS_SUBDOMAIN(state->domain)) {
-         subreq = sdap_ad_tokengroups_initgr_mapping_send(state, ev, opts,
-                                                          sysdb, domain, sh,
-                                                          name, orig_dn,
-@@ -1216,7 +1218,7 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
-     req = tevent_req_callback_data(subreq, struct tevent_req);
-     state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
- 
--    if (state->use_id_mapping) {
-+    if (state->use_id_mapping && !IS_SUBDOMAIN(state->domain)) {
-         ret = sdap_ad_tokengroups_initgr_mapping_recv(subreq);
-     } else {
-         ret = sdap_ad_tokengroups_initgr_posix_recv(subreq);
-diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c
-index c107b700b84b8c178051fd4505f3947be8373de2..f58564aec0628c827672950f767401ee32051b59 100644
---- a/src/providers/ldap/sdap_async_nested_groups.c
-+++ b/src/providers/ldap/sdap_async_nested_groups.c
-@@ -239,15 +239,39 @@ sdap_nested_group_hash_group(struct sdap_nested_group_ctx *group_ctx,
-     struct sdap_attr_map *map = group_ctx->opts->group_map;
-     gid_t gid;
-     errno_t ret;
-+    int32_t ad_group_type;
-+    bool posix_group = true;
-+
-+    if (group_ctx->opts->schema_type == SDAP_SCHEMA_AD) {
-+        ret = sysdb_attrs_get_int32_t(group, SYSDB_GROUP_TYPE, &ad_group_type);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_int32_t failed.\n"));
-+            return ret;
-+        }
-+
-+        DEBUG(SSSDBG_TRACE_ALL, ("AD group has type flags %#x.\n",
-+                                 ad_group_type));
-+        /* Only security groups from AD are considered for POSIX groups.
-+         * Additionally only global and universal group are taken to account
-+         * for trusted domains. */
-+        if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY)
-+                || (IS_SUBDOMAIN(group_ctx->domain)
-+                    && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL)
-+                        || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) {
-+            posix_group = false;
-+            gid = 0;
-+            DEBUG(SSSDBG_TRACE_FUNC, ("Filtering AD group.\n"));
-+        }
-+    }
- 
-     ret = sysdb_attrs_get_uint32_t(group, map[SDAP_AT_GROUP_GID].sys_name,
-                                    &gid);
--    if (ret == ENOENT || (ret == EOK && gid == 0)) {
-+    if (ret == ENOENT || (ret == EOK && gid == 0) || !posix_group) {
-         DEBUG(SSSDBG_TRACE_ALL,
-              ("The group's gid was %s\n", ret == ENOENT ? "missing" : "zero"));
-         DEBUG(SSSDBG_TRACE_INTERNAL,
-              ("Marking group as non-posix and setting GID=0!\n"));
--        if (ret == ENOENT) {
-+        if (ret == ENOENT || !posix_group) {
-             ret = sysdb_attrs_add_uint32(group,
-                                          map[SDAP_AT_GROUP_GID].sys_name, 0);
-             if (ret != EOK) {
--- 
-1.8.4.2
-
diff --git a/SOURCES/0026-SSSD-Load-a-user-to-run-a-service-as-from-configurat.patch b/SOURCES/0026-SSSD-Load-a-user-to-run-a-service-as-from-configurat.patch
new file mode 100644
index 0000000..646f2f7
--- /dev/null
+++ b/SOURCES/0026-SSSD-Load-a-user-to-run-a-service-as-from-configurat.patch
@@ -0,0 +1,216 @@
+From b8a3625690f39e22d8cd699598384bad472b6373 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 5 Aug 2014 13:52:48 +0200
+Subject: [PATCH 26/46] SSSD: Load a user to run a service as from
+ configuration
+
+Related:
+    https://fedorahosted.org/sssd/ticket/2370
+
+Adds a option, user to run as, that is specified in the [sssd] section. When
+this option is specified, SSSD will run as this user and his private
+group. When these are not specified, SSSD will run as the configure-time
+user and group (usually root).
+
+Currently all services and providers are started as root. There is a
+temporary svc_supported_as_nonroot() function that returns true for a
+service if that service runs and was tested as nonroot and false
+otherwise. Currently this function always returns false, but will be
+amended in future patches.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit a10ac1d0a7210def232205a48c53a075930e82f6)
+---
+ src/confdb/confdb.h                  |  1 +
+ src/config/SSSDConfig/__init__.py.in |  1 +
+ src/config/SSSDConfigTest.py         |  1 +
+ src/config/etc/sssd.api.conf         |  1 +
+ src/man/sssd.conf.5.xml              | 13 +++++++++
+ src/monitor/monitor.c                | 56 ++++++++++++++++++++++++++++++++++++
+ 6 files changed, 73 insertions(+)
+
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index 34d4610654c24017bcad8608332c71232d665d40..159aa9f2c44ed91c94a40c98d5a7710793f0aa85 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -69,6 +69,7 @@
+ #define CONFDB_MONITOR_KRB5_RCACHEDIR "krb5_rcache_dir"
+ #define CONFDB_MONITOR_DEFAULT_DOMAIN "default_domain_suffix"
+ #define CONFDB_MONITOR_OVERRIDE_SPACE "override_space"
++#define CONFDB_MONITOR_USER_RUNAS "user"
+ 
+ /* Both monitor and domains */
+ #define CONFDB_NAME_REGEX   "re_expression"
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 6c95530868d7c078ccf13622f3ba916392b0c732..b4560ea2b33f2c3b82bff42fb6a36302a146c99f 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -56,6 +56,7 @@ option_strings = {
+     'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'),
+     'krb5_rcache_dir' : _('Directory on the filesystem where SSSD should store Kerberos replay cache files.'),
+     'default_domain_suffix' : _('Domain to add to names without a domain component.'),
++    'user' : _('The user to drop privileges to'),
+ 
+     # [nss]
+     'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 2d12bc02af1768d22c8bfa9a21b1fc24bf199af4..78e22f6eff19aac8289d769dc9f565b2d548f4b3 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -280,6 +280,7 @@ class SSSDConfigTestSSSDService(unittest.TestCase):
+             're_expression',
+             'full_name_format',
+             'krb5_rcache_dir',
++            'user',
+             'default_domain_suffix',
+             'debug_level',
+             'debug_timestamps',
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index a20f5aa44dbadd24f644bffc9954df9e088979b9..c16769a3985f495922d255dacebccc11f6a0ea1d 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -23,6 +23,7 @@ sbus_timeout = int, None, false
+ re_expression = str, None, false
+ full_name_format = str, None, false
+ krb5_rcache_dir = str, None, false
++user = str, None, false
+ default_domain_suffix = str, None, false
+ 
+ [nss]
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 77690432b841221328d65403830cf4a1ac12dba0..e2cb0b81b61063750995064b6ce83f9615049534 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -297,6 +297,19 @@
+                         </listitem>
+                     </varlistentry>
+                     <varlistentry>
++                        <term>user (string)</term>
++                        <listitem>
++                            <para>
++                                The user to drop the privileges to where
++                                appropriate to avoid running as the
++                                root user.
++                            </para>
++                            <para>
++                                Default: not set, process will run as root
++                            </para>
++                        </listitem>
++                    </varlistentry>
++                    <varlistentry>
+                         <term>default_domain_suffix (string)</term>
+                         <listitem>
+                             <para>
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index edd1c2dfc674d8a7ca9d069d6499c0dcc959f210..df1cd5ca14c759f7aab98094a2b8ad35731c35e6 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -170,6 +170,10 @@ struct mt_ctx {
+     struct sss_sigchild_ctx *sigchld_ctx;
+     bool is_daemon;
+     pid_t parent_pid;
++
++    /* For running unprivileged services */
++    uid_t uid;
++    gid_t gid;
+ };
+ 
+ static int start_service(struct mt_svc *mt_svc);
+@@ -910,6 +914,29 @@ static char *check_services(char **services)
+     return NULL;
+ }
+ 
++static int get_service_user(struct mt_ctx *ctx)
++{
++    errno_t ret;
++    char *user_str;
++
++    ret = confdb_get_string(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
++                            CONFDB_MONITOR_USER_RUNAS,
++                            SSSD_USER, &user_str);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get the user to run as\n");
++        return ret;
++    }
++
++    ret = sss_user_by_name_or_uid(user_str, &ctx->uid, &ctx->gid);
++    talloc_free(user_str);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
++        return ret;
++    }
++
++    return EOK;
++}
++
+ static int get_monitor_config(struct mt_ctx *ctx)
+ {
+     int ret;
+@@ -955,6 +982,12 @@ static int get_monitor_config(struct mt_ctx *ctx)
+         ctx->num_services++;
+     }
+ 
++    ret = get_service_user(ctx);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to get the unprivileged user\n");
++        return ret;
++    }
++
+     ret = confdb_get_domains(ctx->cdb, &ctx->domains);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n");
+@@ -1020,6 +1053,14 @@ static errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
+     return EOK;
+ }
+ 
++/* This is a temporary function that returns false if the service
++ * being started was only tested when running as root.
++ */
++static bool svc_supported_as_nonroot(const char *svc_name)
++{
++    return false;
++}
++
+ static int get_service_config(struct mt_ctx *ctx, const char *name,
+                               struct mt_svc **svc_cfg)
+ {
+@@ -1027,6 +1068,8 @@ static int get_service_config(struct mt_ctx *ctx, const char *name,
+     char *path;
+     struct mt_svc *svc;
+     time_t now = time(NULL);
++    uid_t uid = 0;
++    gid_t gid = 0;
+ 
+     *svc_cfg = NULL;
+ 
+@@ -1066,6 +1109,11 @@ static int get_service_config(struct mt_ctx *ctx, const char *name,
+         return ret;
+     }
+ 
++    if (svc_supported_as_nonroot(svc->name)) {
++        uid = ctx->uid;
++        gid = ctx->gid;
++    }
++
+     if (!svc->command) {
+         svc->command = talloc_asprintf(
+             svc, "%s/sssd_%s", SSSD_LIBEXEC_PATH, svc->name
+@@ -1075,6 +1123,14 @@ static int get_service_config(struct mt_ctx *ctx, const char *name,
+             return ENOMEM;
+         }
+ 
++        svc->command = talloc_asprintf_append(svc->command,
++                " --uid %"SPRIuid" --gid %"SPRIgid,
++                uid, gid);
++        if (!svc->command) {
++            talloc_free(svc);
++            return ENOMEM;
++        }
++
+         if (cmdline_debug_level != SSSDBG_UNRESOLVED) {
+             svc->command = talloc_asprintf_append(
+                 svc->command, " -d %#.4x", cmdline_debug_level
+-- 
+1.9.3
+
diff --git a/SOURCES/0027-AD-cross-domain-membership-fix.patch b/SOURCES/0027-AD-cross-domain-membership-fix.patch
deleted file mode 100644
index 5f273b4..0000000
--- a/SOURCES/0027-AD-cross-domain-membership-fix.patch
+++ /dev/null
@@ -1,639 +0,0 @@
-From 402af69c0bb7ea8b84e36f3567de6086042cb152 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 18 Dec 2013 13:47:31 +0100
-Subject: [PATCH 27/31] AD: cross-domain membership fix
-
-A recent patch directed all call related to group membership lookups to
-the AD LDAP port to fix an issue related to missing group memberships in
-the Global Catalog. As a side-effect it broke cross-domain
-group-memberships because those cannot be resolved by the connection to
-the LDAP port.
-
-The patch tires to fix this by restoring the original behaviour in the
-top-level lookup calls in the AD provider and switching to the LDAP port
-only for the LDAP request which is expected to return the full group
-membership.
-
-Additionally this patch contains a related fix for the tokenGroups with
-Posix attributes patch. The original connection, typically a Global
-Catalog connection in the AD case is passed down the stack so that the
-group lookup after the tokenGroups request can run over the same
-connection.
----
- src/providers/ad/ad_id.c                      |  19 +--
- src/providers/ad/ad_init.c                    |   2 +
- src/providers/ldap/sdap_async.h               |   1 +
- src/providers/ldap/sdap_async_groups.c        |  62 +++++++-
- src/providers/ldap/sdap_async_initgroups.c    |  50 ++++++-
- src/providers/ldap/sdap_async_initgroups_ad.c | 197 ++++++++++++++++++++++----
- 6 files changed, 281 insertions(+), 50 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 19bc65825be21c6419db1e92db642be0a14b97a8..cf71b172dd7c241a9280a7ea72ef2518f66a7435 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -199,6 +199,8 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-     case BE_REQ_USER: /* user */
-     case BE_REQ_BY_SECID:   /* by SID */
-     case BE_REQ_USER_AND_GROUP: /* get SID */
-+    case BE_REQ_GROUP: /* group */
-+    case BE_REQ_INITGROUPS: /* init groups for user */
-         /* Always try GC first */
-         clist[0] = ad_ctx->gc_ctx;
-         if (IS_SUBDOMAIN(dom) == true) {
-@@ -215,23 +217,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-          */
-         clist[1] = ad_ctx->ldap_ctx;
-         break;
--
--    case BE_REQ_GROUP: /* group */
--    case BE_REQ_INITGROUPS: /* init groups for user */
--        if (IS_SUBDOMAIN(dom)) {
--            sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom);
--            if (sdom == NULL || sdom->pvt == NULL) {
--                DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n",
--                                            dom->name));
--                return NULL;
--            }
--            subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
--            clist[0] = subdom_id_ctx->ldap_ctx;
--        } else {
--            clist[0] = ad_ctx->ldap_ctx;
--        }
--        break;
--
-     default:
-         clist[0] = ad_ctx->ldap_ctx;
-         break;
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index d06efbd082bd6bba74fb6616c7dd722c99244988..332bfda3801db3824ce1896d37e65e2c3a6b8b8b 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -214,6 +214,8 @@ sssm_ad_id_init(struct be_ctx *bectx,
-         goto done;
-     }
- 
-+    ad_ctx->sdap_id_ctx->opts->sdom->pvt = ad_ctx;
-+
-     /* Set up the ID mapping object */
-     ret = sdap_idmap_init(ad_ctx->sdap_id_ctx, ad_ctx->sdap_id_ctx,
-                           &ad_ctx->sdap_id_ctx->opts->idmap_ctx);
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index f47437553a2d35dac90d86209848e840a237c3fb..33e8708ab7e80ab4280df300fdc300d4ecd18305 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -297,6 +297,7 @@ struct tevent_req *
- sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-                                     struct tevent_context *ev,
-                                     struct sdap_id_ctx *id_ctx,
-+                                    struct sdap_id_conn_ctx *conn,
-                                     struct sdap_options *opts,
-                                     struct sysdb_ctx *sysdb,
-                                     struct sss_domain_info *domain,
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 33648c5da367c908d085a71a9a9017cb294bb300..9eece9a6e4baaf302a28b57a63dae45a0741136c 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -26,6 +26,7 @@
- #include "providers/ldap/sdap_async_private.h"
- #include "providers/ldap/ldap_common.h"
- #include "providers/ldap/sdap_idmap.h"
-+#include "providers/ad/ad_common.h"
- 
- /* ==Group-Parsing Routines=============================================== */
- 
-@@ -1540,9 +1541,13 @@ struct sdap_get_groups_state {
- 
-     size_t base_iter;
-     struct sdap_search_base **search_bases;
-+
-+    struct sdap_handle *ldap_sh;
-+    struct sdap_id_op *op;
- };
- 
- static errno_t sdap_get_groups_next_base(struct tevent_req *req);
-+static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq);
- static void sdap_get_groups_process(struct tevent_req *subreq);
- static void sdap_get_groups_done(struct tevent_req *subreq);
- 
-@@ -1558,7 +1563,9 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
- {
-     errno_t ret;
-     struct tevent_req *req;
-+    struct tevent_req *subreq;
-     struct sdap_get_groups_state *state;
-+    struct ad_id_ctx *subdom_id_ctx;
- 
-     req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);
-     if (!req) return NULL;
-@@ -1586,6 +1593,30 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
-         goto done;
-     }
- 
-+    /* With AD by default the Global Catalog is used for lookup. But the GC
-+     * group object might not have full group membership data. To make sure we
-+     * connect to an LDAP server of the group's domain. */
-+    if (state->opts->schema_type == SDAP_SCHEMA_AD && sdom->pvt != NULL) {
-+        subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
-+        state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
-+        if (!state->op) {
-+            DEBUG(2, ("sdap_id_op_create failed\n"));
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        subreq = sdap_id_op_connect_send(state->op, state, &ret);
-+        if (subreq == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        tevent_req_set_callback(subreq,
-+                                sdap_get_groups_ldap_connect_done,
-+                                req);
-+        return req;
-+    }
-+
-     ret = sdap_get_groups_next_base(req);
- 
- done:
-@@ -1597,6 +1628,34 @@ done:
-     return req;
- }
- 
-+static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req;
-+    struct sdap_get_groups_state *state;
-+    int ret;
-+    int dp_error;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct sdap_get_groups_state);
-+
-+    ret = sdap_id_op_connect_recv(subreq, &dp_error);
-+    talloc_zfree(subreq);
-+
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    state->ldap_sh = sdap_id_op_handle(state->op);
-+
-+    ret = sdap_get_groups_next_base(req);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+    }
-+
-+    return;
-+}
-+
- static errno_t sdap_get_groups_next_base(struct tevent_req *req)
- {
-     struct tevent_req *subreq;
-@@ -1617,7 +1676,8 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-            state->search_bases[state->base_iter]->basedn));
- 
-     subreq = sdap_get_generic_send(
--            state, state->ev, state->opts, state->sh,
-+            state, state->ev, state->opts,
-+            state->ldap_sh != NULL ? state->ldap_sh : state->sh,
-             state->search_bases[state->base_iter]->basedn,
-             state->search_bases[state->base_iter]->scope,
-             state->filter, state->attrs,
-diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
-index 1b865af0a113222b3c9c11e9401718abad577fd7..aba7ba42dade8923ae91f5bc8962e03d038c15a1 100644
---- a/src/providers/ldap/sdap_async_initgroups.c
-+++ b/src/providers/ldap/sdap_async_initgroups.c
-@@ -2749,6 +2749,10 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
-     const char *orig_dn;
-     const char *cname;
-     bool in_transaction = false;
-+    char *expected_basedn;
-+    size_t expected_basedn_len;
-+    size_t dn_len;
-+    size_t c = 0;
- 
-     DEBUG(9, ("Receiving info for the user\n"));
- 
-@@ -2788,11 +2792,50 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
-     } else if (count != 1) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("Expected one user entry and got %zu\n", count));
--        tevent_req_error(req, EINVAL);
--        return;
-+
-+        ret = domain_to_basedn(state, state->dom->name, &expected_basedn);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("domain_to_basedn failed.\n"));
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+        expected_basedn = talloc_asprintf(state, "%s%s",
-+                                                 "cn=users,", expected_basedn);
-+        if (expected_basedn == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("talloc_append failed.\n"));
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+
-+        DEBUG(SSSDBG_TRACE_ALL, ("Expected BaseDN is [%s].\n", expected_basedn));
-+        expected_basedn_len = strlen(expected_basedn);
-+
-+        for (c = 0; c < count; c++) {
-+            ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-+                tevent_req_error(req, ret);
-+                return;
-+            }
-+            dn_len = strlen(orig_dn);
-+
-+            if (dn_len > expected_basedn_len
-+                    && strcasecmp(orig_dn + (dn_len - expected_basedn_len),
-+                                  expected_basedn) == 0) {
-+                DEBUG(SSSDBG_TRACE_ALL,
-+                      ("Found matching dn [%s].\n", orig_dn));
-+                break;
-+            }
-+        }
-+
-+        if (c == count) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("No matching DN found.\n"));
-+            tevent_req_error(req, EINVAL);
-+            return;
-+        }
-     }
- 
--    state->orig_user = usr_attrs[0];
-+    state->orig_user = usr_attrs[c];
- 
-     ret = sysdb_transaction_start(state->sysdb);
-     if (ret) {
-@@ -2858,6 +2901,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
-              */
-             subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev,
-                                                          state->id_ctx,
-+                                                         state->conn,
-                                                          state->opts,
-                                                          state->sysdb,
-                                                          state->dom,
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index f1bf77e8614c30b214118140e380c23c40c1195b..8f8f0a4cc635818dcc7f75f9da603ce2f55c820f 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -25,6 +25,7 @@
- #include "providers/ldap/ldap_common.h"
- #include "providers/ldap/sdap_async_private.h"
- #include "providers/ldap/sdap_idmap.h"
-+#include "providers/ad/ad_common.h"
- #include "lib/idmap/sss_idmap.h"
- 
- struct sdap_ad_match_rule_initgr_state {
-@@ -528,6 +529,7 @@ done:
- struct sdap_ad_resolve_sids_state {
-     struct tevent_context *ev;
-     struct sdap_id_ctx *id_ctx;
-+    struct sdap_id_conn_ctx *conn;
-     struct sdap_options *opts;
-     struct sss_domain_info *domain;
-     char **sids;
-@@ -543,6 +545,7 @@ static struct tevent_req *
- sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx,
-                           struct tevent_context *ev,
-                           struct sdap_id_ctx *id_ctx,
-+                          struct sdap_id_conn_ctx *conn,
-                           struct sdap_options *opts,
-                           struct sss_domain_info *domain,
-                           char **sids)
-@@ -560,6 +563,7 @@ sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx,
- 
-     state->ev = ev;
-     state->id_ctx = id_ctx;
-+    state->conn = conn;
-     state->opts = opts;
-     state->domain = get_domains_head(domain);
-     state->sids = sids;
-@@ -618,7 +622,7 @@ static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req)
-     }
- 
-     subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain,
--                             state->id_ctx->conn, state->current_sid,
-+                             state->conn, state->current_sid,
-                              BE_FILTER_SECID, BE_ATTR_CORE, false);
-     if (subreq == NULL) {
-         return ENOMEM;
-@@ -673,12 +677,21 @@ static errno_t sdap_ad_resolve_sids_recv(struct tevent_req *req)
- 
- 
- struct sdap_ad_tokengroups_initgr_mapping_state {
-+    struct tevent_context *ev;
-+    struct sdap_options *opts;
-+    struct sdap_handle *sh;
-     struct sdap_idmap_ctx *idmap_ctx;
-     struct sysdb_ctx *sysdb;
-     struct sss_domain_info *domain;
-+    const char *orig_dn;
-+    int timeout;
-     const char *username;
-+
-+    struct sdap_id_op *op;
- };
- 
-+static void
-+sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq);
- static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq);
- 
- static struct tevent_req *
-@@ -695,6 +708,8 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx,
-     struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL;
-     struct tevent_req *req = NULL;
-     struct tevent_req *subreq = NULL;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *subdom_id_ctx;
-     errno_t ret;
- 
-     req = tevent_req_create(mem_ctx, &state,
-@@ -704,36 +719,92 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx,
-         return NULL;
-     }
- 
-+    state->ev = ev;
-+    state->opts = opts;
-+    state->sh = sh;
-     state->idmap_ctx = opts->idmap_ctx;
-     state->sysdb = sysdb;
-     state->domain = domain;
-+    state->timeout = timeout;
-+    state->orig_dn = orig_dn;
-     state->username = talloc_strdup(state, name);
-     if (state->username == NULL) {
-         ret = ENOMEM;
-         goto immediately;
-     }
- 
--    subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn,
--                                          timeout);
-+    sdom = sdap_domain_get(opts, domain);
-+    if (sdom == NULL || sdom->pvt == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n",
-+                                    domain->name));
-+        ret = EINVAL;
-+        goto immediately;
-+    }
-+    subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
-+    state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
-+    if (!state->op) {
-+        DEBUG(2, ("sdap_id_op_create failed\n"));
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    subreq = sdap_id_op_connect_send(state->op, state, &ret);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto immediately;
-     }
- 
-+    tevent_req_set_callback(subreq,
-+                            sdap_ad_tokengroups_initgr_mapping_connect_done,
-+                            req);
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+
-+    return req;
-+}
-+
-+static void
-+sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq)
-+{
-+    struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    int ret;
-+    int dp_error = DP_ERR_FATAL;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req,
-+                            struct sdap_ad_tokengroups_initgr_mapping_state);
-+
-+
-+    ret = sdap_id_op_connect_recv(subreq, &dp_error);
-+    talloc_zfree(subreq);
-+
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    subreq = sdap_get_ad_tokengroups_send(state, state->ev, state->opts,
-+                                          sdap_id_op_handle(state->op),
-+                                          state->username,
-+                                          state->orig_dn, state->timeout);
-+    if (subreq == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    }
-+
-     tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_done,
-                             req);
- 
--    return req;
--
--immediately:
--    if (ret == EOK) {
--        tevent_req_done(req);
--    } else {
--        tevent_req_error(req, ret);
--    }
--    tevent_req_post(req, ev);
--
--    return req;
-+    return;
- }
- 
- static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq)
-@@ -896,22 +967,31 @@ static int sdap_ad_tokengroups_initgr_mapping_recv(struct tevent_req *req)
- struct sdap_ad_tokengroups_initgr_posix_state {
-     struct tevent_context *ev;
-     struct sdap_id_ctx *id_ctx;
-+    struct sdap_id_conn_ctx *conn;
-     struct sdap_options *opts;
-+    struct sdap_handle *sh;
-     struct sysdb_ctx *sysdb;
-     struct sss_domain_info *domain;
-+    const char *orig_dn;
-+    int timeout;
-     const char *username;
-+
-+    struct sdap_id_op *op;
- };
- 
- static void
- sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq);
- 
- static void
-+sdap_ad_tokengroups_initgr_posix_sids_connect_done(struct tevent_req *subreq);
-+static void
- sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq);
- 
- static struct tevent_req *
- sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx,
-                                       struct tevent_context *ev,
-                                       struct sdap_id_ctx *id_ctx,
-+                                      struct sdap_id_conn_ctx *conn,
-                                       struct sdap_options *opts,
-                                       struct sysdb_ctx *sysdb,
-                                       struct sss_domain_info *domain,
-@@ -923,6 +1003,8 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx,
-     struct sdap_ad_tokengroups_initgr_posix_state *state = NULL;
-     struct tevent_req *req = NULL;
-     struct tevent_req *subreq = NULL;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *subdom_id_ctx;
-     errno_t ret;
- 
-     req = tevent_req_create(mem_ctx, &state,
-@@ -934,36 +1016,91 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx,
- 
-     state->ev = ev;
-     state->id_ctx = id_ctx;
-+    state->conn = conn;
-     state->opts = opts;
-+    state->sh = sh;
-     state->sysdb = sysdb;
-     state->domain = domain;
-+    state->orig_dn = orig_dn;
-+    state->timeout = timeout;
-     state->username = talloc_strdup(state, name);
-     if (state->username == NULL) {
-         ret = ENOMEM;
-         goto immediately;
-     }
- 
--    subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn,
--                                          timeout);
-+    sdom = sdap_domain_get(opts, domain);
-+    if (sdom == NULL || sdom->pvt == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n",
-+                                    domain->name));
-+        ret = EINVAL;
-+        goto immediately;
-+    }
-+    subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
-+    state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
-+    if (!state->op) {
-+        DEBUG(2, ("sdap_id_op_create failed\n"));
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    subreq = sdap_id_op_connect_send(state->op, state, &ret);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto immediately;
-     }
- 
-+    tevent_req_set_callback(subreq,
-+                            sdap_ad_tokengroups_initgr_posix_sids_connect_done,
-+                            req);
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+
-+    return req;
-+}
-+
-+static void
-+sdap_ad_tokengroups_initgr_posix_sids_connect_done(struct tevent_req *subreq)
-+{
-+    struct sdap_ad_tokengroups_initgr_posix_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    int ret;
-+    int dp_error = DP_ERR_FATAL;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req,
-+                            struct sdap_ad_tokengroups_initgr_posix_state);
-+
-+
-+    ret = sdap_id_op_connect_recv(subreq, &dp_error);
-+    talloc_zfree(subreq);
-+
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    subreq = sdap_get_ad_tokengroups_send(state, state->ev, state->opts,
-+                                          sdap_id_op_handle(state->op),
-+                                          state->username, state->orig_dn,
-+                                          state->timeout);
-+    if (subreq == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    }
-+
-     tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_done,
-                             req);
- 
--    return req;
--
--immediately:
--    if (ret == EOK) {
--        tevent_req_done(req);
--    } else {
--        tevent_req_error(req, ret);
--    }
--    tevent_req_post(req, ev);
--
--    return req;
-+    return;
- }
- 
- static void
-@@ -1089,6 +1226,7 @@ sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq)
-     /* download missing SIDs */
-     missing_sids = talloc_steal(state, missing_sids);
-     subreq = sdap_ad_resolve_sids_send(state, state->ev, state->id_ctx,
-+                                       state->conn,
-                                        state->opts, state->domain,
-                                        missing_sids);
-     if (subreq == NULL) {
-@@ -1154,6 +1292,7 @@ struct tevent_req *
- sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-                                     struct tevent_context *ev,
-                                     struct sdap_id_ctx *id_ctx,
-+                                    struct sdap_id_conn_ctx *conn,
-                                     struct sdap_options *opts,
-                                     struct sysdb_ctx *sysdb,
-                                     struct sss_domain_info *domain,
-@@ -1184,8 +1323,8 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
-                                                          name, orig_dn,
-                                                          timeout);
-     } else {
--        subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, opts,
--                                                       sysdb, domain, sh,
-+        subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, conn,
-+                                                       opts, sysdb, domain, sh,
-                                                        name, orig_dn,
-                                                        timeout);
-     }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0027-SBUS-Chown-the-sbus-socket-if-needed.patch b/SOURCES/0027-SBUS-Chown-the-sbus-socket-if-needed.patch
new file mode 100644
index 0000000..0398ee0
--- /dev/null
+++ b/SOURCES/0027-SBUS-Chown-the-sbus-socket-if-needed.patch
@@ -0,0 +1,165 @@
+From 2b8bb71a6f17dd0348ae07f0488d3de76b791c7f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 7 Oct 2014 11:30:01 +0200
+Subject: [PATCH 27/46] SBUS: Chown the sbus socket if needed
+
+When setting up the sbus server, we might need to chown the sbus socket
+to make sure non-root peers, running as the SSSD user are able to access
+the file.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 5960687483a5d3d99093c9d6ab64e11c9bde7f7b)
+---
+ src/monitor/monitor.c            |  6 +++++-
+ src/providers/data_provider_be.c |  2 +-
+ src/providers/proxy/proxy_init.c |  2 +-
+ src/sbus/sbus_client.c           | 15 +++++++++++++--
+ src/sbus/sssd_dbus.h             |  1 +
+ src/sbus/sssd_dbus_server.c      | 18 ++++++++++++++++--
+ src/tests/common_dbus.c          |  4 ++--
+ 7 files changed, 39 insertions(+), 9 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index df1cd5ca14c759f7aab98094a2b8ad35731c35e6..b6777784cd289e85c865fc16490d0287a63192a5 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -515,7 +515,11 @@ static int monitor_dbus_init(struct mt_ctx *ctx)
+         return ret;
+     }
+ 
+-    ret = sbus_new_server(ctx, ctx->ev, monitor_address,
++    /* If a service is running as unprivileged user, we need to make sure this
++     * user can access the monitor sbus server. root is still king, so we don't
++     * lose any access.
++     */
++    ret = sbus_new_server(ctx, ctx->ev, monitor_address, ctx->uid, ctx->gid,
+                           false, &ctx->sbus_srv, monitor_service_init, ctx);
+ 
+     talloc_free(monitor_address);
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 18b50214b0795709d583d5891bf4f6fd220bcb11..122c5b091751b641f815ddff5c56ac99ace69939 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -2263,7 +2263,7 @@ static int be_srv_init(struct be_ctx *ctx)
+         return ret;
+     }
+ 
+-    ret = sbus_new_server(ctx, ctx->ev, sbus_address,
++    ret = sbus_new_server(ctx, ctx->ev, sbus_address, 0, 0,
+                           true, &ctx->sbus_srv, be_client_init, ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
+diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
+index dd1b75826fbfc384dd37ba659a8653547cc35bcf..1e734511766f2c0f58cffc7d726a26ecfd6c9a27 100644
+--- a/src/providers/proxy/proxy_init.c
++++ b/src/providers/proxy/proxy_init.c
+@@ -522,7 +522,7 @@ int sssm_proxy_auth_init(struct be_ctx *bectx,
+         goto done;
+     }
+ 
+-    ret = sbus_new_server(ctx, bectx->ev, sbus_address,
++    ret = sbus_new_server(ctx, bectx->ev, sbus_address, 0, 0,
+                           false, &ctx->sbus_srv, proxy_client_init, ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
+diff --git a/src/sbus/sbus_client.c b/src/sbus/sbus_client.c
+index 6cf5002dc2b8f3b85a3110298db8255b82172ddd..8ad4c0f36a929e341793cca61fe12808e14f6bc6 100644
+--- a/src/sbus/sbus_client.c
++++ b/src/sbus/sbus_client.c
+@@ -32,6 +32,8 @@ int sbus_client_init(TALLOC_CTX *mem_ctx,
+     struct sbus_connection *conn = NULL;
+     int ret;
+     char *filename;
++    uid_t check_uid;
++    gid_t check_gid;
+ 
+     /* Validate input */
+     if (server_address == NULL) {
+@@ -45,8 +47,17 @@ int sbus_client_init(TALLOC_CTX *mem_ctx,
+         return EIO;
+     }
+ 
+-    ret = check_file(filename,
+-                     0, 0, S_IFSOCK|S_IRUSR|S_IWUSR, 0, NULL, true);
++    check_uid = geteuid();
++    check_gid = getegid();
++
++    /* Ignore ownership checks when the server runs as root. This is the
++     * case when privileged monitor is setting up sockets for unprivileged
++     * responders */
++    if (check_uid == 0) check_uid = -1;
++    if (check_gid == 0) check_gid = -1;
++
++    ret = check_file(filename, check_uid, check_gid,
++                     S_IFSOCK|S_IRUSR|S_IWUSR, 0, NULL, true);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "check_file failed for [%s].\n", filename);
+         return EIO;
+diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
+index 372521a3575f967b751c9e13a7d830d9c3b43584..d01926368ce0ae5312d8ea0057a89d9a7176836b 100644
+--- a/src/sbus/sssd_dbus.h
++++ b/src/sbus/sssd_dbus.h
+@@ -132,6 +132,7 @@ sbus_new_interface(TALLOC_CTX *mem_ctx,
+ int sbus_new_server(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *ev,
+                     const char *address,
++                    uid_t uid, gid_t gid,
+                     bool use_symlink,
+                     struct sbus_connection **server,
+                     sbus_server_conn_init_fn init_fn, void *init_pvt_data);
+diff --git a/src/sbus/sssd_dbus_server.c b/src/sbus/sssd_dbus_server.c
+index 3a7de8ff019160b2305516945740dfb6453d578b..18fb98df61f1740898f725cb0ae9924f5e2f7716 100644
+--- a/src/sbus/sssd_dbus_server.c
++++ b/src/sbus/sssd_dbus_server.c
+@@ -181,6 +181,7 @@ remove_socket_symlink(const char *symlink_name)
+ int sbus_new_server(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *ev,
+                     const char *address,
++                    uid_t uid, gid_t gid,
+                     bool use_symlink,
+                     struct sbus_connection **_server,
+                     sbus_server_conn_init_fn init_fn,
+@@ -260,9 +261,22 @@ int sbus_new_server(TALLOC_CTX *mem_ctx,
+     if ((stat_buf.st_mode & ~S_IFMT) != (S_IRUSR|S_IWUSR)) {
+         ret = chmod(filename, (S_IRUSR|S_IWUSR));
+         if (ret != EOK) {
++            ret = errno;
+             DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "chmod failed for [%s]: [%d][%s].\n", filename, errno,
+-                                                         strerror(errno));
++                  "chmod failed for [%s]: [%d][%s].\n", filename, ret,
++                                                        sss_strerror(ret));
++            ret = EIO;
++            goto done;
++        }
++    }
++
++    if (stat_buf.st_uid != uid || stat_buf.st_gid != gid) {
++        ret = chown(filename, uid, gid);
++        if (ret != EOK) {
++            ret = errno;
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "chown failed for [%s]: [%d][%s].\n", filename, ret,
++                                                        sss_strerror(ret));
+             ret = EIO;
+             goto done;
+         }
+diff --git a/src/tests/common_dbus.c b/src/tests/common_dbus.c
+index 3117c080dc3106517bee933a458583f35b04fa63..1b0ae88dc05a1514938218e97a50e9ef7b54b193 100644
+--- a/src/tests/common_dbus.c
++++ b/src/tests/common_dbus.c
+@@ -112,8 +112,8 @@ mock_server_child(void *data)
+     ctx = talloc_new(NULL);
+     loop = tevent_context_init(ctx);
+ 
+-    verify_eq (sbus_new_server(ctx, loop, mock->dbus_address, false,
+-                               &server, on_accept_connection, mock), EOK);
++    verify_eq (sbus_new_server(ctx, loop, mock->dbus_address, geteuid(), getegid(),
++                               false, &server, on_accept_connection, mock), EOK);
+ 
+     tevent_add_fd(loop, ctx, mock->sync_fds[1], TEVENT_FD_READ,
+                   on_sync_fd_written, &stop_server);
+-- 
+1.9.3
+
diff --git a/SOURCES/0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch b/SOURCES/0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch
deleted file mode 100644
index 3083367..0000000
--- a/SOURCES/0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch
+++ /dev/null
@@ -1,497 +0,0 @@
-From 1dced7370e55be16154bbb649606f928765819d0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Dec 2013 20:45:44 +0100
-Subject: [PATCH 28/31] AD: Add a utility function to create list of
- connections
-
-ad_id.c and ad_access.c used the same block of code. With the upcoming
-option to disable GC lookups, we should unify the code in a function to
-avoid breaking one of the code paths.
-
-The same applies for the LDAP connection to the trusted AD DC.
-
-Includes a unit test.
----
- Makefile.am                       |  28 +++++
- src/providers/ad/ad_access.c      |  16 +--
- src/providers/ad/ad_access.h      |   4 +-
- src/providers/ad/ad_common.c      |  52 +++++++++
- src/providers/ad/ad_common.h      |   7 ++
- src/providers/ad/ad_id.c          |  29 ++---
- src/providers/ad/ad_init.c        |   3 +-
- src/tests/cmocka/test_ad_common.c | 221 ++++++++++++++++++++++++++++++++++++++
- 8 files changed, 319 insertions(+), 41 deletions(-)
- create mode 100644 src/tests/cmocka/test_ad_common.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 583ccdb499306268640bfb894f673c42945e19ff..da407038089f3c010dea139735db9e0e2f000943 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -152,6 +152,7 @@ if HAVE_CMOCKA
-         test_sss_idmap \
-         test_utils \
-         ad_access_filter_tests \
-+        ad_common_tests \
-         test_search_bases
- endif
- 
-@@ -1398,6 +1399,7 @@ ad_access_filter_tests_SOURCES = \
-     src/util/sss_krb5.c \
-     src/util/find_uid.c \
-     src/util/user_info_msg.c \
-+    src/providers/ad/ad_common.c \
-     src/tests/cmocka/test_ad_access_filter.c
- ad_access_filter_tests_CFLAGS = \
-     $(AM_CFLAGS) \
-@@ -1416,6 +1418,32 @@ ad_access_filter_tests_LDADD = \
-     libsss_krb5_common.la \
-     libsss_test_common.la
- 
-+ad_common_tests_SOURCES = \
-+    $(sssd_be_SOURCES) \
-+    src/util/sss_ldap.c \
-+    src/util/sss_krb5.c \
-+    src/util/find_uid.c \
-+    src/util/user_info_msg.c \
-+    src/tests/cmocka/test_ad_common.c
-+ad_common_tests_CFLAGS = \
-+    $(AM_CFLAGS) \
-+    $(SYSTEMD_LOGIN_CFLAGS) \
-+    -DUNIT_TESTING
-+ad_common_tests_LDFLAGS = \
-+    -Wl,-wrap,sdap_set_sasl_options
-+ad_common_tests_LDADD = \
-+    $(PAM_LIBS) \
-+    $(CMOCKA_LIBS) \
-+    $(SSSD_LIBS) \
-+    $(CARES_LIBS) \
-+    $(KRB5_LIBS) \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    $(SYSTEMD_LOGIN_LIBS) \
-+    libsss_ldap_common.la \
-+    libsss_idmap.la \
-+    libsss_krb5_common.la \
-+    libsss_test_common.la
-+
- endif
- 
- noinst_PROGRAMS = pam_test_client
-diff --git a/src/providers/ad/ad_access.c b/src/providers/ad/ad_access.c
-index 6995172db304810899e538b37572e4ba953db3e7..68a292abc88daa2f10f6797db50cc75335e80483 100644
---- a/src/providers/ad/ad_access.c
-+++ b/src/providers/ad/ad_access.c
-@@ -274,26 +274,12 @@ ad_access_send(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    state->clist = talloc_zero_array(state, struct sdap_id_conn_ctx *, 3);
-+    state->clist = ad_gc_conn_list(state, ctx->ad_id_ctx, domain);
-     if (state->clist == NULL) {
-         ret = ENOMEM;
-         goto done;
-     }
- 
--    /* Always try GC first */
--    ctx->gc_ctx->ignore_mark_offline = false;
--    state->clist[0] = ctx->gc_ctx;
--    if (IS_SUBDOMAIN(domain) == false) {
--        /* fall back to ldap if gc is not available */
--        state->clist[0]->ignore_mark_offline = true;
--
--        /* With root domain users we have the option to
--         * fall back to LDAP in case ie POSIX attributes
--         * are used but not replicated to GC
--         */
--        state->clist[1] = ctx->ldap_ctx;
--    }
--
-     ret = ad_access_step(req, state->clist[state->cindex]);
-     if (ret != EOK) {
-         goto done;
-diff --git a/src/providers/ad/ad_access.h b/src/providers/ad/ad_access.h
-index ca5e69729c574be53b7da04df0ff89446da04c58..3bd19ccc508b43f7103c7041dcc8573a00235097 100644
---- a/src/providers/ad/ad_access.h
-+++ b/src/providers/ad/ad_access.h
-@@ -26,9 +26,7 @@
- struct ad_access_ctx {
-     struct dp_option *ad_options;
-     struct sdap_access_ctx *sdap_access_ctx;
--
--    struct sdap_id_conn_ctx *ldap_ctx;
--    struct sdap_id_conn_ctx *gc_ctx;
-+    struct ad_id_ctx *ad_id_ctx;
- };
- 
- void
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index f679c11ad18078b454b778ef30e40cca716412cb..af0ec839964233c7642205f4489e5b6462509848 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1096,3 +1096,55 @@ ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx)
- 
-     return ad_ctx;
- }
-+
-+struct sdap_id_conn_ctx *
-+ad_get_dom_ldap_conn(struct ad_id_ctx *ad_ctx, struct sss_domain_info *dom)
-+{
-+    struct sdap_id_conn_ctx *conn;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *subdom_id_ctx;
-+
-+    if (IS_SUBDOMAIN(dom)) {
-+        sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom);
-+        if (sdom == NULL || sdom->pvt == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n",
-+                                        dom->name));
-+            return NULL;
-+        }
-+        subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
-+        conn = subdom_id_ctx->ldap_ctx;
-+    } else {
-+        conn = ad_ctx->ldap_ctx;
-+    }
-+
-+    return conn;
-+}
-+
-+struct sdap_id_conn_ctx **
-+ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
-+                struct sss_domain_info *dom)
-+{
-+    struct sdap_id_conn_ctx **clist;
-+
-+    clist = talloc_zero_array(mem_ctx, struct sdap_id_conn_ctx *, 3);
-+    if (clist == NULL) return NULL;
-+
-+    /* Always try GC first */
-+    clist[0] = ad_ctx->gc_ctx;
-+    if (IS_SUBDOMAIN(dom) == true) {
-+        clist[0]->ignore_mark_offline = false;
-+        /* Subdomain users are only present in GC. */
-+        return clist;
-+    }
-+
-+    /* fall back to ldap if gc is not available */
-+    clist[0]->ignore_mark_offline = true;
-+
-+    /* With root domain users we have the option to
-+     * fall back to LDAP in case ie POSIX attributes
-+     * are used but not replicated to GC
-+     */
-+    clist[1] = ad_ctx->ldap_ctx;
-+
-+    return clist;
-+}
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index b8b73c042b8a5433f720c89c04447c07cd3eac43..ed5b8584dc5327a24e60985486c6155604271fd2 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -115,6 +115,13 @@ ad_get_dyndns_options(struct be_ctx *be_ctx,
- struct ad_id_ctx *
- ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx);
- 
-+struct sdap_id_conn_ctx **
-+ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
-+               struct sss_domain_info *dom);
-+
-+struct sdap_id_conn_ctx *
-+ad_get_dom_ldap_conn(struct ad_id_ctx *ad_ctx, struct sss_domain_info *dom);
-+
- /* AD dynamic DNS updates */
- errno_t ad_dyndns_init(struct be_ctx *be_ctx,
-                        struct ad_options *ctx);
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index cf71b172dd7c241a9280a7ea72ef2518f66a7435..e47c41863a14eed695907548d64f4559fbae629d 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -188,12 +188,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-               struct sss_domain_info *dom, struct be_acct_req *ar)
- {
-     struct sdap_id_conn_ctx **clist;
--    struct sdap_domain *sdom;
--    struct ad_id_ctx *subdom_id_ctx;
--
--    /* LDAP, GC, sentinel */
--    clist = talloc_zero_array(breq, struct sdap_id_conn_ctx *, 3);
--    if (clist == NULL) return NULL;
- 
-     switch (ar->entry_type & BE_REQ_TYPE_MASK) {
-     case BE_REQ_USER: /* user */
-@@ -201,24 +195,17 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-     case BE_REQ_USER_AND_GROUP: /* get SID */
-     case BE_REQ_GROUP: /* group */
-     case BE_REQ_INITGROUPS: /* init groups for user */
--        /* Always try GC first */
--        clist[0] = ad_ctx->gc_ctx;
--        if (IS_SUBDOMAIN(dom) == true) {
--            clist[0]->ignore_mark_offline = false;
--            /* Subdomain users are only present in GC. */
--            break;
--        }
--        /* fall back to ldap if gc is not available */
--        clist[0]->ignore_mark_offline = true;
--
--        /* With root domain users we have the option to
--         * fall back to LDAP in case ie POSIX attributes
--         * are used but not replicated to GC
--         */
--        clist[1] = ad_ctx->ldap_ctx;
-+        clist = ad_gc_conn_list(breq, ad_ctx, dom);
-+        if (clist == NULL) return NULL;
-         break;
-+
-     default:
-+        /* Requests for other object should only contact LDAP by default */
-+        clist = talloc_zero_array(breq, struct sdap_id_conn_ctx *, 2);
-+        if (clist == NULL) return NULL;
-+
-         clist[0] = ad_ctx->ldap_ctx;
-+        clist[1] = NULL;
-         break;
-     }
- 
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index 332bfda3801db3824ce1896d37e65e2c3a6b8b8b..ed69a7d9889bac1281b5ff7c7b0f290ab09173fb 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -377,8 +377,7 @@ sssm_ad_access_init(struct be_ctx *bectx,
-     if (ret != EOK) {
-         goto fail;
-     }
--    access_ctx->ldap_ctx = ad_id_ctx->ldap_ctx;
--    access_ctx->gc_ctx = ad_id_ctx->gc_ctx;
-+    access_ctx->ad_id_ctx = ad_id_ctx;
- 
-     ret = dp_copy_options(access_ctx, ad_options->basic, AD_OPTS_BASIC,
-                           &access_ctx->ad_options);
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..648b68f2dc05947b1fbb4c680ec63d3c2c6275b3
---- /dev/null
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -0,0 +1,221 @@
-+/*
-+    Authors:
-+        Jakub Hrozek <jhrozek@redhat.com>
-+
-+    Copyright (C) 2013 Red Hat
-+
-+    SSSD tests: AD access control filter tests
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include <talloc.h>
-+#include <tevent.h>
-+#include <errno.h>
-+#include <popt.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <ifaddrs.h>
-+#include <arpa/inet.h>
-+
-+/* In order to access opaque types */
-+#include "providers/ad/ad_common.c"
-+
-+#include "tests/cmocka/common_mock.h"
-+
-+#define DOMNAME     "domname"
-+#define SUBDOMNAME  "sub."DOMNAME
-+#define REALMNAME   DOMNAME
-+#define HOST_NAME   "ad."REALMNAME
-+
-+struct ad_common_test_ctx {
-+    struct ad_id_ctx *ad_ctx;
-+    struct ad_id_ctx *subdom_ad_ctx;
-+
-+    struct sss_domain_info *dom;
-+    struct sss_domain_info *subdom;
-+};
-+
-+static void
-+ad_common_test_setup(void **state)
-+{
-+    struct ad_common_test_ctx *test_ctx;
-+    errno_t ret;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *ad_ctx;
-+    struct ad_id_ctx *subdom_ad_ctx;
-+    struct sdap_id_conn_ctx *subdom_ldap_ctx;
-+
-+    assert_true(leak_check_setup());
-+    check_leaks_push(global_talloc_context);
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct ad_common_test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    test_ctx->dom = talloc_zero(test_ctx, struct sss_domain_info);
-+    assert_non_null(test_ctx->dom);
-+    test_ctx->dom->name = discard_const(DOMNAME);
-+
-+    test_ctx->subdom = talloc_zero(test_ctx, struct sss_domain_info);
-+    assert_non_null(test_ctx->subdom);
-+    test_ctx->subdom->name = discard_const(SUBDOMNAME);
-+    test_ctx->subdom->parent = test_ctx->dom;
-+
-+    ad_ctx = talloc_zero(test_ctx, struct ad_id_ctx);
-+    assert_non_null(ad_ctx);
-+
-+    ad_ctx->ad_options = ad_create_default_options(ad_ctx,
-+                                                   REALMNAME, HOST_NAME);
-+    assert_non_null(ad_ctx->ad_options);
-+
-+    ad_ctx->gc_ctx = talloc_zero(ad_ctx, struct sdap_id_conn_ctx);
-+    assert_non_null(ad_ctx->gc_ctx);
-+
-+    ad_ctx->ldap_ctx = talloc_zero(ad_ctx, struct sdap_id_conn_ctx);
-+    assert_non_null(ad_ctx->ldap_ctx);
-+
-+    ad_ctx->sdap_id_ctx = talloc_zero(ad_ctx, struct sdap_id_ctx);
-+    assert_non_null(ad_ctx->sdap_id_ctx);
-+
-+    ad_ctx->sdap_id_ctx->opts = talloc_zero(ad_ctx->sdap_id_ctx,
-+                                            struct sdap_options);
-+    assert_non_null(ad_ctx->sdap_id_ctx->opts);
-+
-+    ret = sdap_domain_add(ad_ctx->sdap_id_ctx->opts, test_ctx->dom, &sdom);
-+    assert_int_equal(ret, EOK);
-+
-+    subdom_ad_ctx = talloc_zero(test_ctx, struct ad_id_ctx);
-+    assert_non_null(subdom_ad_ctx);
-+
-+    subdom_ldap_ctx = talloc_zero(subdom_ad_ctx, struct sdap_id_conn_ctx);
-+    assert_non_null(subdom_ldap_ctx);
-+    subdom_ad_ctx->ldap_ctx = subdom_ldap_ctx;
-+
-+    ret = sdap_domain_add(ad_ctx->sdap_id_ctx->opts, test_ctx->subdom, &sdom);
-+    assert_int_equal(ret, EOK);
-+    sdom->pvt = subdom_ad_ctx;
-+
-+    test_ctx->ad_ctx = ad_ctx;
-+    test_ctx->subdom_ad_ctx = subdom_ad_ctx;
-+
-+    check_leaks_push(test_ctx);
-+    *state = test_ctx;
-+}
-+
-+static void
-+ad_common_test_teardown(void **state)
-+{
-+    struct ad_common_test_ctx *test_ctx = talloc_get_type(*state,
-+                                                  struct ad_common_test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    assert_true(check_leaks_pop(test_ctx) == true);
-+    talloc_free(test_ctx);
-+    assert_true(check_leaks_pop(global_talloc_context) == true);
-+    assert_true(leak_check_teardown());
-+}
-+
-+errno_t
-+__wrap_sdap_set_sasl_options(struct sdap_options *id_opts,
-+                             char *default_primary,
-+                             char *default_realm,
-+                             const char *keytab_path)
-+{
-+    /* Pretend SASL is fine */
-+    return EOK;
-+}
-+
-+void test_ldap_conn_list(void **state)
-+{
-+    struct sdap_id_conn_ctx *conn;
-+
-+    struct ad_common_test_ctx *test_ctx = talloc_get_type(*state,
-+                                                     struct ad_common_test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    conn = ad_get_dom_ldap_conn(test_ctx->ad_ctx, test_ctx->dom);
-+    assert_true(conn == test_ctx->ad_ctx->ldap_ctx);
-+
-+    conn = ad_get_dom_ldap_conn(test_ctx->ad_ctx, test_ctx->subdom);
-+    assert_true(conn == test_ctx->subdom_ad_ctx->ldap_ctx);
-+}
-+
-+void test_conn_list(void **state)
-+{
-+    struct sdap_id_conn_ctx **conn_list;
-+
-+    struct ad_common_test_ctx *test_ctx = talloc_get_type(*state,
-+                                                     struct ad_common_test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->dom);
-+    assert_non_null(conn_list);
-+
-+    assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx);
-+    /* If there is a fallback, we should ignore the offline mode */
-+    assert_true(conn_list[0]->ignore_mark_offline);
-+    assert_true(conn_list[1] == test_ctx->ad_ctx->ldap_ctx);
-+    assert_false(conn_list[1]->ignore_mark_offline);
-+    assert_null(conn_list[2]);
-+    talloc_free(conn_list);
-+
-+    conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->subdom);
-+    assert_non_null(conn_list);
-+
-+    assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx);
-+    assert_false(conn_list[0]->ignore_mark_offline);
-+    assert_null(conn_list[1]);
-+    talloc_free(conn_list);
-+}
-+
-+int main(int argc, const char *argv[])
-+{
-+    poptContext pc;
-+    int opt;
-+    struct poptOption long_options[] = {
-+        POPT_AUTOHELP
-+        SSSD_DEBUG_OPTS
-+        POPT_TABLEEND
-+    };
-+
-+    const UnitTest tests[] = {
-+        unit_test_setup_teardown(test_ldap_conn_list,
-+                                 ad_common_test_setup,
-+                                 ad_common_test_teardown),
-+        unit_test_setup_teardown(test_conn_list,
-+                                 ad_common_test_setup,
-+                                 ad_common_test_teardown),
-+    };
-+
-+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
-+    debug_level = SSSDBG_INVALID;
-+
-+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
-+    while((opt = poptGetNextOpt(pc)) != -1) {
-+        switch(opt) {
-+        default:
-+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
-+                    poptBadOption(pc, 0), poptStrerror(opt));
-+            poptPrintUsage(pc, stderr, 0);
-+            return 1;
-+        }
-+    }
-+    poptFreeContext(pc);
-+
-+    DEBUG_INIT(debug_level);
-+
-+    tests_set_cwd();
-+
-+    return run_tests(tests);
-+}
--- 
-1.8.4.2
-
diff --git a/SOURCES/0028-SBUS-Allow-connections-from-other-UIDs.patch b/SOURCES/0028-SBUS-Allow-connections-from-other-UIDs.patch
new file mode 100644
index 0000000..e410782
--- /dev/null
+++ b/SOURCES/0028-SBUS-Allow-connections-from-other-UIDs.patch
@@ -0,0 +1,78 @@
+From 1017fbf75cc0859c691b120482fd13b52b44780b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 7 Oct 2014 19:44:44 +0200
+Subject: [PATCH 28/46] SBUS: Allow connections from other UIDs
+
+Unless dbus_connection_set_unix_user_function() is used, D-Bus only
+allows connections from UID 0. This patch adds a custom checker function
+that allows either UID 0 or the pre-configured SSSD user ID.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit aa871e019f00493dfa53b48f906132bf94eeae9f)
+---
+ src/monitor/monitor.c           |  3 +++
+ src/sbus/sssd_dbus.h            |  4 ++++
+ src/sbus/sssd_dbus_connection.c | 20 ++++++++++++++++++++
+ 3 files changed, 27 insertions(+)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index b6777784cd289e85c865fc16490d0287a63192a5..fc6b2963fff41a2a2aefdaf502817f6764e95b1e 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -2392,6 +2392,9 @@ static int monitor_service_init(struct sbus_connection *conn, void *data)
+     mini->ctx = ctx;
+     mini->conn = conn;
+ 
++    /* Allow access from the SSSD user */
++    sbus_allow_uid(conn, &ctx->uid);
++
+     /* 10 seconds should be plenty */
+     tv = tevent_timeval_current_ofs(10, 0);
+ 
+diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
+index d01926368ce0ae5312d8ea0057a89d9a7176836b..5b128eaedb320cb745c1b635867e1b53ca556ec9 100644
+--- a/src/sbus/sssd_dbus.h
++++ b/src/sbus/sssd_dbus.h
+@@ -209,6 +209,10 @@ int sbus_conn_send(struct sbus_connection *conn,
+ void sbus_conn_send_reply(struct sbus_connection *conn,
+                           DBusMessage *reply);
+ 
++/* Set up D-BUS access control. If there is a SSSD user, we must allow
++ * him to connect. root is always allowed */
++void sbus_allow_uid(struct sbus_connection *conn, uid_t *uid);
++
+ /*
+  * This structure is passed to all dbus method and property
+  * handlers. It is a talloc context which will be valid until
+diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
+index 06256a85b5e81b39d50923db6d41b64015114ce1..6102ef9ae4715d36a623b802b9095ec1c99c1a39 100644
+--- a/src/sbus/sssd_dbus_connection.c
++++ b/src/sbus/sssd_dbus_connection.c
+@@ -922,3 +922,23 @@ void sbus_conn_send_reply(struct sbus_connection *conn, DBusMessage *reply)
+ {
+     dbus_connection_send(conn->dbus.conn, reply, NULL);
+ }
++
++dbus_bool_t is_uid_sssd_user(DBusConnection *connection,
++                             unsigned long   uid,
++                             void           *data)
++{
++    uid_t sssd_user = * (uid_t *) data;
++
++    if (uid == 0 || uid == sssd_user) {
++        return TRUE;
++    }
++
++    return FALSE;
++}
++
++void sbus_allow_uid(struct sbus_connection *conn, uid_t *uid)
++{
++    dbus_connection_set_unix_user_function(sbus_get_connection(conn),
++                                           is_uid_sssd_user,
++                                           uid, NULL);
++}
+-- 
+1.9.3
+
diff --git a/SOURCES/0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch b/SOURCES/0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch
deleted file mode 100644
index 03ff29d..0000000
--- a/SOURCES/0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch
+++ /dev/null
@@ -1,175 +0,0 @@
-From 168396cd93b3f0e42b4842f520f2bcece91274c6 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 29 Nov 2013 11:39:09 +0100
-Subject: [PATCH 29/31] AD: Add a new option to turn off GC lookups
-
-SSSD now defaults to using GC by default. For some environments, for
-instance those that don't or can't replicate the POSIX attributes to
-Global Catalog, this might not be desirable.
-
-This patch introduces a new option ad_enable_gc, that is enabled by
-default. Setting this option to false makes the SSSD contact only the
-LDAP port of AD DCs.
----
- src/config/etc/sssd.api.d/sssd-ad.conf |  1 +
- src/man/sssd-ad.5.xml                  | 17 +++++++++++++++++
- src/providers/ad/ad_common.c           | 31 ++++++++++++++++++-------------
- src/providers/ad/ad_common.h           |  1 +
- src/providers/ad/ad_opts.h             |  1 +
- src/tests/cmocka/test_ad_common.c      | 20 ++++++++++++++++++++
- 6 files changed, 58 insertions(+), 13 deletions(-)
-
-diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
-index 9f606f6c4da65d4bfb20a97ee27801dac9307868..00e8968d2b6dab33a39005f11a497cb3e2185302 100644
---- a/src/config/etc/sssd.api.d/sssd-ad.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
-@@ -5,6 +5,7 @@ ad_backup_server = str, None, false
- ad_hostname = str, None, false
- ad_enable_dns_sites = bool, None, false
- ad_access_filter = str, None, false
-+ad_enable_gc = bool, None, false
- ldap_uri = str, None, false
- ldap_backup_uri = str, None, false
- ldap_search_base = str, None, false
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index e31f87a96a14907c64166e53da443ad735c6e85e..38cc31278cf87c98ca9e53cf91fda7b141bff78d 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -228,6 +228,23 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com)
-                 </varlistentry>
- 
-                 <varlistentry>
-+                    <term>ad_enable_gc (boolean)</term>
-+                    <listitem>
-+                        <para>
-+                            By default, the SSSD connects to the Global
-+                            Catalog first to retrieve users and uses the
-+                            LDAP port to retrieve group memberships or
-+                            as a fallback. Disabling this option makes
-+                            the SSSD only connect to the LDAP port of the
-+                            current AD server.
-+                        </para>
-+                        <para>
-+                            Default: true
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-+                <varlistentry>
-                     <term>dyndns_update (boolean)</term>
-                     <listitem>
-                         <para>
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index af0ec839964233c7642205f4489e5b6462509848..a5ea4f587f30575a5903d8ae1a459f53512c011f 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1125,26 +1125,31 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
-                 struct sss_domain_info *dom)
- {
-     struct sdap_id_conn_ctx **clist;
-+    int cindex = 0;
- 
-     clist = talloc_zero_array(mem_ctx, struct sdap_id_conn_ctx *, 3);
-     if (clist == NULL) return NULL;
- 
-     /* Always try GC first */
--    clist[0] = ad_ctx->gc_ctx;
--    if (IS_SUBDOMAIN(dom) == true) {
--        clist[0]->ignore_mark_offline = false;
--        /* Subdomain users are only present in GC. */
--        return clist;
-+    if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC)) {
-+        clist[cindex] = ad_ctx->gc_ctx;
-+        if (IS_SUBDOMAIN(dom) == true) {
-+            clist[cindex]->ignore_mark_offline = false;
-+            /* Subdomain users are only present in GC. */
-+            return clist;
-+        }
-+        /* fall back to ldap if gc is not available */
-+        clist[cindex]->ignore_mark_offline = true;
-+        cindex++;
-     }
- 
--    /* fall back to ldap if gc is not available */
--    clist[0]->ignore_mark_offline = true;
--
--    /* With root domain users we have the option to
--     * fall back to LDAP in case ie POSIX attributes
--     * are used but not replicated to GC
--     */
--    clist[1] = ad_ctx->ldap_ctx;
-+    if (IS_SUBDOMAIN(dom) == false) {
-+        /* With root domain users we have the option to
-+         * fall back to LDAP in case ie POSIX attributes
-+         * are used but not replicated to GC
-+         */
-+        clist[cindex] = ad_ctx->ldap_ctx;
-+    }
- 
-     return clist;
- }
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index ed5b8584dc5327a24e60985486c6155604271fd2..d370cef69124c127f41d7c4cbaa25713363e7752 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -42,6 +42,7 @@ enum ad_basic_opt {
-     AD_KRB5_REALM,
-     AD_ENABLE_DNS_SITES,
-     AD_ACCESS_FILTER,
-+    AD_ENABLE_GC,
- 
-     AD_OPTS_BASIC /* opts counter */
- };
-diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
-index 8022a16274a04389b7a64b491ec28a0c3c55aaef..5b7b1c89f5f45d7cc744a955e6378390948a99fd 100644
---- a/src/providers/ad/ad_opts.h
-+++ b/src/providers/ad/ad_opts.h
-@@ -36,6 +36,7 @@ struct dp_option ad_basic_opts[] = {
-     { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING},
-     { "ad_enable_dns_sites", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
-     { "ad_access_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING},
-+    { "ad_enable_gc", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
-     DP_OPTION_TERMINATOR
- };
- 
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-index 648b68f2dc05947b1fbb4c680ec63d3c2c6275b3..07502b82d43d730562c60125b639d8e7d1034458 100644
---- a/src/tests/cmocka/test_ad_common.c
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -159,6 +159,8 @@ void test_conn_list(void **state)
-                                                      struct ad_common_test_ctx);
-     assert_non_null(test_ctx);
- 
-+    assert_true(dp_opt_get_bool(test_ctx->ad_ctx->ad_options->basic,
-+                                AD_ENABLE_GC));
-     conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->dom);
-     assert_non_null(conn_list);
- 
-@@ -177,6 +179,24 @@ void test_conn_list(void **state)
-     assert_false(conn_list[0]->ignore_mark_offline);
-     assert_null(conn_list[1]);
-     talloc_free(conn_list);
-+
-+    dp_opt_set_bool(test_ctx->ad_ctx->ad_options->basic, AD_ENABLE_GC, false);
-+    assert_false(dp_opt_get_bool(test_ctx->ad_ctx->ad_options->basic,
-+                                 AD_ENABLE_GC));
-+
-+    conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->dom);
-+    assert_non_null(conn_list);
-+
-+    assert_true(conn_list[0] == test_ctx->ad_ctx->ldap_ctx);
-+    assert_false(conn_list[0]->ignore_mark_offline);
-+    assert_null(conn_list[1]);
-+    talloc_free(conn_list);
-+
-+    conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->subdom);
-+    assert_non_null(conn_list);
-+
-+    assert_null(conn_list[0]);
-+    talloc_free(conn_list);
- }
- 
- int main(int argc, const char *argv[])
--- 
-1.8.4.2
-
diff --git a/SOURCES/0029-BE-Own-the-sbus-socket-as-the-SSSD-user.patch b/SOURCES/0029-BE-Own-the-sbus-socket-as-the-SSSD-user.patch
new file mode 100644
index 0000000..18c8342
--- /dev/null
+++ b/SOURCES/0029-BE-Own-the-sbus-socket-as-the-SSSD-user.patch
@@ -0,0 +1,115 @@
+From 2bb5d331997232e5b1c589062b7960215fd08047 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 15 Oct 2014 15:58:58 +0200
+Subject: [PATCH 29/46] BE: Own the sbus socket as the SSSD user
+
+In some cases, the back end might still be running as root, but the
+responder would be running unprivileged. In this case, we need to allow
+connecting from the SSSD user ID.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 19e9c1c1a21790974400db9349637788727b6564)
+---
+ src/monitor/monitor.c            |  8 ++++++++
+ src/providers/data_provider_be.c | 16 ++++++++++++----
+ src/providers/dp_backend.h       |  2 ++
+ 3 files changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index fc6b2963fff41a2a2aefdaf502817f6764e95b1e..905e66f25601d155557487ae9c7eb6d3145d3a83 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1306,6 +1306,14 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name,
+             return ENOMEM;
+         }
+ 
++        svc->command = talloc_asprintf_append(svc->command,
++                " --uid %"SPRIuid" --gid %"SPRIgid,
++                ctx->uid, ctx->gid);
++        if (!svc->command) {
++            talloc_free(svc);
++            return ENOMEM;
++        }
++
+         if (cmdline_debug_level != SSSDBG_UNRESOLVED) {
+             svc->command = talloc_asprintf_append(
+                 svc->command, " -d %#.4x", cmdline_debug_level
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 122c5b091751b641f815ddff5c56ac99ace69939..2716e4a8b38f3ff9a5b48a861ecc31f18f9fcbce 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -2226,6 +2226,9 @@ static int be_client_init(struct sbus_connection *conn, void *data)
+     becli->conn = conn;
+     becli->initialized = false;
+ 
++    /* Allow access from the SSSD user */
++    sbus_allow_uid(conn, &bectx->uid);
++
+     /* 5 seconds should be plenty */
+     tv = tevent_timeval_current_ofs(5, 0);
+ 
+@@ -2251,7 +2254,8 @@ static int be_client_init(struct sbus_connection *conn, void *data)
+ 
+ /* be_srv_init
+  * set up per-domain sbus channel */
+-static int be_srv_init(struct be_ctx *ctx)
++static int be_srv_init(struct be_ctx *ctx,
++                       uid_t uid, gid_t gid)
+ {
+     char *sbus_address;
+     int ret;
+@@ -2263,7 +2267,10 @@ static int be_srv_init(struct be_ctx *ctx)
+         return ret;
+     }
+ 
+-    ret = sbus_new_server(ctx, ctx->ev, sbus_address, 0, 0,
++    ctx->uid = uid;
++    ctx->gid = gid;
++
++    ret = sbus_new_server(ctx, ctx->ev, sbus_address, uid, gid,
+                           true, &ctx->sbus_srv, be_client_init, ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
+@@ -2554,6 +2561,7 @@ done:
+ 
+ int be_process_init(TALLOC_CTX *mem_ctx,
+                     const char *be_domain,
++                    uid_t uid, gid_t gid,
+                     struct tevent_context *ev,
+                     struct confdb_ctx *cdb)
+ {
+@@ -2609,7 +2617,7 @@ int be_process_init(TALLOC_CTX *mem_ctx,
+         goto fail;
+     }
+ 
+-    ret = be_srv_init(ctx);
++    ret = be_srv_init(ctx, uid, gid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up server bus\n");
+         goto fail;
+@@ -2870,7 +2878,7 @@ int main(int argc, const char *argv[])
+     }
+ 
+     ret = be_process_init(main_ctx,
+-                          be_domain,
++                          be_domain, uid, gid,
+                           main_ctx->event_ctx,
+                           main_ctx->confdb_ctx);
+     if (ret != EOK) {
+diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
+index 075681ff9dd641daf56929c05cb94170cd1b292a..e4213b44b32e8b9cb942dfcfef4998aa732d113c 100644
+--- a/src/providers/dp_backend.h
++++ b/src/providers/dp_backend.h
+@@ -116,6 +116,8 @@ struct be_ctx {
+     struct sss_domain_info *domain;
+     const char *identity;
+     const char *conf_path;
++    uid_t uid;
++    gid_t gid;
+     struct be_failover_ctx *be_fo;
+     struct be_resolv_ctx *be_res;
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch b/SOURCES/0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch
deleted file mode 100644
index 7190d1f..0000000
--- a/SOURCES/0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From dfebe8a952561e51fe1d603886ba4e979b29d889 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 13 Dec 2013 20:11:11 +0100
-Subject: [PATCH 30/31] AD: Enable fallback to LDAP of trusted domain
-
-Since we have the LDAP port of a trusted AD GC always available now, we
-can always perform a fallback.
----
- src/providers/ad/ad_common.c      | 14 +-------------
- src/tests/cmocka/test_ad_common.c |  7 ++++---
- 2 files changed, 5 insertions(+), 16 deletions(-)
-
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index a5ea4f587f30575a5903d8ae1a459f53512c011f..99fa4c07af2a79bb3ca195214ddb0dbd60c61620 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1133,23 +1133,11 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
-     /* Always try GC first */
-     if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC)) {
-         clist[cindex] = ad_ctx->gc_ctx;
--        if (IS_SUBDOMAIN(dom) == true) {
--            clist[cindex]->ignore_mark_offline = false;
--            /* Subdomain users are only present in GC. */
--            return clist;
--        }
--        /* fall back to ldap if gc is not available */
-         clist[cindex]->ignore_mark_offline = true;
-         cindex++;
-     }
- 
--    if (IS_SUBDOMAIN(dom) == false) {
--        /* With root domain users we have the option to
--         * fall back to LDAP in case ie POSIX attributes
--         * are used but not replicated to GC
--         */
--        clist[cindex] = ad_ctx->ldap_ctx;
--    }
-+    clist[cindex] = ad_get_dom_ldap_conn(ad_ctx, dom);
- 
-     return clist;
- }
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-index 07502b82d43d730562c60125b639d8e7d1034458..bbd56b1b9b78cb78cb24726522822ad2f7ae9980 100644
---- a/src/tests/cmocka/test_ad_common.c
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -176,8 +176,9 @@ void test_conn_list(void **state)
-     assert_non_null(conn_list);
- 
-     assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx);
--    assert_false(conn_list[0]->ignore_mark_offline);
--    assert_null(conn_list[1]);
-+    assert_true(conn_list[0]->ignore_mark_offline);
-+    assert_true(conn_list[1] == test_ctx->subdom_ad_ctx->ldap_ctx);
-+    assert_false(conn_list[1]->ignore_mark_offline);
-     talloc_free(conn_list);
- 
-     dp_opt_set_bool(test_ctx->ad_ctx->ad_options->basic, AD_ENABLE_GC, false);
-@@ -195,7 +196,7 @@ void test_conn_list(void **state)
-     conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->subdom);
-     assert_non_null(conn_list);
- 
--    assert_null(conn_list[0]);
-+    assert_true(conn_list[0] == test_ctx->subdom_ad_ctx->ldap_ctx);
-     talloc_free(conn_list);
- }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0030-MONITOR-Allow-confdb-to-be-accessed-by-nonroot-user.patch b/SOURCES/0030-MONITOR-Allow-confdb-to-be-accessed-by-nonroot-user.patch
new file mode 100644
index 0000000..b111c2d
--- /dev/null
+++ b/SOURCES/0030-MONITOR-Allow-confdb-to-be-accessed-by-nonroot-user.patch
@@ -0,0 +1,51 @@
+From 1c27362249606583545f7b0c465a3088879439a1 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 9 Oct 2014 17:15:56 +0200
+Subject: [PATCH 30/46] MONITOR: Allow confdb to be accessed by nonroot user
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 579e5d4b7a3ca161ea7518b2996905fa22c15995)
+---
+ src/monitor/monitor.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 905e66f25601d155557487ae9c7eb6d3145d3a83..37f6e928be3508762e1c3afadbb67762f5cc1d38 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1696,7 +1696,6 @@ static errno_t load_configuration(TALLOC_CTX *mem_ctx,
+         DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error initializing confdb\n");
+         goto done;
+     }
+-    talloc_zfree(cdb_file);
+ 
+     ret = confdb_init_db(config_file, ctx->cdb);
+     if (ret != EOK) {
+@@ -1712,11 +1711,23 @@ static errno_t load_configuration(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
++    /* Allow configuration database to be accessible
++     * when SSSD runs as nonroot */
++    ret = chown(cdb_file, ctx->uid, ctx->gid);
++    if (ret != 0) {
++        ret = errno;
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "chown failed for [%s]: [%d][%s].\n",
++              cdb_file, ret, sss_strerror(ret));
++        goto done;
++    }
++
+     *monitor = ctx;
+ 
+     ret = EOK;
+ 
+ done:
++    talloc_free(cdb_file);
+     if (ret != EOK) {
+         talloc_free(ctx);
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0031-Bump-sss_idmap-version-to-3-0-3.patch b/SOURCES/0031-Bump-sss_idmap-version-to-3-0-3.patch
deleted file mode 100644
index 57a1353..0000000
--- a/SOURCES/0031-Bump-sss_idmap-version-to-3-0-3.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From eb03d9c884e6d69af31d079a3bcb572de1a5838b Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Mon, 4 Nov 2013 11:59:49 +0100
-Subject: [PATCH 31/31] Bump sss_idmap version to 3:0:3
-
-New functions were added.
----
- Makefile.am | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index da407038089f3c010dea139735db9e0e2f000943..16648f9aa2275b60ec84a95ff8a26b1225b97918 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -612,7 +612,7 @@ libsss_idmap_la_SOURCES = \
-     src/lib/idmap/sss_idmap_conv.c \
-     src/util/murmurhash3.c
- libsss_idmap_la_LDFLAGS = \
--    -version-info 2:0:2
-+    -version-info 3:0:3
- 
- dist_pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc
- libsss_nss_idmap_la_SOURCES = \
--- 
-1.8.4.2
-
diff --git a/SOURCES/0031-SYSDB-Allow-calling-chown-on-the-sysdb-file-from-mon.patch b/SOURCES/0031-SYSDB-Allow-calling-chown-on-the-sysdb-file-from-mon.patch
new file mode 100644
index 0000000..5d69f05
--- /dev/null
+++ b/SOURCES/0031-SYSDB-Allow-calling-chown-on-the-sysdb-file-from-mon.patch
@@ -0,0 +1,94 @@
+From 3c97e3ab74309934687e65a768fb843d8b4608fa Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 9 Oct 2014 17:21:30 +0200
+Subject: [PATCH 31/46] SYSDB: Allow calling chown on the sysdb file from
+ monitor
+
+Sysdb must be accessible for the nonroot sssd
+processes.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 0887c35bdb85adf0a4376dc8963294ea5a9d6da6)
+---
+ src/db/sysdb.c        | 21 +++++++++++++++++++++
+ src/db/sysdb.h        |  9 +++++++++
+ src/monitor/monitor.c |  3 ++-
+ 3 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb.c b/src/db/sysdb.c
+index 8d6f00b52976228bfc9dfdc93503148837677346..1f02585e747dda6aadde772f76f30d3d69c4cfc0 100644
+--- a/src/db/sysdb.c
++++ b/src/db/sysdb.c
+@@ -1322,6 +1322,16 @@ int sysdb_init(TALLOC_CTX *mem_ctx,
+                struct sss_domain_info *domains,
+                bool allow_upgrade)
+ {
++    return sysdb_init_ext(mem_ctx, domains, allow_upgrade, false, 0, 0);
++}
++
++int sysdb_init_ext(TALLOC_CTX *mem_ctx,
++                   struct sss_domain_info *domains,
++                   bool allow_upgrade,
++                   bool chown_dbfile,
++                   uid_t uid,
++                   gid_t gid)
++{
+     struct sss_domain_info *dom;
+     struct sysdb_ctx *sysdb;
+     int ret;
+@@ -1343,6 +1353,17 @@ int sysdb_init(TALLOC_CTX *mem_ctx,
+             return ret;
+         }
+ 
++        if (chown_dbfile) {
++            ret = chown(sysdb->ldb_file, uid, gid);
++            if (ret != 0) {
++                ret = errno;
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Cannot set sysdb ownership to %"SPRIuid":%"SPRIgid"\n",
++                      uid, gid);
++                return ret;
++            }
++        }
++
+         dom->sysdb = talloc_move(dom, &sysdb);
+     }
+ 
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 0d0971d98dd684e47ae8ec067447169f41ebba67..ebb1bbedaf2df3030a012f1f0be8c5a069399cc3 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -533,6 +533,15 @@ uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom,
+ int sysdb_init(TALLOC_CTX *mem_ctx,
+                struct sss_domain_info *domains,
+                bool allow_upgrade);
++
++/* Same as sysdb_init, but additionally allows to change
++ * file ownership of the sysdb databases. */
++int sysdb_init_ext(TALLOC_CTX *mem_ctx,
++                   struct sss_domain_info *domains,
++                   bool allow_upgrade,
++                   bool chown_dbfile,
++                   uid_t uid, gid_t gid);
++
+ /* used to initialize only one domain database.
+  * Do NOT use if sysdb_init has already been called */
+ int sysdb_domain_init(TALLOC_CTX *mem_ctx,
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 37f6e928be3508762e1c3afadbb67762f5cc1d38..04702428c4ed7fd1d77c6f18e491fa69b3700f4f 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -2312,7 +2312,8 @@ static int monitor_process_init(struct mt_ctx *ctx,
+     if (!tmp_ctx) {
+         return ENOMEM;
+     }
+-    ret = sysdb_init(tmp_ctx, ctx->domains, true);
++    ret = sysdb_init_ext(tmp_ctx, ctx->domains, true,
++                         true, ctx->uid, ctx->gid);
+     if (ret != EOK) {
+         SYSDB_VERSION_ERROR_DAEMON(ret);
+         return ret;
+-- 
+1.9.3
+
diff --git a/SOURCES/0032-AD-Refresh-subdomain-data-structures-on-startup.patch b/SOURCES/0032-AD-Refresh-subdomain-data-structures-on-startup.patch
deleted file mode 100644
index ff6078a..0000000
--- a/SOURCES/0032-AD-Refresh-subdomain-data-structures-on-startup.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From 1213f1a45e222b3c1b304262c51900d8ab2a886a Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 13 Dec 2013 19:11:47 +0100
-Subject: [PATCH 32/34] AD: Refresh subdomain data structures on startup
-
-Previously, if no changes were done to the list of subdomains, the SSSD
-didn't update its list of sdap_domain mappings for the new subdomain.
-This resulted in errors as no id_ctx was present for the subdomain
-during lookup.
-
-This patch moves the block of code performed during update to a function
-of its own and calls it during provider initialization as well.
----
- src/providers/ad/ad_subdomains.c | 49 ++++++++++++++++++++++++++--------------
- 1 file changed, 32 insertions(+), 17 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 100fb13e99f7bf4b3946b1f5c5f9c626674bfb46..e438a688c364084a3f2bbca338a39d61aa86b5d6 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -414,6 +414,31 @@ done:
-     return ret;
- }
- 
-+static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
-+{
-+    errno_t ret;
-+
-+    ret = sysdb_update_subdomains(ctx->be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n"));
-+        return ret;
-+    }
-+
-+    ret = sss_write_domain_mappings(ctx->be_ctx->domain, false);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("sss_krb5_write_mappings failed.\n"));
-+        /* Just continue */
-+    }
-+
-+    ret = ads_store_sdap_subdom(ctx, ctx->be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("ads_store_sdap_subdom failed.\n"));
-+        return ret;
-+    }
-+
-+    return EOK;
-+}
-+
- static void ad_subdomains_get_conn_done(struct tevent_req *req);
- static void ad_subdomains_master_dom_done(struct tevent_req *req);
- static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx);
-@@ -619,25 +644,15 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
-         goto done;
-     }
- 
-+    DEBUG(SSSDBG_TRACE_LIBS, ("There are %schanges\n",
-+                    refresh_has_changes ? "" : "no "));
-+
-     if (refresh_has_changes) {
--        ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain);
-+        ret = ad_subdom_reinit(ctx->sd_ctx);
-         if (ret != EOK) {
--            DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n"));
-+            DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n"));
-             goto done;
-         }
--
--        ret = ads_store_sdap_subdom(ctx->sd_ctx, ctx->sd_ctx->be_ctx->domain);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_OP_FAILURE, ("ads_store_sdap_subdom failed.\n"));
--            goto done;
--        }
--
--        ret = sss_write_domain_mappings(ctx->sd_ctx->be_ctx->domain, false);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("sss_krb5_write_mappings failed.\n"));
--            /* Just continue */
--        }
-     }
- 
-     ret = EOK;
-@@ -783,9 +798,9 @@ int ad_subdom_init(struct be_ctx *be_ctx,
-         return EFAULT;
-     }
- 
--    ret = sysdb_update_subdomains(be_ctx->domain);
-+    ret = ad_subdom_reinit(ctx);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. "
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not reinitialize subdomains. "
-               "Users from trusted domains might not be resolved correctly\n"));
-         /* Ignore this error and try to discover the subdomains later */
-     }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0032-NSS-Run-as-a-user-specified-by-monitor.patch b/SOURCES/0032-NSS-Run-as-a-user-specified-by-monitor.patch
new file mode 100644
index 0000000..4ac28ba
--- /dev/null
+++ b/SOURCES/0032-NSS-Run-as-a-user-specified-by-monitor.patch
@@ -0,0 +1,48 @@
+From d4bbfc12cae1eb2efe2451885605c37ec7702a21 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 21 Sep 2014 13:52:05 +0200
+Subject: [PATCH 32/46] NSS: Run as a user specified by monitor
+
+Adds the NSS responder to the list of services known to work as a
+non-root user and becomes the specified user after starting the NSS
+responder.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 5d19966eda424bd71964c6913b84d705dce3b350)
+---
+ src/monitor/monitor.c      | 3 +++
+ src/responder/nss/nsssrv.c | 3 ++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 04702428c4ed7fd1d77c6f18e491fa69b3700f4f..297648a60836cec1bd95c0a2972c8d14be32675a 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1062,6 +1062,9 @@ static errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
+  */
+ static bool svc_supported_as_nonroot(const char *svc_name)
+ {
++    if (strcmp(svc_name, "nss") == 0) {
++        return true;
++    }
+     return false;
+ }
+ 
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index 420fd3d316959a67737f23e9a8b3d1c797583ea3..dbbdb4f844410eabe01f184ccdf8d9deb41833f4 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -568,7 +568,8 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_nss";
+ 
+-    ret = server_setup("sssd[nss]", 0, 0, 0, CONFDB_NSS_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[nss]", 0, uid, gid, CONFDB_NSS_CONF_ENTRY,
++                       &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+-- 
+1.9.3
+
diff --git a/SOURCES/0033-IPA-Refresh-subdomain-data-structures-on-startup.patch b/SOURCES/0033-IPA-Refresh-subdomain-data-structures-on-startup.patch
deleted file mode 100644
index 2d070bf..0000000
--- a/SOURCES/0033-IPA-Refresh-subdomain-data-structures-on-startup.patch
+++ /dev/null
@@ -1,93 +0,0 @@
-From 3a1056929310cf304449baf3feed94bc8fe46383 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 17 Dec 2013 17:22:45 +0100
-Subject: [PATCH 33/34] IPA: Refresh subdomain data structures on startup
-
-Write domain-mappings at startup and initialize internal data structures
-on provider startup, not only during updates.
----
- src/providers/ipa/ipa_subdomains.c | 51 ++++++++++++++++++++++++--------------
- 1 file changed, 32 insertions(+), 19 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 416e21913be8e991c9f496ff2b54f238b602f304..56fd4f99654aa07f822c49d6d39526765785f0de 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -267,6 +267,35 @@ ipa_ad_subdom_refresh(struct be_ctx *be_ctx,
-     return EOK;
- }
- 
-+static errno_t
-+ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
-+{
-+    errno_t ret;
-+
-+    ret = sysdb_update_subdomains(ctx->be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n"));
-+        return ret;
-+    }
-+
-+    ret = ipa_ad_subdom_refresh(ctx->be_ctx, ctx->id_ctx, ctx->be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n"));
-+        return ret;
-+    }
-+
-+    ret = sss_write_domain_mappings(ctx->be_ctx->domain,
-+                    dp_opt_get_bool(ctx->id_ctx->ipa_options->basic,
-+                    IPA_SERVER_MODE));
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+                ("sss_krb5_write_mappings failed.\n"));
-+        /* Just continue */
-+    }
-+
-+    return EOK;
-+}
-+
- static void
- ipa_ad_subdom_remove(struct ipa_subdomains_ctx *ctx,
-                      struct sss_domain_info *subdom)
-@@ -921,27 +950,11 @@ static void ipa_subdomains_handler_done(struct tevent_req *req)
-     }
- 
-     if (refresh_has_changes) {
--        ret = sysdb_update_subdomains(domain);
-+        ret = ipa_subdom_reinit(ctx->sd_ctx);
-         if (ret != EOK) {
--            DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n"));
-+            DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n"));
-             goto done;
-         }
--
--        ret = ipa_ad_subdom_refresh(ctx->sd_ctx->be_ctx, ctx->sd_ctx->id_ctx,
--                                    domain);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n"));
--            goto done;
--        }
--
--        ret = sss_write_domain_mappings(domain,
--                        dp_opt_get_bool(ctx->sd_ctx->id_ctx->ipa_options->basic,
--                        IPA_SERVER_MODE));
--        if (ret != EOK) {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("sss_krb5_write_mappings failed.\n"));
--            /* Just continue */
--        }
-     }
- 
-     ret = sysdb_master_domain_update(domain);
-@@ -1289,7 +1302,7 @@ int ipa_subdom_init(struct be_ctx *be_ctx,
-         DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom offline callback"));
-     }
- 
--    ret = sysdb_update_subdomains(be_ctx->domain);
-+    ret = ipa_subdom_reinit(ctx);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. "
-               "Users from trusted domains might not be resolved correctly\n"));
--- 
-1.8.4.2
-
diff --git a/SOURCES/0033-responder_common-Create-fd-for-pipe-in-helper.patch b/SOURCES/0033-responder_common-Create-fd-for-pipe-in-helper.patch
new file mode 100644
index 0000000..06adf5c
--- /dev/null
+++ b/SOURCES/0033-responder_common-Create-fd-for-pipe-in-helper.patch
@@ -0,0 +1,212 @@
+From 2d5dbb5dbe674f012fc044f03441538b9b400983 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 15 Oct 2014 17:35:12 +0200
+Subject: [PATCH 33/46] responder_common: Create fd for pipe in helper
+
+Move creating of file descriptor for pipes into
+helper function and make this function public.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 2ce29e05e62b2702ba4df5f3316eaf250b0ada7f)
+---
+ src/responder/common/responder.h        |   2 +
+ src/responder/common/responder_common.c | 135 +++++++++++++++-----------------
+ 2 files changed, 65 insertions(+), 72 deletions(-)
+
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index 97552ec472c5baa285b41cc48b51149f3ef6adb5..d233710782fe7df1bbcc338e3815d1701557519e 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -176,6 +176,8 @@ responder_get_domain(struct resp_ctx *rctx, const char *domain);
+ errno_t responder_get_domain_by_id(struct resp_ctx *rctx, const char *id,
+                                    struct sss_domain_info **_ret_dom);
+ 
++int create_pipe_fd(const char *sock_name, int *fd, mode_t umaskval);
++
+ /* responder_cmd.c */
+ int sss_cmd_empty_packet(struct sss_packet *packet);
+ int sss_cmd_send_empty(struct cli_ctx *cctx, TALLOC_CTX *freectx);
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index 0ec2372e8d08f1002b303b5edc6897f17cee9699..a262a2c1487c786404b6d0d4c720edd1679279d0 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -584,10 +584,69 @@ static int sss_dp_init(struct resp_ctx *rctx,
+     return EOK;
+ }
+ 
++int create_pipe_fd(const char *sock_name, int *fd, mode_t umaskval)
++{
++    struct sockaddr_un addr;
++    errno_t ret;
++
++    *fd = socket(AF_UNIX, SOCK_STREAM, 0);
++    if (*fd == -1) {
++        return EIO;
++    }
++
++    umask(umaskval);
++
++    ret = set_nonblocking(*fd);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    ret = set_close_on_exec(*fd);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sun_family = AF_UNIX;
++    strncpy(addr.sun_path, sock_name, sizeof(addr.sun_path) - 1);
++    addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
++
++    /* make sure we have no old sockets around */
++    ret = unlink(sock_name);
++    if (ret != 0 && errno != ENOENT) {
++        ret = errno;
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot remove old socket (errno=%d), bind might fail!\n", ret);
++    }
++
++    if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "Unable to bind on socket '%s'\n", sock_name);
++        ret = EIO;
++        goto done;
++    }
++    if (listen(*fd, 10) != 0) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "Unable to listen on socket '%s'\n", sock_name);
++        ret = EIO;
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    /* we want default permissions on created files to be very strict,
++       so set our umask to 0177 */
++    umask(0177);
++    if (ret != EOK) {
++        close(*fd);
++    }
++    return ret;
++}
++
+ /* create a unix socket and listen to it */
+ static int set_unix_socket(struct resp_ctx *rctx)
+ {
+-    struct sockaddr_un addr;
+     errno_t ret;
+     struct accept_fd_ctx *accept_ctx;
+ 
+@@ -628,42 +687,11 @@ static int set_unix_socket(struct resp_ctx *rctx)
+ #endif
+ 
+     if (rctx->sock_name != NULL ) {
+-        rctx->lfd = socket(AF_UNIX, SOCK_STREAM, 0);
+-        if (rctx->lfd == -1) {
+-            return EIO;
+-        }
+-
+         /* Set the umask so that permissions are set right on the socket.
+          * It must be readable and writable by anybody on the system. */
+-        umask(0111);
+-
+-        ret = set_nonblocking(rctx->lfd);
++        ret = create_pipe_fd(rctx->sock_name, &rctx->lfd, 0111);
+         if (ret != EOK) {
+-            goto failed;
+-        }
+-
+-        ret = set_close_on_exec(rctx->lfd);
+-        if (ret != EOK) {
+-            goto failed;
+-        }
+-
+-        memset(&addr, 0, sizeof(addr));
+-        addr.sun_family = AF_UNIX;
+-        strncpy(addr.sun_path, rctx->sock_name, sizeof(addr.sun_path)-1);
+-        addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
+-
+-        /* make sure we have no old sockets around */
+-        unlink(rctx->sock_name);
+-
+-        if (bind(rctx->lfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Unable to bind on socket '%s'\n", rctx->sock_name);
+-            goto failed;
+-        }
+-        if (listen(rctx->lfd, 10) != 0) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Unable to listen on socket '%s'\n", rctx->sock_name);
+-            goto failed;
++            return ret;
+         }
+ 
+         accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
+@@ -682,42 +710,11 @@ static int set_unix_socket(struct resp_ctx *rctx)
+ 
+     if (rctx->priv_sock_name != NULL ) {
+         /* create privileged pipe */
+-        rctx->priv_lfd = socket(AF_UNIX, SOCK_STREAM, 0);
+-        if (rctx->priv_lfd == -1) {
+-            close(rctx->lfd);
+-            return EIO;
+-        }
+-
+-        umask(0177);
+-
+-        ret = set_nonblocking(rctx->priv_lfd);
++        ret = create_pipe_fd(rctx->priv_sock_name, &rctx->priv_lfd, 0177);
+         if (ret != EOK) {
+             goto failed;
+         }
+ 
+-        ret = set_close_on_exec(rctx->priv_lfd);
+-        if (ret != EOK) {
+-            goto failed;
+-        }
+-
+-        memset(&addr, 0, sizeof(addr));
+-        addr.sun_family = AF_UNIX;
+-        strncpy(addr.sun_path, rctx->priv_sock_name, sizeof(addr.sun_path)-1);
+-        addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
+-
+-        unlink(rctx->priv_sock_name);
+-
+-        if (bind(rctx->priv_lfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Unable to bind on socket '%s'\n", rctx->priv_sock_name);
+-            goto failed;
+-        }
+-        if (listen(rctx->priv_lfd, 10) != 0) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Unable to listen on socket '%s'\n", rctx->priv_sock_name);
+-            goto failed;
+-        }
+-
+         accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
+         if(!accept_ctx) goto failed;
+         accept_ctx->rctx = rctx;
+@@ -733,15 +730,9 @@ static int set_unix_socket(struct resp_ctx *rctx)
+         }
+     }
+ 
+-    /* we want default permissions on created files to be very strict,
+-       so set our umask to 0177 */
+-    umask(0177);
+     return EOK;
+ 
+ failed:
+-    /* we want default permissions on created files to be very strict,
+-       so set our umask to 0177 */
+-    umask(0177);
+     close(rctx->lfd);
+     close(rctx->priv_lfd);
+     return EIO;
+-- 
+1.9.3
+
diff --git a/SOURCES/0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch b/SOURCES/0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch
deleted file mode 100644
index d3f683f..0000000
--- a/SOURCES/0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From 414d36bc08bf3ddb8c742f4548711cc0b448bb85 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 18 Dec 2013 18:14:46 +0100
-Subject: [PATCH 34/34] IPA: Call ipa_ad_subdom_refresh when server mode is
- initialized
-
-ipa_ad_subdom_refresh was called before IPA server context was
-initialized. On IPA server, this caused the code to dereference a NULL
-pointer and crash.
----
- src/providers/ipa/ipa_subdomains.c | 20 ++++++++++++++------
- 1 file changed, 14 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 56fd4f99654aa07f822c49d6d39526765785f0de..2d28d7cd0538b204eb2818e71e029dec19456a1c 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -278,12 +278,6 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
-         return ret;
-     }
- 
--    ret = ipa_ad_subdom_refresh(ctx->be_ctx, ctx->id_ctx, ctx->be_ctx->domain);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n"));
--        return ret;
--    }
--
-     ret = sss_write_domain_mappings(ctx->be_ctx->domain,
-                     dp_opt_get_bool(ctx->id_ctx->ipa_options->basic,
-                     IPA_SERVER_MODE));
-@@ -955,6 +949,13 @@ static void ipa_subdomains_handler_done(struct tevent_req *req)
-             DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n"));
-             goto done;
-         }
-+
-+        ret = ipa_ad_subdom_refresh(ctx->sd_ctx->be_ctx, ctx->sd_ctx->id_ctx,
-+                                    domain);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n"));
-+            goto done;
-+        }
-     }
- 
-     ret = sysdb_master_domain_update(domain);
-@@ -1316,6 +1317,7 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx,
- {
-     char *realm;
-     char *hostname;
-+    errno_t ret;
- 
-     if (dp_opt_get_bool(id_ctx->ipa_options->basic,
-                         IPA_SERVER_MODE) == false) {
-@@ -1360,5 +1362,11 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx,
-     id_ctx->server_mode->trusts = NULL;
-     id_ctx->server_mode->ext_groups = NULL;
- 
-+    ret = ipa_ad_subdom_refresh(be_ctx, id_ctx, be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n"));
-+        return ret;
-+    }
-+
-     return EOK;
- }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0034-TEST-Unit-test-for-create_pipe_fd.patch b/SOURCES/0034-TEST-Unit-test-for-create_pipe_fd.patch
new file mode 100644
index 0000000..dd2c9a4
--- /dev/null
+++ b/SOURCES/0034-TEST-Unit-test-for-create_pipe_fd.patch
@@ -0,0 +1,131 @@
+From 92cf06af1c5ee8be33722e76c79a3c290b9f67c8 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 17 Oct 2014 16:44:05 +0200
+Subject: [PATCH 34/46] TEST: Unit test for create_pipe_fd
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 4a5cced91df68a85ef0b30de8efe104c8a0aab7a)
+---
+ src/tests/cwrap/test_responder_common.c | 91 +++++++++++++++++++++++++++++++++
+ 1 file changed, 91 insertions(+)
+
+diff --git a/src/tests/cwrap/test_responder_common.c b/src/tests/cwrap/test_responder_common.c
+index 23dcf753f184cdecaf39c73c6e9be0e23e6df968..7e3f2e025a0dce15cc93e560a42bb566eff9fb30 100644
+--- a/src/tests/cwrap/test_responder_common.c
++++ b/src/tests/cwrap/test_responder_common.c
+@@ -23,6 +23,7 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
++#include <talloc.h>
+ 
+ #include <popt.h>
+ #include "util/util.h"
+@@ -105,6 +106,93 @@ void test_csv_to_uid_list_neg(void **state)
+     talloc_free(tmp_ctx);
+ }
+ 
++struct create_pipe_ctx {
++    int fd;
++    const char *sock_name;
++};
++
++void test_create_pipe_fd_setup(void **state)
++{
++    struct create_pipe_ctx *ctx;
++
++    ctx = talloc(global_talloc_context, struct create_pipe_ctx);
++    assert_non_null(ctx);
++    ctx->fd = -1;
++
++    *state = ctx;
++}
++
++void check_sock_properties(struct create_pipe_ctx *ctx, mode_t mode)
++{
++    int ret;
++    int optval;
++    socklen_t optlen;
++    struct stat sbuf;
++
++    /* Check existence of the file and the permissions */
++    ret = stat(ctx->sock_name, &sbuf);
++    assert_int_equal(ret, 0);
++    assert_true(S_ISSOCK(sbuf.st_mode));
++    assert_true((sbuf.st_mode & ~S_IFMT) == mode);
++
++    /* Check it's a UNIX socket */
++    optlen = sizeof(optval);
++    ret = getsockopt(ctx->fd, SOL_SOCKET, SO_DOMAIN, &optval, &optlen);
++    assert_int_equal(ret, 0);
++    assert_int_equal(optval, AF_UNIX);
++
++    optlen = sizeof(optval);
++    ret = getsockopt(ctx->fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
++    assert_int_equal(ret, 0);
++    assert_int_equal(optval, SOCK_STREAM);
++
++    /* Make sure this is a listening socket */
++    optlen = sizeof(optval);
++    ret = getsockopt(ctx->fd, SOL_SOCKET, SO_ACCEPTCONN, &optval, &optlen);
++    assert_int_equal(ret, 0);
++    assert_int_equal(optval, 1);
++
++    /* Check the right protocol */
++    optlen = sizeof(optval);
++    ret = getsockopt(ctx->fd, SOL_SOCKET, SO_PROTOCOL, &optval, &optlen);
++    assert_int_equal(ret, 0);
++    assert_int_equal(optval, 0);
++
++}
++
++void test_create_pipe_fd(void **state)
++{
++    int ret;
++    struct create_pipe_ctx *ctx;
++
++    ctx = talloc_get_type(*state, struct create_pipe_ctx);
++
++    ctx->sock_name = __FUNCTION__;
++
++    ret = create_pipe_fd(ctx->sock_name, &ctx->fd, 0111);
++    assert_int_equal(ret, EOK);
++    assert_int_not_equal(ctx->fd, -1);
++    check_sock_properties(ctx, 0666);
++
++    /* Make sure we can overwrite an existing socket */
++    ret = create_pipe_fd(ctx->sock_name, &ctx->fd, 0000);
++    assert_int_equal(ret, EOK);
++    assert_int_not_equal(ctx->fd, -1);
++    check_sock_properties(ctx, 0777);
++}
++
++void test_create_pipe_fd_teardown(void **state)
++{
++    struct create_pipe_ctx *ctx;
++
++    ctx = talloc_get_type(*state, struct create_pipe_ctx);
++
++    if (ctx->fd != -1) {
++        unlink(ctx->sock_name);
++        close(ctx->fd);
++    }
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -119,6 +207,9 @@ int main(int argc, const char *argv[])
+         unit_test(test_uid_csv_to_uid_list),
+         unit_test(test_name_csv_to_uid_list),
+         unit_test(test_csv_to_uid_list_neg),
++        unit_test_setup_teardown(test_create_pipe_fd,
++                                 test_create_pipe_fd_setup,
++                                 test_create_pipe_fd_teardown)
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+1.9.3
+
diff --git a/SOURCES/0035-responders-Do-not-initialize-pipe-fd-if-already-pres.patch b/SOURCES/0035-responders-Do-not-initialize-pipe-fd-if-already-pres.patch
new file mode 100644
index 0000000..db698b6
--- /dev/null
+++ b/SOURCES/0035-responders-Do-not-initialize-pipe-fd-if-already-pres.patch
@@ -0,0 +1,187 @@
+From 4bab32c01bce266c68838c9edac9a567f8b1f413 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 15 Oct 2014 18:01:55 +0200
+Subject: [PATCH 35/46] responders: Do not initialize pipe fd if already
+ present
+
+Allow to skip initialization of pipe file descriptor
+if the responder context already has one.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 8bccd95e275fae760a991da394235e4e70e57bbd)
+---
+ src/responder/autofs/autofssrv.c        |  2 +-
+ src/responder/common/responder.h        |  2 ++
+ src/responder/common/responder_common.c | 20 ++++++++++++++------
+ src/responder/ifp/ifpsrv.c              |  2 +-
+ src/responder/nss/nsssrv.c              |  2 +-
+ src/responder/pac/pacsrv.c              |  2 +-
+ src/responder/pam/pamsrv.c              |  4 ++--
+ src/responder/ssh/sshsrv.c              |  2 +-
+ src/responder/sudo/sudosrv.c            |  2 +-
+ 9 files changed, 24 insertions(+), 14 deletions(-)
+
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index 931cf018bfe15b37bf8e5f93a21c7ab61d238c18..12a7a777e214fa4c3821eb58ff602b3f3efb987a 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -132,7 +132,7 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
+     autofs_cmds = get_autofs_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            autofs_cmds,
+-                           SSS_AUTOFS_SOCKET_NAME, NULL,
++                           SSS_AUTOFS_SOCKET_NAME, -1, NULL, -1,
+                            CONFDB_AUTOFS_CONF_ENTRY,
+                            SSS_AUTOFS_SBUS_SERVICE_NAME,
+                            SSS_AUTOFS_SBUS_SERVICE_VERSION,
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index d233710782fe7df1bbcc338e3815d1701557519e..8837e11425be36c67da038287de48c069ae335cd 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -159,7 +159,9 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
+                      struct confdb_ctx *cdb,
+                      struct sss_cmd_table sss_cmds[],
+                      const char *sss_pipe_name,
++                     int pipe_fd,
+                      const char *sss_priv_pipe_name,
++                     int priv_pipe_fd,
+                      const char *confdb_service_path,
+                      const char *svc_name,
+                      uint16_t svc_version,
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index a262a2c1487c786404b6d0d4c720edd1679279d0..85aa04335b72c38fb7a128f04315e3c4189c5d56 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -689,9 +689,11 @@ static int set_unix_socket(struct resp_ctx *rctx)
+     if (rctx->sock_name != NULL ) {
+         /* Set the umask so that permissions are set right on the socket.
+          * It must be readable and writable by anybody on the system. */
+-        ret = create_pipe_fd(rctx->sock_name, &rctx->lfd, 0111);
+-        if (ret != EOK) {
+-            return ret;
++        if (rctx->lfd == -1) {
++            ret = create_pipe_fd(rctx->sock_name, &rctx->lfd, 0111);
++            if (ret != EOK) {
++                return ret;
++            }
+         }
+ 
+         accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
+@@ -710,9 +712,11 @@ static int set_unix_socket(struct resp_ctx *rctx)
+ 
+     if (rctx->priv_sock_name != NULL ) {
+         /* create privileged pipe */
+-        ret = create_pipe_fd(rctx->priv_sock_name, &rctx->priv_lfd, 0177);
+-        if (ret != EOK) {
+-            goto failed;
++        if (rctx->priv_lfd == -1) {
++            ret = create_pipe_fd(rctx->priv_sock_name, &rctx->priv_lfd, 0177);
++            if (ret != EOK) {
++                goto failed;
++            }
+         }
+ 
+         accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
+@@ -755,7 +759,9 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
+                      struct confdb_ctx *cdb,
+                      struct sss_cmd_table sss_cmds[],
+                      const char *sss_pipe_name,
++                     int pipe_fd,
+                      const char *sss_priv_pipe_name,
++                     int priv_pipe_fd,
+                      const char *confdb_service_path,
+                      const char *svc_name,
+                      uint16_t svc_version,
+@@ -779,6 +785,8 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
+     rctx->sss_cmds = sss_cmds;
+     rctx->sock_name = sss_pipe_name;
+     rctx->priv_sock_name = sss_priv_pipe_name;
++    rctx->lfd = pipe_fd;
++    rctx->priv_lfd = priv_pipe_fd;
+     rctx->confdb_service_path = confdb_service_path;
+     rctx->shutting_down = false;
+ 
+diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
+index 8d8fe885abb8ef53ee7f49e763ba78c4dda9a983..eddeec9812bdd650bfbfb78ede91bf3704113504 100644
+--- a/src/responder/ifp/ifpsrv.c
++++ b/src/responder/ifp/ifpsrv.c
+@@ -310,7 +310,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
+     ifp_cmds = get_ifp_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            ifp_cmds,
+-                           NULL, NULL,
++                           NULL, -1, NULL, -1,
+                            CONFDB_IFP_CONF_ENTRY,
+                            SSS_IFP_SBUS_SERVICE_NAME,
+                            SSS_IFP_SBUS_SERVICE_VERSION,
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index dbbdb4f844410eabe01f184ccdf8d9deb41833f4..cfb146464d224cdb8b517d23a86421da7eaccd1f 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -392,7 +392,7 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
+ 
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            nss_cmds,
+-                           SSS_NSS_SOCKET_NAME, NULL,
++                           SSS_NSS_SOCKET_NAME, -1, NULL, -1,
+                            CONFDB_NSS_CONF_ENTRY,
+                            NSS_SBUS_SERVICE_NAME,
+                            NSS_SBUS_SERVICE_VERSION,
+diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
+index b76691de829b4f40937a07ea83825a606950aa1e..e427cd756f4031218a8fb99c30bf709e21680039 100644
+--- a/src/responder/pac/pacsrv.c
++++ b/src/responder/pac/pacsrv.c
+@@ -119,7 +119,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
+ 
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            pac_cmds,
+-                           SSS_PAC_SOCKET_NAME, NULL,
++                           SSS_PAC_SOCKET_NAME, -1, NULL, -1,
+                            CONFDB_PAC_CONF_ENTRY,
+                            PAC_SBUS_SERVICE_NAME,
+                            PAC_SBUS_SERVICE_VERSION,
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index 91b395080820b27f5d57341e59dd739e674be31a..a3f8662738c26a537bc21d8d419e65e49c4828c9 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -194,8 +194,8 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
+     pam_cmds = get_pam_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            pam_cmds,
+-                           SSS_PAM_SOCKET_NAME,
+-                           SSS_PAM_PRIV_SOCKET_NAME,
++                           SSS_PAM_SOCKET_NAME, -1,
++                           SSS_PAM_PRIV_SOCKET_NAME, -1,
+                            CONFDB_PAM_CONF_ENTRY,
+                            SSS_PAM_SBUS_SERVICE_NAME,
+                            SSS_PAM_SBUS_SERVICE_VERSION,
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index 1328d1746b9e2d6474d6c2f8ce2825be463ca3e7..b154ee1baa16de68f642d2e967b8e7c873c8d4e7 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -92,7 +92,7 @@ int ssh_process_init(TALLOC_CTX *mem_ctx,
+     ssh_cmds = get_ssh_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            ssh_cmds,
+-                           SSS_SSH_SOCKET_NAME, NULL,
++                           SSS_SSH_SOCKET_NAME, -1, NULL, -1,
+                            CONFDB_SSH_CONF_ENTRY,
+                            SSS_SSH_SBUS_SERVICE_NAME,
+                            SSS_SSH_SBUS_SERVICE_VERSION,
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index 30752c9dacdc390b24fe837c0630333b5e171448..038e3fd7da0829ce554a31694725c3dddaf5c038 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -93,7 +93,7 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
+     sudo_cmds = get_sudo_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            sudo_cmds,
+-                           SSS_SUDO_SOCKET_NAME, NULL,
++                           SSS_SUDO_SOCKET_NAME, -1, NULL, -1,
+                            CONFDB_SUDO_CONF_ENTRY,
+                            SSS_SUDO_SBUS_SERVICE_NAME,
+                            SSS_SUDO_SBUS_SERVICE_VERSION,
+-- 
+1.9.3
+
diff --git a/SOURCES/0035-sss_cache-initialize-names-member-of-sss_domain_info.patch b/SOURCES/0035-sss_cache-initialize-names-member-of-sss_domain_info.patch
deleted file mode 100644
index 825f38f..0000000
--- a/SOURCES/0035-sss_cache-initialize-names-member-of-sss_domain_info.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From ca3dda947538ca1c16386d4c3f86f97eee7d0abc Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 25 Nov 2013 17:54:06 +0100
-Subject: [PATCH 35/41] sss_cache: initialize names member of sss_domain_info
-
-sss_tc_fqname() called by sss_get_domain_name() requires that the names
-member of the sss_domain_info struct is set to work properly. If the
-names struct is properly initialized in sss_domain_info the separate one
-in the tool context is not needed anymore.
-
-Related to https://fedorahosted.org/sssd/ticket/1741
----
- src/tools/sss_cache.c | 23 ++++++++++-------------
- 1 file changed, 10 insertions(+), 13 deletions(-)
-
-diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
-index fa2e29de8bf8a035dd725aa3190af1c2a2091e05..3b6e62393f6cf0f6ccc94aea8cf19bf3aedc444f 100644
---- a/src/tools/sss_cache.c
-+++ b/src/tools/sss_cache.c
-@@ -63,7 +63,6 @@ static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
- struct cache_tool_ctx {
-     struct confdb_ctx *confdb;
-     struct sss_domain_info *domains;
--    struct sss_names_ctx *nctx;
- 
-     char *user_filter;
-     char *group_filter;
-@@ -209,7 +208,7 @@ static errno_t update_filter(struct cache_tool_ctx *tctx,
-         return ENOMEM;
-     }
- 
--    ret = sss_parse_name(tmp_ctx, tctx->nctx, name,
-+    ret = sss_parse_name(tmp_ctx, dinfo->names, name,
-                          &parsed_domain, &parsed_name);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, ("sss_parse_name failed\n"));
-@@ -280,17 +279,6 @@ static errno_t update_all_filters(struct cache_tool_ctx *tctx,
- {
-     errno_t ret;
- 
--    if (IS_SUBDOMAIN(dinfo)) {
--        ret = sss_names_init(tctx, tctx->confdb, dinfo->parent->name,
--                             &tctx->nctx);
--    } else {
--        ret = sss_names_init(tctx, tctx->confdb, dinfo->name, &tctx->nctx);
--    }
--    if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, ("sss_names_init() failed\n"));
--        return ret;
--    }
--
-     /* Update user filter */
-     ret = update_filter(tctx, dinfo, tctx->user_name,
-                         tctx->update_user_filter, "(%s=%s)", false,
-@@ -467,6 +455,7 @@ errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain)
- {
-     char *confdb_path;
-     int ret;
-+    struct sss_domain_info *dinfo;
- 
-     confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
-     if (confdb_path == NULL) {
-@@ -505,6 +494,14 @@ errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain)
-         }
-     }
- 
-+    for (dinfo = ctx->domains; dinfo; dinfo = get_next_domain(dinfo, false)) {
-+        ret = sss_names_init(ctx, ctx->confdb, dinfo->name, &dinfo->names);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("sss_names_init() failed\n"));
-+            return ret;
-+        }
-+    }
-+
-     return EOK;
- }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0036-PAM-Create-pipe-file-descriptors-before-privileges-a.patch b/SOURCES/0036-PAM-Create-pipe-file-descriptors-before-privileges-a.patch
new file mode 100644
index 0000000..bbf32df
--- /dev/null
+++ b/SOURCES/0036-PAM-Create-pipe-file-descriptors-before-privileges-a.patch
@@ -0,0 +1,85 @@
+From 69c41ad3d74684dac43a1f767bc00ca97b4518b5 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 15 Oct 2014 18:15:53 +0200
+Subject: [PATCH 36/46] PAM: Create pipe file descriptors before privileges are
+ dropped
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit b547bd685cb71bb450b0c86487767f02e66f6cea)
+---
+ src/responder/pam/pamsrv.c | 30 ++++++++++++++++++++++++++----
+ 1 file changed, 26 insertions(+), 4 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index a3f8662738c26a537bc21d8d419e65e49c4828c9..d3cf0c770ad2978e101f40453137ade8d826b8e1 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -181,7 +181,8 @@ done:
+ 
+ static int pam_process_init(TALLOC_CTX *mem_ctx,
+                             struct tevent_context *ev,
+-                            struct confdb_ctx *cdb)
++                            struct confdb_ctx *cdb,
++                            int pipe_fd, int priv_pipe_fd)
+ {
+     struct resp_ctx *rctx;
+     struct sss_cmd_table *pam_cmds;
+@@ -194,8 +195,8 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
+     pam_cmds = get_pam_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            pam_cmds,
+-                           SSS_PAM_SOCKET_NAME, -1,
+-                           SSS_PAM_PRIV_SOCKET_NAME, -1,
++                           SSS_PAM_SOCKET_NAME, pipe_fd,
++                           SSS_PAM_PRIV_SOCKET_NAME, priv_pipe_fd,
+                            CONFDB_PAM_CONF_ENTRY,
+                            SSS_PAM_SBUS_SERVICE_NAME,
+                            SSS_PAM_SBUS_SERVICE_VERSION,
+@@ -318,6 +319,8 @@ int main(int argc, const char *argv[])
+     int ret;
+     uid_t uid;
+     gid_t gid;
++    int pipe_fd;
++    int priv_pipe_fd;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+@@ -347,6 +350,24 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_pam";
+ 
++    /* Crate pipe file descriptors here before privileges are dropped
++     * in server_setup() */
++    ret = create_pipe_fd(SSS_PAM_SOCKET_NAME, &pipe_fd, 0111);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "create_pipe_fd failed [%d]: %s.\n",
++              ret, sss_strerror(ret));
++        return 2;
++    }
++
++    ret = create_pipe_fd(SSS_PAM_PRIV_SOCKET_NAME, &priv_pipe_fd, 0177);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "create_pipe_fd failed (priviledged pipe) [%d]: %s.\n",
++              ret, sss_strerror(ret));
++        return 2;
++    }
++
+     ret = server_setup("sssd[pam]", 0, 0, 0, CONFDB_PAM_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+@@ -359,7 +380,8 @@ int main(int argc, const char *argv[])
+ 
+     ret = pam_process_init(main_ctx,
+                            main_ctx->event_ctx,
+-                           main_ctx->confdb_ctx);
++                           main_ctx->confdb_ctx,
++                           pipe_fd, priv_pipe_fd);
+     if (ret != EOK) return 3;
+ 
+     /* loop on main */
+-- 
+1.9.3
+
diff --git a/SOURCES/0036-sss_cache-fix-case-sensitivity-issue.patch b/SOURCES/0036-sss_cache-fix-case-sensitivity-issue.patch
deleted file mode 100644
index b9ca7c5..0000000
--- a/SOURCES/0036-sss_cache-fix-case-sensitivity-issue.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From 2db8726f09800d64231f403198742d22a04a8d8b Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 26 Nov 2013 10:27:50 +0100
-Subject: [PATCH 36/41] sss_cache: fix case-sensitivity issue
-
-For case-insensitive domains the lower-case name for case-insensitive
-searches is stored in SYSDB_NAME_ALIAS.
-
-Related to https://fedorahosted.org/sssd/ticket/1741
----
- src/tools/sss_cache.c | 63 +++++++++++++++++++++++++++++----------------------
- 1 file changed, 36 insertions(+), 27 deletions(-)
-
-diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
-index 3b6e62393f6cf0f6ccc94aea8cf19bf3aedc444f..56dc47afdcb92b71dc1ef71d7f26fdf276a1c45f 100644
---- a/src/tools/sss_cache.c
-+++ b/src/tools/sss_cache.c
-@@ -196,6 +196,8 @@ static errno_t update_filter(struct cache_tool_ctx *tctx,
-     TALLOC_CTX *tmp_ctx = NULL;
-     char *use_name = NULL;
-     char *filter;
-+    char *sanitized;
-+    char *lc_sanitized;
- 
-     if (!name || !update) {
-         /* Nothing to do */
-@@ -215,6 +217,14 @@ static errno_t update_filter(struct cache_tool_ctx *tctx,
-         goto done;
-     }
- 
-+    if (parsed_domain != NULL && strcasecmp(dinfo->name, parsed_domain) != 0) {
-+        /* We were able to parse the domain from given fqdn, but it
-+         * does not match with currently processed domain. */
-+        filter = NULL;
-+        ret = EOK;
-+        goto done;
-+    }
-+
-     if (!dinfo->case_sensitive && !force_case_sensitivity) {
-         use_name = sss_tc_utf8_str_tolower(tmp_ctx, parsed_name);
-         if (!use_name) {
-@@ -232,41 +242,40 @@ static errno_t update_filter(struct cache_tool_ctx *tctx,
-             ret = ENOMEM;
-             goto done;
-         }
-+    }
- 
--        if (!strcasecmp(dinfo->name, parsed_domain)) {
--            if (fmt) {
--                filter = talloc_asprintf(tmp_ctx, fmt,
--                                         SYSDB_NAME, use_name);
--            } else {
--                filter = talloc_strdup(tmp_ctx, use_name);
--            }
--            if (filter == NULL) {
--                DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
--                ret = ENOMEM;
--                goto done;
--            }
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, use_name, dinfo,
-+                                      &sanitized, &lc_sanitized);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to sanitize the given name.\n"));
-+        goto done;
-+    }
-+
-+    if (fmt) {
-+        if (!dinfo->case_sensitive && !force_case_sensitivity) {
-+            filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)(%s=%s))",
-+                                     SYSDB_NAME_ALIAS, lc_sanitized,
-+                                     SYSDB_NAME_ALIAS, sanitized);
-         } else {
--            /* We were able to parse the domain from given fqdn, but it
--             * does not match with currently processed domain. */
--            filter = NULL;
-+            filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, sanitized);
-         }
-     } else {
--        if (fmt) {
--            filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, name);
--        } else {
--            filter = talloc_strdup(tmp_ctx, name);
--        }
--        if (filter == NULL) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
--            ret = ENOMEM;
--            goto done;
--        }
-+        filter = talloc_strdup(tmp_ctx, sanitized);
-+    }
-+    if (filter == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
-+        ret = ENOMEM;
-+        goto done;
-     }
- 
--    talloc_free(*_filter);
--    *_filter = talloc_steal(tctx, filter);
-     ret = EOK;
-+
- done:
-+    if (ret == EOK) {
-+        talloc_free(*_filter);
-+        *_filter = talloc_steal(tctx, filter);
-+    }
-+
-     talloc_free(tmp_ctx);
-     return ret;
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0037-Add-sysdb_attrs_add_lc_name_alias.patch b/SOURCES/0037-Add-sysdb_attrs_add_lc_name_alias.patch
deleted file mode 100644
index 96db4f3..0000000
--- a/SOURCES/0037-Add-sysdb_attrs_add_lc_name_alias.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From b1f74ee745aa84f53fe330d55fafb9810012f875 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 28 Nov 2013 11:28:39 +0100
-Subject: [PATCH 37/41] Add sysdb_attrs_add_lc_name_alias
-
----
- src/db/sysdb.c          | 22 ++++++++++++++++++++++
- src/db/sysdb.h          |  2 ++
- src/tests/sysdb-tests.c | 29 +++++++++++++++++++++++++++++
- 3 files changed, 53 insertions(+)
-
-diff --git a/src/db/sysdb.c b/src/db/sysdb.c
-index da5dbe84c2415025a188544f4b4c944888f07888..2a4be58008fc1164765db26aaba3886071448d30 100644
---- a/src/db/sysdb.c
-+++ b/src/db/sysdb.c
-@@ -618,6 +618,28 @@ int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs,
-     return ret;
- }
- 
-+int sysdb_attrs_add_lc_name_alias(struct sysdb_attrs *attrs,
-+                                  const char *value)
-+{
-+    char *lc_str;
-+    int ret;
-+
-+    if (attrs == NULL || value == NULL) {
-+        return EINVAL;
-+    }
-+
-+    lc_str = sss_tc_utf8_str_tolower(attrs, value);
-+    if (lc_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot convert name to lowercase\n"));
-+        return ENOMEM;
-+    }
-+
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_str);
-+    talloc_free(lc_str);
-+
-+    return ret;
-+}
-+
- int sysdb_attrs_copy_values(struct sysdb_attrs *src,
-                             struct sysdb_attrs *dst,
-                             const char *name)
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 4d5ef0b4794a85aa7fbc8f261d42eddd1043284e..f3358d642efd1c13203061c43e455a5c26c72740 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -274,6 +274,8 @@ int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs,
-                            const char *name, uint32_t value);
- int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs,
-                            const char *name, time_t value);
-+int sysdb_attrs_add_lc_name_alias(struct sysdb_attrs *attrs,
-+                                  const char *value);
- int sysdb_attrs_copy_values(struct sysdb_attrs *src,
-                             struct sysdb_attrs *dst,
-                             const char *name);
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index ddbf6f28fd5024945fedcb3c6e2122948c4f1459..63ffac82e15849e5f6534462ce7c58b183412acc 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -4422,6 +4422,33 @@ START_TEST(test_sysdb_svc_remove_alias)
- }
- END_TEST
- 
-+#define LC_NAME_ALIAS_TEST_VAL "TeSt VaLuE"
-+#define LC_NAME_ALIAS_CHECK_VAL "test value"
-+START_TEST(test_sysdb_attrs_add_lc_name_alias)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    const char *str;
-+
-+    ret = sysdb_attrs_add_lc_name_alias(NULL, NULL);
-+    fail_unless(ret == EINVAL, "EINVAL not returned for NULL input");
-+
-+    attrs = sysdb_new_attrs(NULL);
-+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
-+
-+    ret = sysdb_attrs_add_lc_name_alias(attrs, LC_NAME_ALIAS_TEST_VAL);
-+    fail_unless(ret == EOK, "sysdb_attrs_add_lc_name_alias failed");
-+
-+    ret = sysdb_attrs_get_string(attrs, SYSDB_NAME_ALIAS, &str);
-+    fail_unless(ret == EOK, "sysdb_attrs_get_string failed");
-+    fail_unless(strcmp(str, LC_NAME_ALIAS_CHECK_VAL) == 0,
-+                "Unexpected value, expected [%s], got [%s]",
-+                LC_NAME_ALIAS_CHECK_VAL, str);
-+
-+    talloc_free(attrs);
-+}
-+END_TEST
-+
- START_TEST(test_sysdb_has_enumerated)
- {
-     errno_t ret;
-@@ -5188,6 +5215,8 @@ Suite *create_sysdb_suite(void)
-     tcase_add_test(tc_sysdb, test_sysdb_store_services);
-     tcase_add_test(tc_sysdb, test_sysdb_svc_remove_alias);
- 
-+    tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias);
-+
- /* Add all test cases to the test suite */
-     suite_add_tcase(s, tc_sysdb);
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0037-PAM-Run-pam-responder-as-nonroot.patch b/SOURCES/0037-PAM-Run-pam-responder-as-nonroot.patch
new file mode 100644
index 0000000..78d50f8
--- /dev/null
+++ b/SOURCES/0037-PAM-Run-pam-responder-as-nonroot.patch
@@ -0,0 +1,43 @@
+From 157250faaf48514f1580c3de4abb224c190d243b Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 9 Oct 2014 17:25:34 +0200
+Subject: [PATCH 37/46] PAM: Run pam responder as nonroot
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 4e1892cdfcc5300d6632200c38ba67f2783d15f2)
+---
+ src/monitor/monitor.c      | 3 ++-
+ src/responder/pam/pamsrv.c | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 297648a60836cec1bd95c0a2972c8d14be32675a..2f622e571478b2a71ef29ed518ca3b80c077b766 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1062,7 +1062,8 @@ static errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
+  */
+ static bool svc_supported_as_nonroot(const char *svc_name)
+ {
+-    if (strcmp(svc_name, "nss") == 0) {
++    if ((strcmp(svc_name, "nss") == 0)
++        || (strcmp(svc_name, "pam") == 0)) {
+         return true;
+     }
+     return false;
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index d3cf0c770ad2978e101f40453137ade8d826b8e1..c7e3c20b2731efb9393bc820ab09486c48e0a9ea 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -368,7 +368,7 @@ int main(int argc, const char *argv[])
+         return 2;
+     }
+ 
+-    ret = server_setup("sssd[pam]", 0, 0, 0, CONFDB_PAM_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[pam]", 0, uid, gid, CONFDB_PAM_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+-- 
+1.9.3
+
diff --git a/SOURCES/0038-AUTOFS-Run-the-autofs-responder-as-the-SSSD-user.patch b/SOURCES/0038-AUTOFS-Run-the-autofs-responder-as-the-SSSD-user.patch
new file mode 100644
index 0000000..87f2823
--- /dev/null
+++ b/SOURCES/0038-AUTOFS-Run-the-autofs-responder-as-the-SSSD-user.patch
@@ -0,0 +1,43 @@
+From f39e5c757a4f3b244d0372f5a57e1714bc890bc3 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 17 Oct 2014 17:30:07 +0200
+Subject: [PATCH 38/46] AUTOFS: Run the autofs responder as the SSSD user
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 287cc55b9086dd3c4e2a5fb84784e09767860142)
+---
+ src/monitor/monitor.c            | 3 ++-
+ src/responder/autofs/autofssrv.c | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 2f622e571478b2a71ef29ed518ca3b80c077b766..4e461aa78e47ec6cedb77dd030f72c273a00a495 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1063,7 +1063,8 @@ static errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
+ static bool svc_supported_as_nonroot(const char *svc_name)
+ {
+     if ((strcmp(svc_name, "nss") == 0)
+-        || (strcmp(svc_name, "pam") == 0)) {
++        || (strcmp(svc_name, "pam") == 0)
++        || (strcmp(svc_name, "autofs") == 0)) {
+         return true;
+     }
+     return false;
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index 12a7a777e214fa4c3821eb58ff602b3f3efb987a..44474ee0858d92fb5965de07773e3ad1e020ebfd 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -238,7 +238,7 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_autofs";
+ 
+-    ret = server_setup("sssd[autofs]", 0, 0, 0,
++    ret = server_setup("sssd[autofs]", 0, uid, gid,
+                        CONFDB_AUTOFS_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) {
+         return 2;
+-- 
+1.9.3
+
diff --git a/SOURCES/0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch b/SOURCES/0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch
deleted file mode 100644
index 0679bf7..0000000
--- a/SOURCES/0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch
+++ /dev/null
@@ -1,195 +0,0 @@
-From e90d014c1ce95a30f4be2383a4b4f47ad21c5601 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 28 Nov 2013 12:31:24 +0100
-Subject: [PATCH 38/41] Use sysdb_attrs_add_lc_name_alias to add
- case-insensitive alias
-
----
- src/providers/ipa/ipa_s2n_exop.c     | 27 ++++++---------------------
- src/providers/ldap/sdap_async.c      | 21 ++++++++++++++++-----
- src/providers/proxy/proxy_id.c       | 20 ++------------------
- src/providers/proxy/proxy_netgroup.c | 10 +---------
- src/responder/pac/pacsrv_utils.c     |  4 ++--
- 5 files changed, 27 insertions(+), 55 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index d8506aaae2582f496033212e5abeef753244c21a..8bad16d42facac3a585a4fdf579c3d2bb913dd71 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -651,7 +651,6 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
-     struct sysdb_attrs *user_attrs = NULL;
-     struct sysdb_attrs *group_attrs = NULL;
-     char *name;
--    char *lc_name;
-     char *realm;
-     char *upn;
-     struct berval *bv_req = NULL;
-@@ -767,16 +766,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
-                 goto done;
-             }
- 
--            lc_name = sss_tc_utf8_str_tolower(user_attrs, name);
--            if (lc_name == NULL) {
--                DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
--                ret =  ENOMEM;
--                goto done;
--            }
--
--            ret = sysdb_attrs_add_string(user_attrs, SYSDB_NAME_ALIAS, lc_name);
-+            ret = sysdb_attrs_add_lc_name_alias(user_attrs, name);
-             if (ret != EOK) {
--                DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n"));
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      ("sysdb_attrs_add_lc_name_alias failed.\n"));
-                 goto done;
-             }
- 
-@@ -852,18 +845,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
-                 goto done;
-             }
- 
--            lc_name = sss_tc_utf8_str_tolower(group_attrs, name);
--            if (lc_name == NULL) {
--                DEBUG(SSSDBG_CRIT_FAILURE,
--                      ("Cannot convert name to lowercase\n"));
--                ret = ENOMEM;
--                goto done;
--            }
--
--            ret = sysdb_attrs_add_string(group_attrs, SYSDB_NAME_ALIAS,
--                                         lc_name);
-+            ret = sysdb_attrs_add_lc_name_alias(group_attrs, name);
-             if (ret != EOK) {
--                DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n"));
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      ("sysdb_attrs_add_lc_name_alias failed.\n"));
-                 goto done;
-             }
- 
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index f5cc962b34c8ef5e8c8dc9cf90b77d782b389032..e905d2dd6d539baadcd29aa0869ca04e845947e2 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -2318,12 +2318,23 @@ sdap_save_all_names(const char *name,
-             goto done;
-         }
- 
--        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, domname);
--        if (ret) {
--            DEBUG(SSSDBG_OP_FAILURE, ("Failed to add alias [%s] into the "
--                                      "attribute list\n", aliases[i]));
--            goto done;
-+        if (lowercase) {
-+            ret = sysdb_attrs_add_lc_name_alias(attrs, domname);
-+            if (ret) {
-+                DEBUG(SSSDBG_OP_FAILURE, ("Failed to add lower-cased version "
-+                                          "of alias [%s] into the "
-+                                          "attribute list\n", aliases[i]));
-+                goto done;
-+            }
-+        } else {
-+            ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, domname);
-+            if (ret) {
-+                DEBUG(SSSDBG_OP_FAILURE, ("Failed to add alias [%s] into the "
-+                                          "attribute list\n", aliases[i]));
-+                goto done;
-+            }
-         }
-+
-     }
- 
-     ret = EOK;
-diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
-index 963aad2d0676a665d69be2ea2996ad49cb2bacc6..2c01aad5ae86e11d22383d6b618073ef8e9d6dbb 100644
---- a/src/providers/proxy/proxy_id.c
-+++ b/src/providers/proxy/proxy_id.c
-@@ -223,7 +223,6 @@ static int save_user(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
- {
-     const char *shell;
-     const char *gecos;
--    char *lower;
-     struct sysdb_attrs *attrs = NULL;
-     errno_t ret;
-     const char *cased_alias;
-@@ -249,14 +248,7 @@ static int save_user(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
-     }
- 
-     if (lowercase) {
--        lower = sss_tc_utf8_str_tolower(attrs, pwd->pw_name);
--        if (!lower) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
--            talloc_zfree(attrs);
--            return ENOMEM;
--        }
--
--        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower);
-+        ret = sysdb_attrs_add_lc_name_alias(attrs, pwd->pw_name);
-         if (ret) {
-             DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n"));
-             talloc_zfree(attrs);
-@@ -540,7 +532,6 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom,
- {
-     errno_t ret, sret;
-     struct sysdb_attrs *attrs = NULL;
--    char *lower;
-     const char *cased_alias;
-     TALLOC_CTX *tmp_ctx;
-     time_t now = time(NULL);
-@@ -595,14 +586,7 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom,
-         }
- 
-         if (dom->case_sensitive == false) {
--            lower = sss_tc_utf8_str_tolower(attrs, grp->gr_name);
--            if (!lower) {
--                DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
--                ret = ENOMEM;
--                goto done;
--            }
--
--            ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower);
-+            ret = sysdb_attrs_add_lc_name_alias(attrs, grp->gr_name);
-             if (ret) {
-                 DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n"));
-                 ret = ENOMEM;
-diff --git a/src/providers/proxy/proxy_netgroup.c b/src/providers/proxy/proxy_netgroup.c
-index 04a0b18d7079aa15d04562ee5c785caed4456fb5..bb0bc171b8c3688a92c14f711669f752653a39f0 100644
---- a/src/providers/proxy/proxy_netgroup.c
-+++ b/src/providers/proxy/proxy_netgroup.c
-@@ -74,17 +74,9 @@ static errno_t save_netgroup(struct sysdb_ctx *sysdb,
-                              uint64_t cache_timeout)
- {
-     errno_t ret;
--    char *lower;
- 
-     if (lowercase) {
--        lower = sss_tc_utf8_str_tolower(NULL, name);
--        if (!lower) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
--            return ENOMEM;
--        }
--
--        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower);
--        talloc_free(lower);
-+        ret = sysdb_attrs_add_lc_name_alias(attrs, name);
-         if (ret) {
-             DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n"));
-             return ret;
-diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
-index 30055a1345b7d943e6adf822438263c92e53b51a..6a6ea2e357483c68533c501b93c16383ee644048 100644
---- a/src/responder/pac/pacsrv_utils.c
-+++ b/src/responder/pac/pacsrv_utils.c
-@@ -483,9 +483,9 @@ errno_t get_pwd_from_pac(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, pwd->pw_name);
-+    ret = sysdb_attrs_add_lc_name_alias(attrs, pwd->pw_name);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n"));
-+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_lc_name_alias failed.\n"));
-         goto done;
-     }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0039-PAC-Run-the-pac-responder-as-the-SSSD-user.patch b/SOURCES/0039-PAC-Run-the-pac-responder-as-the-SSSD-user.patch
new file mode 100644
index 0000000..d57f2b7
--- /dev/null
+++ b/SOURCES/0039-PAC-Run-the-pac-responder-as-the-SSSD-user.patch
@@ -0,0 +1,44 @@
+From 1afda474301754a095c55497aaee1fd038a8dcd0 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 17 Oct 2014 17:31:31 +0200
+Subject: [PATCH 39/46] PAC: Run the pac responder as the SSSD user
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 22f4bcbb211bf800af647ad1fc9595a8020a6fe6)
+---
+ src/monitor/monitor.c      | 3 ++-
+ src/responder/pac/pacsrv.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 4e461aa78e47ec6cedb77dd030f72c273a00a495..61a9f0b849a460da88b393b4f08795fb7a571886 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1064,7 +1064,8 @@ static bool svc_supported_as_nonroot(const char *svc_name)
+ {
+     if ((strcmp(svc_name, "nss") == 0)
+         || (strcmp(svc_name, "pam") == 0)
+-        || (strcmp(svc_name, "autofs") == 0)) {
++        || (strcmp(svc_name, "autofs") == 0)
++        || (strcmp(svc_name, "pac") == 0)) {
+         return true;
+     }
+     return false;
+diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
+index e427cd756f4031218a8fb99c30bf709e21680039..3eb21c8fff85343249494bcc06d97cda4b738034 100644
+--- a/src/responder/pac/pacsrv.c
++++ b/src/responder/pac/pacsrv.c
+@@ -247,7 +247,8 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_pac";
+ 
+-    ret = server_setup("sssd[pac]", 0, 0, 0, CONFDB_PAC_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[pac]", 0, uid, gid,
++                       CONFDB_PAC_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+     ret = die_if_parent_died();
+-- 
+1.9.3
+
diff --git a/SOURCES/0039-Use-lower-case-name-for-case-insensitive-searches.patch b/SOURCES/0039-Use-lower-case-name-for-case-insensitive-searches.patch
deleted file mode 100644
index ac7d540..0000000
--- a/SOURCES/0039-Use-lower-case-name-for-case-insensitive-searches.patch
+++ /dev/null
@@ -1,356 +0,0 @@
-From b0af402f8201d28922892b18792474f4ec546f36 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 13 Dec 2013 11:44:59 +0100
-Subject: [PATCH 39/41] Use lower-case name for case-insensitive searches
-
-The patch makes sure that a completely lower-cased version of a fully
-qualified name is used for case insensitive searches. Currently there
-are code paths where the domain name was used as configured and was not
-lower-cased.
-
-To make sure this patch does not break with old entries in the cache or
-case sensitive domains a third template was added to the related filters
-templates which is either filled with a completely lower-cased version or
-with the old version. The other two template values are unchanged.
----
- src/db/sysdb.h                       | 10 +++++-----
- src/db/sysdb_ops.c                   |  8 +++++---
- src/db/sysdb_search.c                | 30 ++++++++++++++++++++--------
- src/responder/pam/pam_LOCAL_domain.c |  4 ++--
- src/tests/cmocka/test_utils.c        | 38 ++++++++++++++++++++++++++++++++++++
- src/util/sss_tc_utf8.c               | 30 ++++++++++++++++++++++++++++
- src/util/util.h                      |  6 ++++++
- 7 files changed, 108 insertions(+), 18 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index f3358d642efd1c13203061c43e455a5c26c72740..f1ed8158ccff70f85940d63f247e23451c22c30f 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -144,23 +144,23 @@
- #define SYSDB_NC "objectclass="SYSDB_NETGROUP_CLASS
- #define SYSDB_MPGC "|("SYSDB_UC")("SYSDB_GC")"
- 
--#define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
-+#define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
- #define SYSDB_PWUID_FILTER "(&("SYSDB_UC")("SYSDB_UIDNUM"=%lu))"
- #define SYSDB_PWSID_FILTER "(&("SYSDB_UC")("SYSDB_SID_STR"=%s))"
- #define SYSDB_PWENT_FILTER "("SYSDB_UC")"
- 
--#define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
-+#define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
- #define SYSDB_GRGID_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=%lu))"
- #define SYSDB_GRSID_FILTER "(&("SYSDB_GC")("SYSDB_SID_STR"=%s))"
- #define SYSDB_GRENT_FILTER "("SYSDB_GC")"
--#define SYSDB_GRNAM_MPG_FILTER "(&("SYSDB_MPGC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
-+#define SYSDB_GRNAM_MPG_FILTER "(&("SYSDB_MPGC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
- #define SYSDB_GRGID_MPG_FILTER "(&("SYSDB_MPGC")("SYSDB_GIDNUM"=%lu))"
- #define SYSDB_GRENT_MPG_FILTER "("SYSDB_MPGC")"
- 
- #define SYSDB_INITGR_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=*))"
- 
--#define SYSDB_NETGR_FILTER "(&("SYSDB_NC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
--#define SYSDB_NETGR_TRIPLES_FILTER "(|("SYSDB_NAME"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_MEMBEROF"=%s))"
-+#define SYSDB_NETGR_FILTER "(&("SYSDB_NC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
-+#define SYSDB_NETGR_TRIPLES_FILTER "(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_MEMBEROF"=%s))"
- 
- #define SYSDB_SID_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_SID_STR"=%s))"
- 
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 890bf1eb3cc5fc0b6eb6f7a145aee6d87945cd8d..a5dfd443c84b87609881f9042b3e82958c3b0e5f 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -305,6 +305,7 @@ int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx,
-     struct ldb_dn *basedn;
-     size_t msgs_count = 0;
-     char *sanitized_name;
-+    char *lc_sanitized_name;
-     char *filter;
-     int ret;
- 
-@@ -320,13 +321,14 @@ int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, name, domain, &sanitized_name,
-+                                      &lc_sanitized_name);
-     if (ret != EOK) {
-         goto done;
-     }
- 
--    filter = talloc_asprintf(tmp_ctx, SYSDB_PWNAM_FILTER, sanitized_name,
--                             sanitized_name);
-+    filter = talloc_asprintf(tmp_ctx, SYSDB_PWNAM_FILTER, lc_sanitized_name,
-+                             sanitized_name, sanitized_name);
-     if (!filter) {
-         ret = ENOMEM;
-         goto done;
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index d15fc73ce2272bff53650ae9dd0dbdad99a849e6..308710a2c780b9a709930b7d8a16a0c07471aff7 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -38,6 +38,7 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
-     struct ldb_dn *base_dn;
-     struct ldb_result *res;
-     char *sanitized_name;
-+    char *lc_sanitized_name;
-     const char *src_name;
-     int ret;
- 
-@@ -61,13 +62,15 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_filter_sanitize(tmp_ctx, src_name, &sanitized_name);
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, src_name, domain,
-+                                      &sanitized_name, &lc_sanitized_name);
-     if (ret != EOK) {
-         goto done;
-     }
- 
-     ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn,
-                      LDB_SCOPE_SUBTREE, attrs, SYSDB_PWNAM_FILTER,
-+                     lc_sanitized_name,
-                      sanitized_name, sanitized_name);
-     if (ret) {
-         ret = sysdb_error_to_errno(ret);
-@@ -214,6 +217,7 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
-     struct ldb_dn *base_dn;
-     struct ldb_result *res;
-     const char *src_name;
-+    char *lc_sanitized_name;
-     int ret;
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -243,14 +247,15 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_filter_sanitize(tmp_ctx, src_name, &sanitized_name);
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, src_name, domain,
-+                                      &sanitized_name, &lc_sanitized_name);
-     if (ret != EOK) {
-         goto done;
-     }
- 
-     ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn,
-                      LDB_SCOPE_SUBTREE, attrs, fmt_filter,
--                     sanitized_name, sanitized_name);
-+                     lc_sanitized_name, sanitized_name, sanitized_name);
-     if (ret) {
-         ret = sysdb_error_to_errno(ret);
-         goto done;
-@@ -481,6 +486,7 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
-     struct ldb_dn *base_dn;
-     struct ldb_result *res;
-     char *sanitized_name;
-+    char *lc_sanitized_name;
-     int ret;
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -495,14 +501,15 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, name, domain, &sanitized_name,
-+                                      &lc_sanitized_name);
-     if (ret != EOK) {
-         goto done;
-     }
- 
-     ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn,
-                      LDB_SCOPE_SUBTREE, attributes,
--                     SYSDB_PWNAM_FILTER, sanitized_name,
-+                     SYSDB_PWNAM_FILTER, lc_sanitized_name, sanitized_name,
-                      sanitized_name);
-     if (ret) {
-         ret = sysdb_error_to_errno(ret);
-@@ -785,6 +792,7 @@ errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx,
-     struct ldb_dn *base_dn;
-     struct ldb_result *result;
-     char *sanitized_netgroup;
-+    char *lc_sanitized_netgroup;
-     char *netgroup_dn;
-     int lret;
-     errno_t ret;
-@@ -802,7 +810,9 @@ errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_filter_sanitize(tmp_ctx, netgroup, &sanitized_netgroup);
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, netgroup, domain,
-+                                      &sanitized_netgroup,
-+                                      &lc_sanitized_netgroup);
-     if (ret != EOK) {
-         goto done;
-     }
-@@ -816,7 +826,7 @@ errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx,
- 
-     lret = ldb_search(sysdb->ldb, tmp_ctx, &result, base_dn,
-                      LDB_SCOPE_SUBTREE, attrs,
--                     SYSDB_NETGR_TRIPLES_FILTER,
-+                     SYSDB_NETGR_TRIPLES_FILTER, lc_sanitized_netgroup,
-                      sanitized_netgroup, sanitized_netgroup,
-                      netgroup_dn);
-     ret = sysdb_error_to_errno(lret);
-@@ -843,6 +853,7 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx,
-     struct ldb_dn *base_dn;
-     struct ldb_result *result;
-     char *sanitized_netgroup;
-+    char *lc_sanitized_netgroup;
-     int ret;
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -857,7 +868,9 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_filter_sanitize(tmp_ctx, netgrname, &sanitized_netgroup);
-+    ret = sss_filter_sanitize_for_dom(tmp_ctx, netgrname, domain,
-+                                      &sanitized_netgroup,
-+                                      &lc_sanitized_netgroup);
-     if (ret != EOK) {
-         goto done;
-     }
-@@ -865,6 +878,7 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx,
-     ret = ldb_search(sysdb->ldb, tmp_ctx, &result, base_dn,
-                      LDB_SCOPE_SUBTREE, attributes,
-                      SYSDB_NETGR_FILTER,
-+                     lc_sanitized_netgroup,
-                      sanitized_netgroup,
-                      sanitized_netgroup);
-     if (ret) {
-diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c
-index e7776cba3b74a86ef63dad30f08b4436a59a89be..49ddbcda39468e6a4f2065d97df309ce881b6aa4 100644
---- a/src/responder/pam/pam_LOCAL_domain.c
-+++ b/src/responder/pam/pam_LOCAL_domain.c
-@@ -258,12 +258,12 @@ int LOCAL_pam_handler(struct pam_auth_req *preq)
- 
-     if (res->count < 1) {
-         DEBUG(4, ("No user found with filter ["SYSDB_PWNAM_FILTER"]\n",
--                  pd->user, pd->user));
-+                  pd->user, pd->user, pd->user));
-         pd->pam_status = PAM_USER_UNKNOWN;
-         goto done;
-     } else if (res->count > 1) {
-         DEBUG(4, ("More than one object found with filter ["SYSDB_PWNAM_FILTER"]\n",
--                  pd->user, pd->user));
-+                  pd->user, pd->user, pd->user));
-         lreq->error = EFAULT;
-         goto done;
-     }
-diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
-index 1be59ab69cfa632010c5e1700dc79f59b6f48fde..61e8e9f07ca2f6772b12fe602acb3d2872b39c10 100644
---- a/src/tests/cmocka/test_utils.c
-+++ b/src/tests/cmocka/test_utils.c
-@@ -177,6 +177,41 @@ void test_find_subdomain_by_sid_missing_sid(void **state)
-     }
- }
- 
-+#define TEST_SANITIZE_INPUT "TestUser@Test.Domain"
-+#define TEST_SANITIZE_LC_INPUT "testuser@test.domain"
-+
-+void test_sss_filter_sanitize_for_dom(void **state)
-+{
-+    struct dom_list_test_ctx *test_ctx;
-+    int ret;
-+    char *sanitized;
-+    char *lc_sanitized;
-+    struct sss_domain_info *dom;
-+
-+    test_ctx = talloc_get_type(*state, struct dom_list_test_ctx);
-+    dom = test_ctx->dom_list;
-+
-+    dom->case_sensitive = true;
-+
-+    ret = sss_filter_sanitize_for_dom(test_ctx, TEST_SANITIZE_INPUT, dom,
-+                                      &sanitized, &lc_sanitized);
-+    assert_int_equal(ret, EOK);
-+    assert_string_equal(sanitized, TEST_SANITIZE_INPUT);
-+    assert_string_equal(lc_sanitized, TEST_SANITIZE_INPUT);
-+    talloc_free(sanitized);
-+    talloc_free(lc_sanitized);
-+
-+    dom->case_sensitive = false;
-+
-+    ret = sss_filter_sanitize_for_dom(test_ctx, TEST_SANITIZE_INPUT, dom,
-+                                      &sanitized, &lc_sanitized);
-+    assert_int_equal(ret, EOK);
-+    assert_string_equal(sanitized, TEST_SANITIZE_INPUT);
-+    assert_string_equal(lc_sanitized, TEST_SANITIZE_LC_INPUT);
-+    talloc_free(sanitized);
-+    talloc_free(lc_sanitized);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -194,6 +229,9 @@ int main(int argc, const char *argv[])
-                                  setup_dom_list, teardown_dom_list),
-         unit_test_setup_teardown(test_find_subdomain_by_sid_missing_sid,
-                                  setup_dom_list, teardown_dom_list),
-+
-+        unit_test_setup_teardown(test_sss_filter_sanitize_for_dom,
-+                                 setup_dom_list, teardown_dom_list),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-diff --git a/src/util/sss_tc_utf8.c b/src/util/sss_tc_utf8.c
-index 6a976211f7b77d329ba3261577c43466406f3da9..e1426a44f3518783dca4f22cd6016cdde92d0f56 100644
---- a/src/util/sss_tc_utf8.c
-+++ b/src/util/sss_tc_utf8.c
-@@ -55,3 +55,33 @@ sss_tc_utf8_tolower(TALLOC_CTX *mem_ctx, const uint8_t *s, size_t len, size_t *_
-     return ret;
- }
- 
-+errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx,
-+                                    const char *input,
-+                                    struct sss_domain_info *dom,
-+                                    char **sanitized,
-+                                    char **lc_sanitized)
-+{
-+    int ret;
-+
-+    ret = sss_filter_sanitize(mem_ctx, input, sanitized);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sss_filter_sanitize failed.\n"));
-+        return ret;
-+    }
-+
-+    if (dom->case_sensitive) {
-+        *lc_sanitized = talloc_strdup(mem_ctx, *sanitized);
-+    } else {
-+        *lc_sanitized = sss_tc_utf8_str_tolower(mem_ctx, *sanitized);
-+    }
-+
-+    if (*lc_sanitized == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("%s failed.\n",
-+                                              dom->case_sensitive ?
-+                                                    "talloc_strdup" :
-+                                                    "sss_tc_utf8_str_tolower"));
-+        return ENOMEM;
-+    }
-+
-+    return EOK;
-+}
-diff --git a/src/util/util.h b/src/util/util.h
-index 058c1c27986f9749a18dd4c92ddb9428349a1dac..3334476ab83a137d957765fe2c9afba4ad0d014c 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -484,6 +484,12 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
-                             const char *input,
-                             char **sanitized);
- 
-+errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx,
-+                                    const char *input,
-+                                    struct sss_domain_info *dom,
-+                                    char **sanitized,
-+                                    char **lc_sanitized);
-+
- char *
- sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr);
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0040-Add-new-option-ldap_group_type.patch b/SOURCES/0040-Add-new-option-ldap_group_type.patch
deleted file mode 100644
index 0f0f27f..0000000
--- a/SOURCES/0040-Add-new-option-ldap_group_type.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-From fd56e9302454869c636c2e40322eec52391b4c4f Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 9 Dec 2013 12:17:43 +0100
-Subject: [PATCH 40/41] Add new option ldap_group_type
-
----
- src/config/SSSDConfig/__init__.py.in     |  1 +
- src/config/etc/sssd.api.d/sssd-ad.conf   |  1 +
- src/config/etc/sssd.api.d/sssd-ipa.conf  |  1 +
- src/config/etc/sssd.api.d/sssd-ldap.conf |  1 +
- src/db/sysdb.h                           |  1 +
- src/man/sssd-ldap.5.xml                  | 21 +++++++++++++++++++++
- src/providers/ad/ad_opts.h               |  1 +
- src/providers/ipa/ipa_opts.h             |  1 +
- src/providers/ldap/ldap_opts.h           |  3 +++
- src/providers/ldap/sdap.h                |  1 +
- 10 files changed, 32 insertions(+)
-
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index af5903c65e05411d5773f1f9b1f742fdb832433c..8563a91e7afe680edfa0b9dd951ac7ab5a0fd3b0 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -284,6 +284,7 @@ option_strings = {
-     'ldap_group_uuid' : _('Group UUID attribute'),
-     'ldap_group_objectsid' : _("objectSID attribute"),
-     'ldap_group_modify_timestamp' : _('Modification time attribute for groups'),
-+    'ldap_group_type' : _('Type of the group and other flags'),
-     #replaced by ldap_entry_usn# 'ldap_group_entry_usn' : _('entryUSN attribute'),
-     'ldap_group_nesting_level' : _('Maximum nesting level SSSd will follow'),
- 
-diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
-index 00e8968d2b6dab33a39005f11a497cb3e2185302..6b136f2ec88614092cf1ceb4e2cea79db064d468 100644
---- a/src/config/etc/sssd.api.d/sssd-ad.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
-@@ -91,6 +91,7 @@ ldap_group_uuid = str, None, false
- ldap_group_objectsid = str, None, false
- ldap_group_modify_timestamp = str, None, false
- ldap_group_entry_usn = str, None, false
-+ldap_group_type = int, None, false
- ldap_force_upper_case_realm = bool, None, false
- ldap_group_nesting_level = int, None, false
- ldap_netgroup_search_base = str, None, false
-diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
-index bc14fbe3d4153bd7a7ca4ffe0351edf0b8c02ee4..a94b5f09b073c050bff597d66c8164e4f38a9bfe 100644
---- a/src/config/etc/sssd.api.d/sssd-ipa.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
-@@ -98,6 +98,7 @@ ldap_group_uuid = str, None, false
- ldap_group_objectsid = str, None, false
- ldap_group_modify_timestamp = str, None, false
- ldap_group_entry_usn = str, None, false
-+ldap_group_type = int, None, false
- ldap_force_upper_case_realm = bool, None, false
- ldap_group_nesting_level = int, None, false
- ldap_netgroup_search_base = str, None, false
-diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
-index eb239664c49e9d516468c184dfeac190ecf8ddd8..4f5a06800d4ba4dacea08285b9db3abdc44df8f3 100644
---- a/src/config/etc/sssd.api.d/sssd-ldap.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
-@@ -93,6 +93,7 @@ ldap_group_uuid = str, None, false
- ldap_group_objectsid = str, None, false
- ldap_group_modify_timestamp = str, None, false
- ldap_group_entry_usn = str, None, false
-+ldap_group_type = int, None, false
- ldap_group_nesting_level = int, None, false
- ldap_force_upper_case_realm = bool, None, false
- ldap_netgroup_search_base = str, None, false
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index f1ed8158ccff70f85940d63f247e23451c22c30f..9bcd7be0960fcfa390fb9150594ea84880a14eea 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -76,6 +76,7 @@
- #define SYSDB_POSIX "isPosix"
- #define SYSDB_USER_CATEGORY "userCategory"
- #define SYSDB_HOST_CATEGORY "hostCategory"
-+#define SYSDB_GROUP_TYPE "groupType"
- 
- #define SYSDB_GECOS "gecos"
- #define SYSDB_LAST_LOGIN "lastLogin"
-diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
-index efe22c9d22adccb244fe99603a74eb93dbddea7f..cc58544c38e8ffa779f0a1b22a69caaf3f193ce1 100644
---- a/src/man/sssd-ldap.5.xml
-+++ b/src/man/sssd-ldap.5.xml
-@@ -849,6 +849,27 @@
-                 </varlistentry>
- 
-                 <varlistentry>
-+                    <term>ldap_group_type (integer)</term>
-+                    <listitem>
-+                        <para>
-+                            The LDAP attribute that contains an integer value
-+                            indicating the type of the group and maybe other
-+                            flags.
-+                        </para>
-+                        <para>
-+                            This attribute is currently only used by the AD
-+                            provider to determine if a group is a domain local
-+                            groups and has to be filtered out for trusted
-+                            domains.
-+                        </para>
-+                        <para>
-+                            Default: groupType in the AD provider, othewise not
-+                            set
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-+                <varlistentry>
-                     <term>ldap_group_nesting_level (integer)</term>
-                     <listitem>
-                         <para>
-diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
-index 5b7b1c89f5f45d7cc744a955e6378390948a99fd..0deeec99a9c1944301b80d1f25713b5d0504e88c 100644
---- a/src/providers/ad/ad_opts.h
-+++ b/src/providers/ad/ad_opts.h
-@@ -209,6 +209,7 @@ struct sdap_attr_map ad_2008r2_group_map[] = {
-     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
-     { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
-     { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL },
-+    { "ldap_group_type", "groupType", SYSDB_GROUP_TYPE, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
-index 5ec36c550b166e07a9ed2f2c31474c55d0ecdaee..27dc3e2f977383836c18cb824abceb03c9e9056c 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -209,6 +209,7 @@ struct sdap_attr_map ipa_group_map[] = {
-     { "ldap_group_objectsid", "ipaNTSecurityIdentifier", SYSDB_SID_STR, NULL },
-     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
-     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
-+    { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
-index a6c821f3ac3ad951a3b45168b298b96fefb96b60..9593dfd30a81db60b7358c66975871507340aa4b 100644
---- a/src/providers/ldap/ldap_opts.h
-+++ b/src/providers/ldap/ldap_opts.h
-@@ -187,6 +187,7 @@ struct sdap_attr_map rfc2307_group_map[] = {
-     { "ldap_group_objectsid", NULL, SYSDB_SID, NULL },
-     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
-     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
-+    { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-@@ -241,6 +242,7 @@ struct sdap_attr_map rfc2307bis_group_map[] = {
-     { "ldap_group_objectsid", NULL, SYSDB_SID, NULL },
-     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
-     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
-+    { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-@@ -293,6 +295,7 @@ struct sdap_attr_map gen_ad2008r2_group_map[] = {
-     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
-     { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
-     { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL },
-+    { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index a7ea94eb810a96b61862bd8cc6fcd800c3e8e0cb..d408be0a65cdd840d8379b7af4c0ab1e67ed3f5c 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -296,6 +296,7 @@ enum sdap_group_attrs {
-     SDAP_AT_GROUP_OBJECTSID,
-     SDAP_AT_GROUP_MODSTAMP,
-     SDAP_AT_GROUP_USN,
-+    SDAP_AT_GROUP_TYPE,
- 
-     SDAP_OPTS_GROUP /* attrs counter */
- };
--- 
-1.8.4.2
-
diff --git a/SOURCES/0040-SUDO-Run-the-sudo-responder-as-the-SSSD-user.patch b/SOURCES/0040-SUDO-Run-the-sudo-responder-as-the-SSSD-user.patch
new file mode 100644
index 0000000..2fc6840
--- /dev/null
+++ b/SOURCES/0040-SUDO-Run-the-sudo-responder-as-the-SSSD-user.patch
@@ -0,0 +1,43 @@
+From 88b6f5da86301ac3f76cacdc99d7ab5045a5a3a6 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 17 Oct 2014 18:14:45 +0200
+Subject: [PATCH 40/46] SUDO: Run the sudo responder as the SSSD user
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 3f9e2c24dbc14b2eafbe4f5a5ee16fe9af3c3f75)
+---
+ src/monitor/monitor.c        | 3 ++-
+ src/responder/sudo/sudosrv.c | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 61a9f0b849a460da88b393b4f08795fb7a571886..d09aeba9033ff1460f9d4a6c51f35edbf2e67fa6 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1065,7 +1065,8 @@ static bool svc_supported_as_nonroot(const char *svc_name)
+     if ((strcmp(svc_name, "nss") == 0)
+         || (strcmp(svc_name, "pam") == 0)
+         || (strcmp(svc_name, "autofs") == 0)
+-        || (strcmp(svc_name, "pac") == 0)) {
++        || (strcmp(svc_name, "pac") == 0)
++        || (strcmp(svc_name, "sudo") == 0)) {
+         return true;
+     }
+     return false;
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index 038e3fd7da0829ce554a31694725c3dddaf5c038..a25f98ecabaa952a7cd87c54cd302903cb563faf 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -195,7 +195,7 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_sudo";
+ 
+-    ret = server_setup("sssd[sudo]", 0, 0, 0, CONFDB_SUDO_CONF_ENTRY,
++    ret = server_setup("sssd[sudo]", 0, uid, gid, CONFDB_SUDO_CONF_ENTRY,
+                        &main_ctx);
+     if (ret != EOK) {
+         return 2;
+-- 
+1.9.3
+
diff --git a/SOURCES/0041-Add-sysdb_attrs_get_int32_t.patch b/SOURCES/0041-Add-sysdb_attrs_get_int32_t.patch
deleted file mode 100644
index 04d3a63..0000000
--- a/SOURCES/0041-Add-sysdb_attrs_get_int32_t.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 91c41b25f3d2e5a6074d1dd73c3355f9159d2cae Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 10 Dec 2013 10:14:02 +0100
-Subject: [PATCH 41/41] Add sysdb_attrs_get_int32_t
-
----
- src/db/sysdb.c | 26 ++++++++++++++++++++++++++
- src/db/sysdb.h |  2 ++
- 2 files changed, 28 insertions(+)
-
-diff --git a/src/db/sysdb.c b/src/db/sysdb.c
-index 2a4be58008fc1164765db26aaba3886071448d30..0e07ed60858298a1ac85d06146ccb98c5899a705 100644
---- a/src/db/sysdb.c
-+++ b/src/db/sysdb.c
-@@ -366,6 +366,32 @@ int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
-     return EOK;
- }
- 
-+int sysdb_attrs_get_int32_t(struct sysdb_attrs *attrs, const char *name,
-+                             int32_t *value)
-+{
-+    struct ldb_message_element *el;
-+    int ret;
-+    char *endptr;
-+    int32_t val;
-+
-+    ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
-+    if (ret) {
-+        return ret;
-+    }
-+
-+    if (el->num_values != 1) {
-+        return ERANGE;
-+    }
-+
-+    errno = 0;
-+    val = strtoint32((const char *) el->values[0].data, &endptr, 10);
-+    if (errno != 0) return errno;
-+    if (*endptr) return EINVAL;
-+
-+    *value = val;
-+    return EOK;
-+}
-+
- int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name,
-                              uint32_t *value)
- {
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 9bcd7be0960fcfa390fb9150594ea84880a14eea..255a135f0cad788e4c952b86fe24ca10f5e63732 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -294,6 +294,8 @@ errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name,
-                              bool *value);
- int sysdb_attrs_get_uint16_t(struct sysdb_attrs *attrs, const char *name,
-                              uint16_t *value);
-+int sysdb_attrs_get_int32_t(struct sysdb_attrs *attrs, const char *name,
-+                             int32_t *value);
- int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name,
-                              uint32_t *value);
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0041-SSH-Run-the-ssh-responder-as-the-SSSD-user.patch b/SOURCES/0041-SSH-Run-the-ssh-responder-as-the-SSSD-user.patch
new file mode 100644
index 0000000..86d2d0b
--- /dev/null
+++ b/SOURCES/0041-SSH-Run-the-ssh-responder-as-the-SSSD-user.patch
@@ -0,0 +1,44 @@
+From 48db24e8e576c2bde0acdf41c4228fc2a29b4db4 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 17 Oct 2014 18:14:53 +0200
+Subject: [PATCH 41/46] SSH: Run the ssh responder as the SSSD user
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Simo Sorce <simo@redhat.com>
+(cherry picked from commit 76c8dafad2a18cf1514635aa766062085c23a5c8)
+---
+ src/monitor/monitor.c      | 3 ++-
+ src/responder/ssh/sshsrv.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index d09aeba9033ff1460f9d4a6c51f35edbf2e67fa6..0dea327213a1ad04b6f69c0ffb0fb87254420796 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -1066,7 +1066,8 @@ static bool svc_supported_as_nonroot(const char *svc_name)
+         || (strcmp(svc_name, "pam") == 0)
+         || (strcmp(svc_name, "autofs") == 0)
+         || (strcmp(svc_name, "pac") == 0)
+-        || (strcmp(svc_name, "sudo") == 0)) {
++        || (strcmp(svc_name, "sudo") == 0)
++        || (strcmp(svc_name, "ssh") == 0)) {
+         return true;
+     }
+     return false;
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index b154ee1baa16de68f642d2e967b8e7c873c8d4e7..b1969b49de8579f0136c3afa78eb16d68c81ee4e 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -215,7 +215,8 @@ int main(int argc, const char *argv[])
+     /* set up things like debug, signals, daemonization, etc... */
+     debug_log_file = "sssd_ssh";
+ 
+-    ret = server_setup("sssd[ssh]", 0, 0, 0, CONFDB_SSH_CONF_ENTRY, &main_ctx);
++    ret = server_setup("sssd[ssh]", 0, uid, gid,
++                       CONFDB_SSH_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) {
+         return 2;
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0042-IPA-fix-for-recent-AD-group-membership-changes.patch b/SOURCES/0042-IPA-fix-for-recent-AD-group-membership-changes.patch
deleted file mode 100644
index fa294ce..0000000
--- a/SOURCES/0042-IPA-fix-for-recent-AD-group-membership-changes.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From 32388a70e254021473cca2caf8fcc77fdf7e7635 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 7 Jan 2014 13:04:58 +0100
-Subject: [PATCH 42/43] IPA: fix for recent AD group membership changes
-
----
- src/providers/ipa/ipa_subdomains.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 2d28d7cd0538b204eb2818e71e029dec19456a1c..9efbd725f1102d34af2107801286bca1c6412c19 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -192,6 +192,8 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
-         return ret;
-     }
-
-+    sdom->pvt = ad_id_ctx;
-+
-     /* Set up the ID mapping object */
-     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
-         id_ctx->sdap_id_ctx->opts->idmap_ctx;
---
-1.8.4.2
diff --git a/SOURCES/0042-SBUS-Fix-error-handling-after-closing-container.patch b/SOURCES/0042-SBUS-Fix-error-handling-after-closing-container.patch
new file mode 100644
index 0000000..b7ed294
--- /dev/null
+++ b/SOURCES/0042-SBUS-Fix-error-handling-after-closing-container.patch
@@ -0,0 +1,38 @@
+From 06db46d511ea4d5cce23354ed3c3a0069f06e27f Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 10 Oct 2014 19:23:33 +0200
+Subject: [PATCH 42/46] SBUS: Fix error handling after closing container
+
+If function dbus_message_iter_close_container fail the return variable ret will
+be set to EINVAL, but function will not be immediately terminated.
+"goto done" was missing.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 82b5395c1519b9392ddd323ece0845b51a994bbc)
+---
+ src/sbus/sssd_dbus_request.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
+index 7729d4e0d7bf6e517e2efce4dbeb064f6f471b87..677ed532f7555f6aeba378ebd9a0b06167ddfa1b 100644
+--- a/src/sbus/sssd_dbus_request.c
++++ b/src/sbus/sssd_dbus_request.c
+@@ -286,6 +286,7 @@ int sbus_request_return_array_as_variant(struct sbus_request *dbus_req,
+                                         DBUS_ERROR_FAILED,
+                                         "Could not close array\n"));
+         ret = EINVAL;
++        goto done;
+     }
+ 
+     dbret = dbus_message_iter_close_container(&iter, &variant_iter);
+@@ -298,6 +299,7 @@ int sbus_request_return_array_as_variant(struct sbus_request *dbus_req,
+                                         DBUS_ERROR_FAILED,
+                                         "Could not close variant\n"));
+         ret = EINVAL;
++        goto done;
+     }
+ 
+ done:
+-- 
+1.9.3
+
diff --git a/SOURCES/0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch b/SOURCES/0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch
deleted file mode 100644
index 1f5f205..0000000
--- a/SOURCES/0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 147af349a5642f85689cbfe68136f0e01706330e Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 8 Jan 2014 08:11:46 +0100
-Subject: [PATCH 43/43] LDAP: Fix typo and use the right attribute map
-
-https://fedorahosted.org/sssd/ticket/2191
-
-There was a copy-n-paste bug in the code that resulted in using a wrong
-attribute map. This could lead to the primary name not being selected
-correctly.
----
- src/providers/ldap/sdap.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
-index 078326ad3614ed2cd41659ea279642a46a0e24e1..ddcf199b61311b69fde54c3ee25f2338ceb05576 100644
---- a/src/providers/ldap/sdap.c
-+++ b/src/providers/ldap/sdap.c
-@@ -1246,7 +1246,7 @@ errno_t sdap_get_user_primary_name(TALLOC_CTX *memctx,
-                                    const char **_user_name)
- {
-     return sdap_get_primary_name(memctx,
--                                 opts->group_map[SDAP_AT_USER_NAME].name,
-+                                 opts->user_map[SDAP_AT_USER_NAME].name,
-                                  attrs, dom, _user_name);
- }
-
---
-1.8.4.2
diff --git a/SOURCES/0043-TESTS-Add-tests-for-the-views-related-option-maps.patch b/SOURCES/0043-TESTS-Add-tests-for-the-views-related-option-maps.patch
new file mode 100644
index 0000000..5ea2aa3
--- /dev/null
+++ b/SOURCES/0043-TESTS-Add-tests-for-the-views-related-option-maps.patch
@@ -0,0 +1,33 @@
+From f44e8711e3e1b81132d11084feb34ba62919429e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 2 Oct 2014 11:10:47 +0200
+Subject: [PATCH 43/46] TESTS: Add tests for the views-related option maps
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit b1593daeecdb40c72ef8c58546bda65c57d4e35c)
+---
+ src/tests/ipa_ldap_opt-tests.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/tests/ipa_ldap_opt-tests.c b/src/tests/ipa_ldap_opt-tests.c
+index 3504092d444d89ab59e074237a3f8589aeebbcda..8587e8df77cf30cfef9cf2e5ca6484c3bc881876 100644
+--- a/src/tests/ipa_ldap_opt-tests.c
++++ b/src/tests/ipa_ldap_opt-tests.c
+@@ -228,12 +228,13 @@ START_TEST(test_sdap_opt_sentinel)
+ 
+     fail_unless_sdap_opt_is_terminator(&netgroup_map[SDAP_OPTS_NETGROUP]);
+     fail_unless_sdap_opt_is_terminator(&ad_netgroup_map[SDAP_OPTS_NETGROUP]);
+-
+     fail_unless_sdap_opt_is_terminator(&ipa_netgroup_map[IPA_OPTS_NETGROUP]);
+ 
+     fail_unless_sdap_opt_is_terminator(&ipa_host_map[IPA_OPTS_HOST]);
+     fail_unless_sdap_opt_is_terminator(&ipa_hostgroup_map[IPA_OPTS_HOSTGROUP]);
+     fail_unless_sdap_opt_is_terminator(&ipa_selinux_user_map[IPA_OPTS_SELINUX_USERMAP]);
++    fail_unless_sdap_opt_is_terminator(&ipa_view_map[IPA_OPTS_VIEW]);
++    fail_unless_sdap_opt_is_terminator(&ipa_override_map[IPA_OPTS_OVERRIDE]);
+ 
+     fail_unless_sdap_opt_is_terminator(&service_map[SDAP_OPTS_SERVICES]);
+     fail_unless_sdap_opt_is_terminator(&ad_service_map[SDAP_OPTS_SERVICES]);
+-- 
+1.9.3
+
diff --git a/SOURCES/0044-RESPONDERS-refactor-create_pipe_fd.patch b/SOURCES/0044-RESPONDERS-refactor-create_pipe_fd.patch
new file mode 100644
index 0000000..28f0ad7
--- /dev/null
+++ b/SOURCES/0044-RESPONDERS-refactor-create_pipe_fd.patch
@@ -0,0 +1,95 @@
+From efcfaeed63cff84f547c5ae9e5fd8ee02d0bae21 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Thu, 23 Oct 2014 15:05:05 +0100
+Subject: [PATCH 44/46] RESPONDERS: refactor create_pipe_fd()
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2470
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit f3b9a5b3cf62124bdb5fc11ae2fe6a89ff921539)
+---
+ src/responder/common/responder.h        |  2 +-
+ src/responder/common/responder_common.c | 21 ++++++++++++---------
+ 2 files changed, 13 insertions(+), 10 deletions(-)
+
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index 8837e11425be36c67da038287de48c069ae335cd..cd2b3232c53e919c7d47170ccd1016a8604c9742 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -178,7 +178,7 @@ responder_get_domain(struct resp_ctx *rctx, const char *domain);
+ errno_t responder_get_domain_by_id(struct resp_ctx *rctx, const char *id,
+                                    struct sss_domain_info **_ret_dom);
+ 
+-int create_pipe_fd(const char *sock_name, int *fd, mode_t umaskval);
++int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval);
+ 
+ /* responder_cmd.c */
+ int sss_cmd_empty_packet(struct sss_packet *packet);
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index 85aa04335b72c38fb7a128f04315e3c4189c5d56..9a13c95d63d93df96ffceb51f969eb562c3a6b08 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -584,24 +584,25 @@ static int sss_dp_init(struct resp_ctx *rctx,
+     return EOK;
+ }
+ 
+-int create_pipe_fd(const char *sock_name, int *fd, mode_t umaskval)
++int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
+ {
+     struct sockaddr_un addr;
+     errno_t ret;
++    int fd;
+ 
+-    *fd = socket(AF_UNIX, SOCK_STREAM, 0);
+-    if (*fd == -1) {
++    fd = socket(AF_UNIX, SOCK_STREAM, 0);
++    if (fd == -1) {
+         return EIO;
+     }
+ 
+     umask(umaskval);
+ 
+-    ret = set_nonblocking(*fd);
++    ret = set_nonblocking(fd);
+     if (ret != EOK) {
+         goto done;
+     }
+ 
+-    ret = set_close_on_exec(*fd);
++    ret = set_close_on_exec(fd);
+     if (ret != EOK) {
+         goto done;
+     }
+@@ -619,13 +620,13 @@ int create_pipe_fd(const char *sock_name, int *fd, mode_t umaskval)
+               "Cannot remove old socket (errno=%d), bind might fail!\n", ret);
+     }
+ 
+-    if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
++    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "Unable to bind on socket '%s'\n", sock_name);
+         ret = EIO;
+         goto done;
+     }
+-    if (listen(*fd, 10) != 0) {
++    if (listen(fd, 10) == -1) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "Unable to listen on socket '%s'\n", sock_name);
+         ret = EIO;
+@@ -638,8 +639,10 @@ done:
+     /* we want default permissions on created files to be very strict,
+        so set our umask to 0177 */
+     umask(0177);
+-    if (ret != EOK) {
+-        close(*fd);
++    if (ret == EOK) {
++        *_fd = fd;
++    } else {
++        close(fd);
+     }
+     return ret;
+ }
+-- 
+1.9.3
+
diff --git a/SOURCES/0044-pac-fix-double-free.patch b/SOURCES/0044-pac-fix-double-free.patch
deleted file mode 100644
index afc6cf0..0000000
--- a/SOURCES/0044-pac-fix-double-free.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 47bc6c387ab1d3f835167c528bb57f688080af1a Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Mon, 11 Nov 2013 12:47:53 +0100
-Subject: [PATCH 44/47] pac: fix double free
-
----
- src/responder/pac/pacsrv_utils.c | 14 ++++++--------
- 1 file changed, 6 insertions(+), 8 deletions(-)
-
-diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
-index 6a6ea2e357483c68533c501b93c16383ee644048..a82320fcae3b0494e7b6b322428e3a17ed729b4a 100644
---- a/src/responder/pac/pacsrv_utils.c
-+++ b/src/responder/pac/pacsrv_utils.c
-@@ -74,6 +74,7 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-     struct sss_domain_info *user_dom;
-     struct sss_domain_info *group_dom;
-     char *sid_str = NULL;
-+    char *msid_str = NULL;
-     char *user_dom_sid_str = NULL;
-     size_t user_dom_sid_str_len;
-     enum idmap_error_code err;
-@@ -231,24 +232,22 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
- 
-     }
- 
--    talloc_zfree(sid_str);
--
-     for(s = 0; s < info3->sidcount; s++) {
-         err = sss_idmap_smb_sid_to_sid(pac_ctx->idmap_ctx, info3->sids[s].sid,
--                                       &sid_str);
-+                                       &msid_str);
-         if (err != IDMAP_SUCCESS) {
-             DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_smb_sid_to_sid failed.\n"));
-             ret = EFAULT;
-             goto done;
-         }
- 
--        key.str = sid_str;
-+        key.str = msid_str;
-         value.ul = 0;
- 
--        ret = responder_get_domain_by_id(pac_ctx->rctx, sid_str, &group_dom);
-+        ret = responder_get_domain_by_id(pac_ctx->rctx, msid_str, &group_dom);
-         if (ret == EOK) {
-             ret = sysdb_search_object_by_sid(mem_ctx, group_dom->sysdb,
--                                             group_dom, sid_str, NULL, &msg);
-+                                             group_dom, msid_str, NULL, &msg);
-             if (ret == EOK && msg->count == 1 ) {
-                 value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0],
-                                                        SYSDB_GIDNUM, 0);
-@@ -257,14 +256,13 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-         }
- 
-         ret = hash_enter(sid_table, &key, &value);
-+        sss_idmap_free_sid(pac_ctx->idmap_ctx, msid_str);
-         if (ret != HASH_SUCCESS) {
-             DEBUG(SSSDBG_OP_FAILURE, ("hash_enter failed [%d][%s].\n",
-                                       ret, hash_error_string(ret)));
-             ret = EIO;
-             goto done;
-         }
--
--        sss_idmap_free_sid(pac_ctx->idmap_ctx, sid_str);
-     }
- 
-     ret = EOK;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0045-RESPONDERS-Don-t-hard-code-umask-value-in-utility-fu.patch b/SOURCES/0045-RESPONDERS-Don-t-hard-code-umask-value-in-utility-fu.patch
new file mode 100644
index 0000000..706c165
--- /dev/null
+++ b/SOURCES/0045-RESPONDERS-Don-t-hard-code-umask-value-in-utility-fu.patch
@@ -0,0 +1,51 @@
+From 39087a3cbdadb2f61aee6f2f81e365f5e0e65fb0 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Fri, 24 Oct 2014 10:06:55 +0100
+Subject: [PATCH 45/46] RESPONDERS: Don't hard-code umask value in utility
+ function
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2468
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit cbcb834028794a4c658a85965516113f8c0760c1)
+---
+ src/responder/common/responder_common.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index 9a13c95d63d93df96ffceb51f969eb562c3a6b08..6646fa2587a8299de40eaef35830351136b8149a 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -587,6 +587,7 @@ static int sss_dp_init(struct resp_ctx *rctx,
+ int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
+ {
+     struct sockaddr_un addr;
++    mode_t orig_umaskval;
+     errno_t ret;
+     int fd;
+ 
+@@ -595,7 +596,7 @@ int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
+         return EIO;
+     }
+ 
+-    umask(umaskval);
++    orig_umaskval = umask(umaskval);
+ 
+     ret = set_nonblocking(fd);
+     if (ret != EOK) {
+@@ -636,9 +637,8 @@ int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
+     ret = EOK;
+ 
+ done:
+-    /* we want default permissions on created files to be very strict,
+-       so set our umask to 0177 */
+-    umask(0177);
++    /* restore previous umask value */
++    umask(orig_umaskval);
+     if (ret == EOK) {
+         *_fd = fd;
+     } else {
+-- 
+1.9.3
+
diff --git a/SOURCES/0045-pac-fix-potential-memory-leaks.patch b/SOURCES/0045-pac-fix-potential-memory-leaks.patch
deleted file mode 100644
index 3658ae5..0000000
--- a/SOURCES/0045-pac-fix-potential-memory-leaks.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From 7e60e5991e97443044ae9c097131c84e9538cc42 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 12 Nov 2013 13:41:49 +0100
-Subject: [PATCH 45/47] pac: fix potential memory leaks
-
----
- src/responder/pac/pacsrv_utils.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
-index a82320fcae3b0494e7b6b322428e3a17ed729b4a..53edcc286119aa4a315285827da96e5d157afec9 100644
---- a/src/responder/pac/pacsrv_utils.c
-+++ b/src/responder/pac/pacsrv_utils.c
-@@ -82,7 +82,7 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-     hash_key_t key;
-     hash_value_t value;
-     char *rid_start;
--    struct ldb_result *msg;
-+    struct ldb_result *msg = NULL;
-     char *user_sid_str = NULL;
-     char *primary_group_sid_str = NULL;
- 
-@@ -154,8 +154,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-                                      sid_str, NULL, &msg);
-     if (ret == EOK && msg->count == 1) {
-         value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], SYSDB_UIDNUM, 0);
--        talloc_free(msg);
-     }
-+    talloc_zfree(msg);
- 
-     ret = hash_enter(sid_table, &key, &value);
-     if (ret != HASH_SUCCESS) {
-@@ -189,8 +189,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-                                      sid_str, NULL, &msg);
-     if (ret == EOK && msg->count == 1) {
-         value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], SYSDB_GIDNUM, 0);
--        talloc_free(msg);
-     }
-+    talloc_zfree(msg);
- 
-     ret = hash_enter(sid_table, &key, &value);
-     if (ret != HASH_SUCCESS) {
-@@ -219,8 +219,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-         if (ret == EOK && msg->count == 1) {
-             value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0],
-                                                    SYSDB_GIDNUM, 0);
--            talloc_free(msg);
-         }
-+        talloc_zfree(msg);
- 
-         ret = hash_enter(sid_table, &key, &value);
-         if (ret != HASH_SUCCESS) {
-@@ -251,8 +251,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
-             if (ret == EOK && msg->count == 1 ) {
-                 value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0],
-                                                        SYSDB_GIDNUM, 0);
--                talloc_free(msg);
-             }
-+            talloc_zfree(msg);
-         }
- 
-         ret = hash_enter(sid_table, &key, &value);
--- 
-1.8.4.2
-
diff --git a/SOURCES/0046-RESPONDERS-Set-default-value-for-umask.patch b/SOURCES/0046-RESPONDERS-Set-default-value-for-umask.patch
new file mode 100644
index 0000000..fdb94a3
--- /dev/null
+++ b/SOURCES/0046-RESPONDERS-Set-default-value-for-umask.patch
@@ -0,0 +1,129 @@
+From 7c30e5abf469134253d5bdec29cda7b47c41ca3e Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Fri, 24 Oct 2014 12:42:50 +0100
+Subject: [PATCH 46/46] RESPONDERS: Set default value for umask
+
+Resolves: https://fedorahosted.org/sssd/ticket/2468
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 458f5245dd5130d12666cce6faf8ef1ec7f80169)
+---
+ src/responder/autofs/autofssrv.c | 2 ++
+ src/responder/common/responder.h | 4 ++++
+ src/responder/ifp/ifpsrv.c       | 2 ++
+ src/responder/nss/nsssrv.c       | 2 ++
+ src/responder/pac/pacsrv.c       | 2 ++
+ src/responder/pam/pamsrv.c       | 2 ++
+ src/responder/ssh/sshsrv.c       | 2 ++
+ src/responder/sudo/sudosrv.c     | 2 ++
+ 8 files changed, 18 insertions(+)
+
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index 44474ee0858d92fb5965de07773e3ad1e020ebfd..91f529135e9bd74a5cf89edadd98fb2368630b5e 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -220,6 +220,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can decide if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index cd2b3232c53e919c7d47170ccd1016a8604c9742..e3c0f226775d279ea8c0f300cc2de54d2f7f9b72 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -38,6 +38,10 @@
+ 
+ extern hash_table_t *dp_requests;
+ 
++/* we want default permissions on created files to be very strict,
++ * so set our umask to 0177 */
++#define DFL_RSP_UMASK 0177
++
+ /* if there is a provider other than the special local */
+ #define NEED_CHECK_PROVIDER(provider) \
+     (provider != NULL && strcmp(provider, "local") != 0)
+diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
+index eddeec9812bdd650bfbfb78ede91bf3704113504..367438c71b77576f1c7c3054061db684fd134c20 100644
+--- a/src/responder/ifp/ifpsrv.c
++++ b/src/responder/ifp/ifpsrv.c
+@@ -454,6 +454,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index cfb146464d224cdb8b517d23a86421da7eaccd1f..1bbeaa1534ee3e0db72dda13ff9d01ef7fba6adf 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -550,6 +550,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
+index 3eb21c8fff85343249494bcc06d97cda4b738034..859ae86a54daf268c73ab97b0a1f67967d7e714f 100644
+--- a/src/responder/pac/pacsrv.c
++++ b/src/responder/pac/pacsrv.c
+@@ -229,6 +229,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can decide if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index c7e3c20b2731efb9393bc820ab09486c48e0a9ea..886136b420b6184a86ce6e0d9ac84dd3dea9a94b 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -332,6 +332,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index b1969b49de8579f0136c3afa78eb16d68c81ee4e..1bcf4e21a89e4e7b7697e9d90ab239cbf9d231e9 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -197,6 +197,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index a25f98ecabaa952a7cd87c54cd302903cb563faf..e480c7a43d453cffcd6ca07e41402c1cf6eef91c 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -177,6 +177,8 @@ int main(int argc, const char *argv[])
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+     debug_level = SSSDBG_INVALID;
+ 
++    umask(DFL_RSP_UMASK);
++
+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+     while((opt = poptGetNextOpt(pc)) != -1) {
+         switch(opt) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0046-responder-Set-forest-attribute-in-AD-domains.patch b/SOURCES/0046-responder-Set-forest-attribute-in-AD-domains.patch
deleted file mode 100644
index 54068b1..0000000
--- a/SOURCES/0046-responder-Set-forest-attribute-in-AD-domains.patch
+++ /dev/null
@@ -1,321 +0,0 @@
-From 6ac0feca0cdc66fc8d8a612e25d37a49d27c0233 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <pavel.reichl@redhat.com>
-Date: Tue, 17 Dec 2013 17:32:04 +0000
-Subject: [PATCH 46/47] responder: Set forest attribute in AD domains
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2160
----
- src/db/sysdb.h                     |  3 ++-
- src/db/sysdb_subdomains.c          | 35 ++++++++++++++++++++++++++++-
- src/providers/ad/ad_domain_info.c  | 46 +++++++++++++++++++++++++++++++-------
- src/providers/ad/ad_domain_info.h  |  3 ++-
- src/providers/ad/ad_id.c           |  5 +++--
- src/providers/ad/ad_subdomains.c   |  9 +++++---
- src/providers/ipa/ipa_subdomains.c |  2 +-
- src/providers/ldap/sdap_access.c   |  2 +-
- 8 files changed, 87 insertions(+), 18 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 255a135f0cad788e4c952b86fe24ca10f5e63732..9677294b22e47f5169d7631673beec2dbc6117ad 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -388,7 +388,8 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain);
- errno_t sysdb_master_domain_update(struct sss_domain_info *domain);
- 
- errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
--                                     const char *flat, const char *id);
-+                                     const char *flat, const char *id,
-+                                     const char* forest);
- 
- errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name);
- 
-diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
-index 43c75799cdc2856916b2dc95c3a544ef99b56081..9c2926c00b0cc08cb8e317ae838e26c82506ee37 100644
---- a/src/db/sysdb_subdomains.c
-+++ b/src/db/sysdb_subdomains.c
-@@ -208,6 +208,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
-                            SYSDB_SUBDOMAIN_REALM,
-                            SYSDB_SUBDOMAIN_FLAT,
-                            SYSDB_SUBDOMAIN_ID,
-+                           SYSDB_SUBDOMAIN_FOREST,
-                            NULL};
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -278,13 +279,27 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
-         }
-     }
- 
-+    tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_FOREST,
-+                                          NULL);
-+    if (tmp_str != NULL &&
-+        (domain->forest == NULL ||
-+         strcasecmp(tmp_str, domain->forest) != 0)) {
-+        talloc_free(domain->forest);
-+        domain->forest = talloc_strdup(domain, tmp_str);
-+        if (domain->forest == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
- done:
-     talloc_free(tmp_ctx);
-     return ret;
- }
- 
- errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
--                                     const char *flat, const char *id)
-+                                     const char *flat, const char *id,
-+                                     const char* forest)
- {
-     TALLOC_CTX *tmp_ctx;
-     struct ldb_message *msg;
-@@ -345,6 +360,24 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
-         do_update = true;
-     }
- 
-+   if (forest != NULL && (domain->forest == NULL ||
-+                       strcmp(domain->forest, forest) != 0)) {
-+        ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FOREST,
-+                                LDB_FLAG_MOD_REPLACE, NULL);
-+        if (ret != LDB_SUCCESS) {
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+
-+        ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FOREST, forest);
-+        if (ret != LDB_SUCCESS) {
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+
-+        do_update = true;
-+    }
-+
-     if (do_update == false) {
-         ret = EOK;
-         goto done;
-diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c
-index eff2034d12261510ed7535dee7098a6e68f1f2c2..5475c5bc7ec74e81080566c6fbd6919c54a60f40 100644
---- a/src/providers/ad/ad_domain_info.c
-+++ b/src/providers/ad/ad_domain_info.c
-@@ -41,9 +41,9 @@
- #define MASTER_DOMAIN_SID_FILTER "objectclass=domain"
- 
- static errno_t
--netlogon_get_flat_name(TALLOC_CTX *mem_ctx,
--                       struct sysdb_attrs *reply,
--                       char **_flat_name)
-+netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
-+                         struct sysdb_attrs *reply,
-+                         char **_flat_name, char **_forest)
- {
-     errno_t ret;
-     struct ldb_message_element *el;
-@@ -52,6 +52,7 @@ netlogon_get_flat_name(TALLOC_CTX *mem_ctx,
-     enum ndr_err_code ndr_err;
-     struct netlogon_samlogon_response response;
-     const char *flat_name;
-+    const char *forest;
- 
-     ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el);
-     if (ret != EOK) {
-@@ -92,11 +93,13 @@ netlogon_get_flat_name(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
-+    /* get flat name */
-     if (response.data.nt5_ex.domain_name != NULL &&
-         *response.data.nt5_ex.domain_name != '\0') {
-         flat_name = response.data.nt5_ex.domain_name;
-     } else {
--        DEBUG(SSSDBG_MINOR_FAILURE, ("No netlogon data available\n"));
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              ("No netlogon domain name data available\n"));
-         ret = ENOENT;
-         goto done;
-     }
-@@ -107,6 +110,24 @@ netlogon_get_flat_name(TALLOC_CTX *mem_ctx,
-         ret = ENOMEM;
-         goto done;
-     }
-+
-+    /* get forest */
-+    if (response.data.nt5_ex.forest != NULL &&
-+        *response.data.nt5_ex.forest != '\0') {
-+        forest = response.data.nt5_ex.forest;
-+    } else {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("No netlogon forest data available\n"));
-+        ret = ENOENT;
-+        goto done;
-+    }
-+
-+    *_forest = talloc_strdup(mem_ctx, forest);
-+    if (*_forest == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     ret = EOK;
- done:
-     talloc_free(ndr_pull);
-@@ -124,6 +145,7 @@ struct ad_master_domain_state {
-     int base_iter;
- 
-     char *flat;
-+    char *forest;
-     char *sid;
- };
- 
-@@ -338,14 +360,17 @@ ad_master_domain_netlogon_done(struct tevent_req *subreq)
- 
-     /* Exactly one flat name. Carry on */
- 
--    ret = netlogon_get_flat_name(state, reply[0], &state->flat);
-+    ret = netlogon_get_domain_info(state, reply[0], &state->flat,
-+                                   &state->forest);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not get the flat name\n"));
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              ("Could not get the flat name or forest\n"));
-         /* Not fatal. Just quit. */
-         goto done;
-     }
--
-     DEBUG(SSSDBG_TRACE_FUNC, ("Found flat name [%s].\n", state->flat));
-+    DEBUG(SSSDBG_TRACE_FUNC, ("Found forest [%s].\n", state->forest));
-+
- done:
-     tevent_req_done(req);
-     return;
-@@ -355,7 +380,8 @@ errno_t
- ad_master_domain_recv(struct tevent_req *req,
-                       TALLOC_CTX *mem_ctx,
-                       char **_flat,
--                      char **_id)
-+                      char **_id,
-+                      char **_forest)
- {
-     struct ad_master_domain_state *state = tevent_req_data(req,
-                                               struct ad_master_domain_state);
-@@ -366,6 +392,10 @@ ad_master_domain_recv(struct tevent_req *req,
-         *_flat = talloc_steal(mem_ctx, state->flat);
-     }
- 
-+    if (_forest) {
-+        *_forest = talloc_steal(mem_ctx, state->forest);
-+    }
-+
-     if (_id) {
-         *_id = talloc_steal(mem_ctx, state->sid);
-     }
-diff --git a/src/providers/ad/ad_domain_info.h b/src/providers/ad/ad_domain_info.h
-index d21706396034509a498391e666e03a8e2eda8e08..d3a6416cebd07b524aceedcb63a18c4467e3dc4e 100644
---- a/src/providers/ad/ad_domain_info.h
-+++ b/src/providers/ad/ad_domain_info.h
-@@ -36,6 +36,7 @@ errno_t
- ad_master_domain_recv(struct tevent_req *req,
-                       TALLOC_CTX *mem_ctx,
-                       char **_flat,
--                      char **_id);
-+                      char **_id,
-+                      char **_forest);
- 
- #endif /* _AD_MASTER_DOMAIN_H_ */
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index e47c41863a14eed695907548d64f4559fbae629d..44bfa00986b6c0ebfa65dd7b83dd45eb64b87946 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -519,9 +519,10 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-                                                 struct ad_enumeration_state);
-     char *flat_name;
-     char *master_sid;
-+    char *forest;
- 
-     ret = ad_master_domain_recv(subreq, state,
--                                &flat_name, &master_sid);
-+                                &flat_name, &master_sid, &forest);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Cannot retrieve master domain info\n"));
-@@ -530,7 +531,7 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-     }
- 
-     ret = sysdb_master_domain_add_info(state->sdom->dom,
--                                       flat_name, master_sid);
-+                                       flat_name, master_sid, forest);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Cannot save master domain info\n"));
-         tevent_req_error(req, ret);
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index e438a688c364084a3f2bbca338a39d61aa86b5d6..62c3e16d0d3323a32848b4fbf54d2a151c16f64c 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -85,6 +85,7 @@ struct ad_subdomains_req_ctx {
- 
-     char *master_sid;
-     char *flat_name;
-+    char *forest;
- };
- 
- static errno_t
-@@ -294,7 +295,7 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
- 
-     /* AD subdomains are currently all mpg and do not enumerate */
-     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
--                                mpg, false, NULL);
-+                                mpg, false, domain->forest);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
-         goto done;
-@@ -539,7 +540,8 @@ static void ad_subdomains_master_dom_done(struct tevent_req *req)
-     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
- 
-     ret = ad_master_domain_recv(req, ctx,
--                                &ctx->flat_name, &ctx->master_sid);
-+                                &ctx->flat_name, &ctx->master_sid,
-+                                &ctx->forest);
-     talloc_zfree(req);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Cannot retrieve master domain info\n"));
-@@ -547,7 +549,8 @@ static void ad_subdomains_master_dom_done(struct tevent_req *req)
-     }
- 
-     ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
--                                       ctx->flat_name, ctx->master_sid);
-+                                       ctx->flat_name, ctx->master_sid,
-+                                       ctx->forest);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Cannot save master domain info\n"));
-         goto done;
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 9efbd725f1102d34af2107801286bca1c6412c19..d9c204451f1b734ee98ce4c48f3f139731e47dec 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -1076,7 +1076,7 @@ static void ipa_subdomains_handler_master_done(struct tevent_req *req)
-         }
- 
-         ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
--                                           flat, id);
-+                                           flat, id, NULL);
-     } else {
-         ctx->search_base_iter++;
-         ret = ipa_subdomains_handler_get(ctx, IPA_SUBDOMAINS_MASTER);
-diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
-index 6b387271a229668ddfa5d67143a585e667a16ddd..f0df24e7f3a855304b0cfd9d075ac67334f9bb1a 100644
---- a/src/providers/ldap/sdap_access.c
-+++ b/src/providers/ldap/sdap_access.c
-@@ -214,7 +214,7 @@ static void sdap_access_filter_done(struct tevent_req *subreq)
-     ret = sdap_access_filter_recv(subreq);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
--        DEBUG(1, ("Error retrieving access check result.\n"));
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Error retrieving access check result.\n"));
-         tevent_req_error(req, ret);
-         return;
-     }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch b/SOURCES/0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch
deleted file mode 100644
index 706968d..0000000
--- a/SOURCES/0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch
+++ /dev/null
@@ -1,146 +0,0 @@
-From 91ab35daf713e146dfae53a67f6b86b424c897d5 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 8 Jan 2014 17:12:17 +0100
-Subject: [PATCH 47/47] LDAP: Add a new error code for malformed access control
- filter
-
-https://fedorahosted.org/sssd/ticket/2164
-
-The patch adds a new error code and special cases the new code so that
-access is denied and a nicer log message is shown.
----
- src/providers/ldap/sdap_access.c              |  8 +++++++-
- src/providers/ldap/sdap_async.c               | 12 ++++++------
- src/providers/ldap/sdap_async_groups_ad.c     |  2 +-
- src/providers/ldap/sdap_async_initgroups_ad.c |  4 ++--
- src/util/util_errors.c                        |  1 +
- src/util/util_errors.h                        |  1 +
- 6 files changed, 18 insertions(+), 10 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
-index f0df24e7f3a855304b0cfd9d075ac67334f9bb1a..29e83eb43cf78107e2075e1aa95211abac6d2df1 100644
---- a/src/providers/ldap/sdap_access.c
-+++ b/src/providers/ldap/sdap_access.c
-@@ -855,9 +855,15 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
-             }
-         } else if (dp_error == DP_ERR_OFFLINE) {
-             ret = sdap_access_filter_decide_offline(req);
-+        } else if (ret == ERR_INVALID_FILTER) {
-+            sss_log(SSS_LOG_ERR,
-+                    "Malformed access control filter [%s]\n", state->filter);
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                ("Malformed access control filter [%s]\n", state->filter));
-+            ret = ERR_ACCESS_DENIED;
-         } else {
-             DEBUG(1, ("sdap_get_generic_send() returned error [%d][%s]\n",
--                      ret, strerror(ret)));
-+                      ret, sss_strerror(ret)));
-         }
- 
-         goto done;
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index e905d2dd6d539baadcd29aa0869ca04e845947e2..367007bde0011ed4de283b2a50b22538830a5275 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -1306,9 +1306,9 @@ static errno_t sdap_get_generic_ext_step(struct tevent_req *req)
-                 sss_log(SSS_LOG_ERR, "LDAP connection error, %s",
-                                      sss_ldap_err2string(lret));
-             }
--        }
--
--        else {
-+        } else if (lret == LDAP_FILTER_ERROR) {
-+            ret = ERR_INVALID_FILTER;
-+        } else {
-             ret = EIO;
-         }
-         goto done;
-@@ -1570,7 +1570,7 @@ static void sdap_get_generic_done(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret) {
-         DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
--                  ret, strerror(ret)));
-+                  ret, sss_strerror(ret)));
-         tevent_req_error(req, ret);
-         return;
-     }
-@@ -1790,7 +1790,7 @@ static void sdap_x_deref_search_done(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret) {
-         DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
--                  ret, strerror(ret)));
-+                  ret, sss_strerror(ret)));
-         tevent_req_error(req, ret);
-         return;
-     }
-@@ -2049,7 +2049,7 @@ static void sdap_asq_search_done(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret) {
-         DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
--                  ret, strerror(ret)));
-+                  ret, sss_strerror(ret)));
-         tevent_req_error(req, ret);
-         return;
-     }
-diff --git a/src/providers/ldap/sdap_async_groups_ad.c b/src/providers/ldap/sdap_async_groups_ad.c
-index 9b61c697d5789c3ec3467ec52a7171f6a640ce9e..6a8a4fd139657040ff83cad10ba35a0dde4a0122 100644
---- a/src/providers/ldap/sdap_async_groups_ad.c
-+++ b/src/providers/ldap/sdap_async_groups_ad.c
-@@ -183,7 +183,7 @@ sdap_get_ad_match_rule_members_step(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
--              ("LDAP search failed: [%s]\n", strerror(ret)));
-+              ("LDAP search failed: [%s]\n", sss_strerror(ret)));
-         tevent_req_error(req, ret);
-         return;
-     }
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index 8f8f0a4cc635818dcc7f75f9da603ce2f55c820f..724f308da68daf05e2dc4cc6c64cac347ab8a0ca 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -208,7 +208,7 @@ sdap_get_ad_match_rule_initgroups_step(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
--              ("LDAP search failed: [%s]\n", strerror(ret)));
-+              ("LDAP search failed: [%s]\n", sss_strerror(ret)));
-         goto error;
-     }
- 
-@@ -383,7 +383,7 @@ static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
--              ("LDAP search failed: [%s]\n", strerror(ret)));
-+              ("LDAP search failed: [%s]\n", sss_strerror(ret)));
-         goto done;
-     }
- 
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 114c8b04fd354b166d14e526a3bab6a6c0c05951..633257e8da0ef039e555a07ad8b51125114ca01c 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -51,6 +51,7 @@ struct err_string error_to_str[] = {
-     { "Entry not found" }, /* ERR_NOT_FOUND */
-     { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */
-     { "Missing configuration file" }, /* ERR_MISSING_CONF */
-+    { "Malformed search filter" }, /* ERR_INVALID_FILTER, */
- };
- 
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index bca45f392b0357c3f1c848768358cb1d47514715..1332085031dbe6935cbdc94543fa14b09fe81028 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -73,6 +73,7 @@ enum sssd_errors {
-     ERR_NOT_FOUND,
-     ERR_DOMAIN_NOT_FOUND,
-     ERR_MISSING_CONF,
-+    ERR_INVALID_FILTER,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0047-nss-group-enumeration-fix.patch b/SOURCES/0047-nss-group-enumeration-fix.patch
new file mode 100644
index 0000000..ce1f157
--- /dev/null
+++ b/SOURCES/0047-nss-group-enumeration-fix.patch
@@ -0,0 +1,37 @@
+From d8d007c12bac73df4931722c4f7b57fa778bf105 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 24 Oct 2014 11:28:54 +0200
+Subject: [PATCH 47/48] nss: group enumeration fix
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The view/override patches introduced and issue with group enumeration
+where all groups are returned with the same name. This patch should fix
+it.
+
+Fixes: https://fedorahosted.org/sssd/ticket/2475
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 4b2b722319f11c81c06f488f3962a6b6280f4b9f)
+---
+ src/responder/nss/nsssrv_cmd.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 4ec99c153b25db26d482eec8da6ca52487967abc..9fca644be164e682f787bda61ea39afa8b703874 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -2669,6 +2669,9 @@ static int fill_grent(struct sss_packet *packet,
+         rsize = 0;
+ 
+         /* find group name/gid */
++
++        /* start with an empty name for each iteration */
++        orig_name = NULL;
+         if (DOM_HAS_VIEWS(dom)) {
+             orig_name = ldb_msg_find_attr_as_string(msg,
+                                                     OVERRIDE_PREFIX SYSDB_NAME,
+-- 
+1.9.3
+
diff --git a/SOURCES/0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch b/SOURCES/0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch
deleted file mode 100644
index 0b1fb22..0000000
--- a/SOURCES/0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 103f7efda7b84e7c791af2ebc2255e61e826fd75 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <ab@samba.org>
-Date: Tue, 24 Dec 2013 13:01:46 +0200
-Subject: [PATCH 48/48] FAST: when parsing krb5_child response, make sure to
- not miss OTP message if it was last one
-
-The last message in the stream might be with empty payload which means we get
-only message type and message length (0) returned, i.e. 8 bytes left remaining
-in the stream after processing preceding message. This makes our calculation at
-the end of a message processing loop incorrect -- p+2*sizeof(int32_t) can be
-equal to len, after all.
-
-Fixes FAST processing for FreeIPA native OTP case:
-https://fedorahosted.org/sssd/ticket/2186
----
- src/providers/krb5/krb5_child_handler.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
-index 92dec0d2afb1627b61c3dd1037e91546a7ee08d6..d6c1dc1f9707444a82e433a375839cadf73f1259 100644
---- a/src/providers/krb5/krb5_child_handler.c
-+++ b/src/providers/krb5/krb5_child_handler.c
-@@ -548,8 +548,9 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
-          * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because
-          * sizeof() counts the trailing '\0' of a string. */
-         pref_len = sizeof(CCACHE_ENV_NAME);
--        if (msg_len > pref_len &&
--            strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) {
-+        if ((msg_type == SSS_PAM_ENV_ITEM) &&
-+            (msg_len > pref_len) &&
-+            (strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0)) {
-             ccname = (char *) &buf[p+pref_len];
-             ccname_len = msg_len-pref_len;
-         }
-@@ -600,7 +601,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
- 
-         p += msg_len;
- 
--        if ((p < len) && (p + 2*sizeof(int32_t) >= len)) {
-+        if ((p < len) && (p + 2*sizeof(int32_t) > len)) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   ("The remainder of the message is too short.\n"));
-             return EINVAL;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0048-nss-preserve-service-name-in-getsrv-call.patch b/SOURCES/0048-nss-preserve-service-name-in-getsrv-call.patch
new file mode 100644
index 0000000..4c0b651
--- /dev/null
+++ b/SOURCES/0048-nss-preserve-service-name-in-getsrv-call.patch
@@ -0,0 +1,58 @@
+From e6c49e90d752fdbdf5d12ac18ccb9f297baaa8f1 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 23 Oct 2014 20:27:57 +0200
+Subject: [PATCH 48/48] nss: preserve service name in getsrv call
+
+About case_sensitive=preserving and services.
+
+The name of the service can be preserved in
+result of 'getent service'. However we
+should still lowercase the protocol and
+service aliases because they serve as keys
+in some queries to sysdb. The lowercasing is done
+by the provider already. If we did not do that,
+we would lose case insesnsitivity.
+
+With this patch the responder preserves the
+case of service name and protocol, to match
+the case that is stored in the sysdb (however
+the protocol is already lowercased by provider,
+so it was done only for consistent use of the
+case_sensitive=preserve option in the responders
+and only the case of name is the same as in
+ldap).
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/2460
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit c4e278c2637547640d28bda007c9c38a17956fcc)
+---
+ src/responder/nss/nsssrv_services.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_services.c b/src/responder/nss/nsssrv_services.c
+index 7741768021cc4a669bd3eda286cd1f25876a55f6..f6abc445c82d268dafb4d1e1fa7336ad01912f9e 100644
+--- a/src/responder/nss/nsssrv_services.c
++++ b/src/responder/nss/nsssrv_services.c
+@@ -642,7 +642,7 @@ fill_service(struct sss_packet *packet,
+ 
+         /* Get the service name */
+         orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+-        tmpstr = sss_get_cased_name(tmp_ctx, orig_name, dom->case_sensitive);
++        tmpstr = sss_get_cased_name(tmp_ctx, orig_name, dom->case_preserve);
+         if (tmpstr == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "Could not identify service name, skipping\n");
+@@ -677,7 +677,7 @@ fill_service(struct sss_packet *packet,
+             orig_proto = (const char *)el->values[0].data;
+         }
+ 
+-        tmpstr = sss_get_cased_name(tmp_ctx, orig_proto, dom->case_sensitive);
++        tmpstr = sss_get_cased_name(tmp_ctx, orig_proto, dom->case_preserve);
+         if (tmpstr == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "sss_get_cased_name failed, skipping\n");
+-- 
+1.9.3
+
diff --git a/SOURCES/0049-UTIL-Inherit-parent-domain-s-default_shell.patch b/SOURCES/0049-UTIL-Inherit-parent-domain-s-default_shell.patch
deleted file mode 100644
index 5d3c101..0000000
--- a/SOURCES/0049-UTIL-Inherit-parent-domain-s-default_shell.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 14bafb02c396396e04412a4981b98ae75534294a Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 14 Jan 2014 10:55:39 +0100
-Subject: [PATCH 49/53] UTIL: Inherit parent domain's default_shell
-
-Some override parameters were not inherited when creating subdomains.
-Especially with AD trusts, this gave strange results.
----
- src/util/domain_info_utils.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
-index 61efc0b40dcd8969b635781549feab3eee79299e..98678f97b95d271a0d2e18daadae7f3f9a79f89e 100644
---- a/src/util/domain_info_utils.c
-+++ b/src/util/domain_info_utils.c
-@@ -271,10 +271,13 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
-     dom->group_timeout = parent->group_timeout;
-     dom->netgroup_timeout = parent->netgroup_timeout;
-     dom->service_timeout = parent->service_timeout;
--    dom->override_homedir = parent->override_homedir;
-     dom->names = parent->names;
- 
-+    dom->override_homedir = parent->override_homedir;
-+    dom->fallback_homedir = parent->fallback_homedir;
-     dom->subdomain_homedir = parent->subdomain_homedir;
-+    dom->override_shell = parent->override_shell;
-+    dom->default_shell = parent->default_shell;
- 
-     if (parent->sysdb == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Missing sysdb context in parent domain.\n"));
--- 
-1.8.4.2
-
diff --git a/SOURCES/0049-sdap_print_server-use-getpeername-to-get-server-addr.patch b/SOURCES/0049-sdap_print_server-use-getpeername-to-get-server-addr.patch
new file mode 100644
index 0000000..3b644fa
--- /dev/null
+++ b/SOURCES/0049-sdap_print_server-use-getpeername-to-get-server-addr.patch
@@ -0,0 +1,27 @@
+From 29ee270deee5f3c0b049f612245a734e626b6b33 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 24 Oct 2014 18:27:07 +0200
+Subject: [PATCH 49/64] sdap_print_server: use getpeername() to get server
+ address
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ldap/sdap_async.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
+index 560d13789b88b7b7f3a09558fa2d2844f0fa036e..a6954620bd0f27b5f2d2e45563af9d1440d9cf7c 100644
+--- a/src/providers/ldap/sdap_async.c
++++ b/src/providers/ldap/sdap_async.c
+@@ -1107,7 +1107,7 @@ static void sdap_print_server(struct sdap_handle *sh)
+         return;
+     }
+ 
+-    ret = getsockname(fd, (struct sockaddr *) &ss, &ss_len);
++    ret = getpeername(fd, (struct sockaddr *) &ss, &ss_len);
+     if (ret == -1) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "getsockname failed\n");
+         return;
+-- 
+1.9.3
+
diff --git a/SOURCES/0050-IPA-Don-t-fail-the-request-when-BE-doesn-t-find-the-.patch b/SOURCES/0050-IPA-Don-t-fail-the-request-when-BE-doesn-t-find-the-.patch
new file mode 100644
index 0000000..0cd0508
--- /dev/null
+++ b/SOURCES/0050-IPA-Don-t-fail-the-request-when-BE-doesn-t-find-the-.patch
@@ -0,0 +1,53 @@
+From 07ca52cf9c0727c42880ed03b4ffb3e6c5f7b97d Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 29 Oct 2014 20:30:20 +0100
+Subject: [PATCH 50/64] IPA: Don't fail the request when BE doesn't find the
+ object
+
+The IPA subdomain code treated ENOENT as a fatal error, which resulted
+in a loud error message and the whole request being aborted. This patch
+ignores ENOENT.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains_id.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index b67006ce6e0b4bf9c794016c1dfc923ac6da3624..0a1c4c17eed37b2eb12a8c758e49fc17c3b642b5 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -942,7 +942,7 @@ static errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    if (ret != EOK) {
++    if (ret != EOK && ret != ENOENT) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Failed to make request to our cache: [%d]: [%s]\n",
+                ret, sss_strerror(ret));
+@@ -951,8 +951,6 @@ static errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+ 
+     *_msg = msg;
+ 
+-    ret = EOK;
+-
+ done:
+     return ret;
+ }
+@@ -978,7 +976,11 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
+ 
+     ret = get_object_from_cache(state, state->user_dom, state->ar,
+                                 &state->obj_msg);
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Object not found, ending request\n");
++        tevent_req_done(req);
++        return;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n");
+         goto fail;
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0050-NSS-Use-plain-user-name-when-expanding-homedir.patch b/SOURCES/0050-NSS-Use-plain-user-name-when-expanding-homedir.patch
deleted file mode 100644
index 7fddcbd..0000000
--- a/SOURCES/0050-NSS-Use-plain-user-name-when-expanding-homedir.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 90e871a816440af34f095d3b1003476a0978a348 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 14 Jan 2014 11:10:25 +0100
-Subject: [PATCH 50/53] NSS: Use plain user name when expanding homedir
-
----
- src/responder/nss/nsssrv_cmd.c | 13 ++++++++++++-
- 1 file changed, 12 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index 550017c0e4385a7147ed5ef83da2c37cb97c8092..c59078b545842561a7e5f62e9a99da6057b23660 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -172,13 +172,24 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx,
-                                         struct ldb_message *msg,
-                                         struct nss_ctx *nctx,
-                                         struct sss_domain_info *dom,
--                                        const char *name,
-+                                        const char *orig_name,
-                                         uint32_t uid)
- {
-     const char *homedir;
-+    char *name;
-+    char *domname;
-+    errno_t ret;
- 
-     homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL);
- 
-+    /* Subdomain users store FQDN in their name attribute */
-+    ret = sss_parse_name(mem_ctx, dom->names, orig_name, &domname, &name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not parse [%s] into "
-+              "name-value components.\n", orig_name));
-+        return NULL;
-+    }
-+
-     /* Check whether we are unconditionally overriding the server
-      * for home directory locations.
-      */
--- 
-1.8.4.2
-
diff --git a/SOURCES/0051-memberof-check-for-empty-arrays-to-avoid-segfaults.patch b/SOURCES/0051-memberof-check-for-empty-arrays-to-avoid-segfaults.patch
new file mode 100644
index 0000000..a7eb747
--- /dev/null
+++ b/SOURCES/0051-memberof-check-for-empty-arrays-to-avoid-segfaults.patch
@@ -0,0 +1,41 @@
+From 61b6c497901004e34f1bdf6d3c04c2943720a500 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 29 Oct 2014 15:20:12 +0100
+Subject: [PATCH 51/64] memberof: check for empty arrays to avoid segfaults
+
+The arrays with members to add or delete may be empty, i.e. have 0
+entries. In this case further processing should be skipped to avoid
+segfaults later on.
+
+Fixes (hopefully) https://fedorahosted.org/sssd/ticket/2430
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/ldb_modules/memberof.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
+index ceeba0e474dfbe53f7133df996e3bad454fdac9e..995c382a8ee36bfc010f2761010db1fb48343d5d 100644
+--- a/src/ldb_modules/memberof.c
++++ b/src/ldb_modules/memberof.c
+@@ -3654,7 +3654,7 @@ static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
+         }
+     }
+ 
+-    if (ael != NULL) {
++    if (ael != NULL && ael->num > 0) {
+         /* Add itself to the list of the parents to also get the memberuid */
+         parents->dns = talloc_realloc(parents, parents->dns,
+                                     struct ldb_dn *, parents->num + 1);
+@@ -3724,7 +3724,7 @@ static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
+     }
+ 
+     /* prepare del sets */
+-    if (del != NULL) {
++    if (del != NULL && del->num > 0) {
+         for (i = 0; i < del->num; i++) {
+             ret = mbof_append_delop(first, del->dns[i]);
+             if (ret != LDB_SUCCESS) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0051-simple-access-match-objects-using-flat-name.patch b/SOURCES/0051-simple-access-match-objects-using-flat-name.patch
deleted file mode 100644
index cf15b3e..0000000
--- a/SOURCES/0051-simple-access-match-objects-using-flat-name.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 9df26b2f56d249ce69f7fd7d5c40b55dfe119e93 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <pavel.reichl@redhat.com>
-Date: Wed, 8 Jan 2014 15:46:57 +0000
-Subject: [PATCH 51/53] simple access: match objects using flat name
-
-Use flat name to recognise users and groups belonging to main sssd domain.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2189
----
- src/providers/simple/simple_access.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
-index 46b045e531dfc5fcdff4fc4f5370734aca1e377c..f2bfe755039fd7a370749fd3ce94a47c62c216bc 100644
---- a/src/providers/simple/simple_access.c
-+++ b/src/providers/simple/simple_access.c
-@@ -140,7 +140,9 @@ static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx,
-             goto done;
-         }
- 
--        if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0) {
-+        if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0 ||
-+            (be_ctx->domain->flat_name != NULL &&
-+             strcasecmp(domain, be_ctx->domain->flat_name) == 0)) {
-             /* This object belongs to main SSSD domain. Those users and groups
-              * are stored without domain part, so we will strip it off.
-              * */
--- 
-1.8.4.2
-
diff --git a/SOURCES/0052-CONFDB-Detect-fix-misconf-opt-refresh_expired_interv.patch b/SOURCES/0052-CONFDB-Detect-fix-misconf-opt-refresh_expired_interv.patch
new file mode 100644
index 0000000..bcbefd1
--- /dev/null
+++ b/SOURCES/0052-CONFDB-Detect-fix-misconf-opt-refresh_expired_interv.patch
@@ -0,0 +1,45 @@
+From 8d0b8a15a56f1fd12655e838cc17004d12dff8dd Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Thu, 30 Oct 2014 16:50:27 +0000
+Subject: [PATCH 52/64] CONFDB: Detect&fix misconf opt refresh_expired_interval
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related to:
+https://fedorahosted.org/sssd/ticket/2102
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/confdb/confdb.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
+index 8443fe5539e1fd7b6deee6dca7cc689868933757..c55a945a4d3ab4b4070963889a8421d7c78bcad7 100644
+--- a/src/confdb/confdb.c
++++ b/src/confdb/confdb.c
+@@ -1058,6 +1058,21 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+         goto done;
+     }
+ 
++    /* detect and fix misconfiguration */
++    if (domain->refresh_expired_interval > entry_cache_timeout) {
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "refresh_expired_interval (%d) cannot be greater then "
++              "entry_cache_timeout (%u)\n",
++              domain->refresh_expired_interval, entry_cache_timeout);
++
++        domain->refresh_expired_interval = 0.75 * entry_cache_timeout;
++
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "refresh_expired_interval is being set to recommended value "
++              "entry_cache_timeout * 0.75 (%u).\n",
++              domain->refresh_expired_interval);
++    }
++
+     /* Set the PAM warning time, if specified. If not specified, pass on
+      * the "not set" value of "-1" which means "use provider default". The
+      * value 0 means "always display the warning if server sends one" */
+-- 
+1.9.3
+
diff --git a/SOURCES/0052-simple-access-refresh-master-domain-info.patch b/SOURCES/0052-simple-access-refresh-master-domain-info.patch
deleted file mode 100644
index 4069e20..0000000
--- a/SOURCES/0052-simple-access-refresh-master-domain-info.patch
+++ /dev/null
@@ -1,219 +0,0 @@
-From b6c53b49cde8188bf2f8b493b275118472c4482e Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <pavel.reichl@redhat.com>
-Date: Wed, 8 Jan 2014 16:03:08 +0000
-Subject: [PATCH 52/53] simple access: refresh master domain info
-
-To correctly decide if an object is a member of the main sssd domain, a flat name
-is needed. However, the information may not be available when the module is
-inited so it may be necessary to refresh this data later while processing a
-request.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2189
----
- src/providers/simple/simple_access.c | 135 +++++++++++++++++++++++------------
- src/providers/simple/simple_access.h |   2 +
- 2 files changed, 92 insertions(+), 45 deletions(-)
-
-diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
-index f2bfe755039fd7a370749fd3ce94a47c62c216bc..eab62a826b4749aa5e5dab4a8e491fc2263be4fb 100644
---- a/src/providers/simple/simple_access.c
-+++ b/src/providers/simple/simple_access.c
-@@ -32,7 +32,76 @@
- #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups"
- #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups"
- 
-+#define TIMEOUT_OF_REFRESH_FILTER_LISTS 5
-+
- static void simple_access_check(struct tevent_req *req);
-+static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx,
-+                                         struct be_ctx *be_ctx,
-+                                         char **list,
-+                                         char ***_out);
-+
-+static int simple_access_obtain_filter_lists(struct simple_ctx *ctx)
-+{
-+    struct be_ctx *bectx = ctx->be_ctx;
-+    int ret;
-+    int i;
-+    struct {
-+        const char *name;
-+        const char *option;
-+        char **orig_list;
-+        char ***ctx_list;
-+    } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL},
-+                 {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL},
-+                 {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL},
-+                 {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL},
-+                 {NULL, NULL, NULL, NULL}};
-+
-+    lists[0].ctx_list = &ctx->allow_users;
-+    lists[1].ctx_list = &ctx->deny_users;
-+    lists[2].ctx_list = &ctx->allow_groups;
-+    lists[3].ctx_list = &ctx->deny_groups;
-+
-+    ret = sysdb_master_domain_update(bectx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FUNC_DATA, ("Update of master domain failed [%d]: %s.\n",
-+                                 ret, sss_strerror(ret)));
-+        goto failed;
-+    }
-+
-+    for (i = 0; lists[i].name != NULL; i++) {
-+        ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
-+                                        lists[i].option, &lists[i].orig_list);
-+        if (ret == ENOENT) {
-+            DEBUG(SSSDBG_FUNC_DATA, ("%s list is empty.\n", lists[i].name));
-+            *lists[i].ctx_list = NULL;
-+            continue;
-+        } else if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("confdb_get_string_as_list failed.\n"));
-+            goto failed;
-+        }
-+
-+        ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list,
-+                                        lists[i].ctx_list);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to parse %s list [%d]: %s\n",
-+                                        lists[i].name, ret, sss_strerror(ret)));
-+            goto failed;
-+        }
-+    }
-+
-+    if (!ctx->allow_users &&
-+            !ctx->allow_groups &&
-+            !ctx->deny_users &&
-+            !ctx->deny_groups) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("No rules supplied for simple access provider. "
-+               "Access will be granted for all users.\n"));
-+    }
-+    return EOK;
-+
-+failed:
-+    return ret;
-+}
- 
- void simple_access_handler(struct be_req *be_req)
- {
-@@ -40,13 +109,16 @@ void simple_access_handler(struct be_req *be_req)
-     struct pam_data *pd;
-     struct tevent_req *req;
-     struct simple_ctx *ctx;
-+    int ret;
-+    time_t now;
- 
-     pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
- 
-     pd->pam_status = PAM_SYSTEM_ERR;
- 
-     if (pd->cmd != SSS_PAM_ACCT_MGMT) {
--        DEBUG(4, ("simple access does not handles pam task %d.\n", pd->cmd));
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              ("simple access does not handle pam task %d.\n", pd->cmd));
-         pd->pam_status = PAM_MODULE_UNKNOWN;
-         goto done;
-     }
-@@ -54,6 +126,18 @@ void simple_access_handler(struct be_req *be_req)
-     ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
-                           struct simple_ctx);
- 
-+
-+    now = time(NULL);
-+    if ((now - ctx->last_refresh_of_filter_lists)
-+        > TIMEOUT_OF_REFRESH_FILTER_LISTS) {
-+
-+        ret = simple_access_obtain_filter_lists(ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to refresh filter lists\n"));
-+        }
-+        ctx->last_refresh_of_filter_lists = now;
-+    }
-+
-     req = simple_access_check_send(be_req, be_ctx->ev, ctx, pd->user);
-     if (!req) {
-         pd->pam_status = PAM_SYSTEM_ERR;
-@@ -176,18 +260,6 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops,
- {
-     int ret = EINVAL;
-     struct simple_ctx *ctx;
--    int i;
--    struct {
--        const char *name;
--        const char *option;
--        char **orig_list;
--        char ***ctx_list;
--    } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL},
--                 {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL},
--                 {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL},
--                 {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL},
--                 {NULL, NULL, NULL, NULL}};
--
-     ctx = talloc_zero(bectx, struct simple_ctx);
-     if (ctx == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero failed.\n"));
-@@ -196,39 +268,11 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops,
- 
-     ctx->domain = bectx->domain;
-     ctx->be_ctx = bectx;
-+    ctx->last_refresh_of_filter_lists = 0;
- 
--    lists[0].ctx_list = &ctx->allow_users;
--    lists[1].ctx_list = &ctx->deny_users;
--    lists[2].ctx_list = &ctx->allow_groups;
--    lists[3].ctx_list = &ctx->deny_groups;
--
--    for (i = 0; lists[i].name != NULL; i++) {
--        ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
--                                        lists[i].option, &lists[i].orig_list);
--        if (ret == ENOENT) {
--            DEBUG(SSSDBG_FUNC_DATA, ("%s list is empty.\n", lists[i].name));
--            *lists[i].ctx_list = NULL;
--            continue;
--        } else if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("confdb_get_string_as_list failed.\n"));
--            goto failed;
--        }
--
--        ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list,
--                                        lists[i].ctx_list);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to parse %s list [%d]: %s\n",
--                                        lists[i].name, ret, sss_strerror(ret)));
--            goto failed;
--        }
--    }
--
--    if (!ctx->allow_users &&
--            !ctx->allow_groups &&
--            !ctx->deny_users &&
--            !ctx->deny_groups) {
--        DEBUG(SSSDBG_OP_FAILURE, ("No rules supplied for simple access provider. "
--                                  "Access will be granted for all users.\n"));
-+    ret = simple_access_obtain_filter_lists(ctx);
-+    if (ret != EOK) {
-+        goto failed;
-     }
- 
-     *ops = &simple_access_ops;
-@@ -240,3 +284,4 @@ failed:
-     talloc_free(ctx);
-     return ret;
- }
-+
-diff --git a/src/providers/simple/simple_access.h b/src/providers/simple/simple_access.h
-index 15dfaceb2d9a6670d3559e4a945c2c7a633fad44..a618b2e2ec16a2f32bad7ceb1f5adb7523199316 100644
---- a/src/providers/simple/simple_access.h
-+++ b/src/providers/simple/simple_access.h
-@@ -32,6 +32,8 @@ struct simple_ctx {
-     char **deny_users;
-     char **allow_groups;
-     char **deny_groups;
-+
-+    time_t last_refresh_of_filter_lists;
- };
- 
- struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
--- 
-1.8.4.2
-
diff --git a/SOURCES/0053-NSS-add-support-for-subdomain_homedir.patch b/SOURCES/0053-NSS-add-support-for-subdomain_homedir.patch
deleted file mode 100644
index c5b5068..0000000
--- a/SOURCES/0053-NSS-add-support-for-subdomain_homedir.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 7bc2cfa445142254276d712a0ff6622eaf670253 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 15 Jan 2014 15:52:35 +0000
-Subject: [PATCH 53/53] NSS: add support for subdomain_homedir
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2169
----
- src/responder/nss/nsssrv_cmd.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index c59078b545842561a7e5f62e9a99da6057b23660..9ac3680de4d6ff12fe0c77a3963f84934e385276 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -201,6 +201,14 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx,
-                                        name, uid, homedir, dom->name, NULL);
-     }
- 
-+    /* Override home directory location for subdomains.
-+     * This option can be overriden by override_homedir.
-+     */
-+    if (IS_SUBDOMAIN(dom) && dom->subdomain_homedir) {
-+        return expand_homedir_template(mem_ctx, dom->subdomain_homedir,
-+                                       name, uid, homedir, dom->name, NULL);
-+    }
-+
-     if (!homedir || *homedir == '\0') {
-         /* In the case of a NULL or empty homedir, check to see if
-          * we have a fallback homedir to use.
--- 
-1.8.4.2
-
diff --git a/SOURCES/0053-NSS-disable-midpoint-refresh-for-netgroups.patch b/SOURCES/0053-NSS-disable-midpoint-refresh-for-netgroups.patch
new file mode 100644
index 0000000..21fc8ca
--- /dev/null
+++ b/SOURCES/0053-NSS-disable-midpoint-refresh-for-netgroups.patch
@@ -0,0 +1,102 @@
+From ff71a9ad628ec66e36ccc7c9c49c1306fbe0d25c Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Thu, 30 Oct 2014 17:02:45 +0000
+Subject: [PATCH 53/64] NSS: disable midpoint refresh for netgroups
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Disable midpoint refresh for netgroups if periodical refresh of expired
+netgroups is enabled (refresh_expired_interval)
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2102
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/responder/nss/nsssrv_cmd.c | 57 +++++++++++++++++++++++++++++++-----------
+ 1 file changed, 43 insertions(+), 14 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 9fca644be164e682f787bda61ea39afa8b703874..4ac5eb91eab80291e60afad2bf9c65edfbc21e7d 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -559,6 +559,25 @@ static int nss_cmd_getpw_send_reply(struct nss_dom_ctx *dctx, bool filter)
+     return EOK;
+ }
+ 
++/* Currently only refreshing expired netgroups is supported. */
++static bool
++is_refreshed_on_bg(int req_type,
++                   enum sss_dp_acct_type refresh_expired_interval)
++{
++    if (refresh_expired_interval == 0) {
++        return false;
++    }
++
++    switch (req_type) {
++    case SSS_DP_NETGR:
++        return true;
++    default:
++        return false;
++    }
++
++    return false;
++}
++
+ static void nsssrv_dp_send_acct_req_done(struct tevent_req *req);
+ 
+ /* FIXME: do not check res->count, but get in a msgs and check in parent */
+@@ -585,25 +604,35 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
+     if ((req_type == SSS_DP_USER || req_type == SSS_DP_NETGR) &&
+             (res->count > 1)) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+-              "getpwXXX call returned more than one result!"
+-                  " DB Corrupted?\n");
++              "getpwXXX call returned more than one result! DB Corrupted?\n");
+         return ENOENT;
+     }
+ 
+-    /* if we have any reply let's check cache validity */
++    /* if we have any reply let's check cache validity, but ignore netgroups
++     * if refresh_expired_interval is set (which implies that another method
++     * is used to refresh netgroups)
++     */
+     if (res->count > 0) {
+-        if (req_type == SSS_DP_INITGROUPS) {
+-            cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
+-                                                      SYSDB_INITGR_EXPIRE, 1);
+-        }
+-        if (cacheExpire == 0) {
+-            cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
+-                                                      SYSDB_CACHE_EXPIRE, 0);
+-        }
++        if (is_refreshed_on_bg(req_type,
++                               dctx->domain->refresh_expired_interval)) {
++            ret = EOK;
++        } else {
++            if (req_type == SSS_DP_INITGROUPS) {
++                cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
++                                                          SYSDB_INITGR_EXPIRE,
++                                                          1);
++            }
++            if (cacheExpire == 0) {
++                cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
++                                                          SYSDB_CACHE_EXPIRE,
++                                                          0);
++            }
+ 
+-        /* if we have any reply let's check cache validity */
+-        ret = sss_cmd_check_cache(res->msgs[0], nctx->cache_refresh_percent,
+-                                  cacheExpire);
++            /* if we have any reply let's check cache validity */
++            ret = sss_cmd_check_cache(res->msgs[0],
++                                      nctx->cache_refresh_percent,
++                                      cacheExpire);
++        }
+         if (ret == EOK) {
+             DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning..\n");
+             return EOK;
+-- 
+1.9.3
+
diff --git a/SOURCES/0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch b/SOURCES/0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch
deleted file mode 100644
index afca73b..0000000
--- a/SOURCES/0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From e47d40005610c3f6e14d4a656fda2e8cadde4844 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Thu, 16 Jan 2014 16:42:50 +0100
-Subject: [PATCH 54/57] AD: Return right error code from netlogon_get_flat_name
-
-EOK was returned in done section of netlogon_get_flat_name,
-even if error code was set in variable ret.
-
-This patch fixes also warnings from scan-build.
----
- src/providers/ad/ad_domain_info.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c
-index 5475c5bc7ec74e81080566c6fbd6919c54a60f40..28d24b1613040ab1e85cd1504c5469aa60bc08c5 100644
---- a/src/providers/ad/ad_domain_info.c
-+++ b/src/providers/ad/ad_domain_info.c
-@@ -131,7 +131,7 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
-     ret = EOK;
- done:
-     talloc_free(ndr_pull);
--    return EOK;
-+    return ret;
- }
- 
- struct ad_master_domain_state {
--- 
-1.8.4.2
-
diff --git a/SOURCES/0054-IPA-use-ipaUserGroup-object-class-for-groups.patch b/SOURCES/0054-IPA-use-ipaUserGroup-object-class-for-groups.patch
new file mode 100644
index 0000000..a6d6b35
--- /dev/null
+++ b/SOURCES/0054-IPA-use-ipaUserGroup-object-class-for-groups.patch
@@ -0,0 +1,35 @@
+From 65679aaa24942edb448077eb172361b45b4f2a71 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Fri, 31 Oct 2014 14:26:30 +0100
+Subject: [PATCH 54/64] IPA: use ipaUserGroup object class for groups
+
+dfb34c6c82ed5014599bf70de6791e6d79106fc2 changed object class
+of IPA groups from posixGroups to more general groupOfNames.
+However, this object class is used also for roles, permissions and
+privileges which caused SSSD to consider those objects to be groups as
+well during initgroups.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2471
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_opts.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index 4785e0164bf6d9efb574a8703b573f4e8086cab6..0e0eed49cd397fe88ce7bf41579c066088947d04 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -205,7 +205,7 @@ struct sdap_attr_map ipa_user_map[] = {
+ };
+ 
+ struct sdap_attr_map ipa_group_map[] = {
+-    { "ldap_group_object_class", "groupOfNames", SYSDB_GROUP_CLASS, NULL },
++    { "ldap_group_object_class", "ipaUserGroup", SYSDB_GROUP_CLASS, NULL },
+     { "ldap_group_object_class_alt", "posixGroup", SYSDB_GROUP_CLASS, NULL },
+     { "ldap_group_name", "cn", SYSDB_NAME, NULL },
+     { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+-- 
+1.9.3
+
diff --git a/SOURCES/0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch b/SOURCES/0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch
deleted file mode 100644
index 31bc56b..0000000
--- a/SOURCES/0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 380c18bfccd25961cf56c9f61b1ac8641a2022b1 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 16 Jan 2014 20:49:15 +0100
-Subject: [PATCH 55/57] AD: Don't fail the request if ad_account_can_shortcut
- fails
-
----
- src/providers/ad/ad_id.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 44bfa00986b6c0ebfa65dd7b83dd45eb64b87946..ada47753fb337641df582a5a59affe8124fc2035 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -320,7 +320,9 @@ ad_account_info_handler(struct be_req *be_req)
-                                   ar->filter_type, ar->filter_value,
-                                   ar->domain, &shortcut);
-     if (ret != EOK) {
--        goto fail;
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              ("Cannot determine the right domain: %s\n", sss_strerror(ret)));
-+        shortcut = false;
-     }
- 
-     if (shortcut) {
--- 
-1.8.4.2
-
diff --git a/SOURCES/0055-Add-add_strings_lists-utility-function.patch b/SOURCES/0055-Add-add_strings_lists-utility-function.patch
new file mode 100644
index 0000000..981804b
--- /dev/null
+++ b/SOURCES/0055-Add-add_strings_lists-utility-function.patch
@@ -0,0 +1,246 @@
+From a624616892da3dc0ee39659e24cbd5a40ae98e9e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 27 Oct 2014 16:53:44 +0100
+Subject: [PATCH 55/64] Add add_strings_lists() utility function
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/tests/cmocka/test_utils.c | 111 ++++++++++++++++++++++++++++++++++++++++++
+ src/util/util.c               |  65 +++++++++++++++++++++++++
+ src/util/util.h               |  18 +++++++
+ 3 files changed, 194 insertions(+)
+
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index 9d6cbf35f7c2e33c57b3a539b409848c22cf263e..d9781377be70a0d58b0fd1fff2145483dbeb199c 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -875,6 +875,114 @@ void test_expand_homedir_template(void **state)
+     talloc_free(tmp_ctx);
+ }
+ 
++void setup_add_strings_lists(void **state)
++{
++    assert_true(leak_check_setup());
++
++    check_leaks_push(global_talloc_context);
++}
++
++void teardown_add_strings_lists(void **state)
++{
++    assert_true(check_leaks_pop(global_talloc_context) == true);
++    assert_true(leak_check_teardown());
++}
++
++void test_add_strings_lists(void **state)
++{
++    const char *l1[] = {"a", "b", "c", NULL};
++    const char *l2[] = {"1", "2", "3", NULL};
++    char **res;
++    int ret;
++    size_t c;
++    size_t d;
++
++    ret = add_strings_lists(global_talloc_context, NULL, NULL, true, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    assert_null(res[0]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, NULL, NULL, false, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    assert_null(res[0]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, l1, NULL, false, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    for (c = 0; l1[c] != NULL; c++) {
++        /* 'copy_strings' is 'false', pointers must be equal */
++        assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
++    }
++    assert_null(res[c]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, l1, NULL, true, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    for (c = 0; l1[c] != NULL; c++) {
++        /* 'copy_strings' is 'true', pointers must be different, but strings
++         * must be equal */
++        assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
++        assert_string_equal(l1[c], res[c]);
++    }
++    assert_null(res[c]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, NULL, l1, false, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    for (c = 0; l1[c] != NULL; c++) {
++        /* 'copy_strings' is 'false', pointers must be equal */
++        assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
++    }
++    assert_null(res[c]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, NULL, l1, true, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    for (c = 0; l1[c] != NULL; c++) {
++        /* 'copy_strings' is 'true', pointers must be different, but strings
++         * must be equal */
++        assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
++        assert_string_equal(l1[c], res[c]);
++    }
++    assert_null(res[c]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, l1, l2, false, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    for (c = 0; l1[c] != NULL; c++) {
++        /* 'copy_strings' is 'false', pointers must be equal */
++        assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
++    }
++    for (d = 0; l2[d] != NULL; d++) {
++        assert_int_equal(memcmp(&l2[d], &res[c+d], sizeof(char *)), 0);
++    }
++    assert_null(res[c+d]);
++    talloc_free(res);
++
++    ret = add_strings_lists(global_talloc_context, l1, l2, true, &res);
++    assert_int_equal(ret, EOK);
++    assert_non_null(res);
++    for (c = 0; l1[c] != NULL; c++) {
++        /* 'copy_strings' is 'true', pointers must be different, but strings
++         * must be equal */
++        assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
++        assert_string_equal(l1[c], res[c]);
++    }
++    for (d = 0; l2[d] != NULL; d++) {
++        assert_int_not_equal(memcmp(&l2[d], &res[c+d], sizeof(char *)), 0);
++        assert_string_equal(l2[d], res[c+d]);
++    }
++    assert_null(res[c+d]);
++    talloc_free(res);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -919,6 +1027,9 @@ int main(int argc, const char *argv[])
+         unit_test(test_textual_public_key),
+         unit_test(test_replace_whitespaces),
+         unit_test(test_reverse_replace_whitespaces),
++        unit_test_setup_teardown(test_add_strings_lists,
++                                 setup_add_strings_lists,
++                                 teardown_add_strings_lists),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+diff --git a/src/util/util.c b/src/util/util.c
+index d78d37d975e6591bca6ac3f2fa36b5b9f4659a29..2acb8604ac0c2bc7b83ee578c7bbead9a7fd44b3 100644
+--- a/src/util/util.c
++++ b/src/util/util.c
+@@ -815,3 +815,68 @@ const char * const * get_known_services(void)
+ 
+     return svc;
+ }
++
++errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2,
++                          bool copy_strings, char ***_new_list)
++{
++    size_t c;
++    size_t l1_count = 0;
++    size_t l2_count = 0;
++    size_t new_count = 0;
++    char **new;
++    int ret;
++
++    if (l1 != NULL) {
++        for (l1_count = 0; l1[l1_count] != NULL; l1_count++);
++    }
++
++    if (l2 != NULL) {
++        for (l2_count = 0; l2[l2_count] != NULL; l2_count++);
++    }
++
++    new_count = l1_count + l2_count;
++
++    new = talloc_array(mem_ctx, char *, new_count + 1);
++    if (new == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++        return ENOMEM;
++    }
++    new [new_count] = NULL;
++
++    if (copy_strings) {
++        for(c = 0; c < l1_count; c++) {
++            new[c] = talloc_strdup(new, l1[c]);
++            if (new[c] == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++        }
++        for(c = 0; c < l2_count; c++) {
++            new[l1_count + c] = talloc_strdup(new, l2[c]);
++            if (new[l1_count + c] == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++        }
++    } else {
++        if (l1 != NULL) {
++            memcpy(new, l1, sizeof(char *) * l1_count);
++        }
++
++        if (l2 != NULL) {
++            memcpy(&new[l1_count], l2, sizeof(char *) * l2_count);
++        }
++    }
++
++    *_new_list = new;
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        talloc_free(new);
++    }
++
++    return ret;
++}
+diff --git a/src/util/util.h b/src/util/util.h
+index 69074c93c1640a1e4a7e590b7f9feb6cc04804a4..ffc8a87eafa4c4b8271d195c7d27fd10f5aa3568 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -426,6 +426,24 @@ errno_t sss_hash_create_ex(TALLOC_CTX *mem_ctx,
+                            hash_delete_callback *delete_callback,
+                            void *delete_private_data);
+ 
++/**
++ * @brief Add two list of strings
++ *
++ * Create a new NULL-termintated list of strings by adding two lists together.
++ *
++ * @param[in] mem_ctx      Talloc memory context for the new list.
++ * @param[in] l1           First NULL-termintated list of strings.
++ * @param[in] l2           Second NULL-termintated list of strings.
++ * @param[in] copy_strings If set to 'true' the list items will be copied
++ *                         otherwise only the pointers to the items are
++ *                         copied.
++ * @param[out] new_list    New NULL-terminated list of strings. Must be freed
++ *                         with talloc_free() by the caller. If copy_strings
++ *                         is 'true' the new elements will be freed as well.
++ */
++errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2,
++                          bool copy_strings, char ***_new_list);
++
+ /* Copy a NULL-terminated string list
+  * Returns NULL on out of memory error or invalid input
+  */
+-- 
+1.9.3
+
diff --git a/SOURCES/0056-IPA-inherit-ldap_user_extra_attrs-to-AD-subdomains.patch b/SOURCES/0056-IPA-inherit-ldap_user_extra_attrs-to-AD-subdomains.patch
new file mode 100644
index 0000000..585391e
--- /dev/null
+++ b/SOURCES/0056-IPA-inherit-ldap_user_extra_attrs-to-AD-subdomains.patch
@@ -0,0 +1,72 @@
+From 4d1985342d51075f0842c2221c034bbf7cc3d5af Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 24 Oct 2014 15:41:04 +0200
+Subject: [PATCH 56/64] IPA: inherit ldap_user_extra_attrs to AD subdomains
+
+Currently the component of the IPA provider which reads the AD user and
+group attributes in ipa-server-mode uses  default settings for the LDAP
+related attributes. As a result even if ldap_user_extra_attrs is defined
+in sssd.conf no extra attributes are read from AD.
+
+With the patch the value if ldap_user_extra_attrs is inherited to the AD
+subdomains to allow them to read extra attributes as well.
+
+Related to https://fedorahosted.org/sssd/ticket/2464
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index c61c1c666908ec23f8a92e5568222e55ec47be0a..9281aab1b028ebcaee8044b2768c6918efa4e514 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -109,6 +109,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+     char *ad_domain;
+     struct sdap_domain *sdom;
+     errno_t ret;
++    const char *extra_attrs;
+ 
+     ad_options = ad_create_default_options(id_ctx, id_ctx->server_mode->realm,
+                                            id_ctx->server_mode->hostname);
+@@ -135,6 +136,36 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+         return ret;
+     }
+ 
++    extra_attrs = dp_opt_get_string(id_ctx->sdap_id_ctx->opts->basic,
++                            SDAP_USER_EXTRA_ATTRS);
++    if (extra_attrs != NULL) {
++        DEBUG(SSSDBG_TRACE_ALL,
++              "Setting extra attrs for subdomain [%s] to [%s].\n", ad_domain,
++                                                                   extra_attrs);
++
++        ret = dp_opt_set_string(ad_options->id->basic, SDAP_USER_EXTRA_ATTRS,
++                                extra_attrs);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "dp_opt_get_string failed.\n");
++            talloc_free(ad_options);
++            return ret;
++        }
++
++        ret = sdap_extend_map_with_list(ad_options->id, ad_options->id,
++                                        SDAP_USER_EXTRA_ATTRS,
++                                        ad_options->id->user_map,
++                                        SDAP_OPTS_USER,
++                                        &ad_options->id->user_map,
++                                        &ad_options->id->user_map_cnt);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sdap_extend_map_with_list failed.\n");
++            talloc_free(ad_options);
++            return ret;
++        }
++    } else {
++        DEBUG(SSSDBG_TRACE_ALL, "No extra attrs set.\n");
++    }
++
+     gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
+     if (gc_service_name == NULL) {
+         talloc_free(ad_options);
+-- 
+1.9.3
+
diff --git a/SOURCES/0056-MAN-Fix-a-typo.patch b/SOURCES/0056-MAN-Fix-a-typo.patch
deleted file mode 100644
index 4d8b827..0000000
--- a/SOURCES/0056-MAN-Fix-a-typo.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From c5b312ebf55befc4d37f9a279340b55e65475cd3 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 20 Jan 2014 17:04:28 +0100
-Subject: [PATCH 56/57] MAN: Fix a typo
-
----
- src/man/sssd.conf.5.xml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 43c06955d0182afe5a3c7d703f7c08b7cd09f503..b879bdf63c40e80efa21644bd9ba9d2d3477af06 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -489,7 +489,7 @@
-                         <para>
-                             example:
-                             <programlisting>
--override_homedir = /home/%u
-+fallback_homedir = /home/%u
-                             </programlisting>
-                         </para>
-                         <para>
--- 
-1.8.4.2
-
diff --git a/SOURCES/0057-Add-parse_attr_list_ex-helper-function.patch b/SOURCES/0057-Add-parse_attr_list_ex-helper-function.patch
new file mode 100644
index 0000000..56a75c9
--- /dev/null
+++ b/SOURCES/0057-Add-parse_attr_list_ex-helper-function.patch
@@ -0,0 +1,432 @@
+From b86a642a321d3763d997f07c47ec515acbe72cf0 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 28 Oct 2014 19:40:02 +0100
+Subject: [PATCH 57/64] Add parse_attr_list_ex() helper function
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                            |   5 +-
+ src/responder/common/responder.h       |   2 +
+ src/responder/common/responder_utils.c | 151 +++++++++++++++++++++++++++++++++
+ src/responder/ifp/ifp_private.h        |   3 +
+ src/responder/ifp/ifpsrv_util.c        | 117 +------------------------
+ src/tests/cmocka/test_ifp.c            |  51 +++++++++++
+ 6 files changed, 212 insertions(+), 117 deletions(-)
+ create mode 100644 src/responder/common/responder_utils.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 61bf5cf957d4024b67f48cf42f5735b5fa368945..ac8ad1566a5c931bf43526e2d29a57a5f8ade1cf 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -409,6 +409,7 @@ SSSD_RESPONDER_OBJ = \
+     src/responder/common/responder_dp.c \
+     src/responder/common/responder_packet.c \
+     src/responder/common/responder_get_domains.c \
++    src/responder/common/responder_utils.c \
+     src/monitor/monitor_iface_generated.c \
+     src/monitor/monitor_iface_generated.h \
+     src/providers/data_provider_iface_generated.c \
+@@ -2025,7 +2026,9 @@ ifp_tests_SOURCES = \
+     src/tests/cmocka/test_ifp.c \
+     src/responder/ifp/ifpsrv_cmd.c \
+     src/responder/ifp/ifp_iface_generated.c \
+-    src/responder/ifp/ifpsrv_util.c
++    src/responder/ifp/ifpsrv_util.c \
++    src/responder/common/responder_utils.c \
++    $(NULL)
+ ifp_tests_CFLAGS = \
+     $(AM_CFLAGS)
+ ifp_tests_LDADD = \
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index e3c0f226775d279ea8c0f300cc2de54d2f7f9b72..02a215ced435c87ec0439807ab5e575de0d0fe04 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -329,4 +329,6 @@ sss_parse_inp_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx,
+ errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                            char **_name, char **_domname);
+ 
++const char **parse_attr_list_ex(TALLOC_CTX *mem_ctx, const char *conf_str,
++                                const char **defaults);
+ #endif /* __SSS_RESPONDER_H__ */
+diff --git a/src/responder/common/responder_utils.c b/src/responder/common/responder_utils.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..815b61b3971cfda2eda4efc643ea21c3b035b36d
+--- /dev/null
++++ b/src/responder/common/responder_utils.c
+@@ -0,0 +1,151 @@
++
++/*
++   SSSD
++
++   Common Responder utility functions
++
++   Copyright (C) Sumit Bose <sbose@redhat.com> 2014
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++
++#include "util/util.h"
++
++static inline bool
++attr_in_list(const char **list, size_t nlist, const char *str)
++{
++    size_t i;
++
++    for (i = 0; i < nlist; i++) {
++        if (strcasecmp(list[i], str) == 0) {
++            break;
++        }
++    }
++
++    return (i < nlist) ? true : false;
++}
++
++const char **parse_attr_list_ex(TALLOC_CTX *mem_ctx, const char *conf_str,
++                                const char **defaults)
++{
++    TALLOC_CTX *tmp_ctx;
++    errno_t ret;
++    const char **list = NULL;
++    const char **res = NULL;
++    int list_size;
++    char **conf_list = NULL;
++    int conf_list_size = 0;
++    const char **allow = NULL;
++    const char **deny = NULL;
++    int ai = 0, di = 0, li = 0;
++    int i;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return NULL;
++    }
++
++    if (conf_str) {
++        ret = split_on_separator(tmp_ctx, conf_str, ',', true, true,
++                                 &conf_list, &conf_list_size);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "Cannot parse attribute ACL list  %s: %d\n", conf_str, ret);
++            goto done;
++        }
++
++        allow = talloc_zero_array(tmp_ctx, const char *, conf_list_size);
++        deny = talloc_zero_array(tmp_ctx, const char *, conf_list_size);
++        if (allow == NULL || deny == NULL) {
++            goto done;
++        }
++    }
++
++    for (i = 0; i < conf_list_size; i++) {
++        switch (conf_list[i][0]) {
++            case '+':
++                allow[ai] = conf_list[i] + 1;
++                ai++;
++                continue;
++            case '-':
++                deny[di] = conf_list[i] + 1;
++                di++;
++                continue;
++            default:
++                DEBUG(SSSDBG_CRIT_FAILURE, "ACL values must start with "
++                      "either '+' (allow) or '-' (deny), got '%s'\n",
++                      conf_list[i]);
++                goto done;
++        }
++    }
++
++    /* Assume the output will have to hold defaults and all the configured,
++     * values, resize later
++     */
++    list_size = 0;
++    if (defaults != NULL) {
++        while (defaults[list_size]) {
++            list_size++;
++        }
++    }
++    list_size += conf_list_size;
++
++    list = talloc_zero_array(tmp_ctx, const char *, list_size + 1);
++    if (list == NULL) {
++        goto done;
++    }
++
++    /* Start by copying explicitly allowed attributes */
++    for (i = 0; i < ai; i++) {
++        /* if the attribute is explicitly denied, skip it */
++        if (attr_in_list(deny, di, allow[i])) {
++            continue;
++        }
++
++        list[li] = talloc_strdup(list, allow[i]);
++        if (list[li] == NULL) {
++            goto done;
++        }
++        li++;
++
++        DEBUG(SSSDBG_TRACE_INTERNAL,
++              "Added allowed attr %s to whitelist\n", allow[i]);
++    }
++
++    /* Add defaults */
++    if (defaults != NULL) {
++        for (i = 0; defaults[i]; i++) {
++            /* if the attribute is explicitly denied, skip it */
++            if (attr_in_list(deny, di, defaults[i])) {
++                continue;
++            }
++
++            list[li] = talloc_strdup(list, defaults[i]);
++            if (list[li] == NULL) {
++                goto done;
++            }
++            li++;
++
++            DEBUG(SSSDBG_TRACE_INTERNAL,
++                  "Added default attr %s to whitelist\n", defaults[i]);
++        }
++    }
++
++    res = talloc_steal(mem_ctx, list);
++done:
++    talloc_free(tmp_ctx);
++    return res;
++}
+diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h
+index bf2015a9722ff4b4f831cb63cd528881f0f259a8..fb1639c8dfd00f547a666dce67ee7a94c3143618 100644
+--- a/src/responder/ifp/ifp_private.h
++++ b/src/responder/ifp/ifp_private.h
+@@ -82,5 +82,8 @@ char *_ifp_reply_objpath(TALLOC_CTX *mem_ctx, const char *base,
+ errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict,
+                                struct ldb_message_element *el);
+ const char **ifp_parse_attr_list(TALLOC_CTX *mem_ctx, const char *conf_str);
++const char **
++ifp_parse_attr_list_ex(TALLOC_CTX *mem_ctx, const char *conf_str,
++                       const char **defaults);
+ bool ifp_attr_allowed(const char *whitelist[], const char *attr);
+ #endif /* _IFPSRV_PRIVATE_H_ */
+diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
+index c0ab686e4527a2508f67b789151365dfdbb89f25..909bc54870d6442ea9daf8e86d2dc97acfe4b93d 100644
+--- a/src/responder/ifp/ifpsrv_util.c
++++ b/src/responder/ifp/ifpsrv_util.c
+@@ -356,127 +356,12 @@ errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict,
+     return EOK;
+ }
+ 
+-static inline bool
+-attr_in_list(const char **list, size_t nlist, const char *str)
+-{
+-    size_t i;
+-
+-    for (i = 0; i < nlist; i++) {
+-        if (strcasecmp(list[i], str) == 0) {
+-            break;
+-        }
+-    }
+-
+-    return (i < nlist) ? true : false;
+-}
+-
+ const char **
+ ifp_parse_attr_list(TALLOC_CTX *mem_ctx, const char *conf_str)
+ {
+-    TALLOC_CTX *tmp_ctx;
+-    errno_t ret;
+-    const char **list = NULL;
+-    const char **res = NULL;
+-    int list_size;
+-    char **conf_list = NULL;
+-    int conf_list_size = 0;
+-    const char **allow = NULL;
+-    const char **deny = NULL;
+-    int ai = 0, di = 0, li = 0;
+-    int i;
+     const char *defaults[] = IFP_DEFAULT_ATTRS;
+ 
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        return NULL;
+-    }
+-
+-    if (conf_str) {
+-        ret = split_on_separator(tmp_ctx, conf_str, ',', true, true,
+-                                 &conf_list, &conf_list_size);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE,
+-                  "Cannot parse attribute ACL list  %s: %d\n", conf_str, ret);
+-            goto done;
+-        }
+-
+-        allow = talloc_zero_array(tmp_ctx, const char *, conf_list_size);
+-        deny = talloc_zero_array(tmp_ctx, const char *, conf_list_size);
+-        if (allow == NULL || deny == NULL) {
+-            goto done;
+-        }
+-    }
+-
+-    for (i = 0; i < conf_list_size; i++) {
+-        switch (conf_list[i][0]) {
+-            case '+':
+-                allow[ai] = conf_list[i] + 1;
+-                ai++;
+-                continue;
+-            case '-':
+-                deny[di] = conf_list[i] + 1;
+-                di++;
+-                continue;
+-            default:
+-                DEBUG(SSSDBG_CRIT_FAILURE, "ACL values must start with "
+-                      "either '+' (allow) or '-' (deny), got '%s'\n",
+-                      conf_list[i]);
+-                goto done;
+-        }
+-    }
+-
+-    /* Assume the output will have to hold defauls and all the configured,
+-     * values, resize later
+-     */
+-    list_size = 0;
+-    while (defaults[list_size]) {
+-        list_size++;
+-    }
+-    list_size += conf_list_size;
+-
+-    list = talloc_zero_array(tmp_ctx, const char *, list_size + 1);
+-    if (list == NULL) {
+-        goto done;
+-    }
+-
+-    /* Start by copying explicitly allowed attributes */
+-    for (i = 0; i < ai; i++) {
+-        /* if the attribute is explicitly denied, skip it */
+-        if (attr_in_list(deny, di, allow[i])) {
+-            continue;
+-        }
+-
+-        list[li] = talloc_strdup(list, allow[i]);
+-        if (list[li] == NULL) {
+-            goto done;
+-        }
+-        li++;
+-
+-        DEBUG(SSSDBG_TRACE_INTERNAL,
+-              "Added allowed attr %s to whitelist\n", allow[i]);
+-    }
+-
+-    /* Add defaults */
+-    for (i = 0; defaults[i]; i++) {
+-        /* if the attribute is explicitly denied, skip it */
+-        if (attr_in_list(deny, di, defaults[i])) {
+-            continue;
+-        }
+-
+-        list[li] = talloc_strdup(list, defaults[i]);
+-        if (list[li] == NULL) {
+-            goto done;
+-        }
+-        li++;
+-
+-        DEBUG(SSSDBG_TRACE_INTERNAL,
+-              "Added default attr %s to whitelist\n", defaults[i]);
+-    }
+-
+-    res = talloc_steal(mem_ctx, list);
+-done:
+-    talloc_free(tmp_ctx);
+-    return res;
++    return parse_attr_list_ex(mem_ctx, conf_str, defaults);
+ }
+ 
+ bool
+diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c
+index b0f6e09900a956a51c17d1c4cf1a7772dccc3a68..d6e41706d5f55414c0376bd04d299ec6ad73c11e 100644
+--- a/src/tests/cmocka/test_ifp.c
++++ b/src/tests/cmocka/test_ifp.c
+@@ -246,6 +246,29 @@ static void attr_parse_test(const char *expected[], const char *input)
+     talloc_free(test_ctx);
+ }
+ 
++static void attr_parse_test_ex(const char *expected[], const char *input,
++                               const char **defaults)
++{
++    const char **res;
++    TALLOC_CTX *test_ctx;
++
++    test_ctx = talloc_new(NULL);
++    assert_non_null(test_ctx);
++
++    res = parse_attr_list_ex(test_ctx, input, defaults);
++
++    if (expected) {
++        /* Positive test */
++        assert_non_null(res);
++        assert_string_list_equal(res, expected);
++    } else {
++        /* Negative test */
++        assert_null(res);
++    }
++
++    talloc_free(test_ctx);
++}
++
+ void test_attr_acl(void **state)
+ {
+     /* Test defaults */
+@@ -296,6 +319,33 @@ void test_attr_acl(void **state)
+     attr_parse_test(NULL,  "missing_plus_or_minus");
+ }
+ 
++void test_attr_acl_ex(void **state)
++{
++    /* Test defaults */
++    const char *exp_defaults[] = { "abc", "123", "xyz", NULL };
++    attr_parse_test_ex(exp_defaults, NULL, exp_defaults);
++
++    /* Test adding some attributes to the defaults */
++    const char *exp_add[] = { "telephoneNumber", "streetAddress",
++                              "abc", "123", "xyz",
++                              NULL };
++    attr_parse_test_ex(exp_add, "+telephoneNumber, +streetAddress",
++                       exp_defaults);
++
++    /* Test removing some attributes to the defaults */
++    const char *exp_rm[] = { "123", NULL };
++    attr_parse_test_ex(exp_rm, "-abc, -xyz", exp_defaults);
++
++    /* Test adding with empty defaults */
++    const char *exp_add_empty[] = { "telephoneNumber", "streetAddress",
++                                    NULL };
++    attr_parse_test_ex(exp_add_empty, "+telephoneNumber, +streetAddress", NULL);
++
++    /* Test removing with empty defaults */
++    const char *rm_all[] = { NULL };
++    attr_parse_test_ex(rm_all, "-telephoneNumber, -streetAddress", NULL);
++}
++
+ void test_attr_allowed(void **state)
+ {
+     const char *whitelist[] = { "name", "gecos", NULL };
+@@ -452,6 +502,7 @@ int main(int argc, const char *argv[])
+         unit_test(test_path_prefix),
+         unit_test(test_el_to_dict),
+         unit_test(test_attr_acl),
++        unit_test(test_attr_acl_ex),
+         unit_test(test_attr_allowed),
+         unit_test(test_path_escape_unescape),
+         unit_test_setup_teardown(test_reply_path,
+-- 
+1.9.3
+
diff --git a/SOURCES/0057-LDAP-Fix-error-check.patch b/SOURCES/0057-LDAP-Fix-error-check.patch
deleted file mode 100644
index fd1664f..0000000
--- a/SOURCES/0057-LDAP-Fix-error-check.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From fe7f5b1a3a965d1667ba1552a2b1165788f3bd2e Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 17 Jan 2014 10:49:27 +0100
-Subject: [PATCH 57/57] LDAP: Fix error check
-
-https://fedorahosted.org/sssd/ticket/2199
----
- src/providers/ldap/ldap_common.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
-index 35ea81360b4ec61eca6b952cd86fc93a6eda17dc..4c94937aad9e25bd1cd0b6d573da2982b0f1be05 100644
---- a/src/providers/ldap/ldap_common.c
-+++ b/src/providers/ldap/ldap_common.c
-@@ -831,8 +831,8 @@ errno_t common_parse_search_base(TALLOC_CTX *mem_ctx,
-         ret = sdap_create_search_base(search_bases, unparsed_base,
-                                       LDAP_SCOPE_SUBTREE, old_filter,
-                                       &search_bases[0]);
--        if (!search_bases[0]) {
--            ret = ENOMEM;
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("Cannot create new sdap search base\n"));
-             goto done;
-         }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch b/SOURCES/0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch
deleted file mode 100644
index c0ab7e0..0000000
--- a/SOURCES/0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 8509e1fe368b62225b7cf39eb1eec6cac7bf38b3 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 13 Dec 2013 18:20:08 +0100
-Subject: [PATCH 58/60] LDAP: Don't fail if subdomain cannot be found by sid
-
-Domain needn't contain sid if id_provider is ldap.
-With enabled id mapping, user couldn't be stored, because domain
-couldn't be found by sid.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2172
----
- src/providers/ldap/sdap_async_users.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index 7f0b2eea0b5ee909bcf148236c7fc43863fe8c13..65c456c8fffb57cbf9e977a49388dbe250d1412a 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -124,6 +124,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
-     bool use_id_mapping;
-     char *sid_str;
-     char *dom_sid_str = NULL;
-+    struct sss_domain_info *subdomain;
- 
-     DEBUG(SSSDBG_TRACE_FUNC, ("Save user\n"));
- 
-@@ -163,11 +164,12 @@ int sdap_save_user(TALLOC_CTX *memctx,
-     /* If this object has a SID available, we will determine the correct
-      * domain by its SID. */
-     if (sid_str != NULL) {
--        dom = find_subdomain_by_sid(get_domains_head(dom), sid_str);
--        if (dom == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, ("SID %s does not belong to any known "
-+        subdomain = find_subdomain_by_sid(get_domains_head(dom), sid_str);
-+        if (subdomain) {
-+            dom = subdomain;
-+        } else {
-+            DEBUG(SSSDBG_TRACE_FUNC, ("SID %s does not belong to any known "
-                                       "domain\n", sid_str));
--            return ERR_DOMAIN_NOT_FOUND;
-         }
-     }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0058-nss-parse-user_attributes-option.patch b/SOURCES/0058-nss-parse-user_attributes-option.patch
new file mode 100644
index 0000000..c332b66
--- /dev/null
+++ b/SOURCES/0058-nss-parse-user_attributes-option.patch
@@ -0,0 +1,103 @@
+From 3cae708a6deae902ec961e6eef552eeb632bd3ca Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 28 Oct 2014 19:42:47 +0100
+Subject: [PATCH 58/64] nss: parse user_attributes option
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/man/sssd.conf.5.xml    | 26 ++++++++++++++++++++++++++
+ src/responder/nss/nsssrv.c | 20 ++++++++++++++++++++
+ src/responder/nss/nsssrv.h |  2 ++
+ 3 files changed, 48 insertions(+)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index e2cb0b81b61063750995064b6ce83f9615049534..fbaca66724f7023dfa6068c225d6f61af0e662bb 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -711,6 +711,32 @@ fallback_homedir = /home/%u
+                         </para>
+                     </listitem>
+                 </varlistentry>
++                <varlistentry>
++                    <term>user_attributes (string)</term>
++                    <listitem>
++                        <para>
++                            Some of the additional NSS responder requests can
++                            return more attributes than just the POSIX ones
++                            defined by the NSS interface. The list of attributes
++                            is controlled by this option. It is handle the same
++                            way as the <quote>user_attributes</quote> option of
++                            the InfoPipe responder (see
++                            <citerefentry>
++                                <refentrytitle>sssd-ifp</refentrytitle>
++                                <manvolnum>5</manvolnum>
++                            </citerefentry>
++                            for details) but with no default values.
++                        </para>
++                        <para>
++                            To make configuration more easy the NSS responder
++                            will check the InfoPipe option if it is not set for
++                            the NSS responder.
++                        </para>
++                        <para>
++                            Default: not set, fallback to InfoPipe option
++                        </para>
++                    </listitem>
++                </varlistentry>
+             </variablelist>
+         </refsect2>
+         <refsect2 id='PAM'>
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index 1bbeaa1534ee3e0db72dda13ff9d01ef7fba6adf..bce06c3e8b56f3b09126f43a194c1cd6a60efb2c 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -214,6 +214,7 @@ static int nss_get_config(struct nss_ctx *nctx,
+                           struct confdb_ctx *cdb)
+ {
+     int ret;
++    char *tmp_str;
+ 
+     ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY,
+                          CONFDB_NSS_ENUM_CACHE_TIMEOUT, 120,
+@@ -298,6 +299,25 @@ static int nss_get_config(struct nss_ctx *nctx,
+                             &nctx->homedir_substr);
+     if (ret != EOK) goto done;
+ 
++
++    ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
++                            CONFDB_IFP_USER_ATTR_LIST, NULL, &tmp_str);
++    if (ret != EOK) goto done;
++
++    if (tmp_str == NULL) {
++        ret = confdb_get_string(cdb, nctx, CONFDB_IFP_CONF_ENTRY,
++                                CONFDB_IFP_USER_ATTR_LIST, NULL, &tmp_str);
++        if (ret != EOK) goto done;
++    }
++
++    if (tmp_str != NULL) {
++        nctx->extra_attributes = parse_attr_list_ex(nctx, tmp_str, NULL);
++        if (nctx->extra_attributes == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
+     ret = 0;
+ done:
+     return ret;
+diff --git a/src/responder/nss/nsssrv.h b/src/responder/nss/nsssrv.h
+index a5b946b7e4a38d7d8b35ec5df1b6644d01896470..784eba2e0c6b15b106a2323bba1de5523e2937c1 100644
+--- a/src/responder/nss/nsssrv.h
++++ b/src/responder/nss/nsssrv.h
+@@ -75,6 +75,8 @@ struct nss_ctx {
+ 
+     struct sss_idmap_ctx *idmap_ctx;
+     struct sss_names_ctx *global_names;
++
++    const char **extra_attributes;
+ };
+ 
+ struct nss_packet;
+-- 
+1.9.3
+
diff --git a/SOURCES/0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch b/SOURCES/0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch
deleted file mode 100644
index f1573d8..0000000
--- a/SOURCES/0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From adff1d0ac15ef7fd58cf2bc79af60f38c807126c Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 15 Jan 2014 14:55:10 +0100
-Subject: [PATCH 59/60] LDAP: update id mapping detection for ldap provider
-
-For id_provider ldap, it is only necessary to enable option ldap_id_mapping.
-It is an regression introduced in the commit d3e1d88ce7de3216a862b
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2172
----
- src/providers/ldap/sdap_idmap.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c
-index 249201def04131e01722479026b851e47e2283b5..b6455b81fbdedffc92bbaf8bdfbc12c1615a22f5 100644
---- a/src/providers/ldap/sdap_idmap.c
-+++ b/src/providers/ldap/sdap_idmap.c
-@@ -522,6 +522,11 @@ bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx,
-     int ret;
-     TALLOC_CTX *tmp_ctx = NULL;
- 
-+    if (dp_opt_get_bool(ctx->id_ctx->opts->basic, SDAP_ID_MAPPING)
-+        && 0 == strcmp("ldap", ctx->id_ctx->be->bet_info[BET_ID].mod_name)) {
-+        return true;
-+    }
-+
-     err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid,
-                                                    &has_algorithmic_mapping);
-     if (err == IDMAP_SUCCESS) {
--- 
-1.8.4.2
-
diff --git a/SOURCES/0059-nss-return-user_attributes-in-origbyname-request.patch b/SOURCES/0059-nss-return-user_attributes-in-origbyname-request.patch
new file mode 100644
index 0000000..81ce0c0
--- /dev/null
+++ b/SOURCES/0059-nss-return-user_attributes-in-origbyname-request.patch
@@ -0,0 +1,383 @@
+From 9b6c5e3233cdbd5fce7b6beed0cf057fe3d5da61 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 24 Oct 2014 11:30:33 +0200
+Subject: [PATCH 59/64] nss: return user_attributes in origbyname request
+
+To allow IPA clients to offer special attributes of AD users form
+trusted domain the extdom plugin on the IPA server must send them to the
+clients. The extdom plugin already uses sss_nss_getorigbyname() to get
+attributes like the SID and the user principal name. This patch adds the
+attributes given by the NSS/IFP user_attributes option to the list of
+attributes returned by sss_nss_getorigbyname().
+
+Fixes https://fedorahosted.org/sssd/ticket/2464
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/nss/nsssrv_cmd.c  | 120 +++++++++++++++++++++++++++---------
+ src/tests/cmocka/test_nss_srv.c | 133 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 223 insertions(+), 30 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 4ac5eb91eab80291e60afad2bf9c65edfbc21e7d..b100aae08fc04ccf1a295745767c5445cf2e01be 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4148,18 +4148,19 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
+     struct nss_ctx *nctx;
+     int ret;
+     int err;
+-    const char *attrs[] = {SYSDB_NAME, SYSDB_OBJECTCLASS, SYSDB_SID_STR,
+-                           ORIGINALAD_PREFIX SYSDB_NAME,
+-                           ORIGINALAD_PREFIX SYSDB_UIDNUM,
+-                           ORIGINALAD_PREFIX SYSDB_GIDNUM,
+-                           ORIGINALAD_PREFIX SYSDB_GECOS,
+-                           ORIGINALAD_PREFIX SYSDB_HOMEDIR,
+-                           ORIGINALAD_PREFIX SYSDB_SHELL,
+-                           SYSDB_UPN,
+-                           SYSDB_DEFAULT_OVERRIDE_NAME,
+-                           SYSDB_AD_ACCOUNT_EXPIRES,
+-                           SYSDB_AD_USER_ACCOUNT_CONTROL,
+-                           SYSDB_DEFAULT_ATTRS, NULL};
++    const char *default_attrs[] = {SYSDB_NAME, SYSDB_OBJECTCLASS, SYSDB_SID_STR,
++                                   ORIGINALAD_PREFIX SYSDB_NAME,
++                                   ORIGINALAD_PREFIX SYSDB_UIDNUM,
++                                   ORIGINALAD_PREFIX SYSDB_GIDNUM,
++                                   ORIGINALAD_PREFIX SYSDB_GECOS,
++                                   ORIGINALAD_PREFIX SYSDB_HOMEDIR,
++                                   ORIGINALAD_PREFIX SYSDB_SHELL,
++                                   SYSDB_UPN,
++                                   SYSDB_DEFAULT_OVERRIDE_NAME,
++                                   SYSDB_AD_ACCOUNT_EXPIRES,
++                                   SYSDB_AD_USER_ACCOUNT_CONTROL,
++                                   SYSDB_DEFAULT_ATTRS, NULL};
++    const char **attrs;
+     bool user_found = false;
+     bool group_found = false;
+     struct ldb_message *msg = NULL;
+@@ -4281,6 +4282,18 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
+             goto done;
+         }
+ 
++        attrs = default_attrs;
++        if (cmdctx->cmd == SSS_NSS_GETORIGBYNAME
++                && nctx->extra_attributes != NULL) {
++            ret = add_strings_lists(cmdctx, default_attrs,
++                                    nctx->extra_attributes, false,
++                                    discard_const(&attrs));
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "add_strings_lists failed.\n");
++                goto done;
++            }
++        }
++
+         if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
+             ret = sysdb_search_user_by_uid(cmdctx, dom, cmdctx->id, attrs,
+                                            &msg);
+@@ -4593,16 +4606,21 @@ static errno_t fill_sid(struct sss_packet *packet,
+ }
+ 
+ static errno_t fill_orig(struct sss_packet *packet,
++                         struct resp_ctx *rctx,
+                          enum sss_id_type id_type,
+                          struct ldb_message *msg)
+ {
+     int ret;
++    TALLOC_CTX *tmp_ctx;
+     const char *tmp_str;
+     uint8_t *body;
+     size_t blen;
+     size_t pctr = 0;
+     size_t c;
+     size_t sum;
++    size_t found;
++    size_t extra_attrs_count = 0;
++    const char **extra_attrs_list = NULL;
+     const char *orig_attr_list[] = {SYSDB_SID_STR,
+                                     ORIGINALAD_PREFIX SYSDB_NAME,
+                                     ORIGINALAD_PREFIX SYSDB_UIDNUM,
+@@ -4615,42 +4633,83 @@ static errno_t fill_orig(struct sss_packet *packet,
+                                     SYSDB_AD_ACCOUNT_EXPIRES,
+                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                     NULL};
+-    struct sized_string keys[sizeof(orig_attr_list)];
+-    struct sized_string vals[sizeof(orig_attr_list)];
++    struct sized_string *keys;
++    struct sized_string *vals;
++    struct nss_ctx *nctx;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
++    if (nctx->extra_attributes != NULL) {
++        extra_attrs_list = nctx->extra_attributes;
++            for(extra_attrs_count = 0;
++                extra_attrs_list[extra_attrs_count] != NULL;
++                extra_attrs_count++);
++    }
++
++    keys = talloc_array(tmp_ctx, struct sized_string,
++                        sizeof(orig_attr_list) + extra_attrs_count);
++    vals = talloc_array(tmp_ctx, struct sized_string,
++                        sizeof(orig_attr_list) + extra_attrs_count);
++    if (keys == NULL || vals == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
+ 
+     sum = 0;
++    found = 0;
+     for (c = 0; orig_attr_list[c] != NULL; c++) {
+         tmp_str = ldb_msg_find_attr_as_string(msg, orig_attr_list[c], NULL);
+         if (tmp_str != NULL) {
+-            to_sized_string(&keys[c], orig_attr_list[c]);
+-            sum += keys[c].len;
+-            to_sized_string(&vals[c], tmp_str);
+-            sum += vals[c].len;
+-        } else {
+-            vals[c].len = 0;
++            to_sized_string(&keys[found], orig_attr_list[c]);
++            sum += keys[found].len;
++            to_sized_string(&vals[found], tmp_str);
++            sum += vals[found].len;
++
++            found++;
++        }
++    }
++
++    for (c = 0; c < extra_attrs_count; c++) {
++        tmp_str = ldb_msg_find_attr_as_string(msg, extra_attrs_list[c], NULL);
++        if (tmp_str != NULL) {
++            to_sized_string(&keys[found], extra_attrs_list[c]);
++            sum += keys[found].len;
++            to_sized_string(&vals[found], tmp_str);
++            sum += vals[found].len;
++
++            found++;
+         }
+     }
+ 
+     ret = sss_packet_grow(packet, sum +  3 * sizeof(uint32_t));
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
+-        return ret;
++        goto done;
+     }
+ 
+     sss_packet_get_body(packet, &body, &blen);
+     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* Num results */
+     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
+     SAFEALIGN_COPY_UINT32(body + pctr, &id_type, &pctr);
+-    for (c = 0; orig_attr_list[c] != NULL; c++) {
+-        if (vals[c].len != 0) {
+-            memcpy(&body[pctr], keys[c].str, keys[c].len);
+-            pctr+= keys[c].len;
+-            memcpy(&body[pctr], vals[c].str, vals[c].len);
+-            pctr+= vals[c].len;
+-        }
++    for (c = 0; c < found; c++) {
++        memcpy(&body[pctr], keys[c].str, keys[c].len);
++        pctr+= keys[c].len;
++        memcpy(&body[pctr], vals[c].str, vals[c].len);
++        pctr+= vals[c].len;
+     }
+ 
+-    return EOK;
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
+ }
+ 
+ static errno_t fill_name(struct sss_packet *packet,
+@@ -4818,7 +4877,8 @@ static errno_t nss_cmd_getbysid_send_reply(struct nss_dom_ctx *dctx)
+         ret = fill_sid(cctx->creq->out, id_type, dctx->res->msgs[0]);
+         break;
+     case SSS_NSS_GETORIGBYNAME:
+-        ret = fill_orig(cctx->creq->out, id_type, dctx->res->msgs[0]);
++        ret = fill_orig(cctx->creq->out, cctx->rctx, id_type,
++                        dctx->res->msgs[0]);
+         break;
+     default:
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported request type.\n");
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index 65298cdf04e37e85820d3308c773f1c95a21ce31..c318d94be867bbb9991de288cdae45d2ddc29b24 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -52,6 +52,8 @@ struct nss_test_ctx {
+     bool ncache_hit;
+ };
+ 
++const char *global_extra_attrs[] = {"phone", "mobile", NULL};
++
+ struct nss_test_ctx *nss_test_ctx;
+ 
+ /* Mock NSS structure */
+@@ -1000,6 +1002,7 @@ void test_nss_setup(struct sss_test_conf_param params[],
+     nss_test_ctx->rctx = mock_rctx(nss_test_ctx, nss_test_ctx->tctx->ev,
+                                    nss_test_ctx->tctx->dom, nss_test_ctx->nctx);
+     assert_non_null(nss_test_ctx->rctx);
++    nss_test_ctx->rctx->cdb = nss_test_ctx->tctx->confdb;
+     nss_test_ctx->nctx->rctx = nss_test_ctx->rctx;
+ 
+     /* Create client context */
+@@ -1827,6 +1830,122 @@ void test_nss_getorigbyname(void **state)
+     assert_int_equal(ret, EOK);
+ }
+ 
++static int test_nss_getorigbyname_extra_check(uint32_t status, uint8_t *body,
++                                              size_t blen)
++{
++    const char *s;
++    enum sss_id_type id_type;
++    size_t rp = 2 * sizeof(uint32_t);
++
++    assert_int_equal(status, EOK);
++
++    SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp);
++    assert_int_equal(id_type, SSS_ID_TYPE_UID);
++
++    /* Sequence of null terminated strings */
++    s = (char *) body+rp;
++    assert_string_equal(s, SYSDB_SID_STR);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "S-1-2-3-4");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_NAME);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "orig_name");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_UIDNUM);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "1234");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "phone");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "+12-34 56 78");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "mobile");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "+98-76 54 32");
++    rp += strlen(s) + 1;
++    assert_int_equal(rp, blen);
++
++    return EOK;
++}
++
++void test_nss_getorigbyname_extra_attrs(void **state)
++{
++    errno_t ret;
++    struct sysdb_attrs *attrs;
++
++    attrs = sysdb_new_attrs(nss_test_ctx);
++    assert_non_null(attrs);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, "S-1-2-3-4");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, ORIGINALAD_PREFIX SYSDB_NAME,
++                                 "orig_name");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_uint32(attrs, ORIGINALAD_PREFIX SYSDB_UIDNUM, 1234);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, "phone", "+12-34 56 78");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, "mobile", "+98-76 54 32");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, "not_extra", "abc");
++    assert_int_equal(ret, EOK);
++
++    /* Prime the cache with a valid user */
++    ret = sysdb_add_user(nss_test_ctx->tctx->dom,
++                         "testuserorigextra", 2345, 6789,
++                         "test user orig extra",
++                         "/home/testuserorigextra", "/bin/sh", NULL,
++                         attrs, 300, 0);
++    assert_int_equal(ret, EOK);
++
++    mock_input_user_or_group("testuserorigextra");
++    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETORIGBYNAME);
++    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
++
++    /* Query for that user, call a callback when command finishes */
++    set_cmd_cb(test_nss_getorigbyname_extra_check);
++    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETORIGBYNAME,
++                          nss_test_ctx->nss_cmds);
++    assert_int_equal(ret, EOK);
++
++    /* Wait until the test finishes with EOK */
++    ret = test_ev_loop(nss_test_ctx->tctx);
++    assert_int_equal(ret, EOK);
++}
++
+ void nss_test_setup(void **state)
+ {
+     struct sss_test_conf_param params[] = {
+@@ -1848,6 +1967,18 @@ void nss_fqdn_test_setup(void **state)
+     test_nss_setup(params, state);
+ }
+ 
++void nss_test_setup_extra_attr(void **state)
++{
++    struct sss_test_conf_param params[] = {
++        { "enumerate", "false" },
++        { NULL, NULL },             /* Sentinel */
++    };
++
++    test_nss_setup(params, state);
++
++    nss_test_ctx->nctx->extra_attributes = global_extra_attrs;
++}
++
+ void nss_subdom_test_setup(void **state)
+ {
+     const char *const testdom[4] = { TEST_SUBDOM_NAME, "TEST.SUB", "test", "S-3" };
+@@ -1963,6 +2094,8 @@ int main(int argc, const char *argv[])
+                                  nss_test_setup, nss_test_teardown),
+         unit_test_setup_teardown(test_nss_getorigbyname,
+                                  nss_test_setup, nss_test_teardown),
++        unit_test_setup_teardown(test_nss_getorigbyname_extra_attrs,
++                                 nss_test_setup_extra_attr, nss_test_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+1.9.3
+
diff --git a/SOURCES/0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch b/SOURCES/0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch
deleted file mode 100644
index ccfa04f..0000000
--- a/SOURCES/0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 993aaa15cf4b128951fc9bd4a574e7ac5895d942 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 13 Dec 2013 15:33:23 +0100
-Subject: [PATCH 60/60] sdap_idamp: Fall back to another method if sid is wrong
-
-sss_idmap_domain_has_algorithmic_mapping can return also
-IDMAP_SID_INVALID, but it does not mean that idmaping is
-unavailable. We should fall back to another method of detection
-(sss_idmap_domain_by_name_has_algorithmic_mapping)
-and do not return false immediately.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2172
----
- src/providers/ldap/sdap_idmap.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c
-index b6455b81fbdedffc92bbaf8bdfbc12c1615a22f5..57c448fffa1b13699bd8042d33ac729bddb02ca8 100644
---- a/src/providers/ldap/sdap_idmap.c
-+++ b/src/providers/ldap/sdap_idmap.c
-@@ -529,9 +529,15 @@ bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx,
- 
-     err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid,
-                                                    &has_algorithmic_mapping);
--    if (err == IDMAP_SUCCESS) {
-+    switch (err){
-+    case IDMAP_SUCCESS:
-         return has_algorithmic_mapping;
--    } else if (err != IDMAP_SID_UNKNOWN && err != IDMAP_NO_DOMAIN) {
-+    case IDMAP_SID_INVALID: /* FALLTHROUGH */
-+    case IDMAP_SID_UNKNOWN: /* FALLTHROUGH */
-+    case IDMAP_NO_DOMAIN:   /* FALLTHROUGH */
-+        /* continue with idmap_domain_by_name */
-+        break;
-+    default:
-         return false;
-     }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0060-sysdb_get_user_attr_with_views-add-mandatory-overrid.patch b/SOURCES/0060-sysdb_get_user_attr_with_views-add-mandatory-overrid.patch
new file mode 100644
index 0000000..2be9d08
--- /dev/null
+++ b/SOURCES/0060-sysdb_get_user_attr_with_views-add-mandatory-overrid.patch
@@ -0,0 +1,100 @@
+From ac992d1ae46ec5ff44a1300718f12c10b1cbd60a Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 27 Oct 2014 13:33:08 +0100
+Subject: [PATCH 60/64] sysdb_get_user_attr_with_views: add mandatory override
+ attributes
+
+This patch add another attribute with is needs for override processing
+to the attribute list of sysdb_get_user_attr_with_views(). With two
+attribute it does not seem useful to check for existence and add each of
+the attributes conditionally. With this patch they are added
+unconditionally if the domain has views. Additionally the attributes are
+not removed in the end because it is expected that they do not cause any
+harm.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb_search.c | 47 ++++++++---------------------------------------
+ 1 file changed, 8 insertions(+), 39 deletions(-)
+
+diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
+index bbc5af8a02777c1519a9d0b5d77c50559e66f462..dacbd239db6be7e4c738d5bd6b495b613411b126 100644
+--- a/src/db/sysdb_search.c
++++ b/src/db/sysdb_search.c
+@@ -1037,11 +1037,11 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
+     int ret;
+     struct ldb_result *orig_obj = NULL;
+     struct ldb_result *override_obj = NULL;
+-    struct ldb_message_element *el = NULL;
+     const char **attrs = NULL;
+-    bool has_override_dn;
++    const char *mandatory_override_attrs[] = {SYSDB_OVERRIDE_DN,
++                                              SYSDB_OVERRIDE_OBJECT_DN,
++                                              NULL};
+     TALLOC_CTX *tmp_ctx;
+-    int count;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -1049,35 +1049,15 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
+         return ENOMEM;
+     }
+ 
+-    /* Assume that overrideDN is requested to simplify the code. If no view
+-     * is applied it doesn't really matter. */
+-    has_override_dn = true;
+     attrs = attributes;
+ 
+     /* If there are views we first have to search the overrides for matches */
+     if (DOM_HAS_VIEWS(domain)) {
+-        /* We need overrideDN for views, so append it if missing. */
+-        has_override_dn = false;
+-        for (count = 0; attributes[count] != NULL; count++) {
+-            if (strcmp(attributes[count], SYSDB_OVERRIDE_DN) == 0) {
+-                has_override_dn = true;
+-                break;
+-            }
+-        }
+-
+-        if (!has_override_dn) {
+-            /* Copy original attributes and add overrideDN. */
+-            attrs = talloc_zero_array(tmp_ctx, const char *, count + 2);
+-            if (attrs == NULL) {
+-                ret = ENOMEM;
+-                goto done;
+-            }
+-
+-            for (count = 0; attributes[count] != NULL; count++) {
+-                attrs[count] = attributes[count];
+-            }
+-
+-            attrs[count] = SYSDB_OVERRIDE_DN;
++        ret = add_strings_lists(tmp_ctx, attributes, mandatory_override_attrs,
++                                false, discard_const(&attrs));
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "add_strings_lists failed.\n");
++            goto done;
+         }
+ 
+         ret = sysdb_search_user_override_attrs_by_name(tmp_ctx, domain, name,
+@@ -1121,17 +1101,6 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
+-    /* Remove overrideDN if needed. */
+-    if (!has_override_dn && orig_obj != NULL && orig_obj->count == 1) {
+-        el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_OVERRIDE_DN);
+-        if (el == NULL) {
+-            ret = EINVAL;
+-            goto done;
+-        }
+-
+-        ldb_msg_remove_element(orig_obj->msgs[0], el);
+-    }
+-
+     *_res = talloc_steal(mem_ctx, orig_obj);
+     ret = EOK;
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0061-krb5-hint-to-increase-krb5_auth_timeout.patch b/SOURCES/0061-krb5-hint-to-increase-krb5_auth_timeout.patch
deleted file mode 100644
index 14fbea6..0000000
--- a/SOURCES/0061-krb5-hint-to-increase-krb5_auth_timeout.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 4777e706ed485ea61ebb0006c00a3d85440ffe70 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Tue, 21 Jan 2014 12:14:01 +0000
-Subject: [PATCH 61/62] krb5: hint to increase krb5_auth_timeout
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2202
----
- src/providers/krb5/krb5_child_handler.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
-index d6c1dc1f9707444a82e433a375839cadf73f1259..a0e8f610bbb27a25afa6171763a128dc7b8ea04d 100644
---- a/src/providers/krb5/krb5_child_handler.c
-+++ b/src/providers/krb5/krb5_child_handler.c
-@@ -254,7 +254,10 @@ static void krb5_child_timeout(struct tevent_context *ev,
-         return;
-     }
- 
--    DEBUG(9, ("timeout for child [%d] reached.\n", state->child_pid));
-+    DEBUG(SSSDBG_IMPORTANT_INFO,
-+          ("Timeout for child [%d] reached. In case KDC is distant or network "
-+           "is slow you may consider increasing value of krb5_auth_timeout.\n",
-+           state->child_pid));
- 
-     ret = kill(state->child_pid, SIGKILL);
-     if (ret == -1) {
--- 
-1.8.4.2
-
diff --git a/SOURCES/0061-sysdb_add_overrides_to_object-add-new-parameter-and-.patch b/SOURCES/0061-sysdb_add_overrides_to_object-add-new-parameter-and-.patch
new file mode 100644
index 0000000..378f73f
--- /dev/null
+++ b/SOURCES/0061-sysdb_add_overrides_to_object-add-new-parameter-and-.patch
@@ -0,0 +1,214 @@
+From 6f86800fde61c3cd61d8d7884f0da342a616bde4 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 27 Oct 2014 15:11:08 +0100
+Subject: [PATCH 61/64] sysdb_add_overrides_to_object: add new parameter and
+ multi-value support
+
+With the new parameter an attribute list other than the default one can
+be used.
+
+Override attributes with multiple values (e.g. SSH public keys) are now
+supported as well.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb.h                 |  3 ++-
+ src/db/sysdb_search.c          | 24 ++++++++++++++++--------
+ src/db/sysdb_views.c           | 41 +++++++++++++++++++++++++----------------
+ src/responder/nss/nsssrv_cmd.c |  2 +-
+ 4 files changed, 44 insertions(+), 26 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index ebb1bbedaf2df3030a012f1f0be8c5a069399cc3..f582f6a516e43a453741acacbe3ca6957e23fc37 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -487,7 +487,8 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
+ 
+ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+                                       struct ldb_message *obj,
+-                                      struct ldb_message *override_obj);
++                                      struct ldb_message *override_obj,
++                                      const char **req_attrs);
+ 
+ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+                                          struct ldb_message *obj);
+diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
+index dacbd239db6be7e4c738d5bd6b495b613411b126..677257405fae51774d4cd0c17516238e74fb7592 100644
+--- a/src/db/sysdb_search.c
++++ b/src/db/sysdb_search.c
+@@ -124,7 +124,8 @@ errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
+      * the original object. */
+     if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+-                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
++                          override_obj == NULL ? NULL : override_obj->msgs[0],
++                          NULL);
+         if (ret != EOK && ret != ENOENT) {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+             goto done;
+@@ -229,7 +230,8 @@ errno_t sysdb_getpwuid_with_views(TALLOC_CTX *mem_ctx,
+      * the original object. */
+     if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+-                           override_obj == NULL ? NULL : override_obj->msgs[0]);
++                           override_obj == NULL ? NULL : override_obj->msgs[0],
++                           NULL);
+         if (ret != EOK && ret != ENOENT) {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+             goto done;
+@@ -314,7 +316,8 @@ int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
+ 
+     if (DOM_HAS_VIEWS(domain)) {
+         for (c = 0; c < res->count; c++) {
+-            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL);
++            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL,
++                                                NULL);
+             /* enumeration assumes that the cache is up-to-date, hence we do not
+              * need to handle ENOENT separately. */
+             if (ret != EOK) {
+@@ -426,7 +429,8 @@ int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx,
+         }
+ 
+         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+-                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
++                          override_obj == NULL ? NULL : override_obj ->msgs[0],
++                          NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+             goto done;
+@@ -578,7 +582,8 @@ int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx,
+         }
+ 
+         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+-                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
++                          override_obj == NULL ? NULL : override_obj ->msgs[0],
++                          NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+             goto done;
+@@ -734,7 +739,8 @@ int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
+ 
+     if (DOM_HAS_VIEWS(domain)) {
+         for (c = 0; c < res->count; c++) {
+-            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL);
++            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL,
++                                                NULL);
+             /* enumeration assumes that the cache is up-to-date, hence we do not
+              * need to handle ENOENT separately. */
+             if (ret != EOK) {
+@@ -956,7 +962,8 @@ int sysdb_initgroups_with_views(TALLOC_CTX *mem_ctx,
+     if (DOM_HAS_VIEWS(domain)) {
+         /* Skip user entry because it already has override values added */
+         for (c = 1; c < res->count; c++) {
+-            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL);
++            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL,
++                                                NULL);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE,
+                       "sysdb_add_overrides_to_object failed.\n");
+@@ -1083,7 +1090,8 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
+      * the original object. */
+     if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+-                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
++                          override_obj == NULL ? NULL : override_obj ->msgs[0],
++                          attrs);
+         if (ret != EOK && ret != ENOENT) {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+             return ret;
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index a42aa96ed3e0cd7c877ff0c42887ef3f03ef5e0e..f2cf370231b57c3cd2b563eec4ea2a0f3a0935bd 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -948,6 +948,8 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
+  * @param[in] domain Domain struct, needed to access the cache
+  * @oaram[in] obj The original object
+  * @param[in] override_obj The object with the override data, may be NULL
++ * @param[in] req_attrs List of attributes to be requested, if not set a
++ *                      default list dependig on the object type will be used
+  *
+  * @return EOK - Override data was added successfully
+  * @return ENOMEM - There was insufficient memory to complete the operation
+@@ -958,7 +960,8 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
+  */
+ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+                                       struct ldb_message *obj,
+-                                      struct ldb_message *override_obj)
++                                      struct ldb_message *override_obj,
++                                      const char **req_attrs)
+ {
+     int ret;
+     const char *override_dn_str;
+@@ -983,7 +986,8 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+         {NULL, NULL}
+     };
+     size_t c;
+-    const char *tmp_str;
++    size_t d;
++    struct ldb_message_element *tmp_el;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -1016,12 +1020,15 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+             goto done;
+         }
+ 
+-        uid = ldb_msg_find_attr_as_uint64(obj, SYSDB_UIDNUM, 0);
+-        if (uid == 0) {
+-            /* No UID hence group object */
+-            attrs = group_attrs;
+-        } else {
+-            attrs = user_attrs;
++        attrs = req_attrs;
++        if (attrs == NULL) {
++            uid = ldb_msg_find_attr_as_uint64(obj, SYSDB_UIDNUM, 0);
++            if (uid == 0) {
++                /* No UID hence group object */
++                attrs = group_attrs;
++            } else {
++                attrs = user_attrs;
++            }
+         }
+ 
+         ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, override_dn,
+@@ -1050,14 +1057,16 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+     }
+ 
+     for (c = 0; attr_map[c].attr != NULL; c++) {
+-        tmp_str = ldb_msg_find_attr_as_string(override, attr_map[c].attr, NULL);
+-        if (tmp_str != NULL) {
+-            talloc_steal(obj, tmp_str);
+-            ret = ldb_msg_add_string(obj, attr_map[c].new_attr, tmp_str);
+-            if (ret != LDB_SUCCESS) {
+-                DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+-                ret = sysdb_error_to_errno(ret);
+-                goto done;
++        tmp_el = ldb_msg_find_element(override, attr_map[c].attr);
++        if (tmp_el != NULL) {
++            for (d = 0; d < tmp_el->num_values; d++) {
++                ret = ldb_msg_add_steal_value(obj, attr_map[c].new_attr,
++                                              &tmp_el->values[d]);
++                if (ret != LDB_SUCCESS) {
++                    DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_value failed.\n");
++                    ret = sysdb_error_to_errno(ret);
++                    goto done;
++                }
+             }
+         }
+     }
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index b100aae08fc04ccf1a295745767c5445cf2e01be..ff7b6a334f4c1d9dc854296746b0ff83949acd68 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4064,7 +4064,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
+             if (ret == EOK && DOM_HAS_VIEWS(dom)) {
+                 for (c = 0; c < dctx->res->count; c++) {
+                     ret = sysdb_add_overrides_to_object(dom, dctx->res->msgs[c],
+-                                                        NULL);
++                                                        NULL, NULL);
+                     if (ret != EOK) {
+                         DEBUG(SSSDBG_OP_FAILURE,
+                               "sysdb_add_overrides_to_object failed.\n");
+-- 
+1.9.3
+
diff --git a/SOURCES/0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch b/SOURCES/0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch
deleted file mode 100644
index 1957040..0000000
--- a/SOURCES/0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch
+++ /dev/null
@@ -1,111 +0,0 @@
-From 2ea997d55fb7b18bbf153d5fa625b688285dfdb9 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 24 Jan 2014 10:02:23 +0100
-Subject: [PATCH 62/62] LDAP: Don't abort request if no id mapping domain
- matches
-
-If an ID was requested from the back end, but no ID mapping domain
-matched, the request ended with a scary error message. It's better to
-treat the request as if no such ID was found in the domain
-
-Related:
-https://fedorahosted.org/sssd/ticket/2200
----
- src/providers/ad/ad_id.c     |  2 +-
- src/providers/ldap/ldap_id.c | 44 +++++++++++++++++++++++++++++++++++++++-----
- 2 files changed, 40 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index ada47753fb337641df582a5a59affe8124fc2035..e74653b734010712ff0562ce1bcbad2b03aba27e 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -386,7 +386,7 @@ ad_account_info_complete(struct tevent_req *req)
-             error_text = NULL;
-         } else {
-             DEBUG(SSSDBG_FATAL_FAILURE,
--                  ("Bug: dp_error is OK on failed request"));
-+                  ("Bug: dp_error is OK on failed request\n"));
-             dp_error = DP_ERR_FATAL;
-             error_text = req_error_text;
-         }
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 793bc99ebcec883be7db3fc9dd56fa511d8ba3bb..e36c1f697c18e865a47d991dad103fc440456118 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -129,7 +129,20 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-             /* Convert the UID to its objectSID */
-             err = sss_idmap_unix_to_sid(ctx->opts->idmap_ctx->map,
-                                         uid, &sid);
--            if (err != IDMAP_SUCCESS) {
-+            if (err == IDMAP_NO_DOMAIN) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      ("[%s] did not match any configured ID mapping domain\n",
-+                       name));
-+
-+                ret = sysdb_delete_user(state->sysdb,
-+                                        state->domain, NULL, uid);
-+                if (ret == ENOENT) {
-+                    /* Ignore errors to remove users that were not cached previously */
-+                    ret = EOK;
-+                }
-+
-+                goto fail;
-+            } else if (err != IDMAP_SUCCESS) {
-                 DEBUG(SSSDBG_MINOR_FAILURE,
-                       ("Mapping ID [%s] to SID failed: [%s]\n",
-                        name, idmap_error_string(err)));
-@@ -213,7 +226,11 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-     return req;
- 
- fail:
--    tevent_req_error(req, ret);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+    } else {
-+        tevent_req_done(req);
-+    }
-     tevent_req_post(req, ev);
-     return req;
- }
-@@ -496,10 +513,23 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-                 goto fail;
-             }
- 
--            /* Convert the UID to its objectSID */
-+            /* Convert the GID to its objectSID */
-             err = sss_idmap_unix_to_sid(ctx->opts->idmap_ctx->map,
-                                         gid, &sid);
--            if (err != IDMAP_SUCCESS) {
-+            if (err == IDMAP_NO_DOMAIN) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      ("[%s] did not match any configured ID mapping domain\n",
-+                       name));
-+
-+                ret = sysdb_delete_group(state->sysdb,
-+                                         state->domain, NULL, gid);
-+                if (ret == ENOENT) {
-+                    /* Ignore errors to remove users that were not cached previously */
-+                    ret = EOK;
-+                }
-+
-+                goto fail;
-+            } else if (err != IDMAP_SUCCESS) {
-                 DEBUG(SSSDBG_MINOR_FAILURE,
-                       ("Mapping ID [%s] to SID failed: [%s]\n",
-                        name, idmap_error_string(err)));
-@@ -587,7 +617,11 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-     return req;
- 
- fail:
--    tevent_req_error(req, ret);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+    } else {
-+        tevent_req_done(req);
-+    }
-     tevent_req_post(req, ev);
-     return req;
- }
--- 
-1.8.4.2
-
diff --git a/SOURCES/0062-Views-apply-user-SSH-public-key-override.patch b/SOURCES/0062-Views-apply-user-SSH-public-key-override.patch
new file mode 100644
index 0000000..d61f8f8
--- /dev/null
+++ b/SOURCES/0062-Views-apply-user-SSH-public-key-override.patch
@@ -0,0 +1,317 @@
+From a5a3aaafd0c1399f83bd3144344eb9a0da436307 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 16 Oct 2014 13:17:37 +0200
+Subject: [PATCH 62/64] Views: apply user SSH public key override
+
+With this patch the SSH public key override attribute is read from the
+FreeIPA server and saved in the cache with the other override data.
+
+Since it is possible to have multiple public SSH keys this override
+value does not replace any other data but will be added to existing
+values.
+
+Fixes https://fedorahosted.org/sssd/ticket/2454
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb_views.c           |  38 +++++++++----
+ src/man/sssd-ipa.5.xml         |   3 +
+ src/providers/ipa/ipa_common.h |   1 +
+ src/providers/ipa/ipa_opts.h   |   1 +
+ src/responder/ssh/sshsrv_cmd.c | 123 +++++++++++++++++++++++++++++++----------
+ 5 files changed, 126 insertions(+), 40 deletions(-)
+
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index f2cf370231b57c3cd2b563eec4ea2a0f3a0935bd..27b58701fe0f9a4f545df5e4bfb884c04517d0d3 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -560,6 +560,8 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+     TALLOC_CTX *tmp_ctx;
+     struct sysdb_attrs *attrs;
+     size_t c;
++    size_t d;
++    size_t num_values;
+     struct ldb_message_element *el = NULL;
+     const char *allowed_attrs[] = { SYSDB_UIDNUM,
+                                     SYSDB_GIDNUM,
+@@ -567,6 +569,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+                                     SYSDB_HOMEDIR,
+                                     SYSDB_SHELL,
+                                     SYSDB_NAME,
++                                    SYSDB_SSH_PUBKEY,
+                                     NULL };
+     bool override_attrs_found = false;
+ 
+@@ -584,7 +587,6 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+     }
+ 
+     for (c = 0; allowed_attrs[c] != NULL; c++) {
+-        /* TODO: add nameAlias for case-insentitive searches */
+         ret = sysdb_attrs_get_el_ext(override_attrs, allowed_attrs[c], false,
+                                      &el);
+         if (ret == EOK) {
+@@ -607,17 +609,30 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+                     goto done;
+                 }
+             } else {
+-                ret = sysdb_attrs_add_val(attrs,  allowed_attrs[c],
+-                                          &el->values[0]);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
+-                    goto done;
++                num_values = el->num_values;
++                /* Only SYSDB_SSH_PUBKEY is allowed to have multiple values. */
++                if (strcmp(allowed_attrs[c], SYSDB_SSH_PUBKEY) != 0
++                        && num_values != 1) {
++                    DEBUG(SSSDBG_MINOR_FAILURE,
++                          "Override attribute for [%s] has more [%zd] " \
++                          "than one value, using only the first.\n",
++                          allowed_attrs[c], num_values);
++                    num_values = 1;
++                }
++
++                for (d = 0; d < num_values; d++) {
++                    ret = sysdb_attrs_add_val(attrs,  allowed_attrs[c],
++                                              &el->values[d]);
++                    if (ret != EOK) {
++                        DEBUG(SSSDBG_OP_FAILURE,
++                              "sysdb_attrs_add_val failed.\n");
++                        goto done;
++                    }
++                    DEBUG(SSSDBG_TRACE_ALL,
++                          "Override [%s] with [%.*s] for [%s].\n",
++                          allowed_attrs[c], (int) el->values[d].length,
++                          el->values[d].data, ldb_dn_get_linearized(obj_dn));
+                 }
+-                DEBUG(SSSDBG_TRACE_ALL, "Override [%s] with [%.*s] for [%s].\n",
+-                                        allowed_attrs[c],
+-                                        (int) el->values[0].length,
+-                                        el->values[0].data,
+-                                        ldb_dn_get_linearized(obj_dn));
+             }
+         } else if (ret != ENOENT) {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el_ext failed.\n");
+@@ -983,6 +998,7 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+         {SYSDB_HOMEDIR, OVERRIDE_PREFIX SYSDB_HOMEDIR},
+         {SYSDB_SHELL, OVERRIDE_PREFIX SYSDB_SHELL},
+         {SYSDB_NAME, OVERRIDE_PREFIX SYSDB_NAME},
++        {SYSDB_SSH_PUBKEY, OVERRIDE_PREFIX SYSDB_SSH_PUBKEY},
+         {NULL, NULL}
+     };
+     size_t c;
+diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
+index 51f14f8fc16bd2843ef4b426938172c63608176e..e8a716c4104b8038e354b8ae544a04d6773e708b 100644
+--- a/src/man/sssd-ipa.5.xml
++++ b/src/man/sssd-ipa.5.xml
+@@ -626,6 +626,9 @@
+                                     <listitem>
+                                         <para>ldap_user_shell</para>
+                                     </listitem>
++                                    <listitem>
++                                        <para>ldap_user_ssh_public_key</para>
++                                    </listitem>
+                                 </itemizedlist>
+                             </para>
+                             <para>
+diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
+index 0e9324f5b362085153abebcc4894bef607173607..495276548e57e91f9744dda6d8866971b627b4da 100644
+--- a/src/providers/ipa/ipa_common.h
++++ b/src/providers/ipa/ipa_common.h
+@@ -128,6 +128,7 @@ enum ipa_override_attrs {
+     IPA_AT_OVERRIDE_SHELL,
+     IPA_AT_OVERRIDE_GROUP_NAME,
+     IPA_AT_OVERRIDE_GROUP_GID_NUMBER,
++    IPA_AT_OVERRIDE_USER_SSH_PUBLIC_KEY,
+ 
+     IPA_OPTS_OVERRIDE
+ };
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index 0e0eed49cd397fe88ce7bf41579c066088947d04..473eca4f77727e008663d082e954820a9fb0c427 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -283,6 +283,7 @@ struct sdap_attr_map ipa_override_map[] = {
+     { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL },
+     { "ldap_group_name", "cn", SYSDB_NAME, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
++    { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
+index ad831639841d42417008ea6c40c1dea045e5d6cf..5bed2e0adca0e6961337bb744729dd3e5a23c629 100644
+--- a/src/responder/ssh/sshsrv_cmd.c
++++ b/src/responder/ssh/sshsrv_cmd.c
+@@ -232,8 +232,8 @@ ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
+         return EFAULT;
+     }
+ 
+-    ret = sysdb_get_user_attr(cmd_ctx, cmd_ctx->domain,
+-                              cmd_ctx->name, attrs, &res);
++    ret = sysdb_get_user_attr_with_views(cmd_ctx, cmd_ctx->domain,
++                                         cmd_ctx->name, attrs, &res);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Failed to make request to our cache!\n");
+@@ -782,6 +782,65 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
+     return EOK;
+ }
+ 
++static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx,
++                                          struct ldb_message_element *el,
++                                          size_t fqname_len,
++                                          const char *fqname,
++                                          size_t *c)
++{
++    struct cli_ctx *cctx = cmd_ctx->cctx;
++    uint8_t *key;
++    size_t key_len;
++    uint8_t *body;
++    size_t body_len;
++    int ret;
++    size_t d;
++    TALLOC_CTX *tmp_ctx;
++
++    if (el == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n");
++        return EOK;
++    }
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    for (d = 0; d < el->num_values; d++) {
++        key = sss_base64_decode(tmp_ctx, (const char *) el->values[d].data,
++                                &key_len);
++        if (key == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        ret = sss_packet_grow(cctx->creq->out,
++                              3*sizeof(uint32_t) + key_len + fqname_len);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
++            goto done;
++        }
++        sss_packet_get_body(cctx->creq->out, &body, &body_len);
++
++        SAFEALIGN_SET_UINT32(body+(*c), 0, c);
++        SAFEALIGN_SET_UINT32(body+(*c), fqname_len, c);
++        safealign_memcpy(body+(*c), fqname, fqname_len, c);
++        SAFEALIGN_SET_UINT32(body+(*c), key_len, c);
++        safealign_memcpy(body+(*c), key, key_len, c);
++
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
+ static errno_t
+ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
+ {
+@@ -790,14 +849,13 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
+     uint8_t *body;
+     size_t body_len;
+     size_t c = 0;
+-    unsigned int i;
+-    struct ldb_message_element *el;
++    struct ldb_message_element *el = NULL;
++    struct ldb_message_element *el_override = NULL;
++    struct ldb_message_element *el_orig = NULL;
+     uint32_t count = 0;
+     const char *name;
+     char *fqname;
+     uint32_t fqname_len;
+-    uint8_t *key;
+-    size_t key_len;
+ 
+     ret = sss_packet_new(cctx->creq, 0,
+                          sss_packet_get_cmd(cctx->creq->in),
+@@ -811,6 +869,20 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
+         count = el->num_values;
+     }
+ 
++    el_orig = ldb_msg_find_element(cmd_ctx->result,
++                                  ORIGINALAD_PREFIX SYSDB_SSH_PUBKEY);
++    if (el_orig) {
++        count = el_orig->num_values;
++    }
++
++    if (DOM_HAS_VIEWS(cmd_ctx->domain)) {
++        el_override = ldb_msg_find_element(cmd_ctx->result,
++                                           OVERRIDE_PREFIX SYSDB_SSH_PUBKEY);
++        if (el_override) {
++            count += el_override->num_values;
++        }
++    }
++
+     ret = sss_packet_grow(cctx->creq->out, 2*sizeof(uint32_t));
+     if (ret != EOK) {
+         return ret;
+@@ -820,7 +892,7 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
+     SAFEALIGN_SET_UINT32(body+c, count, &c);
+     SAFEALIGN_SET_UINT32(body+c, 0, &c);
+ 
+-    if (!el) {
++    if (count == 0) {
+         return EOK;
+     }
+ 
+@@ -840,30 +912,23 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
+ 
+     fqname_len = strlen(fqname)+1;
+ 
+-    for (i = 0; i < el->num_values; i++) {
+-        key = sss_base64_decode(cmd_ctx,
+-                                (const char *)el->values[i].data,
+-                                &key_len);
+-        if (!key) {
+-            return ENOMEM;
+-        }
++    ret = decode_and_add_base64_data(cmd_ctx, el, fqname_len, fqname, &c);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
++        return ret;
++    }
+ 
+-        ret = sss_packet_grow(cctx->creq->out,
+-                              3*sizeof(uint32_t) + key_len + fqname_len);
+-        if (ret != EOK) {
+-            talloc_free(key);
+-            return ret;
+-        }
+-        sss_packet_get_body(cctx->creq->out, &body, &body_len);
++    ret = decode_and_add_base64_data(cmd_ctx, el_orig, fqname_len, fqname, &c);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
++        return ret;
++    }
+ 
+-        SAFEALIGN_SET_UINT32(body+c, 0, &c);
+-        SAFEALIGN_SET_UINT32(body+c, fqname_len, &c);
+-        safealign_memcpy(body+c, fqname, fqname_len, &c);
+-        SAFEALIGN_SET_UINT32(body+c, key_len, &c);
+-        safealign_memcpy(body+c, key, key_len, &c);
+-
+-        talloc_free(key);
+-        count++;
++    ret = decode_and_add_base64_data(cmd_ctx, el_override, fqname_len, fqname,
++                                     &c);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
++        return ret;
+     }
+ 
+     return EOK;
+-- 
+1.9.3
+
diff --git a/SOURCES/0063-Add-test-for-sysdb_add_overrides_to_object.patch b/SOURCES/0063-Add-test-for-sysdb_add_overrides_to_object.patch
new file mode 100644
index 0000000..0d8d7d3
--- /dev/null
+++ b/SOURCES/0063-Add-test-for-sysdb_add_overrides_to_object.patch
@@ -0,0 +1,290 @@
+From de4be65f95ae8bd10995948e086bb71f047c2887 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 28 Oct 2014 15:53:16 +0100
+Subject: [PATCH 63/64] Add test for sysdb_add_overrides_to_object()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                         |  16 +++
+ src/tests/cmocka/test_sysdb_views.c | 235 ++++++++++++++++++++++++++++++++++++
+ 2 files changed, 251 insertions(+)
+ create mode 100644 src/tests/cmocka/test_sysdb_views.c
+
+diff --git a/Makefile.am b/Makefile.am
+index ac8ad1566a5c931bf43526e2d29a57a5f8ade1cf..60bc67f1ac60c72dc64b3d1adccc9ef1ec989ad5 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -215,6 +215,7 @@ if HAVE_CMOCKA
+         sss_sifp-tests \
+         test_search_bases \
+         sdap-tests \
++        test_sysdb_views \
+         $(NULL)
+ 
+ if BUILD_IFP
+@@ -2060,6 +2061,21 @@ sss_sifp_tests_LDADD = \
+     $(SSSD_INTERNAL_LTLIBS)
+ endif # BUILD_IFP
+ 
++test_sysdb_views_SOURCES = \
++    src/tests/cmocka/test_sysdb_views.c \
++    $(NULL)
++test_sysdb_views_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
++test_sysdb_views_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(LDB_LIBS) \
++    $(POPT_LIBS) \
++    $(TALLOC_LIBS) \
++    $(SSSD_INTERNAL_LTLIBS) \
++    libsss_test_common.la \
++    $(NULL)
++
+ endif # HAVE_CMOCKA
+ 
+ noinst_PROGRAMS = pam_test_client
+diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..38525d6ded8fdbbd1a657f8ca742e51d6ba2b102
+--- /dev/null
++++ b/src/tests/cmocka/test_sysdb_views.c
+@@ -0,0 +1,235 @@
++/*
++    SSSD
++
++    sysdb_views - Tests for view and override related sysdb calls
++
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <stdarg.h>
++#include <stddef.h>
++#include <setjmp.h>
++#include <cmocka.h>
++#include <popt.h>
++
++#include "tests/cmocka/common_mock.h"
++
++#define TESTS_PATH "tests_sysdb"
++#define TEST_CONF_FILE "tests_conf.ldb"
++
++struct sysdb_test_ctx {
++    struct sysdb_ctx *sysdb;
++    struct confdb_ctx *confdb;
++    struct tevent_context *ev;
++    struct sss_domain_info *domain;
++};
++
++static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
++{
++    struct sysdb_test_ctx *test_ctx;
++    char *conf_db;
++    int ret;
++
++    const char *val[2];
++    val[1] = NULL;
++
++    /* Create tests directory if it doesn't exist */
++    /* (relative to current dir) */
++    ret = mkdir(TESTS_PATH, 0775);
++    assert_true(ret == 0 || errno == EEXIST);
++
++    test_ctx = talloc_zero(global_talloc_context, struct sysdb_test_ctx);
++    assert_non_null(test_ctx);
++
++    /* Create an event context
++     * It will not be used except in confdb_init and sysdb_init
++     */
++    test_ctx->ev = tevent_context_init(test_ctx);
++    assert_non_null(test_ctx->ev);
++
++    conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
++    assert_non_null(conf_db);
++    DEBUG(SSSDBG_MINOR_FAILURE, "CONFDB: %s\n", conf_db);
++
++    /* Connect to the conf db */
++    ret = confdb_init(test_ctx, &test_ctx->confdb, conf_db);
++    assert_int_equal(ret, EOK);
++
++    val[0] = "LOCAL";
++    ret = confdb_add_param(test_ctx->confdb, true,
++                           "config/sssd", "domains", val);
++    assert_int_equal(ret, EOK);
++
++    val[0] = "local";
++    ret = confdb_add_param(test_ctx->confdb, true,
++                           "config/domain/LOCAL", "id_provider", val);
++    assert_int_equal(ret, EOK);
++
++    val[0] = enumerate ? "TRUE" : "FALSE";
++    ret = confdb_add_param(test_ctx->confdb, true,
++                           "config/domain/LOCAL", "enumerate", val);
++    assert_int_equal(ret, EOK);
++
++    val[0] = "TRUE";
++    ret = confdb_add_param(test_ctx->confdb, true,
++                           "config/domain/LOCAL", "cache_credentials", val);
++    assert_int_equal(ret, EOK);
++
++    ret = sssd_domain_init(test_ctx, test_ctx->confdb, "local",
++                           TESTS_PATH, &test_ctx->domain);
++    assert_int_equal(ret, EOK);
++
++    test_ctx->sysdb = test_ctx->domain->sysdb;
++
++    *ctx = test_ctx;
++    return EOK;
++}
++
++#define setup_sysdb_tests(ctx) _setup_sysdb_tests((ctx), false)
++
++static void test_sysdb_setup(void **state)
++{
++    int ret;
++    struct sysdb_test_ctx *test_ctx;
++
++    assert_true(leak_check_setup());
++
++    ret = setup_sysdb_tests(&test_ctx);
++    assert_int_equal(ret, EOK);
++
++    *state = (void *) test_ctx;
++}
++
++static void test_sysdb_teardown(void **state)
++{
++    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                         struct sysdb_test_ctx);
++
++    talloc_free(test_ctx);
++    assert_true(leak_check_teardown());
++}
++
++void test_sysdb_add_overrides_to_object(void **state)
++{
++    int ret;
++    struct ldb_message *orig;
++    struct ldb_message *override;
++    struct ldb_message_element *el;
++    char *tmp_str;
++    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                         struct sysdb_test_ctx);
++
++    orig = ldb_msg_new(test_ctx);
++    assert_non_null(orig);
++
++    tmp_str = talloc_strdup(orig,  "ORIGNAME");
++    ret = ldb_msg_add_string(orig, SYSDB_NAME, tmp_str);
++    assert_int_equal(ret, EOK);
++
++    tmp_str = talloc_strdup(orig,  "ORIGGECOS");
++    ret = ldb_msg_add_string(orig, SYSDB_GECOS, tmp_str);
++    assert_int_equal(ret, EOK);
++
++    override = ldb_msg_new(test_ctx);
++    assert_non_null(override);
++
++    tmp_str = talloc_strdup(override, "OVERRIDENAME");
++    ret = ldb_msg_add_string(override, SYSDB_NAME, tmp_str);
++    assert_int_equal(ret, EOK);
++
++    tmp_str = talloc_strdup(override, "OVERRIDEGECOS");
++    ret = ldb_msg_add_string(override, SYSDB_GECOS, tmp_str);
++    assert_int_equal(ret, EOK);
++
++    tmp_str = talloc_strdup(override, "OVERRIDEKEY1");
++    ret = ldb_msg_add_string(override, SYSDB_SSH_PUBKEY, tmp_str);
++    assert_int_equal(ret, EOK);
++
++    tmp_str = talloc_strdup(override, "OVERRIDEKEY2");
++    ret = ldb_msg_add_string(override, SYSDB_SSH_PUBKEY, tmp_str);
++    assert_int_equal(ret, EOK);
++
++
++    ret = sysdb_add_overrides_to_object(test_ctx->domain, orig, override, NULL);
++    assert_int_equal(ret, EOK);
++
++    assert_string_equal(ldb_msg_find_attr_as_string(orig, SYSDB_NAME, NULL),
++                        "ORIGNAME");
++    assert_string_equal(ldb_msg_find_attr_as_string(orig, SYSDB_GECOS, NULL),
++                        "ORIGGECOS");
++    assert_string_equal(ldb_msg_find_attr_as_string(orig,
++                                                    OVERRIDE_PREFIX SYSDB_NAME,
++                                                    NULL),
++                        "OVERRIDENAME");
++    assert_string_equal(ldb_msg_find_attr_as_string(orig,
++                                                    OVERRIDE_PREFIX SYSDB_GECOS,
++                                                    NULL),
++                        "OVERRIDEGECOS");
++
++    el = ldb_msg_find_element(orig, OVERRIDE_PREFIX SYSDB_SSH_PUBKEY);
++    assert_non_null(el);
++    assert_int_equal(el->num_values, 2);
++    assert_int_equal(ldb_val_string_cmp(&el->values[0], "OVERRIDEKEY1"), 0);
++    assert_int_equal(ldb_val_string_cmp(&el->values[1], "OVERRIDEKEY2"), 0);
++}
++
++int main(int argc, const char *argv[])
++{
++    int rv;
++    int no_cleanup = 0;
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
++         _("Do not delete the test database after a test run"), NULL },
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test_setup_teardown(test_sysdb_add_overrides_to_object,
++                                 test_sysdb_setup, test_sysdb_teardown),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    tests_set_cwd();
++    rv = run_tests(tests);
++
++    if (rv == 0 && no_cleanup == 0) {
++        test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_FILE, LOCAL_SYSDB_FILE);
++    }
++    return rv;
++}
+-- 
+1.9.3
+
diff --git a/SOURCES/0063-sudo-memset-tm-when-converting-time-attributes.patch b/SOURCES/0063-sudo-memset-tm-when-converting-time-attributes.patch
deleted file mode 100644
index f53462a..0000000
--- a/SOURCES/0063-sudo-memset-tm-when-converting-time-attributes.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 89eca8339610956f8d95d701dc02d3f8256e2770 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 29 Jan 2014 12:56:08 +0100
-Subject: [PATCH 63/71] sudo: memset tm when converting time attributes
-
-strptime() which is used to parse LDAP time value does not initialize
-all fields of tm structure (especially tm_isdst). This results in
-random behavior - when the tm is converted into timestamp via mktime(),
-the result depends on current value of tm_isdst.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2213
-
-b
----
- src/db/sysdb_sudo.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c
-index 4e98b5b35f3968a1db68c32812eac71670578b60..ceaecbd2666cfb84422bd72b3109da9c4aa0f0f3 100644
---- a/src/db/sysdb_sudo.c
-+++ b/src/db/sysdb_sudo.c
-@@ -56,6 +56,8 @@ static errno_t sysdb_sudo_convert_time(const char *str, time_t *unix_time)
-                              NULL};
- 
-     for (format = formats; *format != NULL; format++) {
-+        /* strptime() may leave some fields uninitialized */
-+        memset(&tm, 0, sizeof(struct tm));
-         tret = strptime(str, *format, &tm);
-         if (tret != NULL && *tret == '\0') {
-             *unix_time = mktime(&tm);
--- 
-1.8.4.2
-
diff --git a/SOURCES/0064-AD-Don-t-mark-domain-as-enumerated-twice.patch b/SOURCES/0064-AD-Don-t-mark-domain-as-enumerated-twice.patch
deleted file mode 100644
index 0e318c1..0000000
--- a/SOURCES/0064-AD-Don-t-mark-domain-as-enumerated-twice.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 392058122b5993a195436c2d5d9833e5e1dd0198 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 16 Dec 2013 03:36:19 +0100
-Subject: [PATCH 64/71] AD: Don't mark domain as enumerated twice
-
-The domain was already marked as enumerated using sysdb_set_enumerated
-in the enumeration request itself.
----
- src/providers/ad/ad_id.c | 13 -------------
- 1 file changed, 13 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index e74653b734010712ff0562ce1bcbad2b03aba27e..85edcf6d604f705f5645f77689c2b4c7471b5edd 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -571,19 +571,6 @@ ad_enumeration_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    /* Ok, we've completed an enumeration. Save this to the
--     * sysdb so we can postpone starting up the enumeration
--     * process on the next SSSD service restart (to avoid
--     * slowing down system boot-up
--     */
--    ret = sysdb_set_enumerated(state->sdom->dom->sysdb,
--                               state->sdom->dom, true);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_MINOR_FAILURE,
--              ("Could not mark domain as having enumerated.\n"));
--        /* This error is non-fatal, so continue */
--    }
--
-     tevent_req_done(req);
- }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0064-Add-ssh-pubkey-to-origbyname-request.patch b/SOURCES/0064-Add-ssh-pubkey-to-origbyname-request.patch
new file mode 100644
index 0000000..c9cd2be
--- /dev/null
+++ b/SOURCES/0064-Add-ssh-pubkey-to-origbyname-request.patch
@@ -0,0 +1,38 @@
+From c6a29b0121b64bbe6b81f2d61c81c480bbf1a858 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 4 Nov 2014 13:58:39 +0100
+Subject: [PATCH 64/64] Add ssh pubkey to origbyname request
+
+Since the IPA clients expects that the extdom plugin delivers the
+default view data for a given user this patch adds the public SSH key to
+the list of returned attributes of the getorigbyname request so that it
+can be send back to the clients.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/nss/nsssrv_cmd.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index ff7b6a334f4c1d9dc854296746b0ff83949acd68..c9c09a082b67741e1d229b419aa7c3ecbf195ddd 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4159,6 +4159,7 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
+                                    SYSDB_DEFAULT_OVERRIDE_NAME,
+                                    SYSDB_AD_ACCOUNT_EXPIRES,
+                                    SYSDB_AD_USER_ACCOUNT_CONTROL,
++                                   SYSDB_SSH_PUBKEY,
+                                    SYSDB_DEFAULT_ATTRS, NULL};
+     const char **attrs;
+     bool user_found = false;
+@@ -4632,6 +4633,7 @@ static errno_t fill_orig(struct sss_packet *packet,
+                                     SYSDB_DEFAULT_OVERRIDE_NAME,
+                                     SYSDB_AD_ACCOUNT_EXPIRES,
+                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
++                                    SYSDB_SSH_PUBKEY,
+                                     NULL};
+     struct sized_string *keys;
+     struct sized_string *vals;
+-- 
+1.9.3
+
diff --git a/SOURCES/0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch b/SOURCES/0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch
deleted file mode 100644
index 284d0d1..0000000
--- a/SOURCES/0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From c6808be838567870a251d79baad1080910f6ec4c Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 10 Dec 2013 17:33:35 +0100
-Subject: [PATCH 65/71] AD: Store info on whether a subdomain is set to
- enumerate
-
-Depending on the state of the subdomain_enumerate variable, the newly
-created subdomain object is created with the right value of "enumerate"
-attribute in the sysdb.
----
- src/providers/ad/ad_subdomains.c | 38 +++++++++++++++++++++++++++++++++-----
- 1 file changed, 33 insertions(+), 5 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 62c3e16d0d3323a32848b4fbf54d2a151c16f64c..348561a85524c203293c713d3f31552a99d74a43 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -223,10 +223,28 @@ ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
-     return EOK;
- }
- 
-+static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
-+                                    struct sysdb_attrs *attrs,
-+                                    bool *_enumerates)
-+{
-+    errno_t ret;
-+    const char *name;
-+
-+    ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-+        return ret;
-+    }
-+
-+    *_enumerates = subdomain_enumerates(parent, name);
-+    return EOK;
-+}
-+
- static errno_t
- ad_subdom_store(struct ad_subdomains_ctx *ctx,
-                 struct sss_domain_info *domain,
--                struct sysdb_attrs *subdom_attrs)
-+                struct sysdb_attrs *subdom_attrs,
-+                bool enumerate)
- {
-     TALLOC_CTX *tmp_ctx;
-     const char *name;
-@@ -293,9 +311,8 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
-                                              name,
-                                              sid_str);
- 
--    /* AD subdomains are currently all mpg and do not enumerate */
-     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
--                                mpg, false, domain->forest);
-+                                mpg, enumerate, domain->forest);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
-         goto done;
-@@ -319,6 +336,7 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
-     const char *value;
-     int c, h;
-     int ret;
-+    bool enumerate;
- 
-     domain = ctx->be_ctx->domain;
-     memset(handled, 0, sizeof(bool) * count);
-@@ -367,7 +385,12 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
-             talloc_zfree(sdom);
-         } else {
-             /* ok let's try to update it */
--            ret = ad_subdom_store(ctx, domain, reply[c]);
-+            ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
-+            if (ret != EOK) {
-+                goto done;
-+            }
-+
-+            ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
-             if (ret) {
-                 /* Nothing we can do about the error. Let's at least try
-                  * to reuse the existing domains
-@@ -396,7 +419,12 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
-         /* Nothing we can do about the error. Let's at least try
-          * to reuse the existing domains.
-          */
--        ret = ad_subdom_store(ctx, domain, reply[c]);
-+        ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+
-+        ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
-         if (ret) {
-             DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to parse subdom data, "
-                   "will try to use cached subdomain\n"));
--- 
-1.8.4.2
-
diff --git a/SOURCES/0065-BUILD-Install-ldap_child-and-as-setuid-if-running-un.patch b/SOURCES/0065-BUILD-Install-ldap_child-and-as-setuid-if-running-un.patch
new file mode 100644
index 0000000..a15d69a
--- /dev/null
+++ b/SOURCES/0065-BUILD-Install-ldap_child-and-as-setuid-if-running-un.patch
@@ -0,0 +1,51 @@
+From fe5108b091e77dac505fd433c2df9c8b5736b21f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 11 Oct 2014 20:22:42 +0200
+Subject: [PATCH 65/71] BUILD: Install ldap_child and as setuid if running
+ under non-privileged user
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The ldap_child permissions should be 4750, owned by root.sssd,
+to make sure only root and sssd can execute the child and if executed by
+sssd, the child will run as root.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ Makefile.am          | 5 +++++
+ contrib/sssd.spec.in | 2 +-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 60bc67f1ac60c72dc64b3d1adccc9ef1ec989ad5..02b087ea37b4e55da7eeb7fb199d282d72129e40 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2844,6 +2844,11 @@ else
+ 	$(MKDIR_P) $(DESTDIR)$(initdir)
+ endif
+ 
++if SSSD_USER
++	chgrp $(SSSD_USER) $(sssdlibexecdir)/ldap_child
++	chmod 4750 $(sssdlibexecdir)/ldap_child
++endif
++
+ install-data-hook:
+ 	rm $(DESTDIR)/$(nsslibdir)/libnss_sss.so.2 \
+        $(DESTDIR)/$(nsslibdir)/libnss_sss.so
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index db3bbcb09d6b27ca785f511ce6414fbeaaf445c6..d2e6cec2610e4c00cb376683cf7e64eb5cdafc5c 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -645,7 +645,7 @@ rm -rf $RPM_BUILD_ROOT
+ %defattr(-,root,root,-)
+ %doc COPYING
+ %{_libdir}/%{name}/libsss_krb5_common.so
+-%{_libexecdir}/%{servicename}/ldap_child
++%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child
+ %{_libexecdir}/%{servicename}/krb5_child
+ 
+ %files krb5 -f sssd_krb5.lang
+-- 
+1.9.3
+
diff --git a/SOURCES/0066-LDAP-Move-sss_krb5_verify_keytab_ex-to-ldap_child.patch b/SOURCES/0066-LDAP-Move-sss_krb5_verify_keytab_ex-to-ldap_child.patch
new file mode 100644
index 0000000..f11e54f
--- /dev/null
+++ b/SOURCES/0066-LDAP-Move-sss_krb5_verify_keytab_ex-to-ldap_child.patch
@@ -0,0 +1,220 @@
+From 73bd041e84e13ac96af4c057882c386fa437b202 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 11 Oct 2014 17:39:21 +0200
+Subject: [PATCH 66/71] LDAP: Move sss_krb5_verify_keytab_ex to ldap_child
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The function was called from one place only, so it makes no sense to
+keep it in a shared module. Moreover, the function should only be
+called from code that runs as root.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/providers/ldap/ldap_child.c | 79 ++++++++++++++++++++++++++++++++++++++++-
+ src/util/sss_krb5.c             | 76 ---------------------------------------
+ src/util/sss_krb5.h             |  3 --
+ 3 files changed, 78 insertions(+), 80 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
+index e5779b70906d90ab855677f04a154e179f2163c6..b8b4b0ad7cfffc7db52b5ca3d9b9a74f12480070 100644
+--- a/src/providers/ldap/ldap_child.c
++++ b/src/providers/ldap/ldap_child.c
+@@ -160,6 +160,83 @@ set_child_debugging(krb5_context ctx)
+     return EOK;
+ }
+ 
++static int lc_verify_keytab_ex(const char *principal,
++                               const char *keytab_name,
++                               krb5_context context,
++                               krb5_keytab keytab)
++{
++    bool found;
++    char *kt_principal;
++    krb5_error_code krberr;
++    krb5_kt_cursor cursor;
++    krb5_keytab_entry entry;
++
++    krberr = krb5_kt_start_seq_get(context, keytab, &cursor);
++    if (krberr) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "Cannot read keytab [%s].\n", KEYTAB_CLEAN_NAME);
++
++        sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. "
++                             "Unable to create GSSAPI-encrypted LDAP "
++                             "connection.",
++                             KEYTAB_CLEAN_NAME, krberr,
++                             sss_krb5_get_error_message(context, krberr));
++
++        return EIO;
++    }
++
++    found = false;
++    while ((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
++        krberr = krb5_unparse_name(context, entry.principal, &kt_principal);
++        if (krberr) {
++            DEBUG(SSSDBG_FATAL_FAILURE,
++                  "Could not parse keytab entry\n");
++            sss_log(SSS_LOG_ERR, "Could not parse keytab entry\n");
++            return EIO;
++        }
++
++        if (strcmp(principal, kt_principal) == 0) {
++            found = true;
++        }
++        free(kt_principal);
++        krberr = sss_krb5_free_keytab_entry_contents(context, &entry);
++        if (krberr) {
++            /* This should never happen. The API docs for this function
++             * specify only success for this function
++             */
++            DEBUG(SSSDBG_CRIT_FAILURE,"Could not free keytab entry contents\n");
++            /* This is non-fatal, so we'll continue here */
++        }
++
++        if (found) {
++            break;
++        }
++    }
++
++    krberr = krb5_kt_end_seq_get(context, keytab, &cursor);
++    if (krberr) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Could not close keytab.\n");
++        sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].",
++                             KEYTAB_CLEAN_NAME);
++        return EIO;
++    }
++
++    if (!found) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "Principal [%s] not found in keytab [%s]\n",
++               principal,
++               KEYTAB_CLEAN_NAME);
++        sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: "
++                             "Principal [%s] was not found. "
++                             "Unable to create GSSAPI-encrypted LDAP connection.",
++                             KEYTAB_CLEAN_NAME, principal);
++
++        return EFAULT;
++    }
++
++    return EOK;
++}
++
+ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+                                                const char *realm_str,
+                                                const char *princ_str,
+@@ -287,7 +364,7 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+     }
+ 
+     /* Verify the keytab */
+-    ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab);
++    ret = lc_verify_keytab_ex(full_princ, keytab_name, context, keytab);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE,
+                 "Unable to verify principal is present in the keytab\n");
+diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
+index b4012593d96bc951143e4bb2ba7a91d118b1a53c..9eb34e17dc1059da9c346d4635a9f3e283308328 100644
+--- a/src/util/sss_krb5.c
++++ b/src/util/sss_krb5.c
+@@ -247,82 +247,6 @@ done:
+     return ret;
+ }
+ 
+-int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name,
+-                              krb5_context context, krb5_keytab keytab)
+-{
+-    bool found;
+-    char *kt_principal;
+-    krb5_error_code krberr;
+-    krb5_kt_cursor cursor;
+-    krb5_keytab_entry entry;
+-
+-    krberr = krb5_kt_start_seq_get(context, keytab, &cursor);
+-    if (krberr) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,
+-              "Cannot read keytab [%s].\n", KEYTAB_CLEAN_NAME);
+-
+-        sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. "
+-                             "Unable to create GSSAPI-encrypted LDAP "
+-                             "connection.",
+-                             KEYTAB_CLEAN_NAME, krberr,
+-                             sss_krb5_get_error_message(context, krberr));
+-
+-        return EIO;
+-    }
+-
+-    found = false;
+-    while((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
+-        krberr = krb5_unparse_name(context, entry.principal, &kt_principal);
+-        if (krberr) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Could not parse keytab entry\n");
+-            sss_log(SSS_LOG_ERR, "Could not parse keytab entry\n");
+-            return EIO;
+-        }
+-
+-        if (strcmp(principal, kt_principal) == 0) {
+-            found = true;
+-        }
+-        free(kt_principal);
+-        krberr = sss_krb5_free_keytab_entry_contents(context, &entry);
+-        if (krberr) {
+-            /* This should never happen. The API docs for this function
+-             * specify only success for this function
+-             */
+-            DEBUG(SSSDBG_CRIT_FAILURE,"Could not free keytab entry contents\n");
+-            /* This is non-fatal, so we'll continue here */
+-        }
+-
+-        if (found) {
+-            break;
+-        }
+-    }
+-
+-    krberr = krb5_kt_end_seq_get(context, keytab, &cursor);
+-    if (krberr) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Could not close keytab.\n");
+-        sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].",
+-                             KEYTAB_CLEAN_NAME);
+-        return EIO;
+-    }
+-
+-    if (!found) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,
+-              "Principal [%s] not found in keytab [%s]\n",
+-               principal,
+-               KEYTAB_CLEAN_NAME);
+-        sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: "
+-                             "Principal [%s] was not found. "
+-                             "Unable to create GSSAPI-encrypted LDAP connection.",
+-                             KEYTAB_CLEAN_NAME, principal);
+-
+-        return EFAULT;
+-    }
+-
+-    return EOK;
+-}
+-
+-
+ enum matching_mode {MODE_NORMAL, MODE_PREFIX, MODE_POSTFIX};
+ /**
+  * We only have primary and instances stored separately, we need to
+diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
+index 83c72097594dc24de1f8ac93d5394b6766a449f4..afa0d1943d8a23ae1543ae3874b5abbfbb4b3372 100644
+--- a/src/util/sss_krb5.h
++++ b/src/util/sss_krb5.h
+@@ -70,9 +70,6 @@ void KRB5_CALLCONV sss_krb5_get_init_creds_opt_free (krb5_context context,
+ 
+ void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name);
+ 
+-int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name,
+-                              krb5_context context, krb5_keytab keytab);
+-
+ krb5_error_code find_principal_in_keytab(krb5_context ctx,
+                                          krb5_keytab keytab,
+                                          const char *pattern_primary,
+-- 
+1.9.3
+
diff --git a/SOURCES/0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch b/SOURCES/0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch
deleted file mode 100644
index bba823a..0000000
--- a/SOURCES/0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch
+++ /dev/null
@@ -1,284 +0,0 @@
-From 1a5d7f670d94cb5c2b4a727e1e4cb3f1debadaa7 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 10 Dec 2013 21:49:45 +0100
-Subject: [PATCH 66/71] LDAP: Pass a private context to enumeration ptask
- instead of hardcoded connection
-
-Previously, the sdap-domain enumeration request used a single connection context to
-download all the data. Now we'd like to use different connections to
-download different objects, so the ID context is passed in and the
-request itself decides which connection to use for the sdap-domain
-enumeration.
----
- src/providers/ad/ad_id.c           | 12 ++++++++----
- src/providers/ad/ad_init.c         |  7 ++++---
- src/providers/ad/ad_subdomains.c   |  8 +++++---
- src/providers/ipa/ipa_subdomains.c |  8 +++++---
- src/providers/ldap/ldap_common.c   | 15 +++++++++------
- src/providers/ldap/ldap_common.h   | 17 +++++++++--------
- src/providers/ldap/ldap_id_enum.c  | 21 ++++++++++++---------
- 7 files changed, 52 insertions(+), 36 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 85edcf6d604f705f5645f77689c2b4c7471b5edd..99383c13bdadfe9eb2af9f9323ca19a9759d4620 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -414,6 +414,7 @@ ad_check_online(struct be_req *be_req)
- }
- 
- struct ad_enumeration_state {
-+    struct ad_id_ctx *id_ctx;
-     struct ldap_enum_ctx *ectx;
-     struct sdap_id_op *sdap_op;
-     struct tevent_context *ev;
-@@ -443,6 +444,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
- 
-     ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
-     if (ectx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n"));
-         ret = EFAULT;
-         goto fail;
-     }
-@@ -450,8 +452,10 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
-     state->ectx = ectx;
-     state->ev = ev;
-     state->sdom = ectx->sdom;
-+    state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
- 
--    state->sdap_op = sdap_id_op_create(state, ectx->conn->conn_cache);
-+    state->sdap_op = sdap_id_op_create(state,
-+                                       state->id_ctx->ldap_ctx->conn_cache);
-     if (state->sdap_op == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n"));
-         ret = ENOMEM;
-@@ -500,7 +504,7 @@ ad_enumeration_conn_done(struct tevent_req *subreq)
-     }
- 
-     subreq = ad_master_domain_send(state, state->ev,
--                                   state->ectx->conn,
-+                                   state->id_ctx->ldap_ctx,
-                                    state->sdap_op,
-                                    state->sdom->dom->name);
-     if (subreq == NULL) {
-@@ -540,8 +544,8 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    subreq = sdap_dom_enum_send(state, state->ev, state->ectx->ctx,
--                                state->sdom, state->ectx->conn);
-+    subreq = sdap_dom_enum_send(state, state->ev, state->id_ctx->sdap_id_ctx,
-+                                state->sdom, state->id_ctx->ldap_ctx);
-     if (subreq == NULL) {
-         /* The ptask API will reschedule the enumeration on its own on
-          * failure */
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index ed69a7d9889bac1281b5ff7c7b0f290ab09173fb..eff6d990d131e3aba124d252d001dd39e78b45cf 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -205,11 +205,12 @@ sssm_ad_id_init(struct be_ctx *bectx,
-         goto done;
-     }
- 
--    ret = sdap_id_setup_tasks(ad_ctx->sdap_id_ctx,
--                              ad_ctx->sdap_id_ctx->conn,
-+    ret = sdap_id_setup_tasks(bectx,
-+                              ad_ctx->sdap_id_ctx,
-                               ad_ctx->sdap_id_ctx->opts->sdom,
-                               ad_enumeration_send,
--                              ad_enumeration_recv);
-+                              ad_enumeration_recv,
-+                              ad_ctx);
-     if (ret != EOK) {
-         goto done;
-     }
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 348561a85524c203293c713d3f31552a99d74a43..e7871cc32407893948fe1b2803258d68c70889c1 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -177,10 +177,12 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
-         return EFAULT;
-     }
- 
--    ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx,
--                              ad_id_ctx->ldap_ctx, sdom,
-+    ret = sdap_id_setup_tasks(be_ctx,
-+                              ad_id_ctx->sdap_id_ctx,
-+                              sdom,
-                               ldap_enumeration_send,
--                              ldap_enumeration_recv);
-+                              ldap_enumeration_recv,
-+                              ad_id_ctx->sdap_id_ctx);
-     if (ret != EOK) {
-         talloc_free(ad_options);
-         return ret;
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index d9c204451f1b734ee98ce4c48f3f139731e47dec..88b6ba52538be83417e98c9a5dd033bea87ebe4b 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -183,10 +183,12 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
-         return EFAULT;
-     }
- 
--    ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx,
--                              ad_id_ctx->ldap_ctx, sdom,
-+    ret = sdap_id_setup_tasks(be_ctx,
-+                              ad_id_ctx->sdap_id_ctx,
-+                              sdom,
-                               ldap_enumeration_send,
--                              ldap_enumeration_recv);
-+                              ldap_enumeration_recv,
-+                              ad_id_ctx->sdap_id_ctx);
-     if (ret != EOK) {
-         talloc_free(ad_options);
-         return ret;
-diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
-index 4c94937aad9e25bd1cd0b6d573da2982b0f1be05..e799c783c118309409faca0294eadc4736d15108 100644
---- a/src/providers/ldap/ldap_common.c
-+++ b/src/providers/ldap/ldap_common.c
-@@ -974,16 +974,18 @@ void sdap_mark_offline(struct sdap_id_ctx *ctx)
- 
- int ldap_id_setup_tasks(struct sdap_id_ctx *ctx)
- {
--    return sdap_id_setup_tasks(ctx, ctx->conn, ctx->opts->sdom,
-+    return sdap_id_setup_tasks(ctx->be, ctx, ctx->opts->sdom,
-                                ldap_enumeration_send,
--                               ldap_enumeration_recv);
-+                               ldap_enumeration_recv,
-+                               ctx);
- }
- 
--int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
--                        struct sdap_id_conn_ctx *conn,
-+int sdap_id_setup_tasks(struct be_ctx *be_ctx,
-+                        struct sdap_id_ctx *ctx,
-                         struct sdap_domain *sdom,
-                         be_ptask_send_t send_fn,
--                        be_ptask_recv_t recv_fn)
-+                        be_ptask_recv_t recv_fn,
-+                        void *pvt)
- {
-     int ret;
- 
-@@ -991,7 +993,8 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
-     if (sdom->dom->enumerate) {
-         DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n",
-                                   sdom->dom->name));
--        ret = ldap_setup_enumeration(ctx, conn, sdom, send_fn, recv_fn);
-+        ret = ldap_setup_enumeration(be_ctx, ctx->opts, sdom,
-+                                     send_fn, recv_fn, pvt);
-     } else {
-         /* the enumeration task, runs the cleanup process by itself,
-          * but if enumeration is not running we need to schedule it */
-diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
-index b3bd950e1dca6df0f5668397d5e5a0796e519862..889d5b118861e4ea3f51ab8a8ea5c5947e2560b9 100644
---- a/src/providers/ldap/ldap_common.h
-+++ b/src/providers/ldap/ldap_common.h
-@@ -95,11 +95,12 @@ void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx,
- 
- /* Set up enumeration and/or cleanup */
- int ldap_id_setup_tasks(struct sdap_id_ctx *ctx);
--int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
--                        struct sdap_id_conn_ctx *conn,
-+int sdap_id_setup_tasks(struct be_ctx *be_ctx,
-+                        struct sdap_id_ctx *ctx,
-                         struct sdap_domain *sdom,
-                         be_ptask_send_t send_fn,
--                        be_ptask_recv_t recv_fn);
-+                        be_ptask_recv_t recv_fn,
-+                        void *pvt);
- 
- struct tevent_req *
- sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
-@@ -177,16 +178,16 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
-  * structure that contains the request data
-  */
- struct ldap_enum_ctx {
--    struct sdap_id_ctx *ctx;
-     struct sdap_domain *sdom;
--    struct sdap_id_conn_ctx *conn;
-+    void *pvt;
- };
- 
--errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
--                               struct sdap_id_conn_ctx *conn,
-+errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
-+                               struct sdap_options *opts,
-                                struct sdap_domain *sdom,
-                                be_ptask_send_t send_fn,
--                               be_ptask_recv_t recv_fn);
-+                               be_ptask_recv_t recv_fn,
-+                               void *pvt);
- struct tevent_req *
- ldap_enumeration_send(TALLOC_CTX *mem_ctx,
-                       struct tevent_context *ev,
-diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
-index 8cccaa916a24beb10fe692d9a0e09f5f47ceb6f7..c791496a6143b23118bf17a58f738fb0bfb5f95a 100644
---- a/src/providers/ldap/ldap_id_enum.c
-+++ b/src/providers/ldap/ldap_id_enum.c
-@@ -27,11 +27,12 @@
- #include "providers/ldap/ldap_common.h"
- #include "providers/ldap/sdap_async_enum.h"
- 
--errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
--                               struct sdap_id_conn_ctx *conn,
-+errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
-+                               struct sdap_options *opts,
-                                struct sdap_domain *sdom,
-                                be_ptask_send_t send_fn,
--                               be_ptask_recv_t recv_fn)
-+                               be_ptask_recv_t recv_fn,
-+                               void *pvt)
- {
-     errno_t ret;
-     time_t first_delay;
-@@ -60,17 +61,16 @@ errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
-         first_delay = 0;
-     }
- 
--    period = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-+    period = dp_opt_get_int(opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
- 
-     ectx = talloc(sdom, struct ldap_enum_ctx);
-     if (ectx == NULL) {
-         return ENOMEM;
-     }
--    ectx->ctx = ctx;
-     ectx->sdom = sdom;
--    ectx->conn = conn;
-+    ectx->pvt = pvt;
- 
--    ret = be_ptask_create(sdom, ctx->be,
-+    ret = be_ptask_create(sdom, be_ctx,
-                           period,                   /* period */
-                           first_delay,              /* first_delay */
-                           5,                        /* enabled delay */
-@@ -91,6 +91,7 @@ errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
- 
- struct ldap_enumeration_state {
-     struct ldap_enum_ctx *ectx;
-+    struct sdap_id_ctx *id_ctx;
-     struct sss_domain_info *dom;
- };
- 
-@@ -118,14 +119,16 @@ ldap_enumeration_send(TALLOC_CTX *mem_ctx,
- 
-     ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
-     if (ectx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n"));
-         ret = EFAULT;
-         goto fail;
-     }
-     state->ectx = ectx;
-     state->dom = ectx->sdom->dom;
-+    state->id_ctx = talloc_get_type_abort(ectx->pvt, struct sdap_id_ctx);
- 
--    subreq = sdap_dom_enum_send(ectx, ev, ectx->ctx, ectx->sdom,
--                                ectx->conn);
-+    subreq = sdap_dom_enum_send(ectx, ev, state->id_ctx, ectx->sdom,
-+                                state->id_ctx->conn);
-     if (subreq == NULL) {
-         /* The ptask API will reschedule the enumeration on its own on
-          * failure */
--- 
-1.8.4.2
-
diff --git a/SOURCES/0067-LDAP-Add-enum-request-with-custom-connection.patch b/SOURCES/0067-LDAP-Add-enum-request-with-custom-connection.patch
deleted file mode 100644
index 04b5e24..0000000
--- a/SOURCES/0067-LDAP-Add-enum-request-with-custom-connection.patch
+++ /dev/null
@@ -1,482 +0,0 @@
-From 431198674303beea2a6a25af6d3fa4e852995b26 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 16 Dec 2013 02:41:53 +0100
-Subject: [PATCH 67/71] LDAP: Add enum request with custom connection
-
-This commit changes the enumerate-sdap-domain request to accept a
-connection context per object that can be enumerated. Internally in the
-request, an sdap_id_op is also created per enumerated object type.
-
-This change will allow i.e. users to be enumerated using GC connection,
-while keeping the LDAP connection for groups and services.
----
- src/providers/ldap/sdap_async_enum.c | 309 +++++++++++++++++++++--------------
- src/providers/ldap/sdap_async_enum.h |  11 ++
- 2 files changed, 193 insertions(+), 127 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index 8487f9a13b279bc71f633590bbab163945fc8f7c..cbc56be20526e6c2323f9fd1b49038dd4bf13fe5 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -47,49 +47,56 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
-                                           bool purge);
- static errno_t enum_groups_recv(struct tevent_req *req);
- 
--/* ==Enumeration-Request==================================================== */
--struct sdap_dom_enum_state {
-+/* ==Enumeration-Request-with-connections=================================== */
-+struct sdap_dom_enum_ex_state {
-     struct tevent_context *ev;
-     struct sdap_id_ctx *ctx;
-     struct sdap_domain *sdom;
--    struct sdap_id_conn_ctx *conn;
--    struct sdap_id_op *op;
-+
-+    struct sdap_id_conn_ctx *user_conn;
-+    struct sdap_id_conn_ctx *group_conn;
-+    struct sdap_id_conn_ctx *svc_conn;
-+    struct sdap_id_op *user_op;
-+    struct sdap_id_op *group_op;
-+    struct sdap_id_op *svc_op;
- 
-     bool purge;
- };
- 
--static errno_t sdap_dom_enum_retry(struct tevent_req *req);
--static void sdap_dom_enum_conn_done(struct tevent_req *subreq);
--static void sdap_dom_enum_users_done(struct tevent_req *subreq);
--static void sdap_dom_enum_groups_done(struct tevent_req *subreq);
--static void sdap_dom_enum_services_done(struct tevent_req *subreq);
-+static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
-+                                      struct sdap_id_op *op,
-+                                      tevent_req_fn tcb);
-+static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq);
- 
- struct tevent_req *
--sdap_dom_enum_send(TALLOC_CTX *memctx,
--                   struct tevent_context *ev,
--                   struct sdap_id_ctx *ctx,
--                   struct sdap_domain *sdom,
--                   struct sdap_id_conn_ctx *conn)
-+sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
-+                      struct tevent_context *ev,
-+                      struct sdap_id_ctx *ctx,
-+                      struct sdap_domain *sdom,
-+                      struct sdap_id_conn_ctx *user_conn,
-+                      struct sdap_id_conn_ctx *group_conn,
-+                      struct sdap_id_conn_ctx *svc_conn)
- {
-     struct tevent_req *req;
--    struct sdap_dom_enum_state *state;
-+    struct sdap_dom_enum_ex_state *state;
-     int t;
-     errno_t ret;
- 
--    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_state);
--    if (!req) return NULL;
-+    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_ex_state);
-+    if (req == NULL) return NULL;
- 
-     state->ev = ev;
-     state->ctx = ctx;
-     state->sdom = sdom;
--    state->conn = conn;
--    state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
--    if (!state->op) {
--        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed\n"));
--        ret = EIO;
--        goto fail;
--    }
--
-+    state->user_conn = user_conn;
-+    state->group_conn = group_conn;
-+    state->svc_conn = svc_conn;
-     sdom->last_enum = tevent_timeval_current();
- 
-     t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-@@ -97,9 +104,17 @@ sdap_dom_enum_send(TALLOC_CTX *memctx,
-         state->purge = true;
-     }
- 
--    ret = sdap_dom_enum_retry(req);
-+    state->user_op = sdap_id_op_create(state, user_conn->conn_cache);
-+    if (state->user_op == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for users\n"));
-+        ret = EIO;
-+        goto fail;
-+    }
-+
-+    ret = sdap_dom_enum_ex_retry(req, state->user_op,
-+                                 sdap_dom_enum_ex_get_users);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, ("ldap_id_enumerate_retry failed\n"));
-+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_dom_enum_ex_retry failed\n"));
-         goto fail;
-     }
- 
-@@ -111,31 +126,32 @@ fail:
-     return req;
- }
- 
--static errno_t sdap_dom_enum_retry(struct tevent_req *req)
-+static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
-+                                      struct sdap_id_op *op,
-+                                      tevent_req_fn tcb)
- {
--    struct sdap_dom_enum_state *state = tevent_req_data(req,
--                                                   struct sdap_dom_enum_state);
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-     struct tevent_req *subreq;
-     errno_t ret;
- 
--    subreq = sdap_id_op_connect_send(state->op, state, &ret);
-+    subreq = sdap_id_op_connect_send(op, state, &ret);
-     if (subreq == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("sdap_id_op_connect_send failed: %d\n", ret));
-         return ret;
-     }
- 
--    tevent_req_set_callback(subreq, sdap_dom_enum_conn_done, req);
-+    tevent_req_set_callback(subreq, tcb, req);
-     return EOK;
- }
- 
--static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
-+static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq)
- {
-+    errno_t ret;
-+    int dp_error;
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct sdap_dom_enum_state *state = tevent_req_data(req,
--                                                   struct sdap_dom_enum_state);
--    int ret, dp_error;
- 
-     ret = sdap_id_op_connect_recv(subreq, &dp_error);
-     talloc_zfree(subreq);
-@@ -150,150 +166,173 @@ static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
-                    "LDAP server: (%d)[%s]\n", ret, strerror(ret)));
-             tevent_req_error(req, ret);
-         }
-+        return false;
-+    }
-+
-+    return true;
-+}
-+
-+static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+
-+    if (sdap_dom_enum_ex_connected(subreq) == false) {
-         return;
-     }
- 
-     subreq = enum_users_send(state, state->ev,
-                              state->ctx, state->sdom,
--                             state->op, state->purge);
-+                             state->user_op, state->purge);
-     if (subreq == NULL) {
-         tevent_req_error(req, ENOMEM);
-         return;
-     }
--    tevent_req_set_callback(subreq, sdap_dom_enum_users_done, req);
-+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req);
- }
- 
--static void sdap_dom_enum_users_done(struct tevent_req *subreq)
-+static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct sdap_dom_enum_state *state = tevent_req_data(req,
--                                                   struct sdap_dom_enum_state);
--    uint64_t err = 0;
--    int ret, dp_error = DP_ERR_FATAL;
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+    errno_t ret;
-+    int dp_error;
- 
--    err = enum_users_recv(subreq);
-+    ret = enum_users_recv(subreq);
-     talloc_zfree(subreq);
--    if (err != EOK && err != ENOENT) {
--        /* We call sdap_id_op_done only on error
--         * as the connection is reused by groups enumeration */
--        ret = sdap_id_op_done(state->op, (int)err, &dp_error);
--        if (dp_error == DP_ERR_OK) {
--            /* retry */
--            ret = sdap_dom_enum_retry(req);
--            if (ret == EOK) {
--                return;
--            }
--
--            dp_error = DP_ERR_FATAL;
--        }
--
--        if (dp_error == DP_ERR_OFFLINE) {
--            tevent_req_done(req);
--        } else {
--            DEBUG(SSSDBG_OP_FAILURE,
--                  ("User enumeration failed with: (%d)[%s]\n",
--                   ret, strerror(ret)));
-+    ret = sdap_id_op_done(state->user_op, ret, &dp_error);
-+    if (dp_error == DP_ERR_OK && ret != EOK) {
-+        /* retry */
-+        ret = sdap_dom_enum_ex_retry(req, state->user_op,
-+                                     sdap_dom_enum_ex_get_users);
-+        if (ret != EOK) {
-             tevent_req_error(req, ret);
-+            return;
-         }
-         return;
-     }
- 
-+    state->group_op = sdap_id_op_create(state, state->group_conn->conn_cache);
-+    if (state->group_op == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for groups\n"));
-+        tevent_req_error(req, EIO);
-+        return;
-+    }
-+
-+    ret = sdap_dom_enum_ex_retry(req, state->group_op,
-+                                 sdap_dom_enum_ex_get_groups);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    /* Continues to sdap_dom_enum_ex_get_groups */
-+}
-+
-+static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+
-+    if (sdap_dom_enum_ex_connected(subreq) == false) {
-+        return;
-+    }
-+
-     subreq = enum_groups_send(state, state->ev, state->ctx,
-                               state->sdom,
--                              state->op, state->purge);
-+                              state->group_op, state->purge);
-     if (subreq == NULL) {
-         tevent_req_error(req, ENOMEM);
-         return;
-     }
--    tevent_req_set_callback(subreq, sdap_dom_enum_groups_done, req);
-+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_groups_done, req);
- }
- 
--static void sdap_dom_enum_groups_done(struct tevent_req *subreq)
-+static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct sdap_dom_enum_state *state = tevent_req_data(req,
--                                                   struct sdap_dom_enum_state);
--    uint64_t err = 0;
--    int ret, dp_error = DP_ERR_FATAL;
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+    int ret;
-+    int dp_error;
- 
--    err = enum_groups_recv(subreq);
-+    ret = enum_groups_recv(subreq);
-     talloc_zfree(subreq);
--    if (err != EOK && err != ENOENT) {
--        /* We call sdap_id_op_done only on error
--         * as the connection is reused by services enumeration */
--        ret = sdap_id_op_done(state->op, (int)err, &dp_error);
--        if (dp_error == DP_ERR_OK && ret != EOK) {
--            /* retry */
--            ret = sdap_dom_enum_retry(req);
--            if (ret == EOK) {
--                return;
--            }
--
--            dp_error = DP_ERR_FATAL;
--        }
--
-+    ret = sdap_id_op_done(state->group_op, ret, &dp_error);
-+    if (dp_error == DP_ERR_OK && ret != EOK) {
-+        /* retry */
-+        ret = sdap_dom_enum_ex_retry(req, state->group_op,
-+                                     sdap_dom_enum_ex_get_groups);
-         if (ret != EOK) {
--            if (dp_error == DP_ERR_OFFLINE) {
--                tevent_req_done(req);
--            } else {
--                DEBUG(SSSDBG_OP_FAILURE,
--                      ("Group enumeration failed with: (%d)[%s]\n",
--                       ret, strerror(ret)));
--                tevent_req_error(req, ret);
--            }
--
-+            tevent_req_error(req, ret);
-             return;
-         }
-+        return;
-+    }
-+
-+
-+    state->svc_op = sdap_id_op_create(state, state->svc_conn->conn_cache);
-+    if (state->svc_op == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for svcs\n"));
-+        tevent_req_error(req, EIO);
-+        return;
-+    }
-+
-+    ret = sdap_dom_enum_ex_retry(req, state->svc_op,
-+                                 sdap_dom_enum_ex_get_svcs);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+}
-+
-+static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+
-+    if (sdap_dom_enum_ex_connected(subreq) == false) {
-+        return;
-     }
- 
-     subreq = enum_services_send(state, state->ev, state->ctx,
--                                state->op, state->purge);
-+                                state->svc_op, state->purge);
-     if (!subreq) {
-         tevent_req_error(req, ENOMEM);
-         return;
-     }
--    tevent_req_set_callback(subreq, sdap_dom_enum_services_done, req);
-+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_svcs_done, req);
- }
- 
--static void sdap_dom_enum_services_done(struct tevent_req *subreq)
-+static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq)
- {
--    errno_t ret;
--    int dp_error = DP_ERR_FATAL;
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct sdap_dom_enum_state *state = tevent_req_data(req,
--                                                   struct sdap_dom_enum_state);
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+    int ret;
-+    int dp_error;
- 
-     ret = enum_services_recv(subreq);
-     talloc_zfree(subreq);
--    if (ret == ENOENT) ret = EOK;
--
--    /* All enumerations are complete, so conclude the
--     * id_op
--     */
--    ret = sdap_id_op_done(state->op, ret, &dp_error);
-+    ret = sdap_id_op_done(state->svc_op, ret, &dp_error);
-     if (dp_error == DP_ERR_OK && ret != EOK) {
-         /* retry */
--        ret = sdap_dom_enum_retry(req);
--        if (ret == EOK) {
--            return;
--        }
--
--        dp_error = DP_ERR_FATAL;
--    }
--
--    if (ret != EOK) {
--        if (dp_error == DP_ERR_OFFLINE) {
--            tevent_req_done(req);
--        } else {
--            DEBUG(SSSDBG_MINOR_FAILURE,
--                  ("Service enumeration failed with: (%d)[%s]\n",
--                   ret, strerror(ret)));
-+        ret = sdap_dom_enum_ex_retry(req, state->user_op,
-+                                     sdap_dom_enum_ex_get_svcs);
-+        if (ret != EOK) {
-             tevent_req_error(req, ret);
-+            return;
-         }
--
-         return;
-     }
- 
-@@ -323,11 +362,27 @@ static void sdap_dom_enum_services_done(struct tevent_req *subreq)
-     tevent_req_done(req);
- }
- 
-+errno_t sdap_dom_enum_ex_recv(struct tevent_req *req)
-+{
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-+
-+/* ==Enumeration-Request==================================================== */
-+struct tevent_req *
-+sdap_dom_enum_send(TALLOC_CTX *memctx,
-+                   struct tevent_context *ev,
-+                   struct sdap_id_ctx *ctx,
-+                   struct sdap_domain *sdom,
-+                   struct sdap_id_conn_ctx *conn)
-+{
-+    return sdap_dom_enum_ex_send(memctx, ev, ctx, sdom, conn, conn, conn);
-+}
-+
- errno_t sdap_dom_enum_recv(struct tevent_req *req)
- {
--    TEVENT_REQ_RETURN_ON_ERROR(req);
--
--    return EOK;
-+    return sdap_dom_enum_ex_recv(req);
- }
- 
- /* ==User-Enumeration===================================================== */
-diff --git a/src/providers/ldap/sdap_async_enum.h b/src/providers/ldap/sdap_async_enum.h
-index 04ec8c6dcbec4bcce0de67b9e10acc857c9e9416..2da38f988913fa0d6f252697925e50e05eb794a6 100644
---- a/src/providers/ldap/sdap_async_enum.h
-+++ b/src/providers/ldap/sdap_async_enum.h
-@@ -27,6 +27,17 @@
- #define _SDAP_ASYNC_ENUM_H_
- 
- struct tevent_req *
-+sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
-+                      struct tevent_context *ev,
-+                      struct sdap_id_ctx *ctx,
-+                      struct sdap_domain *sdom,
-+                      struct sdap_id_conn_ctx *user_conn,
-+                      struct sdap_id_conn_ctx *group_conn,
-+                      struct sdap_id_conn_ctx *svc_conn);
-+
-+errno_t sdap_dom_enum_ex_recv(struct tevent_req *req);
-+
-+struct tevent_req *
- sdap_dom_enum_send(TALLOC_CTX *memctx,
-                    struct tevent_context *ev,
-                    struct sdap_id_ctx *ctx,
--- 
-1.8.4.2
-
diff --git a/SOURCES/0067-LDAP-read-the-correct-data-type-from-ldap_child-s-in.patch b/SOURCES/0067-LDAP-read-the-correct-data-type-from-ldap_child-s-in.patch
new file mode 100644
index 0000000..4b66c75
--- /dev/null
+++ b/SOURCES/0067-LDAP-read-the-correct-data-type-from-ldap_child-s-in.patch
@@ -0,0 +1,34 @@
+From 9524f859a730ef39852ecbba5638f26ab677cdd7 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 19 Oct 2014 19:20:28 +0200
+Subject: [PATCH 67/71] LDAP: read the correct data type from ldap_child's
+ input buffer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The back end wrote uint32_t, the ldap_child process would read int32_t.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/providers/ldap/ldap_child.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
+index b8b4b0ad7cfffc7db52b5ca3d9b9a74f12480070..e1abc9fd73f2ae95f0a0c28159589ebd36d2cf06 100644
+--- a/src/providers/ldap/ldap_child.c
++++ b/src/providers/ldap/ldap_child.c
+@@ -96,8 +96,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
+     }
+ 
+     /* ticket lifetime */
+-    SAFEALIGN_COPY_INT32_CHECK(&ibuf->lifetime, buf + p, size, &p);
+-    DEBUG(SSSDBG_TRACE_LIBS, "lifetime: %d\n", ibuf->lifetime);
++    SAFEALIGN_COPY_UINT32_CHECK(&ibuf->lifetime, buf + p, size, &p);
++    DEBUG(SSSDBG_TRACE_LIBS, "lifetime: %u\n", ibuf->lifetime);
+ 
+     return EOK;
+ }
+-- 
+1.9.3
+
diff --git a/SOURCES/0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch b/SOURCES/0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch
deleted file mode 100644
index b8b61b9..0000000
--- a/SOURCES/0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 1a077f0af935497b972a763a7027924a65476b01 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 28 Jan 2014 13:59:44 +0100
-Subject: [PATCH 68/71] AD: Enumerate users from GC, other entities from LDAP
-
----
- src/providers/ad/ad_id.c | 20 +++++++++++++++++---
- 1 file changed, 17 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 99383c13bdadfe9eb2af9f9323ca19a9759d4620..a47aa4f75ab348b0f4597fea264d770b5abe3184 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -526,6 +526,7 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-     char *flat_name;
-     char *master_sid;
-     char *forest;
-+    struct sdap_id_conn_ctx *user_conn;
- 
-     ret = ad_master_domain_recv(subreq, state,
-                                 &flat_name, &master_sid, &forest);
-@@ -544,8 +545,21 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    subreq = sdap_dom_enum_send(state, state->ev, state->id_ctx->sdap_id_ctx,
--                                state->sdom, state->id_ctx->ldap_ctx);
-+    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
-+        user_conn = state->id_ctx->gc_ctx;
-+    } else {
-+        user_conn = state->id_ctx->ldap_ctx;
-+    }
-+
-+    /* Groups are searched for in LDAP, users in GC. Services (if present,
-+     * which is unlikely in AD) from LDAP as well
-+     */
-+    subreq = sdap_dom_enum_ex_send(state, state->ev,
-+                                   state->id_ctx->sdap_id_ctx,
-+                                   state->sdom,
-+                                   user_conn,                /* Users    */
-+                                   state->id_ctx->ldap_ctx,  /* Groups   */
-+                                   state->id_ctx->ldap_ctx); /* Services */
-     if (subreq == NULL) {
-         /* The ptask API will reschedule the enumeration on its own on
-          * failure */
-@@ -566,7 +580,7 @@ ad_enumeration_done(struct tevent_req *subreq)
-     struct ad_enumeration_state *state = tevent_req_data(req,
-                                                 struct ad_enumeration_state);
- 
--    ret = sdap_dom_enum_recv(subreq);
-+    ret = sdap_dom_enum_ex_recv(subreq);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
--- 
-1.8.4.2
-
diff --git a/SOURCES/0068-LDAP-Drop-privileges-after-kinit-in-ldap_child.patch b/SOURCES/0068-LDAP-Drop-privileges-after-kinit-in-ldap_child.patch
new file mode 100644
index 0000000..fef3059
--- /dev/null
+++ b/SOURCES/0068-LDAP-Drop-privileges-after-kinit-in-ldap_child.patch
@@ -0,0 +1,214 @@
+From 954637494fc8453f71e2b5d93b3d1ea97e31d646 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 19 Oct 2014 19:15:52 +0200
+Subject: [PATCH 68/71] LDAP: Drop privileges after kinit in ldap_child
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+After ldap_child initializes privileges using root-owned keytab, it
+drops privileges to the SSSD user, minimizing the amount of code that
+runs as root.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ Makefile.am                             |  4 +-
+ src/providers/ldap/ldap_child.c         | 96 ++++++++++++++++++++-------------
+ src/providers/ldap/sdap_child_helpers.c |  8 ++-
+ 3 files changed, 70 insertions(+), 38 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 02b087ea37b4e55da7eeb7fb199d282d72129e40..ea296c40f89c552d5825cbce8e95afdc517e8bb5 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2517,7 +2517,9 @@ ldap_child_SOURCES = \
+     src/util/atomic_io.c \
+     src/util/authtok.c \
+     src/util/util.c \
+-    src/util/signal.c
++    src/util/signal.c \
++    src/util/become_user.c \
++    $(NULL)
+ ldap_child_CFLAGS = \
+     $(AM_CFLAGS) \
+     $(POPT_CFLAGS) \
+diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
+index e1abc9fd73f2ae95f0a0c28159589ebd36d2cf06..a922b181715c5e89301e9f50bdb81723d1ff2a6a 100644
+--- a/src/providers/ldap/ldap_child.c
++++ b/src/providers/ldap/ldap_child.c
+@@ -49,6 +49,8 @@ struct input_buffer {
+     const char *princ_str;
+     const char *keytab_name;
+     krb5_deltat lifetime;
++    uid_t uid;
++    gid_t gid;
+ };
+ 
+ static errno_t unpack_buffer(uint8_t *buf, size_t size,
+@@ -99,6 +101,12 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
+     SAFEALIGN_COPY_UINT32_CHECK(&ibuf->lifetime, buf + p, size, &p);
+     DEBUG(SSSDBG_TRACE_LIBS, "lifetime: %u\n", ibuf->lifetime);
+ 
++    /* UID and GID to run as */
++    SAFEALIGN_COPY_UINT32_CHECK(&ibuf->uid, buf + p, size, &p);
++    SAFEALIGN_COPY_UINT32_CHECK(&ibuf->gid, buf + p, size, &p);
++    DEBUG(SSSDBG_FUNC_DATA,
++          "Will run as [%"SPRIuid"][%"SPRIgid"].\n", ibuf->uid, ibuf->gid);
++
+     return EOK;
+ }
+ 
+@@ -242,6 +250,8 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+                                                const char *princ_str,
+                                                const char *keytab_name,
+                                                const krb5_deltat lifetime,
++                                               uid_t uid,
++                                               gid_t gid,
+                                                const char **ccname_out,
+                                                time_t *expire_time_out)
+ {
+@@ -372,42 +382,6 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+         goto done;
+     }
+ 
+-    ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX",
+-                                        DB_PATH, realm_name);
+-    ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s",
+-                                  DB_PATH, realm_name);
+-    if (ccname_file_dummy == NULL || ccname_file == NULL) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    old_umask = umask(077);
+-    fd = mkstemp(ccname_file_dummy);
+-    umask(old_umask);
+-    if (fd == -1) {
+-        ret = errno;
+-        goto done;
+-    }
+-    /* We only care about creating a unique file name here, we don't
+-     * need the fd
+-     */
+-    close(fd);
+-
+-    ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy);
+-    ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file);
+-    if (ccname_dummy == NULL || ccname == NULL) {
+-        krberr = ENOMEM;
+-        goto done;
+-    }
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy);
+-
+-    krberr = krb5_cc_resolve(context, ccname_dummy, &ccache);
+-    if (krberr) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n",
+-                  sss_krb5_get_error_message(context, krberr));
+-        goto done;
+-    }
+-
+     memset(&my_creds, 0, sizeof(my_creds));
+     memset(&options, 0, sizeof(options));
+ 
+@@ -423,8 +397,36 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+     }
+     sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize);
+ 
++    ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s",
++                                  DB_PATH, realm_name);
++    if (ccname_file == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX",
++                                        DB_PATH, realm_name);
++    if (ccname_file_dummy == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    old_umask = umask(077);
++    fd = mkstemp(ccname_file_dummy);
++    umask(old_umask);
++    if (fd == -1) {
++        ret = errno;
++        goto done;
++    }
++    /* We only care about creating a unique file name here, we don't
++     * need the fd
++     */
++    close(fd);
++
+     krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc,
+                                         keytab, 0, NULL, &options);
++    krb5_kt_close(context, keytab);
++    keytab = NULL;
+     if (krberr) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "Failed to init credentials: %s\n",
+@@ -438,6 +440,27 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+     }
+     DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n");
+ 
++    krberr = become_user(uid, gid);
++    if (krberr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
++        goto done;
++    }
++
++    ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy);
++    ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file);
++    if (ccname_dummy == NULL || ccname == NULL) {
++        krberr = ENOMEM;
++        goto done;
++    }
++    DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy);
++
++    krberr = krb5_cc_resolve(context, ccname_dummy, &ccache);
++    if (krberr) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n",
++                  sss_krb5_get_error_message(context, krberr));
++        goto done;
++    }
++
+     /* Use updated principal if changed due to canonicalization. */
+     krberr = krb5_cc_initialize(context, ccache, my_creds.client);
+     if (krberr) {
+@@ -643,6 +666,7 @@ int main(int argc, const char *argv[])
+     kerr = ldap_child_get_tgt_sync(main_ctx,
+                                    ibuf->realm_str, ibuf->princ_str,
+                                    ibuf->keytab_name, ibuf->lifetime,
++                                   ibuf->uid, ibuf->gid,
+                                    &ccname, &expire_time);
+     if (kerr != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child_get_tgt_sync failed.\n");
+diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c
+index 448c5af10e9da8949bcaa39d8a3fa05ec309e16f..e5d46b9b756cd50fadb212da72ad1cc9bdd93330 100644
+--- a/src/providers/ldap/sdap_child_helpers.c
++++ b/src/providers/ldap/sdap_child_helpers.c
+@@ -152,7 +152,7 @@ static errno_t create_tgt_req_send_buffer(TALLOC_CTX *mem_ctx,
+         return ENOMEM;
+     }
+ 
+-    buf->size = 4 * sizeof(uint32_t);
++    buf->size = 6 * sizeof(uint32_t);
+     if (realm_str) {
+         buf->size += strlen(realm_str);
+     }
+@@ -201,6 +201,12 @@ static errno_t create_tgt_req_send_buffer(TALLOC_CTX *mem_ctx,
+     /* lifetime */
+     SAFEALIGN_SET_UINT32(&buf->data[rp], lifetime, &rp);
+ 
++    /* UID and GID to drop privileges to, if needed. The ldap_child process runs as
++     * setuid if the back end runs unprivileged as it needs to access the keytab
++     */
++    SAFEALIGN_SET_UINT32(&buf->data[rp], geteuid(), &rp);
++    SAFEALIGN_SET_UINT32(&buf->data[rp], getegid(), &rp);
++
+     *io_buf = buf;
+     return EOK;
+ }
+-- 
+1.9.3
+
diff --git a/SOURCES/0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch b/SOURCES/0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch
deleted file mode 100644
index 7523a4a..0000000
--- a/SOURCES/0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-From 37722379349e257e2e77583e515ceafa3eee804c Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 21 Jan 2014 23:40:17 +0100
-Subject: [PATCH 69/71] LDAP: Don't clobber original_member during enumeration
-
----
- src/providers/ldap/sdap_async_groups.c | 17 +++++++++++------
- 1 file changed, 11 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 9eece9a6e4baaf302a28b57a63dae45a0741136c..4ed7d4ab9c0c932da49b244f061329a334719159 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -807,6 +807,7 @@ static int sdap_save_groups(TALLOC_CTX *memctx,
-                             int num_groups,
-                             bool populate_members,
-                             hash_table_t *ghosts,
-+                            bool save_orig_member,
-                             char **_usn_value)
- {
-     TALLOC_CTX *tmpctx;
-@@ -864,9 +865,9 @@ static int sdap_save_groups(TALLOC_CTX *memctx,
-         usn_value = NULL;
- 
-         /* if 2 pass savemembers = false */
--        ret = sdap_save_group(tmpctx, sysdb,
--                              opts, dom, groups[i],
--                              populate_members, has_nesting,
-+        ret = sdap_save_group(tmpctx, sysdb, opts, dom, groups[i],
-+                              populate_members,
-+                              has_nesting && save_orig_member,
-                               ghosts, &usn_value, now);
- 
-         /* Do not fail completely on errors.
-@@ -1835,7 +1836,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-                   "to allow unrolling of nested groups.\n"));
-         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
-                                state->groups, state->count, false,
--                               NULL, NULL);
-+                               NULL, true, NULL);
-         if (ret) {
-             DEBUG(2, ("Failed to store groups.\n"));
-             tevent_req_error(req, ret);
-@@ -1887,10 +1888,14 @@ static void sdap_get_groups_done(struct tevent_req *subreq)
- 
-         /* If ignore_group_members is set for the domain, don't update
-          * group memberships in the cache.
-+         *
-+         * If enumeration is on, don't overwrite orig_members as they've been
-+         * saved earlier.
-          */
-         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
-                                state->groups, state->count,
-                                !state->dom->ignore_group_members, NULL,
-+                               !state->enumeration,
-                                &state->higher_usn);
-         if (ret) {
-             DEBUG(2, ("Failed to store groups.\n"));
-@@ -2014,7 +2019,7 @@ static void sdap_ad_match_rule_members_process(struct tevent_req *subreq)
-     /* Now save the group, users and ghosts to the cache */
-     ret = sdap_save_groups(tmp_ctx, state->sysdb, state->dom,
-                            state->opts, state->groups, 1,
--                           false, ghosts, NULL);
-+                           false, ghosts, true, NULL);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
-               ("Could not save group to the cache: [%s]\n",
-@@ -2090,7 +2095,7 @@ static void sdap_nested_done(struct tevent_req *subreq)
-     }
- 
-     ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
--                           groups, group_count, false, ghosts,
-+                           groups, group_count, false, ghosts, true,
-                            &state->higher_usn);
-     if (ret != EOK) {
-         goto fail;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0069-UTIL-Remove-code-duplication-of-struct-io.patch b/SOURCES/0069-UTIL-Remove-code-duplication-of-struct-io.patch
new file mode 100644
index 0000000..6f7d29d
--- /dev/null
+++ b/SOURCES/0069-UTIL-Remove-code-duplication-of-struct-io.patch
@@ -0,0 +1,218 @@
+From 093ac8b41e4baefd2c1102fb897367318de12fb3 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 Oct 2014 12:29:55 +0200
+Subject: [PATCH 69/71] UTIL: Remove code duplication of struct io
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We had struct io and the associated destructor copied twice in the code
+already and need it again in the SELinux provider. Instead of adding
+another copy, move the code to a shared subtree under util/
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/providers/ad/ad_gpo.c               | 43 +++------------------------------
+ src/providers/krb5/krb5_child_handler.c | 38 ++---------------------------
+ src/util/child_common.c                 | 29 ++++++++++++++++++++++
+ src/util/child_common.h                 |  7 ++++++
+ 4 files changed, 41 insertions(+), 76 deletions(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 4dfbd4b6943b477bd93fdd730dfa5b1c5828a10a..80b0d45c2861a64f01fe7835cccee4348084c7da 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3756,46 +3756,9 @@ struct ad_gpo_process_cse_state {
+     pid_t child_pid;
+     uint8_t *buf;
+     ssize_t len;
+-    struct io *io;
++    struct child_io_fds *io;
+ };
+ 
+-struct io {
+-    int read_from_child_fd;
+-    int write_to_child_fd;
+-};
+-
+-static errno_t
+-gpo_child_io_destructor(void *ptr)
+-{
+-    int ret;
+-    struct io *io;
+-
+-    io = talloc_get_type(ptr, struct io);
+-    if (io == NULL) return EOK;
+-
+-    if (io->write_to_child_fd != -1) {
+-        ret = close(io->write_to_child_fd);
+-        io->write_to_child_fd = -1;
+-        if (ret != EOK) {
+-            ret = errno;
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "close failed [%d][%s].\n", ret, strerror(ret));
+-        }
+-    }
+-
+-    if (io->read_from_child_fd != -1) {
+-        ret = close(io->read_from_child_fd);
+-        io->read_from_child_fd = -1;
+-        if (ret != EOK) {
+-            ret = errno;
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "close failed [%d][%s].\n", ret, strerror(ret));
+-        }
+-    }
+-
+-    return EOK;
+-}
+-
+ static errno_t gpo_fork_child(struct tevent_req *req);
+ static void gpo_cse_step(struct tevent_req *subreq);
+ static void gpo_cse_done(struct tevent_req *subreq);
+@@ -3849,7 +3812,7 @@ ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
+     state->gpo_guid = gpo_guid;
+     state->smb_path = smb_path;
+     state->smb_cse_suffix = smb_cse_suffix;
+-    state->io = talloc(state, struct io);
++    state->io = talloc(state, struct child_io_fds);
+     if (state->io == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
+         ret = ENOMEM;
+@@ -3858,7 +3821,7 @@ ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
+ 
+     state->io->write_to_child_fd = -1;
+     state->io->read_from_child_fd = -1;
+-    talloc_set_destructor((void *) state->io, gpo_child_io_destructor);
++    talloc_set_destructor((void *) state->io, child_io_destructor);
+ 
+     /* prepare the data to pass to child */
+     ret = create_cse_send_buffer(state, smb_server, smb_share, smb_path,
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 114e72a33e48da299647c2fe3096b9bf61cf294a..4ba939deb3e0e282b3ca9b2b21226ea7e64e311b 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -41,11 +41,6 @@
+ #define TIME_T_MAX LONG_MAX
+ #define int64_to_time_t(val) ((time_t)((val) < TIME_T_MAX ? val : TIME_T_MAX))
+ 
+-struct io {
+-    int read_from_child_fd;
+-    int write_to_child_fd;
+-};
+-
+ struct handle_child_state {
+     struct tevent_context *ev;
+     struct krb5child_req *kr;
+@@ -55,38 +50,9 @@ struct handle_child_state {
+     struct tevent_timer *timeout_handler;
+     pid_t child_pid;
+ 
+-    struct io *io;
++    struct child_io_fds *io;
+ };
+ 
+-static int child_io_destructor(void *ptr)
+-{
+-    int ret;
+-    struct io *io = talloc_get_type(ptr, struct io);
+-    if (io == NULL) return EOK;
+-
+-    if (io->write_to_child_fd != -1) {
+-        ret = close(io->write_to_child_fd);
+-        io->write_to_child_fd = -1;
+-        if (ret != EOK) {
+-            ret = errno;
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "close failed [%d][%s].\n", ret, strerror(ret));
+-        }
+-    }
+-
+-    if (io->read_from_child_fd != -1) {
+-        ret = close(io->read_from_child_fd);
+-        io->read_from_child_fd = -1;
+-        if (ret != EOK) {
+-            ret = errno;
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "close failed [%d][%s].\n", ret, strerror(ret));
+-        }
+-    }
+-
+-    return EOK;
+-}
+-
+ static errno_t pack_authtok(struct io_buffer *buf, size_t *rp,
+                             struct sss_auth_token *tok)
+ {
+@@ -391,7 +357,7 @@ struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
+     state->child_pid = -1;
+     state->timeout_handler = NULL;
+ 
+-    state->io = talloc(state, struct io);
++    state->io = talloc(state, struct child_io_fds);
+     if (state->io == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
+         ret = ENOMEM;
+diff --git a/src/util/child_common.c b/src/util/child_common.c
+index 81bbab70ed44a6c0a4410909924aec195c643bea..e4a885b6e6e4a1a8a0cabd12ba1544a7c8f0f160 100644
+--- a/src/util/child_common.c
++++ b/src/util/child_common.c
+@@ -772,3 +772,32 @@ void child_cleanup(int readfd, int writefd)
+         }
+     }
+ }
++
++int child_io_destructor(void *ptr)
++{
++    int ret;
++    struct child_io_fds *io = talloc_get_type(ptr, struct child_io_fds);
++    if (io == NULL) return EOK;
++
++    if (io->write_to_child_fd != -1) {
++        ret = close(io->write_to_child_fd);
++        io->write_to_child_fd = -1;
++        if (ret != EOK) {
++            ret = errno;
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "close failed [%d][%s].\n", ret, strerror(ret));
++        }
++    }
++
++    if (io->read_from_child_fd != -1) {
++        ret = close(io->read_from_child_fd);
++        io->read_from_child_fd = -1;
++        if (ret != EOK) {
++            ret = errno;
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "close failed [%d][%s].\n", ret, strerror(ret));
++        }
++    }
++
++    return EOK;
++}
+diff --git a/src/util/child_common.h b/src/util/child_common.h
+index 95865bb529b6b282a57b138d7a85ce93649faa2e..261da7f9c546ddfdb38506e5285024ad201bdd4d 100644
+--- a/src/util/child_common.h
++++ b/src/util/child_common.h
+@@ -45,6 +45,11 @@ struct io_buffer {
+     size_t size;
+ };
+ 
++struct child_io_fds {
++    int read_from_child_fd;
++    int write_to_child_fd;
++};
++
+ /* COMMON SIGCHLD HANDLING */
+ typedef void (*sss_child_fn_t)(int pid, int wait_status, void *pvt);
+ 
+@@ -113,4 +118,6 @@ errno_t exec_child(TALLOC_CTX *mem_ctx,
+ 
+ void child_cleanup(int readfd, int writefd);
+ 
++int child_io_destructor(void *ptr);
++
+ #endif /* __CHILD_COMMON_H__ */
+-- 
+1.9.3
+
diff --git a/SOURCES/0070-DB-Add-sss_ldb_el_to_string_list.patch b/SOURCES/0070-DB-Add-sss_ldb_el_to_string_list.patch
deleted file mode 100644
index 8b9b419..0000000
--- a/SOURCES/0070-DB-Add-sss_ldb_el_to_string_list.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-From 329165182d0decee35f3837c1d2ad899f99e9950 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 28 Jan 2014 14:51:58 +0100
-Subject: [PATCH 70/71] DB: Add sss_ldb_el_to_string_list
-
----
- src/db/sysdb.c          | 41 ++++++++++++++++++++++++++---------------
- src/db/sysdb.h          |  2 ++
- src/tests/sysdb-tests.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 77 insertions(+), 15 deletions(-)
-
-diff --git a/src/db/sysdb.c b/src/db/sysdb.c
-index 0e07ed60858298a1ac85d06146ccb98c5899a705..592cadc1a322ee8504c407a508e34e7eb9465a15 100644
---- a/src/db/sysdb.c
-+++ b/src/db/sysdb.c
-@@ -466,35 +466,46 @@ errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name,
-     return EOK;
- }
- 
--int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
--                                 TALLOC_CTX *mem_ctx, const char ***string)
-+const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx,
-+                                       struct ldb_message_element *el)
- {
--    struct ldb_message_element *el;
--    int ret;
-     unsigned int u;
-     const char **a;
- 
--    ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
--    if (ret) {
--        return ret;
--    }
--
--    a = talloc_array(mem_ctx, const char *, el->num_values + 1);
-+    a = talloc_zero_array(mem_ctx, const char *, el->num_values + 1);
-     if (a == NULL) {
--        return ENOMEM;
-+        return NULL;
-     }
- 
--    memset(a, 0, sizeof(const char *) * (el->num_values + 1));
--
--    for(u = 0; u < el->num_values; u++) {
-+    for (u = 0; u < el->num_values; u++) {
-         a[u] = talloc_strndup(a, (const char *)el->values[u].data,
-                               el->values[u].length);
-         if (a[u] == NULL) {
-             talloc_free(a);
--            return ENOMEM;
-+            return NULL;
-         }
-     }
- 
-+    return a;
-+}
-+
-+int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
-+                                 TALLOC_CTX *mem_ctx, const char ***string)
-+{
-+    struct ldb_message_element *el;
-+    int ret;
-+    const char **a;
-+
-+    ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
-+    if (ret) {
-+        return ret;
-+    }
-+
-+    a = sss_ldb_el_to_string_list(mem_ctx, el);
-+    if (a == NULL) {
-+        return ENOMEM;
-+    }
-+
-     *string = a;
-     return EOK;
- }
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 9677294b22e47f5169d7631673beec2dbc6117ad..5bd2c50ebff1ca1f4bb11d12e40512d8f460acbb 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -288,6 +288,8 @@ int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,
-                              const char *name, char *str);
- int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
-                            const char **string);
-+const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx,
-+                                       struct ldb_message_element *el);
- int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
-                                  TALLOC_CTX *mem_ctx, const char ***string);
- errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name,
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index 63ffac82e15849e5f6534462ce7c58b183412acc..69b09c7d4580595854330062e0f549eab1f8cf22 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -4449,6 +4449,52 @@ START_TEST(test_sysdb_attrs_add_lc_name_alias)
- }
- END_TEST
- 
-+START_TEST(test_sysdb_attrs_get_string_array)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    const char **list;
-+    const char *attrname = "test_attr";
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_message_element *el = NULL;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    fail_unless(tmp_ctx != NULL, "talloc_new failed");
-+
-+    attrs = sysdb_new_attrs(NULL);
-+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
-+
-+    ret = sysdb_attrs_add_string(attrs, attrname, "val1");
-+    fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
-+    ret = sysdb_attrs_add_string(attrs, attrname, "val2");
-+    fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
-+
-+    ret = sysdb_attrs_get_el_ext(attrs, attrname, false, &el);
-+    fail_unless(ret == EOK, "sysdb_attrs_get_el_ext failed");
-+
-+    list = sss_ldb_el_to_string_list(tmp_ctx, el);
-+    fail_if(list == NULL, ("sss_ldb_el_to_string_list failed\n"));
-+
-+    ck_assert_str_eq(list[0], "val1");
-+    ck_assert_str_eq(list[1], "val2");
-+    fail_unless(list[2] == NULL, "Expected terminated list");
-+
-+    talloc_free(list);
-+
-+    ret = sysdb_attrs_get_string_array(attrs, attrname, tmp_ctx, &list);
-+    fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed");
-+
-+    /* This test relies on values keeping the same order. It is the case
-+     * with LDB, but if we ever switch from LDB, we need to amend the test
-+     */
-+    ck_assert_str_eq(list[0], "val1");
-+    ck_assert_str_eq(list[1], "val2");
-+    fail_unless(list[2] == NULL, "Expected terminated list");
-+
-+    talloc_free(tmp_ctx);
-+}
-+END_TEST
-+
- START_TEST(test_sysdb_has_enumerated)
- {
-     errno_t ret;
-@@ -5217,6 +5263,9 @@ Suite *create_sysdb_suite(void)
- 
-     tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias);
- 
-+/* ===== UTIL TESTS ===== */
-+    tcase_add_test(tc_sysdb, test_sysdb_attrs_get_string_array);
-+
- /* Add all test cases to the test suite */
-     suite_add_tcase(s, tc_sysdb);
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0070-UTIL-Remove-more-code-duplication-setting-up-child-p.patch b/SOURCES/0070-UTIL-Remove-more-code-duplication-setting-up-child-p.patch
new file mode 100644
index 0000000..c12d4ca
--- /dev/null
+++ b/SOURCES/0070-UTIL-Remove-more-code-duplication-setting-up-child-p.patch
@@ -0,0 +1,184 @@
+From b95d9cbd6959a3174c4fb963be642f770938e4b7 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 Oct 2014 22:36:59 +0200
+Subject: [PATCH 70/71] UTIL: Remove more code duplication setting up child
+ processes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+All our child processes duplicated the same code that set up the
+debugging all around. Instead of adding yet another copy for the
+selinux_child, add a common utility function.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/providers/ad/ad_gpo.c               | 23 ++---------------------
+ src/providers/krb5/krb5_init_shared.c   | 24 ++++++++----------------
+ src/providers/ldap/sdap_child_helpers.c | 22 +---------------------
+ src/util/child_common.c                 | 29 +++++++++++++++++++++++++++++
+ src/util/child_common.h                 |  2 ++
+ 5 files changed, 42 insertions(+), 58 deletions(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 80b0d45c2861a64f01fe7835cccee4348084c7da..83edbe4fb5a7e617cab95c0330ceae31392b18b2 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -1313,29 +1313,10 @@ ad_gpo_access_check(TALLOC_CTX *mem_ctx,
+ }
+ 
+ #define GPO_CHILD_LOG_FILE "gpo_child"
++
+ static errno_t gpo_child_init(void)
+ {
+-    int ret;
+-    FILE *debug_filep;
+-
+-    if (debug_to_file != 0 && gpo_child_debug_fd == -1) {
+-        ret = open_debug_file_ex(GPO_CHILD_LOG_FILE, &debug_filep, false);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n",
+-                        ret, strerror(ret));
+-            return ret;
+-        }
+-
+-        gpo_child_debug_fd = fileno(debug_filep);
+-        if (gpo_child_debug_fd == -1) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "fileno failed [%d][%s]\n", errno, strerror(errno));
+-            ret = errno;
+-            return ret;
+-        }
+-    }
+-
+-    return EOK;
++    return child_debug_init(GPO_CHILD_LOG_FILE, &gpo_child_debug_fd);
+ }
+ 
+ /*
+diff --git a/src/providers/krb5/krb5_init_shared.c b/src/providers/krb5/krb5_init_shared.c
+index 340eab1f0d432d411e2b807f66b03bffcbd14d1d..3b4bf096ef49d0f2d369fda20462b7fd56d61127 100644
+--- a/src/providers/krb5/krb5_init_shared.c
++++ b/src/providers/krb5/krb5_init_shared.c
+@@ -30,7 +30,6 @@ errno_t krb5_child_init(struct krb5_ctx *krb5_auth_ctx,
+                         struct be_ctx *bectx)
+ {
+     errno_t ret;
+-    FILE *debug_filep;
+     time_t renew_intv = 0;
+     krb5_deltat renew_interval_delta;
+     char *renew_interval_str;
+@@ -83,23 +82,16 @@ errno_t krb5_child_init(struct krb5_ctx *krb5_auth_ctx,
+         goto done;
+     }
+ 
+-    if (debug_to_file != 0) {
+-        ret = open_debug_file_ex(KRB5_CHILD_LOG_FILE, &debug_filep, false);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n",
+-                    ret, strerror(ret));
+-            goto done;
+-        }
+-
+-        krb5_auth_ctx->child_debug_fd = fileno(debug_filep);
+-        if (krb5_auth_ctx->child_debug_fd == -1) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "fileno failed [%d][%s]\n", errno, strerror(errno));
+-            ret = errno;
+-            goto done;
+-        }
++    krb5_auth_ctx->child_debug_fd = -1; /* -1 means not initialized */
++    ret = child_debug_init(KRB5_CHILD_LOG_FILE,
++                           &krb5_auth_ctx->child_debug_fd);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Could not set krb5_child debugging!\n");
++        goto done;
+     }
+ 
++    ret = EOK;
++
+ done:
+     return ret;
+ }
+diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c
+index e5d46b9b756cd50fadb212da72ad1cc9bdd93330..40010989021eb7cf77b96876b2d1c4119ed39163 100644
+--- a/src/providers/ldap/sdap_child_helpers.c
++++ b/src/providers/ldap/sdap_child_helpers.c
+@@ -466,25 +466,5 @@ static errno_t set_tgt_child_timeout(struct tevent_req *req,
+ /* Setup child logging */
+ int sdap_setup_child(void)
+ {
+-    int ret;
+-    FILE *debug_filep;
+-
+-    if (debug_to_file != 0 && ldap_child_debug_fd == -1) {
+-        ret = open_debug_file_ex(LDAP_CHILD_LOG_FILE, &debug_filep, false);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n",
+-                        ret, strerror(ret));
+-            return ret;
+-        }
+-
+-        ldap_child_debug_fd = fileno(debug_filep);
+-        if (ldap_child_debug_fd == -1) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "fileno failed [%d][%s]\n", errno, strerror(errno));
+-            ret = errno;
+-            return ret;
+-        }
+-    }
+-
+-    return EOK;
++    return child_debug_init(LDAP_CHILD_LOG_FILE, &ldap_child_debug_fd);
+ }
+diff --git a/src/util/child_common.c b/src/util/child_common.c
+index e4a885b6e6e4a1a8a0cabd12ba1544a7c8f0f160..cc6a8fa758bfa6efa511c28cd9121e759b590342 100644
+--- a/src/util/child_common.c
++++ b/src/util/child_common.c
+@@ -801,3 +801,32 @@ int child_io_destructor(void *ptr)
+ 
+     return EOK;
+ }
++
++errno_t child_debug_init(const char *logfile, int *debug_fd)
++{
++    int ret;
++    FILE *debug_filep;
++
++    if (debug_fd == NULL) {
++        return EOK;
++    }
++
++    if (debug_to_file != 0 && *debug_fd == -1) {
++        ret = open_debug_file_ex(logfile, &debug_filep, false);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n",
++                        ret, sss_strerror(ret));
++            return ret;
++        }
++
++        *debug_fd = fileno(debug_filep);
++        if (*debug_fd == -1) {
++            DEBUG(SSSDBG_FATAL_FAILURE,
++                  "fileno failed [%d][%s]\n", errno, strerror(errno));
++            ret = errno;
++            return ret;
++        }
++    }
++
++    return EOK;
++}
+diff --git a/src/util/child_common.h b/src/util/child_common.h
+index 261da7f9c546ddfdb38506e5285024ad201bdd4d..e159719a2fca70a4ea044d79530a0d21cb3577e8 100644
+--- a/src/util/child_common.h
++++ b/src/util/child_common.h
+@@ -120,4 +120,6 @@ void child_cleanup(int readfd, int writefd);
+ 
+ int child_io_destructor(void *ptr);
+ 
++errno_t child_debug_init(const char *logfile, int *debug_fd);
++
+ #endif /* __CHILD_COMMON_H__ */
+-- 
+1.9.3
+
diff --git a/SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch b/SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch
deleted file mode 100644
index fc32870..0000000
--- a/SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch
+++ /dev/null
@@ -1,508 +0,0 @@
-From 8c714cbf1d0ce2cbddc4222ade51e1f93f36dbe8 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 22 Jan 2014 15:21:24 +0100
-Subject: [PATCH 71/71] AD: Establish cross-domain memberships after
- enumeration finishes
-
-Because domain enumeration currently works for each domain separately,
-the code has to establish cross-domain memberships after all domains are
-enumerated. The code works as follows:
-
-    1) check if any *sub*domains were enumerated. If not, do nothing
-    2) if any of the groups saved had more original members than
-       sysdb members, check if members of these groups can be linked now
-       that all users and groups are saved using the orig_member
-       attribute of the group matched against originalDN member of the
-       user.
-
-Related:
-https://fedorahosted.org/sssd/ticket/2142
----
- src/providers/ad/ad_id.c         | 390 +++++++++++++++++++++++++++++++++++++--
- src/providers/ad/ad_subdomains.c |  11 --
- 2 files changed, 379 insertions(+), 22 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index a47aa4f75ab348b0f4597fea264d770b5abe3184..e3302c15774ab1c24b16cefc274313e447b31e5c 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -420,10 +420,13 @@ struct ad_enumeration_state {
-     struct tevent_context *ev;
- 
-     struct sdap_domain *sdom;
-+    struct sdap_domain *sditer;
- };
- 
- static void ad_enumeration_conn_done(struct tevent_req *subreq);
- static void ad_enumeration_master_done(struct tevent_req *subreq);
-+static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
-+                            struct ad_id_ctx *id_ctx);
- static void ad_enumeration_done(struct tevent_req *subreq);
- 
- struct tevent_req *
-@@ -452,6 +455,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
-     state->ectx = ectx;
-     state->ev = ev;
-     state->sdom = ectx->sdom;
-+    state->sditer = state->sdom;
-     state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
- 
-     state->sdap_op = sdap_id_op_create(state,
-@@ -526,7 +530,6 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-     char *flat_name;
-     char *master_sid;
-     char *forest;
--    struct sdap_id_conn_ctx *user_conn;
- 
-     ret = ad_master_domain_recv(subreq, state,
-                                 &flat_name, &master_sid, &forest);
-@@ -545,32 +548,57 @@ ad_enumeration_master_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
--        user_conn = state->id_ctx->gc_ctx;
-+    ret = ad_enum_sdom(req, state->sdom, state->id_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+                ("Could not enumerate domain %s\n", state->sdom->dom->name));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    /* Execution will resume in ad_enumeration_done */
-+}
-+
-+static errno_t
-+ad_enum_sdom(struct tevent_req *req,
-+             struct sdap_domain *sd,
-+             struct ad_id_ctx *id_ctx)
-+{
-+    struct sdap_id_conn_ctx *user_conn;
-+    struct tevent_req *subreq;
-+    struct ad_enumeration_state *state = tevent_req_data(req,
-+                                                struct ad_enumeration_state);
-+
-+    if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) {
-+        user_conn = id_ctx->gc_ctx;
-     } else {
--        user_conn = state->id_ctx->ldap_ctx;
-+        user_conn = id_ctx->ldap_ctx;
-     }
- 
-     /* Groups are searched for in LDAP, users in GC. Services (if present,
-      * which is unlikely in AD) from LDAP as well
-      */
-     subreq = sdap_dom_enum_ex_send(state, state->ev,
--                                   state->id_ctx->sdap_id_ctx,
--                                   state->sdom,
--                                   user_conn,                /* Users    */
--                                   state->id_ctx->ldap_ctx,  /* Groups   */
--                                   state->id_ctx->ldap_ctx); /* Services */
-+                                   id_ctx->sdap_id_ctx,
-+                                   sd,
-+                                   user_conn,         /* Users    */
-+                                   id_ctx->ldap_ctx,  /* Groups   */
-+                                   id_ctx->ldap_ctx); /* Services */
-     if (subreq == NULL) {
-         /* The ptask API will reschedule the enumeration on its own on
-          * failure */
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("Failed to schedule enumeration, retrying later!\n"));
--        tevent_req_error(req, ENOMEM);
--        return;
-+        return ENOMEM;
-     }
-     tevent_req_set_callback(subreq, ad_enumeration_done, req);
-+
-+    return EOK;
- }
- 
-+static errno_t ad_enum_cross_dom_members(struct sdap_options *opts,
-+                                         struct sss_domain_info *dom);
-+
- static void
- ad_enumeration_done(struct tevent_req *subreq)
- {
-@@ -579,6 +607,7 @@ ad_enumeration_done(struct tevent_req *subreq)
-                                                       struct tevent_req);
-     struct ad_enumeration_state *state = tevent_req_data(req,
-                                                 struct ad_enumeration_state);
-+    struct ad_id_ctx *subdom_id_ctx;
- 
-     ret = sdap_dom_enum_ex_recv(subreq);
-     talloc_zfree(subreq);
-@@ -589,9 +618,348 @@ ad_enumeration_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    state->sditer = state->sditer->next;
-+    if (state->sditer != NULL) {
-+        subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
-+        if (subdom_id_ctx == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
-+            tevent_req_error(req, EFAULT);
-+            return;
-+        }
-+
-+        ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("Could not enumerate domain %s\n",
-+                  state->sditer->dom->name));
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+
-+        /* Execution will resume in ad_enumeration_done */
-+        return;
-+    }
-+
-+    /* No more subdomains to enumerate. Check if we need to fixup
-+     * cross-domain membership
-+     */
-+    if (state->sditer != state->sdom) {
-+        /* We did enumerate at least one subdomain. Walk the subdomains
-+         * and fixup members for each of them
-+         */
-+        for (state->sditer = state->sdom;
-+             state->sditer;
-+             state->sditer = state->sditer->next) {
-+            ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id,
-+                                            state->sditer->dom);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_MINOR_FAILURE, ("Could not check cross-domain "
-+                      "memberships for %s, group memberships might be "
-+                      "incomplete!\n", state->sdom->dom->name));
-+                continue;
-+            }
-+        }
-+    }
-+
-     tevent_req_done(req);
- }
- 
-+static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx,
-+                                      const struct ldb_message *group,
-+                                      struct sss_domain_info *dom,
-+                                      char ***_group_only);
-+static errno_t ad_group_add_member(struct sdap_options *opts,
-+                                   struct sss_domain_info *group_domain,
-+                                   struct ldb_dn *group_dn,
-+                                   const char *member);
-+
-+static errno_t
-+ad_enum_cross_dom_members(struct sdap_options *opts,
-+                          struct sss_domain_info *dom)
-+{
-+    errno_t ret;
-+    errno_t sret;
-+    char *filter;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = {
-+            SYSDB_NAME,
-+            SYSDB_MEMBER,
-+            SYSDB_ORIG_MEMBER,
-+            NULL
-+    };
-+    size_t count, i, mi;
-+    struct ldb_message **msgs;
-+    bool in_transaction = false;
-+    char **group_only;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) return ENOMEM;
-+
-+    ret = sysdb_transaction_start(dom->sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
-+        goto done;
-+    }
-+    in_transaction = true;
-+
-+    filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME);
-+    if (filter == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_groups(tmp_ctx, dom->sysdb, dom,
-+                              filter, attrs, &count, &msgs);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    for (i = 0; i < count; i++) {
-+        ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n"));
-+        } else if (group_only == NULL) {
-+            DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n"));
-+            continue;
-+        }
-+
-+        /* Group has extra members */
-+        for (mi = 0; group_only[mi]; mi++) {
-+            ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add [%s]: %s\n",
-+                      group_only[mi], strerror(ret)));
-+                continue;
-+            }
-+        }
-+
-+        talloc_zfree(group_only);
-+    }
-+
-+    ret = sysdb_transaction_commit(dom->sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
-+        goto done;
-+    }
-+    in_transaction = false;
-+
-+    ret = EOK;
-+done:
-+    if (in_transaction) {
-+        sret = sysdb_transaction_cancel(dom->sysdb);
-+        if (sret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
-+        }
-+    }
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-+                             struct ldb_dn *dn, char ***_odn_list);
-+
-+static errno_t
-+ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group,
-+                       struct sss_domain_info *dom, char ***_group_only)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_message_element *m, *om;
-+    const char *name;
-+    errno_t ret;
-+    char **sysdb_odn_list;
-+    const char **group_odn_list;
-+    char **group_only = NULL;
-+
-+    if (_group_only == NULL) return EINVAL;
-+    *_group_only = NULL;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) return ENOMEM;
-+
-+    om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
-+    m = ldb_msg_find_element(group, SYSDB_MEMBER);
-+    name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
-+    if (name == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("A group with no name!\n"));
-+        ret = EFAULT;
-+        goto done;
-+    }
-+
-+    if (om == NULL || om->num_values == 0) {
-+        DEBUG(SSSDBG_TRACE_FUNC, ("Group %s has no original members\n", name));
-+        ret = EOK;
-+        goto done;
-+    }
-+
-+    if (m == NULL || (m->num_values < om->num_values)) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              ("Group %s has %d members but %d original members\n",
-+               name, m ? m->num_values : 0, om->num_values));
-+
-+        /* Get the list of originalDN attributes that are already
-+         * linked to the group
-+         */
-+        ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn,
-+                                           &sysdb_odn_list);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  ("Could not retrieve list of original members for %s\n",
-+                  name));
-+            goto done;
-+        }
-+
-+        /* Get the list of original DN attributes the group had in AD */
-+        group_odn_list = sss_ldb_el_to_string_list(tmp_ctx, om);
-+        if (group_odn_list == NULL) {
-+            ret = EFAULT;
-+            goto done;
-+        }
-+
-+        /* Compare the two lists */
-+        ret = diff_string_lists(tmp_ctx, discard_const(group_odn_list),
-+                                sysdb_odn_list, &group_only, NULL, NULL);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  ("Could not compare lists of members for %s\n", name));
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+    *_group_only = talloc_steal(mem_ctx, group_only);
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-+                             struct ldb_dn *dn, char ***_odn_list)
-+{
-+    errno_t ret;
-+    TALLOC_CTX *tmp_ctx;
-+    size_t m_count, i;
-+    struct ldb_message **members;
-+    const char *attrs[] = {
-+            SYSDB_NAME,
-+            SYSDB_ORIG_DN,
-+            NULL
-+    };
-+    char **odn_list;
-+    const char *odn;
-+    size_t oi;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) return ENOMEM;
-+
-+    /* Get all entries member element points to */
-+    ret = sysdb_asq_search(tmp_ctx, dom->sysdb, dn, NULL, SYSDB_MEMBER,
-+                           attrs, &m_count, &members);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1);
-+    if (odn_list == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    /* Get a list of their original DNs */
-+    oi = 0;
-+    for (i = 0; i < m_count; i++) {
-+        odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL);
-+        if (odn == NULL) {
-+            continue;
-+        }
-+
-+        odn_list[oi] = talloc_strdup(odn_list, odn);
-+        if (odn_list[oi] == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        oi++;
-+        DEBUG(SSSDBG_TRACE_INTERNAL, ("Member %s already in sysdb\n", odn));
-+    }
-+
-+    ret = EOK;
-+    *_odn_list = talloc_steal(mem_ctx, odn_list);
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+ad_group_add_member(struct sdap_options *opts,
-+                    struct sss_domain_info *group_domain,
-+                    struct ldb_dn *group_dn,
-+                    const char *member)
-+{
-+    struct sdap_domain *sd;
-+    struct ldb_dn *base_dn;
-+    TALLOC_CTX *tmp_ctx;
-+    errno_t ret;
-+    const char *mem_filter;
-+    size_t msgs_count;
-+    struct ldb_message **msgs;
-+
-+    /* This member would be from a different domain */
-+    sd = sdap_domain_get_by_dn(opts, member);
-+    if (sd == NULL) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("No matching domain for %s\n", member));
-+        return ENOENT;
-+    }
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) return ENOMEM;
-+
-+    mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
-+                                 SYSDB_ORIG_DN, member);
-+    if (mem_filter == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    base_dn = sysdb_domain_dn(sd->dom->sysdb, tmp_ctx, sd->dom);
-+    if (base_dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn,
-+                             LDB_SCOPE_SUBTREE, mem_filter, NULL,
-+                             &msgs_count, &msgs);
-+    if (ret == ENOENT) {
-+        DEBUG(SSSDBG_TRACE_FUNC, ("No member [%s] in sysdb\n", member));
-+        ret = EOK;
-+        goto done;
-+    } else if (ret != EOK) {
-+        goto done;
-+    }
-+    DEBUG(SSSDBG_TRACE_INTERNAL, ("[%s] found in sysdb\n", member));
-+
-+    if (msgs_count != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+               ("Search by orig DN returned %zd results!\n", msgs_count));
-+        ret = EFAULT;
-+        goto done;
-+    }
-+
-+    ret = sysdb_mod_group_member(group_domain->sysdb, msgs[0]->dn,
-+                                 group_dn, SYSDB_MOD_ADD);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Could not add [%s] as a member of [%s]\n",
-+              ldb_dn_get_linearized(msgs[0]->dn),
-+              ldb_dn_get_linearized(group_dn)));
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
- errno_t
- ad_enumeration_recv(struct tevent_req *req)
- {
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index e7871cc32407893948fe1b2803258d68c70889c1..0d9652b5c615add47958cfdc61eba862a332ae4d 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -177,17 +177,6 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
-         return EFAULT;
-     }
- 
--    ret = sdap_id_setup_tasks(be_ctx,
--                              ad_id_ctx->sdap_id_ctx,
--                              sdom,
--                              ldap_enumeration_send,
--                              ldap_enumeration_recv,
--                              ad_id_ctx->sdap_id_ctx);
--    if (ret != EOK) {
--        talloc_free(ad_options);
--        return ret;
--    }
--
-     /* Set up the ID mapping object */
-     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
-         id_ctx->sdap_id_ctx->opts->idmap_ctx;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0071-IPA-Move-setting-the-SELinux-context-to-a-child-proc.patch b/SOURCES/0071-IPA-Move-setting-the-SELinux-context-to-a-child-proc.patch
new file mode 100644
index 0000000..f19dd79
--- /dev/null
+++ b/SOURCES/0071-IPA-Move-setting-the-SELinux-context-to-a-child-proc.patch
@@ -0,0 +1,927 @@
+From e08eb3e3b0586b331a688a4eded2d7f13611016c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 Oct 2014 23:16:40 +0200
+Subject: [PATCH 71/71] IPA: Move setting the SELinux context to a child
+ process
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In order for the sssd_be process to run as unprivileged user, we need to
+move the semanage processing to a process that runs as the root user
+using setuid privileges.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ Makefile.am                       |  27 +++
+ contrib/sssd.spec.in              |   1 +
+ src/providers/ipa/ipa_selinux.c   | 425 +++++++++++++++++++++++++++++++++++---
+ src/providers/ipa/selinux_child.c | 272 ++++++++++++++++++++++++
+ src/util/util_errors.c            |   1 +
+ src/util/util_errors.h            |   1 +
+ 6 files changed, 699 insertions(+), 28 deletions(-)
+ create mode 100644 src/providers/ipa/selinux_child.c
+
+diff --git a/Makefile.am b/Makefile.am
+index ea296c40f89c552d5825cbce8e95afdc517e8bb5..b85341f5845c3cffab8a2c95b1be1d32517316e8 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -146,6 +146,9 @@ endif
+ if BUILD_SAMBA
+ sssdlibexec_PROGRAMS += gpo_child
+ endif
++if BUILD_SEMANAGE
++sssdlibexec_PROGRAMS += selinux_child
++endif
+ 
+ 
+ if BUILD_PAC_RESPONDER
+@@ -2531,6 +2534,26 @@ ldap_child_LDADD = \
+     $(DHASH_LIBS) \
+     $(KRB5_LIBS)
+ 
++if BUILD_SEMANAGE
++selinux_child_SOURCES = \
++    src/providers/ipa/selinux_child.c \
++    src/util/sss_semanage.c \
++    src/util/atomic_io.c \
++    src/util/util.c \
++    $(NULL)
++selinux_child_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(POPT_CFLAGS) \
++    $(NULL)
++selinux_child_LDADD = \
++    libsss_debug.la \
++    $(TALLOC_LIBS) \
++    $(POPT_LIBS) \
++    $(DHASH_LIBS) \
++    $(SEMANAGE_LIBS) \
++    $(NULL)
++endif
++
+ gpo_child_SOURCES = \
+     src/providers/ad/ad_gpo_child.c \
+     src/util/atomic_io.c \
+@@ -2849,6 +2872,10 @@ endif
+ if SSSD_USER
+ 	chgrp $(SSSD_USER) $(sssdlibexecdir)/ldap_child
+ 	chmod 4750 $(sssdlibexecdir)/ldap_child
++if BUILD_SEMANAGE
++	chgrp $(SSSD_USER) $(sssdlibexecdir)/selinux_child
++	chmod 4750 $(sssdlibexecdir)/selinux_child
++endif
+ endif
+ 
+ install-data-hook:
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index d2e6cec2610e4c00cb376683cf7e64eb5cdafc5c..5bfb16707c22dc65376581c88b8eb898949e726f 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -665,6 +665,7 @@ rm -rf $RPM_BUILD_ROOT
+ %doc COPYING
+ %attr(755,root,root) %dir %{pubconfpath}/krb5.include.d
+ %{_libdir}/%{name}/libsss_ipa.so
++%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child
+ %{_mandir}/man5/sssd-ipa.5*
+ 
+ %files ad -f sssd_ad.lang
+diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
+index 7db1c6ed2981e4c4a85d892171bbfa60b006980e..b392d82a61cd523cd5e73e5246013bdbc448ddd5 100644
+--- a/src/providers/ipa/ipa_selinux.c
++++ b/src/providers/ipa/ipa_selinux.c
+@@ -24,6 +24,7 @@
+ #include <security/pam_modules.h>
+ 
+ #include "db/sysdb_selinux.h"
++#include "util/child_common.h"
+ #include "util/sss_selinux.h"
+ #include "providers/ldap/sdap_async.h"
+ #include "providers/ipa/ipa_common.h"
+@@ -37,8 +38,23 @@
+ #include "providers/ipa/ipa_subdomains.h"
+ 
+ #if defined HAVE_SELINUX && defined HAVE_SELINUX_LOGIN_DIR
++
++#ifndef SELINUX_CHILD_DIR
++#ifndef SSSD_LIBEXEC_PATH
++#error "SSSD_LIBEXEC_PATH not defined"
++#endif  /* SSSD_LIBEXEC_PATH */
++
++#define SELINUX_CHILD_DIR SSSD_LIBEXEC_PATH
++#endif /* SELINUX_CHILD_DIR */
++
++#define SELINUX_CHILD SELINUX_CHILD_DIR"/selinux_child"
++#define SELINUX_CHILD_LOG_FILE "selinux_child"
++
+ #include <selinux/selinux.h>
+ 
++/* fd used by the selinux_child process for logging */
++int selinux_child_debug_fd = -1;
++
+ static struct tevent_req *
+ ipa_get_selinux_send(TALLOC_CTX *mem_ctx,
+                      struct be_ctx *be_ctx,
+@@ -274,12 +290,27 @@ struct map_order_ctx {
+ 
+ static errno_t init_map_order_ctx(TALLOC_CTX *mem_ctx, const char *map_order,
+                                   struct map_order_ctx **_mo_ctx);
+-static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
++
++struct selinux_child_input {
++    const char *seuser;
++    const char *mls_range;
++    const char *username;
++};
++
++static errno_t choose_best_seuser(TALLOC_CTX *mem_ctx,
++                                  struct sysdb_attrs **usermaps,
+                                   struct pam_data *pd,
+                                   struct sss_domain_info *user_domain,
+                                   struct map_order_ctx *mo_ctx,
+-                                  const char *default_user);
++                                  const char *default_user,
++                                  struct selinux_child_input **_sci);
+ 
++static struct tevent_req *selinux_child_send(TALLOC_CTX *mem_ctx,
++                                             struct tevent_context *ev,
++                                             struct selinux_child_input *sci);
++static errno_t selinux_child_recv(struct tevent_req *req);
++
++static void ipa_selinux_child_done(struct tevent_req *child_req);
+ 
+ static void ipa_selinux_handler_done(struct tevent_req *req)
+ {
+@@ -299,6 +330,8 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
+     struct sysdb_attrs **hbac_rules = 0;
+     struct sysdb_attrs **best_match_maps;
+     struct map_order_ctx *map_order_ctx;
++    struct selinux_child_input *sci;
++    struct tevent_req *child_req;
+ 
+     ret = ipa_get_selinux_recv(req, breq, &map_count, &maps,
+                                &hbac_count, &hbac_rules,
+@@ -360,14 +393,61 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
+         goto fail;
+     }
+ 
+-    ret = choose_best_seuser(best_match_maps, pd, op_ctx->user_domain,
+-                             map_order_ctx, default_user);
++    ret = choose_best_seuser(breq,
++                             best_match_maps, pd, op_ctx->user_domain,
++                             map_order_ctx, default_user, &sci);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Failed to evaluate ordered SELinux users array.\n");
+         goto fail;
+     }
+ 
++    /* Update the SELinux context in a privileged child as the back end is
++     * running unprivileged
++     */
++    child_req = selinux_child_send(breq, be_ctx->ev, sci);
++    if (child_req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "selinux_child_send() failed\n");
++        ret = ENOMEM;
++        goto fail;
++    }
++    tevent_req_set_callback(child_req, ipa_selinux_child_done, op_ctx);
++    return;
++
++fail:
++    if (in_transaction) {
++        sret = sysdb_transaction_cancel(sysdb);
++        if (sret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
++        }
++    }
++    if (ret == EAGAIN) {
++        be_req_terminate(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
++    } else {
++        be_req_terminate(breq, DP_ERR_FATAL, ret, NULL);
++    }
++}
++
++static void ipa_selinux_child_done(struct tevent_req *child_req)
++{
++    errno_t ret;
++    struct ipa_selinux_op_ctx *op_ctx;
++    struct be_req *breq;
++    struct pam_data *pd;
++    struct be_ctx *be_ctx;
++
++    op_ctx = tevent_req_callback_data(child_req, struct ipa_selinux_op_ctx);
++    breq = op_ctx->be_req;
++    pd = talloc_get_type(be_req_get_data(breq), struct pam_data);
++    be_ctx = be_req_get_be_ctx(breq);
++
++    ret = selinux_child_recv(child_req);
++    talloc_free(child_req);
++    if (ret != EOK) {
++        be_req_terminate(breq, DP_ERR_FATAL, ret, NULL);
++        return;
++    }
++
+     /* If we got here in online mode, set last_update to current time */
+     if (!be_is_offline(be_ctx)) {
+         op_ctx->selinux_ctx->last_update = time(NULL);
+@@ -375,20 +455,6 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
+ 
+     pd->pam_status = PAM_SUCCESS;
+     be_req_terminate(breq, DP_ERR_OK, EOK, "Success");
+-    return;
+-
+-fail:
+-    if (in_transaction) {
+-        sret = sysdb_transaction_cancel(sysdb);
+-        if (sret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
+-        }
+-    }
+-    if (ret == EAGAIN) {
+-        be_req_terminate(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
+-    } else {
+-        be_req_terminate(breq, DP_ERR_FATAL, ret, NULL);
+-    }
+ }
+ 
+ static errno_t
+@@ -652,24 +718,28 @@ done:
+     return ret;
+ }
+ 
+-static errno_t
+-set_seuser_helper(const char *orig_name, struct sss_domain_info *dom,
+-                  const char *seuser_mls_string);
+-
++static errno_t selinux_child_setup(TALLOC_CTX *mem_ctx,
++                                   const char *orig_name,
++                                   struct sss_domain_info *dom,
++                                   const char *seuser_mls_string,
++                                   struct selinux_child_input **_sci);
+ 
+ /* Choose best selinux user based on given order and write
+  * the user to selinux login file. */
+-static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
++static errno_t choose_best_seuser(TALLOC_CTX *mem_ctx,
++                                  struct sysdb_attrs **usermaps,
+                                   struct pam_data *pd,
+                                   struct sss_domain_info *user_domain,
+                                   struct map_order_ctx *mo_ctx,
+-                                  const char *default_user)
++                                  const char *default_user,
++                                  struct selinux_child_input **_sci)
+ {
+     TALLOC_CTX *tmp_ctx;
+     char *seuser_mls_str = NULL;
+     const char *tmp_str;
+     errno_t ret;
+     int i, j;
++    struct selinux_child_input *sci;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -716,15 +786,25 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
+         }
+     }
+ 
+-    ret = set_seuser_helper(pd->user, user_domain, seuser_mls_str);
++    ret = selinux_child_setup(tmp_ctx, pd->user, user_domain, seuser_mls_str, &sci);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Cannot set up child input buffer");
++        goto done;
++    }
++
++    *_sci = talloc_steal(mem_ctx, sci);
++    ret = EOK;
+ done:
+     talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
+ static errno_t
+-set_seuser_helper(const char *orig_name, struct sss_domain_info *dom,
+-                  const char *seuser_mls_string)
++selinux_child_setup(TALLOC_CTX *mem_ctx,
++                    const char *orig_name,
++                    struct sss_domain_info *dom,
++                    const char *seuser_mls_string,
++                    struct selinux_child_input **_sci)
+ {
+     errno_t ret;
+     char *seuser;
+@@ -733,6 +813,7 @@ set_seuser_helper(const char *orig_name, struct sss_domain_info *dom,
+     char *username;
+     char *username_final;
+     TALLOC_CTX *tmp_ctx;
++    struct selinux_child_input *sci;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -778,12 +859,300 @@ set_seuser_helper(const char *orig_name, struct sss_domain_info *dom,
+         username_final = username;
+     }
+ 
+-    ret = set_seuser(username_final, seuser, mls_range);
++    sci = talloc(tmp_ctx, struct selinux_child_input);
++    if (sci == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    sci->seuser = talloc_strdup(sci, seuser);
++    sci->mls_range = talloc_strdup(sci, mls_range);
++    sci->username = talloc_strdup(sci, username);
++    if (sci->seuser == NULL || sci->mls_range == NULL
++        || sci->username == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    *_sci = talloc_steal(mem_ctx, sci);
++    ret = EOK;
+ done:
+     talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
++struct selinux_child_state {
++    struct selinux_child_input *sci;
++    struct tevent_context *ev;
++    struct io_buffer *buf;
++    struct child_io_fds *io;
++};
++
++static errno_t selinux_child_init(void);
++static errno_t selinux_child_create_buffer(struct selinux_child_state *state);
++static errno_t selinux_fork_child(struct selinux_child_state *state);
++static void selinux_child_step(struct tevent_req *subreq);
++static void selinux_child_done(struct tevent_req *subreq);
++static errno_t selinux_child_parse_response(uint8_t *buf, ssize_t len,
++                                            uint32_t *_child_result);
++
++static struct tevent_req *selinux_child_send(TALLOC_CTX *mem_ctx,
++                                             struct tevent_context *ev,
++                                             struct selinux_child_input *sci)
++{
++    struct tevent_req *req;
++    struct tevent_req *subreq;
++    struct selinux_child_state *state;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state, struct selinux_child_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    state->sci = sci;
++    state->ev = ev;
++    state->io = talloc(state, struct child_io_fds);
++    state->buf = talloc(state, struct io_buffer);
++    if (state->io == NULL || state->buf == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    state->io->write_to_child_fd = -1;
++    state->io->read_from_child_fd = -1;
++    talloc_set_destructor((void *) state->io, child_io_destructor);
++
++    ret = selinux_child_init();
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to init the child\n");
++        goto immediately;
++    }
++
++    ret = selinux_child_create_buffer(state);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to create the send buffer\n");
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    ret = selinux_fork_child(state);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to fork the child\n");
++        goto immediately;
++    }
++
++    subreq = write_pipe_send(state, ev, state->buf->data, state->buf->size,
++                             state->io->write_to_child_fd);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++    tevent_req_set_callback(subreq, selinux_child_step, req);
++
++    ret = EOK;
++immediately:
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        tevent_req_post(req, ev);
++    }
++    return req;
++}
++
++static errno_t selinux_child_init(void)
++{
++    return child_debug_init(SELINUX_CHILD_LOG_FILE, &selinux_child_debug_fd);
++}
++
++static errno_t selinux_child_create_buffer(struct selinux_child_state *state)
++{
++    size_t rp;
++    size_t seuser_len;
++    size_t mls_range_len;
++    size_t username_len;
++
++    seuser_len = strlen(state->sci->seuser);
++    mls_range_len = strlen(state->sci->mls_range);
++    username_len = strlen(state->sci->username);
++
++    state->buf->size = 3 * sizeof(uint32_t);
++    state->buf->size += seuser_len + mls_range_len + username_len;
++
++    DEBUG(SSSDBG_TRACE_ALL, "buffer size: %zu\n", state->buf->size);
++
++    state->buf->data = talloc_size(state->buf, state->buf->size);
++    if (state->buf->data == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
++        return ENOMEM;
++    }
++
++    rp = 0;
++
++    /* seuser */
++    SAFEALIGN_SET_UINT32(&state->buf->data[rp], seuser_len, &rp);
++    safealign_memcpy(&state->buf->data[rp], state->sci->seuser,
++                     seuser_len, &rp);
++
++    /* mls_range */
++    SAFEALIGN_SET_UINT32(&state->buf->data[rp], mls_range_len, &rp);
++    safealign_memcpy(&state->buf->data[rp], state->sci->mls_range,
++                     mls_range_len, &rp);
++
++    /* username */
++    SAFEALIGN_SET_UINT32(&state->buf->data[rp], username_len, &rp);
++    safealign_memcpy(&state->buf->data[rp], state->sci->username,
++                     username_len, &rp);
++
++    return EOK;
++}
++
++static errno_t selinux_fork_child(struct selinux_child_state *state)
++{
++    int pipefd_to_child[2];
++    int pipefd_from_child[2];
++    pid_t pid;
++    errno_t ret;
++
++    ret = pipe(pipefd_from_child);
++    if (ret == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "pipe failed [%d][%s].\n", errno, sss_strerror(errno));
++        return ret;
++    }
++
++    ret = pipe(pipefd_to_child);
++    if (ret == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "pipe failed [%d][%s].\n", errno, sss_strerror(errno));
++        return ret;
++    }
++
++    pid = fork();
++
++    if (pid == 0) { /* child */
++        ret = exec_child(state,
++                         pipefd_to_child, pipefd_from_child,
++                         SELINUX_CHILD, selinux_child_debug_fd);
++        DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec selinux_child: [%d][%s].\n",
++              ret, sss_strerror(ret));
++        return ret;
++    } else if (pid > 0) { /* parent */
++        state->io->read_from_child_fd = pipefd_from_child[0];
++        close(pipefd_from_child[1]);
++        state->io->write_to_child_fd = pipefd_to_child[1];
++        close(pipefd_to_child[0]);
++        fd_nonblocking(state->io->read_from_child_fd);
++        fd_nonblocking(state->io->write_to_child_fd);
++
++        ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Could not set up child signal handler\n");
++            return ret;
++        }
++    } else { /* error */
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "fork failed [%d][%s].\n", errno, sss_strerror(errno));
++        return ret;
++    }
++
++    return EOK;
++}
++
++static void selinux_child_step(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    errno_t ret;
++    struct selinux_child_state *state;
++
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct selinux_child_state);
++
++    ret = write_pipe_recv(subreq);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    close(state->io->write_to_child_fd);
++    state->io->write_to_child_fd = -1;
++
++    subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
++    if (subreq == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    tevent_req_set_callback(subreq, selinux_child_done, req);
++}
++
++static void selinux_child_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    struct selinux_child_state *state;
++    uint32_t child_result;
++    errno_t ret;
++    ssize_t len;
++    uint8_t *buf;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct selinux_child_state);
++
++    ret = read_pipe_recv(subreq, state, &buf, &len);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    close(state->io->read_from_child_fd);
++    state->io->read_from_child_fd = -1;
++
++    ret = selinux_child_parse_response(buf, len, &child_result);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "selinux_child_parse_response failed: [%d][%s]\n",
++              ret, strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    } else if (child_result != 0){
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Error in selinux_child: [%d][%s]\n",
++              child_result, strerror(child_result));
++        tevent_req_error(req, ERR_SELINUX_CONTEXT);
++        return;
++    }
++
++    tevent_req_done(req);
++    return;
++}
++
++static errno_t selinux_child_parse_response(uint8_t *buf,
++                                            ssize_t len,
++                                            uint32_t *_child_result)
++{
++    size_t p = 0;
++    uint32_t child_result;
++
++    /* semanage retval */
++    SAFEALIGN_COPY_UINT32_CHECK(&child_result, buf + p, len, &p);
++
++    *_child_result = child_result;
++    return EOK;
++}
++
++static errno_t selinux_child_recv(struct tevent_req *req)
++{
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++    return EOK;
++}
++
+ /* A more generic request to gather all SELinux and HBAC rules. Updates
+  * cache if necessary
+  */
+diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..a624cfd30d6795c305b7673d849213c74de95cd8
+--- /dev/null
++++ b/src/providers/ipa/selinux_child.c
+@@ -0,0 +1,272 @@
++/*
++    SSSD
++
++    IPA back end -- set SELinux context in a child module
++
++    Authors:
++        Jakub Hrozek <jhrozek@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++
++#include <sys/types.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include <popt.h>
++
++#include "util/util.h"
++#include "util/child_common.h"
++#include "providers/dp_backend.h"
++
++struct input_buffer {
++    const char *seuser;
++    const char *mls_range;
++    const char *username;
++};
++
++static errno_t unpack_buffer(uint8_t *buf,
++                             size_t size,
++                             struct input_buffer *ibuf)
++{
++    size_t p = 0;
++    uint32_t len;
++
++    /* seuser */
++    SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
++    DEBUG(SSSDBG_TRACE_INTERNAL, "seuser length: %d\n", len);
++    if (len == 0) {
++        return EINVAL;
++    } else {
++        if ((p + len ) > size) return EINVAL;
++        ibuf->seuser = talloc_strndup(ibuf, (char *)(buf + p), len);
++        if (ibuf->seuser == NULL) return ENOMEM;
++        DEBUG(SSSDBG_TRACE_INTERNAL, "seuser: %s\n", ibuf->seuser);
++        p += len;
++    }
++
++    /* MLS range */
++    SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
++    DEBUG(SSSDBG_TRACE_INTERNAL, "mls_range length: %d\n", len);
++    if (len == 0) {
++        return EINVAL;
++    } else {
++        if ((p + len ) > size) return EINVAL;
++        ibuf->mls_range = talloc_strndup(ibuf, (char *)(buf + p), len);
++        if (ibuf->mls_range == NULL) return ENOMEM;
++        DEBUG(SSSDBG_TRACE_INTERNAL, "mls_range: %s\n", ibuf->mls_range);
++        p += len;
++    }
++
++    /* username */
++    SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
++    DEBUG(SSSDBG_TRACE_INTERNAL, "username length: %d\n", len);
++    if (len == 0) {
++        return EINVAL;
++    } else {
++        if ((p + len ) > size) return EINVAL;
++        ibuf->username = talloc_strndup(ibuf, (char *)(buf + p), len);
++        if (ibuf->username == NULL) return ENOMEM;
++        DEBUG(SSSDBG_TRACE_INTERNAL, "username: %s\n", ibuf->username);
++        p += len;
++    }
++
++    return EOK;
++}
++
++static errno_t pack_buffer(struct response *r, int result)
++{
++    size_t p = 0;
++
++    /* A buffer with the following structure must be created:
++     *   uint32_t status of the request (required)
++     */
++    r->size =  sizeof(uint32_t);
++
++    r->buf = talloc_array(r, uint8_t, r->size);
++    if(r->buf == NULL) {
++        return ENOMEM;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "result [%d]\n", result);
++
++    /* result */
++    SAFEALIGN_SET_UINT32(&r->buf[p], result, &p);
++
++    return EOK;
++}
++
++static errno_t prepare_response(TALLOC_CTX *mem_ctx,
++                                int result,
++                                struct response **rsp)
++{
++    int ret;
++    struct response *r = NULL;
++
++    r = talloc_zero(mem_ctx, struct response);
++    if (r == NULL) {
++        return ENOMEM;
++    }
++
++    r->buf = NULL;
++    r->size = 0;
++
++    ret = pack_buffer(r, result);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "pack_buffer failed\n");
++        return ret;
++    }
++
++    *rsp = r;
++    DEBUG(SSSDBG_TRACE_ALL, "r->size: %zu\n", r->size);
++    return EOK;
++}
++
++int main(int argc, const char *argv[])
++{
++    int opt;
++    poptContext pc;
++    int debug_fd = -1;
++    errno_t ret;
++    TALLOC_CTX *main_ctx = NULL;
++    uint8_t *buf = NULL;
++    ssize_t len = 0;
++    struct input_buffer *ibuf = NULL;
++    struct response *resp = NULL;
++    size_t written;
++
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
++         _("Debug level"), NULL},
++        {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
++         _("Add debug timestamps"), NULL},
++        {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
++         _("Show timestamps with microseconds"), NULL},
++        {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
++         _("An open file descriptor for the debug logs"), NULL},
++        {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
++         &debug_to_stderr, 0,
++         _("Send the debug output to stderr directly."), NULL },
++        POPT_TABLEEND
++    };
++
++    /* Set debug level to invalid value so we can decide if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++        fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                  poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            _exit(-1);
++        }
++    }
++
++    poptFreeContext(pc);
++
++    DEBUG_INIT(debug_level);
++
++    debug_prg_name = talloc_asprintf(NULL, "[sssd[selinux_child[%d]]]", getpid());
++    if (debug_prg_name == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
++        goto fail;
++    }
++
++    if (debug_fd != -1) {
++        ret = set_debug_file_from_fd(debug_fd);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
++        }
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n");
++    DEBUG(SSSDBG_TRACE_INTERNAL,
++          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
++
++    main_ctx = talloc_new(NULL);
++    if (main_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
++        talloc_free(discard_const(debug_prg_name));
++        goto fail;
++    }
++    talloc_steal(main_ctx, debug_prg_name);
++
++    buf = talloc_size(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE);
++    if (buf == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
++        goto fail;
++    }
++
++    ibuf = talloc_zero(main_ctx, struct input_buffer);
++    if (ibuf == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
++        goto fail;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "context initialized\n");
++
++    errno = 0;
++    len = sss_atomic_read_s(STDIN_FILENO, buf, IN_BUF_SIZE);
++    if (len == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n", ret, strerror(ret));
++        goto fail;
++    }
++
++    close(STDIN_FILENO);
++
++    ret = unpack_buffer(buf, len, ibuf);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "unpack_buffer failed.[%d][%s].\n", ret, strerror(ret));
++        goto fail;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "performing selinux operations\n");
++
++    ret = set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range);
++
++    ret = prepare_response(main_ctx, ret, &resp);
++
++    errno = 0;
++
++    written = sss_atomic_write_s(STDOUT_FILENO, resp->buf, resp->size);
++    if (written == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret,
++                    strerror(ret));
++        goto fail;
++    }
++
++    if (written != resp->size) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Expected to write %zu bytes, wrote %zu\n",
++              resp->size, written);
++        goto fail;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "selinux_child completed successfully\n");
++    close(STDOUT_FILENO);
++    talloc_free(main_ctx);
++    return EXIT_SUCCESS;
++fail:
++    DEBUG(SSSDBG_CRIT_FAILURE, "selinux_child failed!\n");
++    close(STDOUT_FILENO);
++    talloc_free(main_ctx);
++    return EXIT_FAILURE;
++}
+diff --git a/src/util/util_errors.c b/src/util/util_errors.c
+index 5b36780ffcdc6733241cdb942865ecdf38da3bca..d5da64622eebe7f779816c7f2090da5b9a9b13f0 100644
+--- a/src/util/util_errors.c
++++ b/src/util/util_errors.c
+@@ -62,6 +62,7 @@ struct err_string error_to_str[] = {
+     { "Bus method not supported" }, /* ERR_SBUS_NOSUP */
+     { "Cannot connect to system bus" }, /* ERR_NO_SYSBUS */
+     { "LDAP search returned a referral" }, /* ERR_REFERRAL */
++    { "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */
+ };
+ 
+ 
+diff --git a/src/util/util_errors.h b/src/util/util_errors.h
+index e040ba903b27d06ec75cea31485d2f3111ca5302..2bc576605e613d674d38b54aae1604c0b044635f 100644
+--- a/src/util/util_errors.h
++++ b/src/util/util_errors.h
+@@ -84,6 +84,7 @@ enum sssd_errors {
+     ERR_SBUS_NOSUP,
+     ERR_NO_SYSBUS,
+     ERR_REFERRAL,
++    ERR_SELINUX_CONTEXT,
+     ERR_LAST            /* ALWAYS LAST */
+ };
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch b/SOURCES/0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch
deleted file mode 100644
index b3f1d9c..0000000
--- a/SOURCES/0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 9118f124fad5fe15c5beb910db08794d9b3d2685 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 24 Jan 2014 16:52:22 +0100
-Subject: [PATCH 72/73] AD SRV: use right domain name for CLDAP ping
-
-Currently always the name of the configured domain was passed to the
-CLDAP request. This will fail if the CLDAP request is send to a DC form
-a different domain.
----
- src/providers/ad/ad_srv.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
-index a238c192e495c3ff6330123d8e53d7d480e88e1b..99502e431e7b8b053e6ec58780abfd10859937be 100644
---- a/src/providers/ad/ad_srv.c
-+++ b/src/providers/ad/ad_srv.c
-@@ -723,7 +723,7 @@ static void ad_srv_plugin_dcs_done(struct tevent_req *subreq)
-                                      state->ctx->be_res,
-                                      state->ctx->host_dbs,
-                                      state->ctx->opts,
--                                     state->ctx->ad_domain,
-+                                     state->discovery_domain,
-                                      dcs, num_dcs);
-     if (subreq == NULL) {
-         ret = ENOMEM;
--- 
-1.8.4.2
-
diff --git a/SOURCES/0072-test_sysdb_views-Use-unique-directory-for-cache.patch b/SOURCES/0072-test_sysdb_views-Use-unique-directory-for-cache.patch
new file mode 100644
index 0000000..904977c
--- /dev/null
+++ b/SOURCES/0072-test_sysdb_views-Use-unique-directory-for-cache.patch
@@ -0,0 +1,48 @@
+From 06e85cb08343ec902f0978ab0b6b373f1f1817f3 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Wed, 5 Nov 2014 22:18:05 +0100
+Subject: [PATCH 72/75] test_sysdb_views: Use unique directory for cache
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Two tests stored cache in the same directory, It can cause failures with
+parallel execution of tests.
+
+sh$ git grep tests_sysdb
+src/tests/cmocka/test_sysdb_views.c:#define TESTS_PATH "tests_sysdb"
+src/tests/sysdb-tests.c:#define TESTS_PATH "tests_sysdb"
+
+This patch also clean up potential leftovers after previous failed
+test_sysdb_views before execution of test suite.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/tests/cmocka/test_sysdb_views.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
+index 38525d6ded8fdbbd1a657f8ca742e51d6ba2b102..9fb2d7201d06e84be83d6a516c5e3a0f15ec0639 100644
+--- a/src/tests/cmocka/test_sysdb_views.c
++++ b/src/tests/cmocka/test_sysdb_views.c
+@@ -30,7 +30,7 @@
+ 
+ #include "tests/cmocka/common_mock.h"
+ 
+-#define TESTS_PATH "tests_sysdb"
++#define TESTS_PATH "tests_sysdb_views"
+ #define TEST_CONF_FILE "tests_conf.ldb"
+ 
+ struct sysdb_test_ctx {
+@@ -226,6 +226,8 @@ int main(int argc, const char *argv[])
+     DEBUG_CLI_INIT(debug_level);
+ 
+     tests_set_cwd();
++    test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_FILE, LOCAL_SYSDB_FILE);
++    test_dom_suite_setup(TESTS_PATH);
+     rv = run_tests(tests);
+ 
+     if (rv == 0 && no_cleanup == 0) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0073-MAN-clarify-which-shell-option-takes-precedence.patch b/SOURCES/0073-MAN-clarify-which-shell-option-takes-precedence.patch
deleted file mode 100644
index e6fd18e..0000000
--- a/SOURCES/0073-MAN-clarify-which-shell-option-takes-precedence.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 045b0cbf342d50ce07fc768fbce63b9bd0309215 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 29 Jan 2014 13:24:15 +0100
-Subject: [PATCH 73/73] MAN: clarify which shell option takes precedence
-
----
- src/man/sssd.conf.5.xml | 13 +++++++------
- 1 file changed, 7 insertions(+), 6 deletions(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index b879bdf63c40e80efa21644bd9ba9d2d3477af06..84770f6b28876278a0ddd6d8a8a8f9a8e0d3146f 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -503,8 +503,9 @@ fallback_homedir = /home/%u
-                     <listitem>
-                         <para>
-                             Override the login shell for all users. This
--                            option can be specified globally in the [nss]
--                            section or per-domain.
-+                            option supersedes any other shell options if
-+                            it takes effect and can be set either in the
-+                            [nss] section or per-domain.
-                         </para>
-                         <para>
-                             Default: not set (SSSD will use the value
-@@ -568,10 +569,10 @@ fallback_homedir = /home/%u
-                     <term>default_shell</term>
-                     <listitem>
-                         <para>
--                            The default shell to use if the provider does not
--                            return one during lookup. This option supersedes
--                            any other shell options if it takes effect and can
--                            be set either in the [nss] section or per-domain.
-+                            The default shell to use if the provider does
-+                            not return one during lookup. This option can
-+                            be specified globally in the [nss] section
-+                            or per-domain.
-                         </para>
-                         <para>
-                             Default: not set (Return NULL if no shell is
--- 
-1.8.4.2
-
diff --git a/SOURCES/0073-selinux_child-Do-not-ignore-return-values.patch b/SOURCES/0073-selinux_child-Do-not-ignore-return-values.patch
new file mode 100644
index 0000000..fcc0efb
--- /dev/null
+++ b/SOURCES/0073-selinux_child-Do-not-ignore-return-values.patch
@@ -0,0 +1,37 @@
+From 863f4705e8961cfc7a21c276d186d3059d20f53e Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 6 Nov 2014 16:35:11 +0100
+Subject: [PATCH 73/75] selinux_child: Do not ignore return values.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ipa/selinux_child.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
+index a624cfd30d6795c305b7673d849213c74de95cd8..a38ffcb26f890349f47478063103e603fe6304cf 100644
+--- a/src/providers/ipa/selinux_child.c
++++ b/src/providers/ipa/selinux_child.c
+@@ -241,8 +241,16 @@ int main(int argc, const char *argv[])
+     DEBUG(SSSDBG_TRACE_FUNC, "performing selinux operations\n");
+ 
+     ret = set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set SELinux login context.\n");
++        goto fail;
++    }
+ 
+     ret = prepare_response(main_ctx, ret, &resp);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to prepare response buffer.\n");
++        goto fail;
++    }
+ 
+     errno = 0;
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0074-IPA-Store-right-username-to-selinux-child-context.patch b/SOURCES/0074-IPA-Store-right-username-to-selinux-child-context.patch
new file mode 100644
index 0000000..968b699
--- /dev/null
+++ b/SOURCES/0074-IPA-Store-right-username-to-selinux-child-context.patch
@@ -0,0 +1,31 @@
+From 66d12b25e5976041f7298b94c9cfe03ee77aa2bb Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Thu, 6 Nov 2014 12:12:04 +0100
+Subject: [PATCH 74/75] IPA: Store right username to selinux child context
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Wrong name would be used with fully qualified names.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/providers/ipa/ipa_selinux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
+index b392d82a61cd523cd5e73e5246013bdbc448ddd5..30ad6f0a7c4622ca5eb9a75ae4f57183543515c6 100644
+--- a/src/providers/ipa/ipa_selinux.c
++++ b/src/providers/ipa/ipa_selinux.c
+@@ -867,7 +867,7 @@ selinux_child_setup(TALLOC_CTX *mem_ctx,
+ 
+     sci->seuser = talloc_strdup(sci, seuser);
+     sci->mls_range = talloc_strdup(sci, mls_range);
+-    sci->username = talloc_strdup(sci, username);
++    sci->username = talloc_strdup(sci, username_final);
+     if (sci->seuser == NULL || sci->mls_range == NULL
+         || sci->username == NULL) {
+         ret = ENOMEM;
+-- 
+1.9.3
+
diff --git a/SOURCES/0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch b/SOURCES/0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch
deleted file mode 100644
index 1caa79e..0000000
--- a/SOURCES/0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 53554c55a75477b0ea719b845ff1660ac1a2ec82 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 24 Jan 2014 17:03:27 +0100
-Subject: [PATCH 74/75] LDAP: store group if subdomain cannot be found by sid
-
-Domain needn't contain sid if id_provider is ldap.
-With enabled id mapping, group couldn't be stored, because domain
-couldn't be found by sid.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2172
----
- src/providers/ldap/sdap_async_groups.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 4ed7d4ab9c0c932da49b244f061329a334719159..ab3691f80aaecca988dcbf0877491a37af3ae49b 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -452,6 +452,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
-     bool posix_group;
-     bool use_id_mapping;
-     char *sid_str;
-+    struct sss_domain_info *subdomain;
-     int32_t ad_group_type;
- 
-     tmpctx = talloc_new(NULL);
-@@ -490,11 +491,12 @@ static int sdap_save_group(TALLOC_CTX *memctx,
-     /* If this object has a SID available, we will determine the correct
-      * domain by its SID. */
-     if (sid_str != NULL) {
--        dom = find_subdomain_by_sid(get_domains_head(dom), sid_str);
--        if (dom == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, ("SID %s does not belong to any known "
-+        subdomain = find_subdomain_by_sid(get_domains_head(dom), sid_str);
-+        if (subdomain) {
-+            dom = subdomain;
-+        } else {
-+            DEBUG(SSSDBG_TRACE_FUNC, ("SID %s does not belong to any known "
-                                       "domain\n", sid_str));
--            return ERR_DOMAIN_NOT_FOUND;
-         }
-     }
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0075-LDAP-require-attribute-groupType-for-AD-groups.patch b/SOURCES/0075-LDAP-require-attribute-groupType-for-AD-groups.patch
deleted file mode 100644
index ea1b78c..0000000
--- a/SOURCES/0075-LDAP-require-attribute-groupType-for-AD-groups.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 42817081e7afe5b67d4151c5ac87b0a48da31a1b Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 29 Jan 2014 14:58:53 +0100
-Subject: [PATCH 75/75] LDAP: require attribute groupType for AD groups
-
-Commit 8280c5213094 introduced filtering local groups for trusted/sub domains,
-but attribute groupType was not available with configuration id_provide ldap
-and ldap_schema ad.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2172
----
- src/providers/ldap/ldap_opts.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
-index 9593dfd30a81db60b7358c66975871507340aa4b..d07051c51aef860943ee8bd4953e8f3d0660a656 100644
---- a/src/providers/ldap/ldap_opts.h
-+++ b/src/providers/ldap/ldap_opts.h
-@@ -295,7 +295,7 @@ struct sdap_attr_map gen_ad2008r2_group_map[] = {
-     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
-     { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
-     { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL },
--    { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
-+    { "ldap_group_type", "groupType", SYSDB_GROUP_TYPE, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
--- 
-1.8.4.2
-
diff --git a/SOURCES/0075-PAM-Remove-authtok-from-PAM-stack-with-OTP.patch b/SOURCES/0075-PAM-Remove-authtok-from-PAM-stack-with-OTP.patch
new file mode 100644
index 0000000..a8c6200
--- /dev/null
+++ b/SOURCES/0075-PAM-Remove-authtok-from-PAM-stack-with-OTP.patch
@@ -0,0 +1,87 @@
+From 5af7fea571868eed16655adffcc9314911e12417 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 20 Oct 2014 22:21:25 +0200
+Subject: [PATCH 75/87] PAM: Remove authtok from PAM stack with OTP
+
+We remove the password from the PAM stack when OTP is used to make sure
+that other pam modules (pam-gnome-keyring, pam_mount) cannot use it anymore
+and have to request a password on their own.
+
+Resolves:
+    https://fedorahosted.org/sssd/ticket/2287
+
+Reviewed-by: Nathaniel McCallum <npmccallum@redhat.com>
+---
+ src/providers/krb5/krb5_auth.c | 14 ++++++++++++++
+ src/sss_client/pam_sss.c       | 16 +++++++++++++++-
+ 2 files changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index f539d5068ec29f7b06f734a3417864b43122b1b7..c96b7aee99da8c3d43a67a04bb1f67ee048d4705 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -1161,6 +1161,20 @@ static void krb5_auth_done(struct tevent_req *subreq)
+         krb5_auth_store_creds(state->domain, pd);
+     }
+ 
++    if (res->otp == true && pd->cmd == SSS_PAM_AUTHENTICATE) {
++        uint32_t otp_flag = 1;
++        ret = pam_add_response(pd, SSS_OTP, sizeof(uint32_t),
++                               (const uint8_t *) &otp_flag);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "pam_add_response failed: %d (%s).\n",
++                  ret, sss_strerror(ret));
++            state->pam_status = PAM_SYSTEM_ERR;
++            state->dp_err = DP_ERR_OK;
++            goto done;
++        }
++    }
++
+     state->pam_status = PAM_SUCCESS;
+     state->dp_err = DP_ERR_OK;
+     ret = EOK;
+diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
+index abe9b05478cbf480b3430dccd1951e9bfb0e29c1..d64e826daeb80be8998ef3b410047e3a44051b07 100644
+--- a/src/sss_client/pam_sss.c
++++ b/src/sss_client/pam_sss.c
+@@ -206,7 +206,7 @@ static size_t add_string_item(enum pam_item_type type, const char *str,
+     return rp;
+ }
+ 
+-static void overwrite_and_free_pam_items(struct pam_items *pi)
++static void overwrite_and_free_authtoks(struct pam_items *pi)
+ {
+     if (pi->pam_authtok != NULL) {
+         _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size);
+@@ -222,6 +222,11 @@ static void overwrite_and_free_pam_items(struct pam_items *pi)
+ 
+     pi->pamstack_authtok = NULL;
+     pi->pamstack_oldauthtok = NULL;
++}
++
++static void overwrite_and_free_pam_items(struct pam_items *pi)
++{
++    overwrite_and_free_authtoks(pi);
+ 
+     free(pi->domain_name);
+     pi->domain_name = NULL;
+@@ -998,6 +1003,15 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
+                     D(("do_pam_conversation failed."));
+                 }
+                 break;
++            case SSS_OTP:
++                D(("OTP was used, removing authtokens."));
++                overwrite_and_free_authtoks(pi);
++                ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
++                if (ret != PAM_SUCCESS) {
++                    D(("Failed to remove PAM_AUTHTOK after using otp [%s]",
++                       pam_strerror(pamh,ret)));
++                }
++                break;
+             default:
+                 D(("Unknown response type [%d]", type));
+         }
+-- 
+1.9.3
+
diff --git a/SOURCES/0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch b/SOURCES/0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch
deleted file mode 100644
index 381c18e..0000000
--- a/SOURCES/0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 3af4a383964cf391e0277bd8a272156a1805e357 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 5 Feb 2014 17:32:20 +0000
-Subject: [PATCH 76/80] MONITOR: Incorrect permissions on sssd.conf
-
-Print user friendly warning when permissions on sssd.conf are incorrect and
-provide hint.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2208
-
-Reviewed-by: Stephen Gallagher <sgallagh@redhat.com>
-(cherry picked from commit b3cc9b98966fa2d90172348c334b3b70c5261ab3)
----
- src/monitor/monitor.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
-index 09f530d2643b45fc31fb4dbe3cb69f2abc5510af..72a8b7c4a376dd9b68349b959cb869b9da059d38 100644
---- a/src/monitor/monitor.c
-+++ b/src/monitor/monitor.c
-@@ -84,6 +84,11 @@
-  */
- #define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__"
- 
-+/* Warning messages */
-+#define CONF_FILE_PERM_ERROR_MSG "Cannot read config file %s. Please check "\
-+                                 "if permissions are 0600 and the file is "\
-+                                 "owned by root.root."
-+
- int cmdline_debug_level;
- int cmdline_debug_timestamps;
- int cmdline_debug_microseconds;
-@@ -2798,7 +2803,8 @@ int main(int argc, const char *argv[])
-         case EPERM:
-         case EACCES:
-             DEBUG(SSSDBG_CRIT_FAILURE,
--                 ("Insufficient permissions to read configuration file.\n"));
-+                  (CONF_FILE_PERM_ERROR_MSG, config_file));
-+            sss_log(SSS_LOG_ALERT, CONF_FILE_PERM_ERROR_MSG, config_file);
-             break;
-         default:
-             DEBUG(SSSDBG_CRIT_FAILURE,
--- 
-1.8.5.3
-
diff --git a/SOURCES/0076-Revert-LDAP-Remove-unused-option-ldap_user_uuid.patch b/SOURCES/0076-Revert-LDAP-Remove-unused-option-ldap_user_uuid.patch
new file mode 100644
index 0000000..8ef2540
--- /dev/null
+++ b/SOURCES/0076-Revert-LDAP-Remove-unused-option-ldap_user_uuid.patch
@@ -0,0 +1,176 @@
+From 60720e16c292cd944677a675728d11d405d8885d Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 5 Nov 2014 17:35:45 +0100
+Subject: [PATCH 76/79] Revert "LDAP: Remove unused option ldap_user_uuid"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit dfb2960ab251f609466fa660449703835c97f99a.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/config/SSSDConfig/__init__.py.in         |  1 +
+ src/config/SSSDConfig/sssd_upgrade_config.py |  1 +
+ src/config/etc/sssd.api.d/sssd-ad.conf       |  1 +
+ src/config/etc/sssd.api.d/sssd-ipa.conf      |  1 +
+ src/config/etc/sssd.api.d/sssd-ldap.conf     |  1 +
+ src/man/sssd-ldap.5.xml                      | 13 +++++++++++++
+ src/providers/ad/ad_opts.h                   |  1 +
+ src/providers/ipa/ipa_opts.h                 |  1 +
+ src/providers/ldap/ldap_opts.h               |  4 ++++
+ src/providers/ldap/sdap.h                    |  1 +
+ 10 files changed, 25 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index b4560ea2b33f2c3b82bff42fb6a36302a146c99f..73195bc46688e14bfdd456f6345e45bdc3d0a8f0 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -272,6 +272,7 @@ option_strings = {
+     'ldap_user_gecos' : _('GECOS attribute'),
+     'ldap_user_home_directory' : _('Home directory attribute'),
+     'ldap_user_shell' : _('Shell attribute'),
++    'ldap_user_uuid' : _('UUID attribute'),
+     'ldap_user_objectsid' : _("objectSID attribute"),
+     'ldap_user_primary_group' : _('Active Directory primary group attribute for ID-mapping'),
+     'ldap_user_principal' : _('User principal attribute (for Kerberos)'),
+diff --git a/src/config/SSSDConfig/sssd_upgrade_config.py b/src/config/SSSDConfig/sssd_upgrade_config.py
+index 3d9f788c3b4707a8b6e8958d11d5068437d31156..97be6543f8f86eb0189843003f675d2efcfcc8a5 100644
+--- a/src/config/SSSDConfig/sssd_upgrade_config.py
++++ b/src/config/SSSDConfig/sssd_upgrade_config.py
+@@ -170,6 +170,7 @@ class SSSDConfigFile(SSSDChangeConf):
+                     'ldap_user_gecos' : 'userGecos',
+                     'ldap_user_home_directory' : 'userHomeDirectory',
+                     'ldap_user_shell' : 'userShell',
++                    'ldap_user_uuid' : 'userUUID',
+                     'ldap_user_principal' : 'userPrincipal',
+                     'ldap_force_upper_case_realm' : 'force_upper_case_realm',
+                     'ldap_user_fullname' : 'userFullname',
+diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
+index 5dd4fb43526849e6b74fbe7cd354afda9af695b0..f8b200eaaf2f1b2ee17214faf2df70b14a2ec93c 100644
+--- a/src/config/etc/sssd.api.d/sssd-ad.conf
++++ b/src/config/etc/sssd.api.d/sssd-ad.conf
+@@ -72,6 +72,7 @@ ldap_user_gid_number = str, None, false
+ ldap_user_gecos = str, None, false
+ ldap_user_home_directory = str, None, false
+ ldap_user_shell = str, None, false
++ldap_user_uuid = str, None, false
+ ldap_user_objectsid = str, None, false
+ ldap_user_primary_group = str, None, false
+ ldap_user_principal = str, None, false
+diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
+index 8713385fc2b6d3b03b75cd5c6557968fdcdad892..91dc9ec9d158758be32f8a3eb5d36be2446fc254 100644
+--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
+@@ -69,6 +69,7 @@ ldap_user_gid_number = str, None, false
+ ldap_user_gecos = str, None, false
+ ldap_user_home_directory = str, None, false
+ ldap_user_shell = str, None, false
++ldap_user_uuid = str, None, false
+ ldap_user_objectsid = str, None, false
+ ldap_user_primary_group = str, None, false
+ ldap_user_principal = str, None, false
+diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
+index 29276bfd74b9fcc67042a138006959896c34fbae..68d5b4953a07398b159f3374ccba7380a642d818 100644
+--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
++++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
+@@ -56,6 +56,7 @@ ldap_user_gid_number = str, None, false
+ ldap_user_gecos = str, None, false
+ ldap_user_home_directory = str, None, false
+ ldap_user_shell = str, None, false
++ldap_user_uuid = str, None, false
+ ldap_user_objectsid = str, None, false
+ ldap_user_primary_group = str, None, false
+ ldap_user_principal = str, None, false
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index 9a9410b415a7419ee303aea6ec2f9f3d41509647..24bc34d3b9ca7a93b241a14ef712d4187306a347 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -338,6 +338,19 @@
+                 </varlistentry>
+ 
+                 <varlistentry>
++                    <term>ldap_user_uuid (string)</term>
++                    <listitem>
++                        <para>
++                            The LDAP attribute that contains the UUID/GUID of
++                            an LDAP user object.
++                        </para>
++                        <para>
++                            Default: nsUniqueId
++                        </para>
++                    </listitem>
++                </varlistentry>
++
++                <varlistentry>
+                     <term>ldap_user_objectsid (string)</term>
+                     <listitem>
+                         <para>
+diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
+index 452516cd24aba4dfbf74376767deb8f5f487253d..ee70b3c4b71b87ab31ac07310a448d7960f8e9a8 100644
+--- a/src/providers/ad/ad_opts.h
++++ b/src/providers/ad/ad_opts.h
+@@ -187,6 +187,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
+     { "ldap_user_principal", "userPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "name", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
++    { "ldap_user_uuid", "objectGUID", SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_user_primary_group", "primaryGroupID", SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index 473eca4f77727e008663d082e954820a9fb0c427..3fe858ca384015b3ffabe7ce391fa51089354719 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -178,6 +178,7 @@ struct sdap_attr_map ipa_user_map[] = {
+     { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
++    { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "ipaNTSecurityIdentifier", SYSDB_SID_STR, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
+index 61e3309fe73e72e82ecb471d9b608db7bea1d2e6..2e937412635e16b4bc541c59055b1c4e7896f045 100644
+--- a/src/providers/ldap/ldap_opts.h
++++ b/src/providers/ldap/ldap_opts.h
+@@ -155,6 +155,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
+     { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", NULL, SYSDB_MEMBEROF, NULL },
++    { "ldap_user_uuid", NULL, SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+@@ -207,6 +208,8 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
+     { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
++    /* FIXME: this is 389ds specific */
++    { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+@@ -259,6 +262,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = {
+     { "ldap_user_principal", "userPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "name", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
++    { "ldap_user_uuid", "objectGUID", SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_user_primary_group", "primaryGroupID", SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index e9e23561c4c74d3b33ebe35aab86fc257bde6237..906fd74090509802909b300d26234f96d324a769 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -256,6 +256,7 @@ enum sdap_user_attrs {
+     SDAP_AT_USER_PRINC,
+     SDAP_AT_USER_FULLNAME,
+     SDAP_AT_USER_MEMBEROF,
++    SDAP_AT_USER_UUID,
+     SDAP_AT_USER_OBJECTSID,
+     SDAP_AT_USER_PRIMARY_GROUP,
+     SDAP_AT_USER_MODSTAMP,
+-- 
+1.9.3
+
diff --git a/SOURCES/0077-Revert-LDAP-Remove-unused-option-ldap_group_uuid.patch b/SOURCES/0077-Revert-LDAP-Remove-unused-option-ldap_group_uuid.patch
new file mode 100644
index 0000000..ff902cb
--- /dev/null
+++ b/SOURCES/0077-Revert-LDAP-Remove-unused-option-ldap_group_uuid.patch
@@ -0,0 +1,176 @@
+From cce184b46a1109d8e1e318b4538ee960ba67619d Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 5 Nov 2014 17:38:05 +0100
+Subject: [PATCH 77/79] Revert "LDAP: Remove unused option ldap_group_uuid"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit b5242c146cc0ca96e2b898a74fb060efda15bc77.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/config/SSSDConfig/__init__.py.in         |  1 +
+ src/config/SSSDConfig/sssd_upgrade_config.py |  1 +
+ src/config/etc/sssd.api.d/sssd-ad.conf       |  1 +
+ src/config/etc/sssd.api.d/sssd-ipa.conf      |  1 +
+ src/config/etc/sssd.api.d/sssd-ldap.conf     |  1 +
+ src/man/sssd-ldap.5.xml                      | 13 +++++++++++++
+ src/providers/ad/ad_opts.h                   |  1 +
+ src/providers/ipa/ipa_opts.h                 |  1 +
+ src/providers/ldap/ldap_opts.h               |  4 ++++
+ src/providers/ldap/sdap.h                    |  1 +
+ 10 files changed, 25 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 73195bc46688e14bfdd456f6345e45bdc3d0a8f0..283ed2d37c894db95bac38c23d25c4ac8d1f4a40 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -309,6 +309,7 @@ option_strings = {
+     'ldap_group_pwd' : _('Group password'),
+     'ldap_group_gid_number' : _('GID attribute'),
+     'ldap_group_member' : _('Group member attribute'),
++    'ldap_group_uuid' : _('Group UUID attribute'),
+     'ldap_group_objectsid' : _("objectSID attribute"),
+     'ldap_group_modify_timestamp' : _('Modification time attribute for groups'),
+     'ldap_group_type' : _('Type of the group and other flags'),
+diff --git a/src/config/SSSDConfig/sssd_upgrade_config.py b/src/config/SSSDConfig/sssd_upgrade_config.py
+index 97be6543f8f86eb0189843003f675d2efcfcc8a5..33d9fed74424a7d3ee28e888aaed724d0a8a94ff 100644
+--- a/src/config/SSSDConfig/sssd_upgrade_config.py
++++ b/src/config/SSSDConfig/sssd_upgrade_config.py
+@@ -184,6 +184,7 @@ class SSSDConfigFile(SSSDChangeConf):
+                     'ldap_group_pwd' : 'userPassword',
+                     'ldap_group_gid_number' : 'groupGidNumber',
+                     'ldap_group_member' : 'groupMember',
++                    'ldap_group_uuid' : 'groupUUID',
+                     'ldap_group_modify_timestamp' : 'modifyTimestamp',
+                     'ldap_network_timeout' : 'network_timeout',
+                     'ldap_offline_timeout' : 'offline_timeout',
+diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
+index f8b200eaaf2f1b2ee17214faf2df70b14a2ec93c..3daa2560b14d74f7686ed47cf1b09e2005eb8917 100644
+--- a/src/config/etc/sssd.api.d/sssd-ad.conf
++++ b/src/config/etc/sssd.api.d/sssd-ad.conf
+@@ -98,6 +98,7 @@ ldap_group_object_class = str, None, false
+ ldap_group_name = str, None, false
+ ldap_group_gid_number = str, None, false
+ ldap_group_member = str, None, false
++ldap_group_uuid = str, None, false
+ ldap_group_objectsid = str, None, false
+ ldap_group_modify_timestamp = str, None, false
+ ldap_group_entry_usn = str, None, false
+diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
+index 91dc9ec9d158758be32f8a3eb5d36be2446fc254..5df52581e67657e41e2f08820b885f100ccd7ca9 100644
+--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
+@@ -95,6 +95,7 @@ ldap_group_object_class = str, None, false
+ ldap_group_name = str, None, false
+ ldap_group_gid_number = str, None, false
+ ldap_group_member = str, None, false
++ldap_group_uuid = str, None, false
+ ldap_group_objectsid = str, None, false
+ ldap_group_modify_timestamp = str, None, false
+ ldap_group_entry_usn = str, None, false
+diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
+index 68d5b4953a07398b159f3374ccba7380a642d818..ba5f56f1942da552fc6ab8f82851714756683a8f 100644
+--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
++++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
+@@ -90,6 +90,7 @@ ldap_group_object_class = str, None, false
+ ldap_group_name = str, None, false
+ ldap_group_gid_number = str, None, false
+ ldap_group_member = str, None, false
++ldap_group_uuid = str, None, false
+ ldap_group_objectsid = str, None, false
+ ldap_group_modify_timestamp = str, None, false
+ ldap_group_entry_usn = str, None, false
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index 24bc34d3b9ca7a93b241a14ef712d4187306a347..f45522bd5f6c599bce7a38d8821cb0a08f6b5df3 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -859,6 +859,19 @@
+                 </varlistentry>
+ 
+                 <varlistentry>
++                    <term>ldap_group_uuid (string)</term>
++                    <listitem>
++                        <para>
++                            The LDAP attribute that contains the UUID/GUID of
++                            an LDAP group object.
++                        </para>
++                        <para>
++                            Default: nsUniqueId
++                        </para>
++                    </listitem>
++                </varlistentry>
++
++                <varlistentry>
+                     <term>ldap_group_objectsid (string)</term>
+                     <listitem>
+                         <para>
+diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
+index ee70b3c4b71b87ab31ac07310a448d7960f8e9a8..ac6006c9200464956ccedb17ff53050fed5fc6ea 100644
+--- a/src/providers/ad/ad_opts.h
++++ b/src/providers/ad/ad_opts.h
+@@ -221,6 +221,7 @@ struct sdap_attr_map ad_2008r2_group_map[] = {
+     { "ldap_group_pwd", NULL, SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
++    { "ldap_group_uuid", "objectGUID", SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL },
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index 3fe858ca384015b3ffabe7ce391fa51089354719..e0478db39913b87c071d8f4daf9c2a0b33a0b0f4 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -212,6 +212,7 @@ struct sdap_attr_map ipa_group_map[] = {
+     { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
++    { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "ipaNTSecurityIdentifier", SYSDB_SID_STR, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
+index 2e937412635e16b4bc541c59055b1c4e7896f045..096a63bd53918ba79378c01257a18e543597209a 100644
+--- a/src/providers/ldap/ldap_opts.h
++++ b/src/providers/ldap/ldap_opts.h
+@@ -189,6 +189,7 @@ struct sdap_attr_map rfc2307_group_map[] = {
+     { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "memberuid", SYSDB_MEMBER, NULL },
++    { "ldap_group_uuid", NULL, SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+@@ -243,6 +244,8 @@ struct sdap_attr_map rfc2307bis_group_map[] = {
+     { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
++    /* FIXME: this is 389ds specific */
++    { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+@@ -296,6 +299,7 @@ struct sdap_attr_map gen_ad2008r2_group_map[] = {
+     { "ldap_group_pwd", NULL, SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
++    { "ldap_group_uuid", "objectGUID", SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL },
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index 906fd74090509802909b300d26234f96d324a769..aa10623a58d7d667205b09e744dc2b924ca821ed 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -295,6 +295,7 @@ enum sdap_group_attrs {
+     SDAP_AT_GROUP_PWD,
+     SDAP_AT_GROUP_GID,
+     SDAP_AT_GROUP_MEMBER,
++    SDAP_AT_GROUP_UUID,
+     SDAP_AT_GROUP_OBJECTSID,
+     SDAP_AT_GROUP_MODSTAMP,
+     SDAP_AT_GROUP_USN,
+-- 
+1.9.3
+
diff --git a/SOURCES/0077-Revert-NSS-add-support-for-subdomain_homedir.patch b/SOURCES/0077-Revert-NSS-add-support-for-subdomain_homedir.patch
deleted file mode 100644
index 3f14be6..0000000
--- a/SOURCES/0077-Revert-NSS-add-support-for-subdomain_homedir.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From e7987aced2a2052d3cbff185f6e53708b552995b Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Tue, 21 Jan 2014 15:06:37 +0000
-Subject: [PATCH 77/80] Revert "NSS: add support for subdomain_homedir"
-
-This reverts commit 1dc7694a1cbc62b0d7e23cc1369579e5ce0071e8.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/responder/nss/nsssrv_cmd.c | 8 --------
- 1 file changed, 8 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index 9ac3680de4d6ff12fe0c77a3963f84934e385276..c59078b545842561a7e5f62e9a99da6057b23660 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -201,14 +201,6 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx,
-                                        name, uid, homedir, dom->name, NULL);
-     }
- 
--    /* Override home directory location for subdomains.
--     * This option can be overriden by override_homedir.
--     */
--    if (IS_SUBDOMAIN(dom) && dom->subdomain_homedir) {
--        return expand_homedir_template(mem_ctx, dom->subdomain_homedir,
--                                       name, uid, homedir, dom->name, NULL);
--    }
--
-     if (!homedir || *homedir == '\0') {
-         /* In the case of a NULL or empty homedir, check to see if
-          * we have a fallback homedir to use.
--- 
-1.8.5.3
-
diff --git a/SOURCES/0078-AD-support-for-subdomain_homedir.patch b/SOURCES/0078-AD-support-for-subdomain_homedir.patch
deleted file mode 100644
index ac57314..0000000
--- a/SOURCES/0078-AD-support-for-subdomain_homedir.patch
+++ /dev/null
@@ -1,233 +0,0 @@
-From 0b813ab764fd0b255e342765b79533e1869cd06e Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 22 Jan 2014 16:47:22 +0000
-Subject: [PATCH 78/80] AD: support for subdomain_homedir
-
-Homedir is defaultly set accordingly to subdomain_homedir for users from AD.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2169
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/ipa/ipa_subdomains_id.c | 190 ++++++++++++++++++++++++++++++++++
- 1 file changed, 190 insertions(+)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index c29a2a3047af105966b636422105abd15e8a3992..fb1ad896885866dd9c34f9db960e09d92763f86d 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -25,6 +25,7 @@
- #include <errno.h>
- 
- #include "util/util.h"
-+#include "util/sss_nss.h"
- #include "util/strtonum.h"
- #include "db/sysdb.h"
- #include "providers/ldap/ldap_common.h"
-@@ -350,6 +351,185 @@ ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
-     return (iter) ? iter->ad_id_ctx : NULL;
- }
- 
-+static errno_t
-+get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-+                              const char *fqname, uint32_t uid,
-+                              const char **_homedir)
-+{
-+    errno_t ret;
-+    char *name;
-+    const char *homedir;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    tmp_ctx = talloc_new(mem_ctx);
-+    if (tmp_ctx == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = sss_parse_name(tmp_ctx, dom->names, fqname, NULL, &name);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir, name,
-+                                      uid, NULL, dom->name, dom->flat_name);
-+
-+    if (homedir == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("expand_homedir_template failed\n"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    if (_homedir == NULL) {
-+        ret = EINVAL;
-+        goto done;
-+    }
-+    *_homedir = talloc_steal(mem_ctx, homedir);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+store_homedir_of_user(struct sss_domain_info *domain,
-+                      const char *fqname, const char *homedir)
-+{
-+    errno_t ret;
-+    errno_t sret;
-+    TALLOC_CTX *tmp_ctx;
-+    bool in_transaction = false;
-+    struct sysdb_attrs *attrs;
-+    struct sysdb_ctx *sysdb = domain->sysdb;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    attrs = sysdb_new_attrs(tmp_ctx);
-+    if (attrs == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, homedir);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, ("Error setting homedir: [%s]\n",
-+                                     strerror(ret)));
-+        goto done;
-+    }
-+
-+    ret = sysdb_transaction_start(sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
-+        goto done;
-+    }
-+
-+    in_transaction = true;
-+
-+    ret = sysdb_set_user_attr(sysdb, domain, fqname, attrs, SYSDB_MOD_REP);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              ("Failed to update homedir information!\n"));
-+        goto done;
-+    }
-+
-+    ret = sysdb_transaction_commit(sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              ("Cannot commit sysdb transaction [%d]: %s.\n",
-+               ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    in_transaction = false;
-+
-+done:
-+    if (in_transaction) {
-+        sret = sysdb_transaction_cancel(sysdb);
-+        if (sret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction.\n"));
-+        }
-+    }
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-+                        int filter_type, const char *filter_value)
-+{
-+    errno_t ret;
-+    uint32_t uid;
-+    const char *fqname;
-+    const char *homedir = NULL;
-+    struct ldb_result *res;
-+
-+    if (filter_type == BE_FILTER_NAME) {
-+        ret = sysdb_getpwnam(mem_ctx, dom->sysdb, dom, filter_value, &res);
-+    } else if (filter_type == BE_FILTER_IDNUM) {
-+        errno = 0;
-+        uid = strtouint32(filter_value, NULL, 10);
-+        if (errno != 0) {
-+            ret = errno;
-+            goto done;
-+        }
-+        ret = sysdb_getpwuid(mem_ctx, dom->sysdb, dom, uid, &res);
-+    } else {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Unsupported filter type: [%d].\n", filter_type));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Failed to make request to our cache: [%d]: [%s]\n",
-+               ret, sss_strerror(ret)));
-+        goto done;
-+    }
-+
-+    if (res->count == 0) {
-+        ret = ENOENT;
-+        goto done;
-+    }
-+
-+    /*
-+     * Homedir is always overriden by subdomain_homedir even if it was
-+     * explicitly set by user.
-+     */
-+    fqname = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
-+    uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
-+    if (uid == 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("UID for user [%s] is not known.\n",
-+                                  filter_value));
-+        ret = ENOENT;
-+        goto done;
-+    }
-+
-+    ret = get_subdomain_homedir_of_user(mem_ctx, dom, fqname, uid, &homedir);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("get_subdomain_homedir_of_user failed: [%d]: [%s]\n",
-+               ret, sss_strerror(ret)));
-+        goto done;
-+    }
-+
-+    ret = store_homedir_of_user(dom, fqname, homedir);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("store_homedir_of_user failed: [%d]: [%s]\n",
-+               ret, sss_strerror(ret)));
-+        goto done;
-+    }
-+
-+done:
-+    return ret;
-+}
-+
- static void
- ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
- {
-@@ -367,6 +547,16 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    ret = apply_subdomain_homedir(state, state->user_dom,
-+                                  state->ar->filter_type,
-+                                  state->ar->filter_value);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("apply_subdomain_homedir failed: [%d]: [%s].\n",
-+               ret, sss_strerror(ret)));
-+        goto fail;
-+    }
-+
-     if ((state->ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS) {
-         tevent_req_done(req);
-         return;
--- 
-1.8.5.3
-
diff --git a/SOURCES/0078-Fix-uuid-defaults.patch b/SOURCES/0078-Fix-uuid-defaults.patch
new file mode 100644
index 0000000..dd94248
--- /dev/null
+++ b/SOURCES/0078-Fix-uuid-defaults.patch
@@ -0,0 +1,102 @@
+From 2d9a33aaa3ecae4af7fb64c64fc2ada176b26a02 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 5 Nov 2014 18:01:07 +0100
+Subject: [PATCH 78/79] Fix uuid defaults
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Recently the uuid attributes for user and groups were removed because
+it was found that there are not used at all and that some of them where
+causing issues (https://fedorahosted.org/sssd/ticket/2383).
+
+The new views/overrides feature of FreeIPA uses the ipaUniqueID attribute
+to relate overrides with the original IPA objects. The previous two
+patches revert the removal of the uuid attributes from users and groups
+with this patch set the default value of these attributes to
+ipaUniqueID from the IPA provider, to objectGUID for the AD provider and
+leaves them unset for the general LDAP case to avoid issues like the one
+from ticket #2383.
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/man/sssd-ldap.5.xml        | 6 ++++--
+ src/providers/ipa/ipa_opts.h   | 4 ++--
+ src/providers/ldap/ldap_opts.h | 6 ++----
+ 3 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index f45522bd5f6c599bce7a38d8821cb0a08f6b5df3..dad6f27933ced506fed7cd040e9fe91968295632 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -345,7 +345,8 @@
+                             an LDAP user object.
+                         </para>
+                         <para>
+-                            Default: nsUniqueId
++                            Default: not set in the general case, objectGUID for
++                            AD and ipaUniqueID for IPA
+                         </para>
+                     </listitem>
+                 </varlistentry>
+@@ -866,7 +867,8 @@
+                             an LDAP group object.
+                         </para>
+                         <para>
+-                            Default: nsUniqueId
++                            Default: not set in the general case, objectGUID for
++                            AD and ipaUniqueID for IPA
+                         </para>
+                     </listitem>
+                 </varlistentry>
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index e0478db39913b87c071d8f4daf9c2a0b33a0b0f4..59282e8699091fbccf08ddfc6825034d4f81a87f 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -178,7 +178,7 @@ struct sdap_attr_map ipa_user_map[] = {
+     { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
+-    { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
++    { "ldap_user_uuid", "ipaUniqueID", SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "ipaNTSecurityIdentifier", SYSDB_SID_STR, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+@@ -212,7 +212,7 @@ struct sdap_attr_map ipa_group_map[] = {
+     { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
+-    { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL },
++    { "ldap_group_uuid", "ipaUniqueID", SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "ipaNTSecurityIdentifier", SYSDB_SID_STR, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
+index 096a63bd53918ba79378c01257a18e543597209a..29d9faf99784bfc3526398488be837a2716ee11d 100644
+--- a/src/providers/ldap/ldap_opts.h
++++ b/src/providers/ldap/ldap_opts.h
+@@ -209,8 +209,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
+     { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL },
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
+-    /* FIXME: this is 389ds specific */
+-    { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
++    { "ldap_user_uuid", NULL, SYSDB_UUID, NULL },
+     { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+@@ -244,8 +243,7 @@ struct sdap_attr_map rfc2307bis_group_map[] = {
+     { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
+-    /* FIXME: this is 389ds specific */
+-    { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL },
++    { "ldap_group_uuid", NULL, SYSDB_UUID, NULL },
+     { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+-- 
+1.9.3
+
diff --git a/SOURCES/0079-MAN-update-of-subdomain_homedir-usage.patch b/SOURCES/0079-MAN-update-of-subdomain_homedir-usage.patch
deleted file mode 100644
index d14bd16..0000000
--- a/SOURCES/0079-MAN-update-of-subdomain_homedir-usage.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 75b31af85b662912d9deb0c6a8f14728f20e5d2d Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 29 Jan 2014 16:55:30 +0000
-Subject: [PATCH 79/80] MAN: update of subdomain_homedir usage
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2169
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/man/sssd.conf.5.xml | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 84770f6b28876278a0ddd6d8a8a8f9a8e0d3146f..5d861c73cfeb41920619d95e5c1e5c1975dcc45b 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -1771,7 +1771,8 @@ fallback_homedir = /home/%u
-                     <listitem>
-                         <para>
-                             Use this homedir as default value for all subdomains
--                            within this domain. See <emphasis>override_homedir</emphasis>
-+                            within this domain in IPA AD trust.
-+                            See <emphasis>override_homedir</emphasis>
-                             for info about possible values. In addition to those, the
-                             expansion below can only be used with
-                             <emphasis>subdomain_homedir</emphasis>.
--- 
-1.8.5.3
-
diff --git a/SOURCES/0079-Revert-LDAP-Change-defaults-for-ldap_user-group_obje.patch b/SOURCES/0079-Revert-LDAP-Change-defaults-for-ldap_user-group_obje.patch
new file mode 100644
index 0000000..fca592e
--- /dev/null
+++ b/SOURCES/0079-Revert-LDAP-Change-defaults-for-ldap_user-group_obje.patch
@@ -0,0 +1,88 @@
+From 7f88b3a46f296520c1d73bb431c5960ba5daeba7 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 7 Nov 2014 13:27:53 +0100
+Subject: [PATCH 79/79] Revert "LDAP: Change defaults for
+ ldap_user/group_objectsid"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit f834f712548db811695ea0fd6d6b31d3bd03e2a3.
+
+OpenLDAP server cannot dereference unknown attributes. The attribute objectSID
+isn't in any standard objectclass on OpenLDAP server. This is a reason why
+objectSID cannot be set by default in rfc2307 map and rfc2307bis map.
+It is the same problem as using non standard attribute "nsUniqueId"
+in ticket https://fedorahosted.org/sssd/ticket/2383
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/man/sssd-ldap.5.xml        | 4 ++--
+ src/providers/ldap/ldap_opts.h | 8 ++++----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index dad6f27933ced506fed7cd040e9fe91968295632..2dcf7e3f8ab5c307e0262efdebfc148c30ea3679 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -360,7 +360,7 @@
+                             necessary for ActiveDirectory servers.
+                         </para>
+                         <para>
+-                            Default: ipaNTSecurityIdentifier for IPA, objectSID
++                            Default: objectSid for ActiveDirectory, not set
+                             for other servers.
+                         </para>
+                     </listitem>
+@@ -882,7 +882,7 @@
+                             necessary for ActiveDirectory servers.
+                         </para>
+                         <para>
+-                            Default: ipaNTSecurityIdentifier for IPA, objectSID
++                            Default: objectSid for ActiveDirectory, not set
+                             for other servers.
+                         </para>
+                     </listitem>
+diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
+index 29d9faf99784bfc3526398488be837a2716ee11d..dedbdac0bcf647337d4c00b1fbb82d6b46be5b54 100644
+--- a/src/providers/ldap/ldap_opts.h
++++ b/src/providers/ldap/ldap_opts.h
+@@ -156,7 +156,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", NULL, SYSDB_MEMBEROF, NULL },
+     { "ldap_user_uuid", NULL, SYSDB_UUID, NULL },
+-    { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
++    { "ldap_user_objectsid", NULL, SYSDB_SID, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_user_entry_usn", NULL, SYSDB_USN, NULL },
+@@ -190,7 +190,7 @@ struct sdap_attr_map rfc2307_group_map[] = {
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "memberuid", SYSDB_MEMBER, NULL },
+     { "ldap_group_uuid", NULL, SYSDB_UUID, NULL },
+-    { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
++    { "ldap_group_objectsid", NULL, SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+     { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
+@@ -210,7 +210,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
+     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
+     { "ldap_user_uuid", NULL, SYSDB_UUID, NULL },
+-    { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
++    { "ldap_user_objectsid", NULL, SYSDB_SID, NULL },
+     { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
+     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_user_entry_usn", NULL, SYSDB_USN, NULL },
+@@ -244,7 +244,7 @@ struct sdap_attr_map rfc2307bis_group_map[] = {
+     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+     { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
+     { "ldap_group_uuid", NULL, SYSDB_UUID, NULL },
+-    { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL },
++    { "ldap_group_objectsid", NULL, SYSDB_SID, NULL },
+     { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+     { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL },
+     { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL },
+-- 
+1.9.3
+
diff --git a/SOURCES/0080-LDAP-Disable-token-groups-by-default.patch b/SOURCES/0080-LDAP-Disable-token-groups-by-default.patch
new file mode 100644
index 0000000..dd0bbcb
--- /dev/null
+++ b/SOURCES/0080-LDAP-Disable-token-groups-by-default.patch
@@ -0,0 +1,55 @@
+From 1ded5712eb3ed631e9787beffdf9cda4d44ae6b5 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 7 Nov 2014 13:58:17 +0100
+Subject: [PATCH 80/80] LDAP: Disable token groups by default
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We tried to speed up processing of initgroup lookups with tokenGroups even for
+the LDAP provider (if remote server is Active Directory), but it turns out that
+there are too many corner cases that we didn't catch during development that
+break. For instance, groups from other trusted domains might appear in TG and
+the LDAP provider isn't equipped to handle them.
+
+Overall, users who wish to use the added speed benefits of tokenGroups are
+advised to use the AD provider.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2483
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/man/sssd-ldap.5.xml        | 2 +-
+ src/providers/ldap/ldap_opts.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index 2dcf7e3f8ab5c307e0262efdebfc148c30ea3679..d7a2a4ac9fa2497a4c347a2a7e77703e53b8a46c 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1022,7 +1022,7 @@
+                           Active Directory Server 2008 and later.
+                         </para>
+                         <para>
+-                            Default: True
++                            Default: True for AD and IPA otherwise False.
+                         </para>
+                     </listitem>
+                 </varlistentry>
+diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
+index dedbdac0bcf647337d4c00b1fbb82d6b46be5b54..f46381e9fac7b93730ce0767154989f2e3b7ebbf 100644
+--- a/src/providers/ldap/ldap_opts.h
++++ b/src/providers/ldap/ldap_opts.h
+@@ -116,7 +116,7 @@ struct dp_option default_basic_opts[] = {
+     { "ldap_idmap_default_domain_sid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_groups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "ldap_initgroups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+-    { "ldap_use_tokengroups", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE},
++    { "ldap_use_tokengroups", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE},
+     { "ldap_rfc2307_fallback_to_local_users", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "ldap_disable_range_retrieval", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
+-- 
+1.9.3
+
diff --git a/SOURCES/0080-utils-handling-NULL-params-in-sss_parse_name.patch b/SOURCES/0080-utils-handling-NULL-params-in-sss_parse_name.patch
deleted file mode 100644
index b8ff0cd..0000000
--- a/SOURCES/0080-utils-handling-NULL-params-in-sss_parse_name.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From 6ab5595ec7360bd4cc4c0494a1e0afedda701961 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Sun, 26 Jan 2014 12:39:43 +0000
-Subject: [PATCH 80/80] utils: handling NULL params in sss_parse_name
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/util/usertools.c | 50 +++++++++++++++++++++++++++-----------------------
- src/util/util.h      |  2 +-
- 2 files changed, 28 insertions(+), 24 deletions(-)
-
-diff --git a/src/util/usertools.c b/src/util/usertools.c
-index 9edae41e0f216f9f0d1660e473f3aa1bf7160b06..fab0a261e82b8c4d8071ced1dac99b8e3b987b00 100644
---- a/src/util/usertools.c
-+++ b/src/util/usertools.c
-@@ -322,7 +322,7 @@ done:
- 
- int sss_parse_name(TALLOC_CTX *memctx,
-                    struct sss_names_ctx *snctx,
--                   const char *orig, char **domain, char **name)
-+                   const char *orig, char **_domain, char **_name)
- {
-     pcre *re = snctx->re;
-     const char *result;
-@@ -346,31 +346,35 @@ int sss_parse_name(TALLOC_CTX *memctx,
- 
-     strnum = ret;
- 
--    result = NULL;
--    ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result);
--    if (ret < 0  || !result) {
--        DEBUG(2, ("Name not found!\n"));
--        return EINVAL;
-+    if (_name != NULL) {
-+        result = NULL;
-+        ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result);
-+        if (ret < 0  || !result) {
-+            DEBUG(2, ("Name not found!\n"));
-+            return EINVAL;
-+        }
-+        *_name = talloc_strdup(memctx, result);
-+        pcre_free_substring(result);
-+        if (!*_name) return ENOMEM;
-     }
--    *name = talloc_strdup(memctx, result);
--    pcre_free_substring(result);
--    if (!*name) return ENOMEM;
- 
--
--    result = NULL;
--    ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", &result);
--    if (ret < 0  || !result) {
--        DEBUG(4, ("Domain not provided!\n"));
--        *domain = NULL;
--    } else {
--        /* ignore "" string */
--        if (*result) {
--            *domain = talloc_strdup(memctx, result);
--            pcre_free_substring(result);
--            if (!*domain) return ENOMEM;
-+    if (_domain != NULL) {
-+        result = NULL;
-+        ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain",
-+                                       &result);
-+        if (ret < 0  || !result) {
-+            DEBUG(4, ("Domain not provided!\n"));
-+            *_domain = NULL;
-         } else {
--            pcre_free_substring(result);
--            *domain = NULL;
-+            /* ignore "" string */
-+            if (*result) {
-+                *_domain = talloc_strdup(memctx, result);
-+                pcre_free_substring(result);
-+                if (!*_domain) return ENOMEM;
-+            } else {
-+                pcre_free_substring(result);
-+                *_domain = NULL;
-+            }
-         }
-     }
- 
-diff --git a/src/util/util.h b/src/util/util.h
-index 3334476ab83a137d957765fe2c9afba4ad0d014c..7b185bcb4287a4afc5bf67b40164cf69b9beeb19 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -349,7 +349,7 @@ int sss_names_init(TALLOC_CTX *mem_ctx,
- 
- int sss_parse_name(TALLOC_CTX *memctx,
-                    struct sss_names_ctx *snctx,
--                   const char *orig, char **domain, char **name);
-+                   const char *orig, char **_domain, char **_name);
- 
- char *
- sss_get_cased_name(TALLOC_CTX *mem_ctx, const char *orig_name,
--- 
-1.8.5.3
-
diff --git a/SOURCES/0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch b/SOURCES/0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch
deleted file mode 100644
index 6c4671b..0000000
--- a/SOURCES/0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch
+++ /dev/null
@@ -1,834 +0,0 @@
-From 3b0d429051648a1545de528ec760c4823088a1d9 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 16 Dec 2013 18:36:12 +0100
-Subject: [PATCH 81/84] LDAP: Detect the presence of POSIX attributes
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When the schema is set to AD and ID mapping is not used, there is a one-time
-check ran when searching for users to detect the presence of POSIX
-attributes in LDAP. If this check fails, the search fails as if no entry
-was found and returns a special error code.
-
-The sdap_server_opts structure is filled every time a client connects to
-a server so the posix check boolean is reset to false again on connecting
-to the server.
-
-It might be better to move the check to where the rootDSE is retrieved,
-but the check depends on several features that are not known to the code
-that retrieves the rootDSE (or the connection code for example) such as what
-the attribute mappings are or the authentication method that should be used.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit e81deec535d11912b87954c81a1edd768c1386c9)
----
- src/providers/ad/ad_id.c              |  50 ++++++++-
- src/providers/ad/ad_id.h              |   1 +
- src/providers/ipa/ipa_subdomains_id.c |   2 +-
- src/providers/ldap/ldap_id.c          | 158 +++++++++++++++++++++++++--
- src/providers/ldap/sdap.h             |   1 +
- src/providers/ldap/sdap_async.c       | 200 ++++++++++++++++++++++++++++++++++
- src/providers/ldap/sdap_async.h       |   9 ++
- src/providers/ldap/sdap_async_enum.c  |  96 +++++++++++++++-
- src/util/util_errors.c                |   1 +
- src/util/util_errors.h                |   1 +
- 10 files changed, 504 insertions(+), 15 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index e3302c15774ab1c24b16cefc274313e447b31e5c..bfae86284355b6c13547aac55b7273133bde851d 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -27,6 +27,28 @@
- #include "providers/ldap/sdap_async_enum.h"
- #include "providers/ldap/sdap_idmap.h"
- 
-+static void
-+disable_gc(struct ad_options *ad_options)
-+{
-+    errno_t ret;
-+
-+    if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
-+        return;
-+    }
-+
-+    DEBUG(SSSDBG_IMPORTANT_INFO, ("POSIX attributes were requested "
-+          "but are not present on the server side. Global Catalog "
-+          "lookups will be disabled\n"));
-+
-+    ret = dp_opt_set_bool(ad_options->basic,
-+                          AD_ENABLE_GC, false);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+                ("Could not turn off GC support\n"));
-+        /* Not fatal */
-+    }
-+}
-+
- struct ad_handle_acct_info_state {
-     struct be_req *breq;
-     struct be_acct_req *ar;
-@@ -34,6 +56,7 @@ struct ad_handle_acct_info_state {
-     struct sdap_id_conn_ctx **conn;
-     struct sdap_domain *sdom;
-     size_t cindex;
-+    struct ad_options *ad_options;
- 
-     int dp_error;
-     const char *err;
-@@ -47,6 +70,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
-                          struct be_req *breq,
-                          struct be_acct_req *ar,
-                          struct sdap_id_ctx *ctx,
-+                         struct ad_options *ad_options,
-                          struct sdap_domain *sdom,
-                          struct sdap_id_conn_ctx **conn)
- {
-@@ -64,6 +88,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
-     state->ctx = ctx;
-     state->sdom = sdom;
-     state->conn = conn;
-+    state->ad_options = ad_options;
-     state->cindex = 0;
- 
-     ret = ad_handle_acct_info_step(req);
-@@ -137,12 +162,14 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
-     if (sdap_err == EOK) {
-         tevent_req_done(req);
-         return;
-+    } else if (sdap_err == ERR_NO_POSIX) {
-+        disable_gc(state->ad_options);
-     } else if (sdap_err != ENOENT) {
-         tevent_req_error(req, EIO);
-         return;
-     }
- 
--    /* Ret is only ENOENT now. Try the next connection */
-+    /* Ret is only ENOENT or ERR_NO_POSIX now. Try the next connection */
-     state->cindex++;
-     ret = ad_handle_acct_info_step(req);
-     if (ret != EAGAIN) {
-@@ -356,7 +383,7 @@ ad_account_info_handler(struct be_req *be_req)
-     }
- 
-     req = ad_handle_acct_info_send(be_req, be_req, ar, sdap_id_ctx,
--                                   sdom, clist);
-+                                   ad_ctx->ad_options, sdom, clist);
-     if (req == NULL) {
-         ret = ENOMEM;
-         goto fail;
-@@ -611,9 +638,24 @@ ad_enumeration_done(struct tevent_req *subreq)
- 
-     ret = sdap_dom_enum_ex_recv(subreq);
-     talloc_zfree(subreq);
--    if (ret != EOK) {
-+    if (ret == ERR_NO_POSIX) {
-+        /* Retry enumerating the same domain again, this time w/o
-+         * connecting to GC
-+         */
-+        disable_gc(state->id_ctx->ad_options);
-+        ret = ad_enum_sdom(req, state->sditer, state->id_ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                ("Could not retry domain %s\n", state->sditer->dom->name));
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+
-+        /* Execution will resume in ad_enumeration_done */
-+        return;
-+    } else if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
--              ("Could not enumerate domain %s\n", state->sdom->dom->name));
-+              ("Could not enumerate domain %s\n", state->sditer->dom->name));
-         tevent_req_error(req, ret);
-         return;
-     }
-diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
-index 74b85645c2d6458617a4064fe3fb3f99696c3741..9eb0ac3754be2fd687ed2257b91854f5fceb82a2 100644
---- a/src/providers/ad/ad_id.h
-+++ b/src/providers/ad/ad_id.h
-@@ -31,6 +31,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
-                          struct be_req *breq,
-                          struct be_acct_req *ar,
-                          struct sdap_id_ctx *ctx,
-+                         struct ad_options *ad_options,
-                          struct sdap_domain *sdom,
-                          struct sdap_id_conn_ctx **conn);
- errno_t
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index fb1ad896885866dd9c34f9db960e09d92763f86d..b61c6a5f4d7605f0cdfa182bbc933d35c4613a79 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -323,7 +323,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-     }
- 
-     subreq = ad_handle_acct_info_send(req, be_req, ar, sdap_id_ctx,
--                                      sdom, clist);
-+                                      ad_id_ctx->ad_options, sdom, clist);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto fail;
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index e36c1f697c18e865a47d991dad103fc440456118..b948ba9f358af994bdbbb99a468f7dbe66e65c1d 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -50,6 +50,7 @@ struct users_get_state {
- 
-     char *filter;
-     const char **attrs;
-+    bool use_id_mapping;
- 
-     int dp_error;
-     int sdap_ret;
-@@ -58,6 +59,8 @@ struct users_get_state {
- 
- static int users_get_retry(struct tevent_req *req);
- static void users_get_connect_done(struct tevent_req *subreq);
-+static void users_get_posix_check_done(struct tevent_req *subreq);
-+static void users_get_search(struct tevent_req *req);
- static void users_get_done(struct tevent_req *subreq);
- 
- struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-@@ -79,7 +82,6 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-     uid_t uid;
-     enum idmap_error_code err;
-     char *sid;
--    bool use_id_mapping;
- 
-     req = tevent_req_create(memctx, &state, struct users_get_state);
-     if (!req) return NULL;
-@@ -103,7 +105,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-     state->name = name;
-     state->filter_type = filter_type;
- 
--    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-+    state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-                                                           ctx->opts->idmap_ctx,
-                                                           sdom->dom->name,
-                                                           sdom->dom->domain_id);
-@@ -116,7 +118,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-         }
-         break;
-     case BE_FILTER_IDNUM:
--        if (use_id_mapping) {
-+        if (state->use_id_mapping) {
-             /* If we're ID-mapping, we need to use the objectSID
-              * in the search filter.
-              */
-@@ -184,7 +186,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-         goto fail;
-     }
- 
--    if (use_id_mapping || filter_type == BE_FILTER_SECID) {
-+    if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
-         /* When mapping IDs or looking for SIDs, we don't want to limit
-          * ourselves to users with a UID value. But there must be a SID to map
-          * from.
-@@ -269,6 +271,75 @@ static void users_get_connect_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    /* If POSIX attributes have been requested with an AD server and we
-+     * have no idea about POSIX attributes support, run a one-time check
-+     */
-+    if (state->use_id_mapping == false &&
-+            state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
-+            state->ctx->srv_opts &&
-+            state->ctx->srv_opts->posix_checked == false) {
-+        subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-+                                       sdap_id_op_handle(state->op),
-+                                       state->sdom->user_search_bases,
-+                                       dp_opt_get_int(state->ctx->opts->basic,
-+                                                      SDAP_SEARCH_TIMEOUT));
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+        tevent_req_set_callback(subreq, users_get_posix_check_done, req);
-+        return;
-+    }
-+
-+    users_get_search(req);
-+}
-+
-+static void users_get_posix_check_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    bool has_posix;
-+    int dp_error;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct users_get_state *state = tevent_req_data(req,
-+                                                    struct users_get_state);
-+
-+    ret = sdap_posix_check_recv(subreq, &has_posix);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        /* We can only finish the id_op on error as the connection
-+         * is re-used by the user search
-+         */
-+        ret = sdap_id_op_done(state->op, ret, &dp_error);
-+        if (dp_error == DP_ERR_OK && ret != EOK) {
-+            /* retry */
-+            ret = users_get_retry(req);
-+            if (ret != EOK) {
-+                tevent_req_error(req, ret);
-+            }
-+            return;
-+        }
-+    }
-+
-+    state->ctx->srv_opts->posix_checked = true;
-+
-+    /* If the check ran to completion, we know for certain about the attributes
-+     */
-+    if (has_posix == false) {
-+        state->sdap_ret = ERR_NO_POSIX;
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    users_get_search(req);
-+}
-+
-+static void users_get_search(struct tevent_req *req)
-+{
-+    struct users_get_state *state = tevent_req_data(req,
-+                                                     struct users_get_state);
-+    struct tevent_req *subreq;
-+
-     subreq = sdap_get_users_send(state, state->ev,
-                                  state->domain, state->sysdb,
-                                  state->ctx->opts,
-@@ -434,6 +505,7 @@ struct groups_get_state {
- 
-     char *filter;
-     const char **attrs;
-+    bool use_id_mapping;
- 
-     int dp_error;
-     int sdap_ret;
-@@ -442,6 +514,8 @@ struct groups_get_state {
- 
- static int groups_get_retry(struct tevent_req *req);
- static void groups_get_connect_done(struct tevent_req *subreq);
-+static void groups_get_posix_check_done(struct tevent_req *subreq);
-+static void groups_get_search(struct tevent_req *req);
- static void groups_get_done(struct tevent_req *subreq);
- 
- struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-@@ -463,7 +537,6 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-     gid_t gid;
-     enum idmap_error_code err;
-     char *sid;
--    bool use_id_mapping;
-     const char *member_filter[2];
- 
-     req = tevent_req_create(memctx, &state, struct groups_get_state);
-@@ -488,7 +561,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-     state->name = name;
-     state->filter_type = filter_type;
- 
--    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-+    state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-                                                           ctx->opts->idmap_ctx,
-                                                           sdom->dom->name,
-                                                           sdom->dom->domain_id);
-@@ -503,7 +576,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-         }
-         break;
-     case BE_FILTER_IDNUM:
--        if (use_id_mapping) {
-+        if (state->use_id_mapping) {
-             /* If we're ID-mapping, we need to use the objectSID
-              * in the search filter.
-              */
-@@ -571,7 +644,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-         goto fail;
-     }
- 
--    if (use_id_mapping || filter_type == BE_FILTER_SECID) {
-+    if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
-         /* When mapping IDs or looking for SIDs, we don't want to limit
-          * ourselves to groups with a GID value
-          */
-@@ -660,6 +733,75 @@ static void groups_get_connect_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    /* If POSIX attributes have been requested with an AD server and we
-+     * have no idea about POSIX attributes support, run a one-time check
-+     */
-+    if (state->use_id_mapping == false &&
-+            state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
-+            state->ctx->srv_opts &&
-+            state->ctx->srv_opts->posix_checked == false) {
-+        subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-+                                       sdap_id_op_handle(state->op),
-+                                       state->sdom->user_search_bases,
-+                                       dp_opt_get_int(state->ctx->opts->basic,
-+                                                      SDAP_SEARCH_TIMEOUT));
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+        tevent_req_set_callback(subreq, groups_get_posix_check_done, req);
-+        return;
-+    }
-+
-+    groups_get_search(req);
-+}
-+
-+static void groups_get_posix_check_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    bool has_posix;
-+    int dp_error;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct groups_get_state *state = tevent_req_data(req,
-+                                                     struct groups_get_state);
-+
-+    ret = sdap_posix_check_recv(subreq, &has_posix);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        /* We can only finish the id_op on error as the connection
-+         * is re-used by the group search
-+         */
-+        ret = sdap_id_op_done(state->op, ret, &dp_error);
-+        if (dp_error == DP_ERR_OK && ret != EOK) {
-+            /* retry */
-+            ret = groups_get_retry(req);
-+            if (ret != EOK) {
-+                tevent_req_error(req, ret);
-+            }
-+            return;
-+        }
-+    }
-+
-+    state->ctx->srv_opts->posix_checked = true;
-+
-+    /* If the check ran to completion, we know for certain about the attributes
-+     */
-+    if (has_posix == false) {
-+        state->sdap_ret = ERR_NO_POSIX;
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    groups_get_search(req);
-+}
-+
-+static void groups_get_search(struct tevent_req *req)
-+{
-+    struct groups_get_state *state = tevent_req_data(req,
-+                                                     struct groups_get_state);
-+    struct tevent_req *subreq;
-+
-     subreq = sdap_get_groups_send(state, state->ev,
-                                   state->sdom,
-                                   state->ctx->opts,
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index d408be0a65cdd840d8379b7af4c0ab1e67ed3f5c..f3f13e9c72b368af0c14e2d830a89a41e8cf77e4 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -446,6 +446,7 @@ struct sdap_server_opts {
-     char *max_group_value;
-     char *max_service_value;
-     char *max_sudo_value;
-+    bool posix_checked;
- };
- 
- struct sdap_id_ctx;
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index 367007bde0011ed4de283b2a50b22538830a5275..1022a093f06ec7e9a50b13160fc9a4660a255e92 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -21,6 +21,7 @@
- 
- #include <ctype.h>
- #include "util/util.h"
-+#include "util/strtonum.h"
- #include "providers/ldap/sdap_async_private.h"
- 
- #define REALM_SEPARATOR '@'
-@@ -2083,6 +2084,205 @@ int sdap_asq_search_recv(struct tevent_req *req,
-     return EOK;
- }
- 
-+/* ==Posix attribute presence test================================= */
-+static errno_t sdap_posix_check_next(struct tevent_req *req);
-+static void sdap_posix_check_done(struct tevent_req *subreq);
-+static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
-+                                      struct sdap_msg *msg,
-+                                      void *pvt);
-+
-+struct sdap_posix_check_state {
-+    struct tevent_context *ev;
-+    struct sdap_options *opts;
-+    struct sdap_handle *sh;
-+    struct sdap_search_base **search_bases;
-+    int timeout;
-+
-+    const char **attrs;
-+    const char *filter;
-+    size_t base_iter;
-+
-+    bool has_posix;
-+};
-+
-+struct tevent_req *
-+sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-+                      struct sdap_options *opts, struct sdap_handle *sh,
-+                      struct sdap_search_base **search_bases,
-+                      int timeout)
-+{
-+    struct tevent_req *req = NULL;
-+    struct sdap_posix_check_state *state;
-+    errno_t ret;
-+
-+    req = tevent_req_create(memctx, &state, struct sdap_posix_check_state);
-+    if (req == NULL) {
-+        return NULL;
-+    }
-+    state->ev = ev;
-+    state->sh = sh;
-+    state->opts = opts;
-+    state->search_bases = search_bases;
-+    state->timeout = timeout;
-+
-+    state->attrs = talloc_array(state, const char *, 4);
-+    if (state->attrs == NULL) {
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+    state->attrs[0] = "objectclass";
-+    state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name;
-+    state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name;
-+    state->attrs[3] = NULL;
-+
-+    state->filter = talloc_asprintf(state, "(|(%s=*)(%s=*))",
-+                                    opts->user_map[SDAP_AT_USER_UID].name,
-+                                    opts->group_map[SDAP_AT_GROUP_GID].name);
-+    if (state->filter == NULL) {
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+
-+    ret = sdap_posix_check_next(req);
-+    if (ret != EOK) {
-+        goto fail;
-+    }
-+
-+    return req;
-+
-+fail:
-+    tevent_req_error(req, ret);
-+    tevent_req_post(req, ev);
-+    return req;
-+}
-+
-+static errno_t sdap_posix_check_next(struct tevent_req *req)
-+{
-+    struct tevent_req *subreq = NULL;
-+    struct sdap_posix_check_state *state =
-+        tevent_req_data(req, struct sdap_posix_check_state);
-+
-+    DEBUG(SSSDBG_TRACE_FUNC,
-+          ("Searching for POSIX attributes with base [%s]\n",
-+           state->search_bases[state->base_iter]->basedn));
-+
-+    subreq = sdap_get_generic_ext_send(state, state->ev, state->opts,
-+                                 state->sh,
-+                                 state->search_bases[state->base_iter]->basedn,
-+                                 LDAP_SCOPE_SUBTREE, state->filter,
-+                                 state->attrs, false,
-+                                 NULL, NULL, 1, state->timeout,
-+                                 false, sdap_posix_check_parse,
-+                                 state);
-+    if (subreq == NULL) {
-+        return ENOMEM;
-+    }
-+    tevent_req_set_callback(subreq, sdap_posix_check_done, req);
-+
-+    return EOK;
-+}
-+
-+static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
-+                                      struct sdap_msg *msg,
-+                                      void *pvt)
-+{
-+    struct berval **vals = NULL;
-+    struct sdap_posix_check_state *state =
-+        talloc_get_type(pvt, struct sdap_posix_check_state);
-+    char *dn;
-+    char *endptr;
-+
-+    dn = ldap_get_dn(sh->ldap, msg->msg);
-+    if (dn == NULL) {
-+        DEBUG(SSSDBG_TRACE_LIBS,
-+              ("Search did not find any entry with POSIX attributes\n"));
-+        goto done;
-+    }
-+    DEBUG(SSSDBG_TRACE_LIBS, ("Found [%s] with POSIX attributes\n", dn));
-+    ldap_memfree(dn);
-+
-+    vals = ldap_get_values_len(sh->ldap, msg->msg,
-+                               state->opts->user_map[SDAP_AT_USER_UID].name);
-+    if (vals == NULL) {
-+        vals = ldap_get_values_len(sh->ldap, msg->msg,
-+                               state->opts->group_map[SDAP_AT_GROUP_GID].name);
-+        if (vals == NULL) {
-+            DEBUG(SSSDBG_TRACE_LIBS, ("Entry does not have POSIX attrs?\n"));
-+            goto done;
-+        }
-+    }
-+
-+    if (vals[0] == NULL) {
-+        DEBUG(SSSDBG_TRACE_LIBS, ("No value for POSIX attr\n"));
-+        goto done;
-+    }
-+
-+    errno = 0;
-+    strtouint32(vals[0]->bv_val, &endptr, 10);
-+    if (errno || *endptr || (vals[0]->bv_val == endptr)) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("POSIX attribute is not a number: %s\n", vals[0]->bv_val));
-+        goto done;
-+    }
-+
-+    state->has_posix = true;
-+done:
-+    ldap_value_free_len(vals);
-+    return EOK;
-+}
-+
-+static void sdap_posix_check_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_posix_check_state *state =
-+        tevent_req_data(req, struct sdap_posix_check_state);
-+    errno_t ret;
-+
-+    ret = sdap_get_generic_ext_recv(subreq);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("sdap_get_generic_ext_recv failed [%d]: %s\n",
-+              ret, strerror(ret)));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    /* Positive hit is definitve, no need to search other bases */
-+    if (state->has_posix == true) {
-+        DEBUG(SSSDBG_FUNC_DATA, ("Server has POSIX attributes\n"));
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    state->base_iter++;
-+    if (state->search_bases[state->base_iter]) {
-+        /* There are more search bases to try */
-+        ret = sdap_posix_check_next(req);
-+        if (ret != EOK) {
-+            tevent_req_error(req, ret);
-+        }
-+        return;
-+    }
-+
-+    /* All bases done! */
-+    DEBUG(SSSDBG_TRACE_LIBS, ("Cycled through all bases\n"));
-+    tevent_req_done(req);
-+}
-+
-+int sdap_posix_check_recv(struct tevent_req *req,
-+                          bool *_has_posix)
-+{
-+    struct sdap_posix_check_state *state = tevent_req_data(req,
-+                                            struct sdap_posix_check_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    *_has_posix = state->has_posix;
-+    return EOK;
-+}
-+
- /* ==Generic Deref Search============================================ */
- enum sdap_deref_type {
-     SDAP_DEREF_OPENLDAP,
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index 33e8708ab7e80ab4280df300fdc300d4ecd18305..593404af3c460f8d956b0832b8f7e398b331729b 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -210,6 +210,15 @@ int sdap_deref_search_recv(struct tevent_req *req,
-                            size_t *reply_count,
-                            struct sdap_deref_attrs ***reply);
- 
-+struct tevent_req *
-+sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-+                      struct sdap_options *opts, struct sdap_handle *sh,
-+                      struct sdap_search_base **search_bases,
-+                      int timeout);
-+
-+int sdap_posix_check_recv(struct tevent_req *req,
-+                          bool *_has_posix);
-+
- errno_t
- sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
-                          const char *attr_name,
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index cbc56be20526e6c2323f9fd1b49038dd4bf13fe5..0c20afa9d7a1b0198bb71cffdafcb14763c1dafb 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -68,6 +68,8 @@ static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
-                                       tevent_req_fn tcb);
- static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq);
- static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq);
-+static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq);
-+static errno_t sdap_dom_enum_search_users(struct tevent_req *req);
- static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq);
- static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq);
- static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq);
-@@ -178,19 +180,109 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
-                                                       struct tevent_req);
-     struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-                                                 struct sdap_dom_enum_ex_state);
-+    bool use_id_mapping;
-+    errno_t ret;
- 
-     if (sdap_dom_enum_ex_connected(subreq) == false) {
-         return;
-     }
- 
-+    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-+                                            state->ctx->opts->idmap_ctx,
-+                                            state->sdom->dom->name,
-+                                            state->sdom->dom->domain_id);
-+
-+    /* If POSIX attributes have been requested with an AD server and we
-+     * have no idea about POSIX attributes support, run a one-time check
-+     */
-+    if (use_id_mapping == false &&
-+            state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
-+            state->ctx->srv_opts &&
-+            state->ctx->srv_opts->posix_checked == false) {
-+        subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-+                                       sdap_id_op_handle(state->user_op),
-+                                       state->sdom->user_search_bases,
-+                                       dp_opt_get_int(state->ctx->opts->basic,
-+                                                      SDAP_SEARCH_TIMEOUT));
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+        tevent_req_set_callback(subreq,
-+                                sdap_dom_enum_ex_posix_check_done, req);
-+        return;
-+    }
-+
-+
-+    ret = sdap_dom_enum_search_users(req);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+    /* Execution resumes in sdap_dom_enum_ex_users_done */
-+}
-+
-+static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    bool has_posix;
-+    int dp_error;
-+
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+
-+    ret = sdap_posix_check_recv(subreq, &has_posix);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        /* We can only finish the id_op on error as the connection
-+         * is re-used by the user search
-+         */
-+        ret = sdap_id_op_done(state->user_op, ret, &dp_error);
-+        if (dp_error == DP_ERR_OK && ret != EOK) {
-+            /* retry */
-+            ret = sdap_dom_enum_ex_retry(req, state->user_op,
-+                                         sdap_dom_enum_ex_get_users);
-+            if (ret != EOK) {
-+                tevent_req_error(req, ret);
-+            }
-+            return;
-+        }
-+    }
-+
-+    state->ctx->srv_opts->posix_checked = true;
-+
-+    /* If the check ran to completion, we know for certain about the attributes
-+     */
-+    if (has_posix == false) {
-+        tevent_req_error(req, ERR_NO_POSIX);
-+        return;
-+    }
-+
-+
-+    ret = sdap_dom_enum_search_users(req);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+    /* Execution resumes in sdap_dom_enum_ex_users_done */
-+}
-+
-+static errno_t sdap_dom_enum_search_users(struct tevent_req *req)
-+{
-+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-+                                                struct sdap_dom_enum_ex_state);
-+    struct tevent_req *subreq;
-+
-     subreq = enum_users_send(state, state->ev,
-                              state->ctx, state->sdom,
-                              state->user_op, state->purge);
-     if (subreq == NULL) {
--        tevent_req_error(req, ENOMEM);
--        return;
-+        return ENOMEM;
-     }
-     tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req);
-+    return EOK;
- }
- 
- static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 633257e8da0ef039e555a07ad8b51125114ca01c..c9b507557da07555c719bb0dd18145e6799a53eb 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -52,6 +52,7 @@ struct err_string error_to_str[] = {
-     { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */
-     { "Missing configuration file" }, /* ERR_MISSING_CONF */
-     { "Malformed search filter" }, /* ERR_INVALID_FILTER, */
-+    { "No POSIX attributes detected" }, /* ERR_NO_POSIX */
- };
- 
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index 1332085031dbe6935cbdc94543fa14b09fe81028..3dd94af1f304d65e22515c859c6f69a021fa7e92 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -74,6 +74,7 @@ enum sssd_errors {
-     ERR_DOMAIN_NOT_FOUND,
-     ERR_MISSING_CONF,
-     ERR_INVALID_FILTER,
-+    ERR_NO_POSIX,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-1.8.5.3
-
diff --git a/SOURCES/0081-proxy-Do-not-try-to-store-same-alias-twice.patch b/SOURCES/0081-proxy-Do-not-try-to-store-same-alias-twice.patch
new file mode 100644
index 0000000..bd7330c
--- /dev/null
+++ b/SOURCES/0081-proxy-Do-not-try-to-store-same-alias-twice.patch
@@ -0,0 +1,161 @@
+From aeb6e3d066122621e1ec043f0c7848363539ca5f Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Fri, 31 Oct 2014 16:39:25 +0100
+Subject: [PATCH 81/82] proxy: Do not try to store same alias twice
+
+LDB does not store attributes if they have the
+same name and value and errors out instead.
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/2461
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/proxy/proxy_id.c | 77 +++++++++++++++++++++++++++---------------
+ 1 file changed, 49 insertions(+), 28 deletions(-)
+
+diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
+index d867ec45f633fb5869f5658e0ac1b54bcbab8369..96d9910f7c81d8e1d4245adc69ebc8af6b5b7112 100644
+--- a/src/providers/proxy/proxy_id.c
++++ b/src/providers/proxy/proxy_id.c
+@@ -222,6 +222,7 @@ static int save_user(struct sss_domain_info *domain,
+     struct sysdb_attrs *attrs = NULL;
+     errno_t ret;
+     const char *cased_alias;
++    const char *lc_pw_name = NULL;
+ 
+     if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
+         shell = pwd->pw_shell;
+@@ -239,31 +240,42 @@ static int save_user(struct sss_domain_info *domain,
+         attrs = sysdb_new_attrs(NULL);
+         if (!attrs) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n");
+-            return ENOMEM;
++            ret = ENOMEM;
++            goto done;
+         }
+     }
+ 
+     if (lowercase) {
+-        ret = sysdb_attrs_add_lc_name_alias(attrs, pwd->pw_name);
++        lc_pw_name = sss_tc_utf8_str_tolower(attrs, pwd->pw_name);
++        if (lc_pw_name == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_pw_name);
+         if (ret) {
+             DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
+-            talloc_zfree(attrs);
+-            return ret;
++            ret = ENOMEM;
++            goto done;
+         }
++
+     }
+ 
+     if (alias) {
+         cased_alias = sss_get_cased_name(attrs, alias, !lowercase);
+         if (!cased_alias) {
+-            talloc_zfree(attrs);
+-            return ENOMEM;
++            ret = ENOMEM;
++            goto done;
+         }
+ 
+-        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias);
+-        if (ret) {
+-            DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
+-            talloc_zfree(attrs);
+-            return ret;
++        /* Add the alias only if it differs from lowercased pw_name */
++        if (lc_pw_name == NULL || strcmp(cased_alias, lc_pw_name) != 0) {
++            ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias);
++            if (ret) {
++                DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
++                goto done;
++            }
+         }
+     }
+ 
+@@ -280,13 +292,14 @@ static int save_user(struct sss_domain_info *domain,
+                            NULL,
+                            cache_timeout,
+                            0);
+-    talloc_zfree(attrs);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE, "Could not add user to cache\n");
+-        return ret;
++        goto done;
+     }
+ 
+-    return EOK;
++done:
++    talloc_zfree(attrs);
++    return ret;
+ }
+ 
+ /* =Getpwuid-wrapper======================================================*/
+@@ -527,6 +540,7 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom,
+     errno_t ret, sret;
+     struct sysdb_attrs *attrs = NULL;
+     const char *cased_alias;
++    const char *lc_gr_name = NULL;
+     TALLOC_CTX *tmp_ctx;
+     time_t now = time(NULL);
+     bool in_transaction = false;
+@@ -578,27 +592,34 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom,
+                 goto done;
+             }
+         }
++    }
+ 
+-        if (dom->case_sensitive == false) {
+-            ret = sysdb_attrs_add_lc_name_alias(attrs, grp->gr_name);
+-            if (ret) {
+-                DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
+-                ret = ENOMEM;
+-                goto done;
+-            }
++    if (dom->case_sensitive == false) {
++        lc_gr_name = sss_tc_utf8_str_tolower(attrs, grp->gr_name);
++        if (lc_gr_name == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
++            ret = ENOMEM;
++            goto done;
+         }
+ 
+-        if (alias) {
+-            cased_alias = sss_get_cased_name(attrs, alias, dom->case_sensitive);
+-            if (!cased_alias) {
+-                talloc_zfree(attrs);
+-                return ENOMEM;
+-            }
++        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_gr_name);
++        if (ret != EOK) {
++            goto done;
++        }
++    }
++
++    if (alias) {
++        cased_alias = sss_get_cased_name(attrs, alias, dom->case_sensitive);
++        if (!cased_alias) {
++            ret = ENOMEM;
++            DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
++            goto done;
++        }
+ 
++        if (lc_gr_name == NULL || strcmp(cased_alias, lc_gr_name)) {
+             ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias);
+             if (ret) {
+                 DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
+-                ret = ENOMEM;
+                 goto done;
+             }
+         }
+-- 
+1.9.3
+
diff --git a/SOURCES/0082-AD-Only-download-domains-that-are-set-to-enumerate.patch b/SOURCES/0082-AD-Only-download-domains-that-are-set-to-enumerate.patch
deleted file mode 100644
index b9b8cc0..0000000
--- a/SOURCES/0082-AD-Only-download-domains-that-are-set-to-enumerate.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 94f1e5966733e1b327a9eba37781379c5d90f8a3 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 5 Feb 2014 16:39:47 +0100
-Subject: [PATCH 82/84] AD: Only download domains that are set to enumerate
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 957c55df7a7086166fb3c14cead6a0dab8f574c1)
----
- src/providers/ad/ad_id.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index bfae86284355b6c13547aac55b7273133bde851d..2d3c11bb838f1418c006f9d79d8552cec1443e66 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -660,7 +660,11 @@ ad_enumeration_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    state->sditer = state->sditer->next;
-+    do {
-+        state->sditer = state->sditer->next;
-+    } while (state->sditer &&
-+             state->sditer->dom->enumerate == false);
-+
-     if (state->sditer != NULL) {
-         subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
-         if (subdom_id_ctx == NULL) {
--- 
-1.8.5.3
-
diff --git a/SOURCES/0082-PROXY-Preserve-service-name-in-proxy-provider.patch b/SOURCES/0082-PROXY-Preserve-service-name-in-proxy-provider.patch
new file mode 100644
index 0000000..cb209dc
--- /dev/null
+++ b/SOURCES/0082-PROXY-Preserve-service-name-in-proxy-provider.patch
@@ -0,0 +1,62 @@
+From 6505a4a36592efe94bfbdbfb07ca4d198a699a8b Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 6 Nov 2014 19:25:59 +0100
+Subject: [PATCH 82/82] PROXY: Preserve service name in proxy provider
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/2461
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/proxy/proxy_services.c | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/proxy/proxy_services.c b/src/providers/proxy/proxy_services.c
+index 16e90b009cba86ea17d8d29a4fbeb19efe6947fc..2aa44dbf7f061b99a551b199d0265393e5399a06 100644
+--- a/src/providers/proxy/proxy_services.c
++++ b/src/providers/proxy/proxy_services.c
+@@ -38,12 +38,14 @@ proxy_save_service(struct sss_domain_info *domain,
+     const char **protocols;
+     const char **cased_aliases;
+     TALLOC_CTX *tmp_ctx;
++    char *lc_alias = NULL;
+     time_t now = time(NULL);
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (!tmp_ctx) return ENOMEM;
+ 
+-    cased_name = sss_get_cased_name(tmp_ctx, svc->s_name, !lowercase);
++    cased_name = sss_get_cased_name(tmp_ctx, svc->s_name,
++                                    domain->case_preserve);
+     if (!cased_name) {
+         ret = ENOMEM;
+         goto done;
+@@ -71,6 +73,24 @@ proxy_save_service(struct sss_domain_info *domain,
+         goto done;
+     }
+ 
++    if (domain->case_preserve) {
++        /* Add lowercased alias to allow case-insensitive lookup */
++        lc_alias = sss_tc_utf8_str_tolower(tmp_ctx, svc->s_name);
++        if (lc_alias == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        ret = add_string_to_list(tmp_ctx, lc_alias,
++                                 discard_const_p(char **, &cased_aliases));
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "Failed to add lowercased name alias.\n");
++            goto done;
++        }
++    }
++
+     ret = sysdb_store_service(domain,
+                               cased_name,
+                               ntohs(svc->s_port),
+-- 
+1.9.3
+
diff --git a/SOURCES/0083-AD-Remove-dead-code.patch b/SOURCES/0083-AD-Remove-dead-code.patch
deleted file mode 100644
index 178d308..0000000
--- a/SOURCES/0083-AD-Remove-dead-code.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 7f9da1ed660e45e276778187260ddbbf411c761e Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 5 Feb 2014 16:40:41 +0100
-Subject: [PATCH 83/84] AD: Remove dead code
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit d3436880c0ec1a7776698c739d4a3edc9a6ac57c)
----
- src/providers/ad/ad_id.c | 8 --------
- 1 file changed, 8 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 2d3c11bb838f1418c006f9d79d8552cec1443e66..87af656b364344a8ef27a444e5dfcf8848939110 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -634,7 +634,6 @@ ad_enumeration_done(struct tevent_req *subreq)
-                                                       struct tevent_req);
-     struct ad_enumeration_state *state = tevent_req_data(req,
-                                                 struct ad_enumeration_state);
--    struct ad_id_ctx *subdom_id_ctx;
- 
-     ret = sdap_dom_enum_ex_recv(subreq);
-     talloc_zfree(subreq);
-@@ -666,13 +665,6 @@ ad_enumeration_done(struct tevent_req *subreq)
-              state->sditer->dom->enumerate == false);
- 
-     if (state->sditer != NULL) {
--        subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
--        if (subdom_id_ctx == NULL) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
--            tevent_req_error(req, EFAULT);
--            return;
--        }
--
-         ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE, ("Could not enumerate domain %s\n",
--- 
-1.8.5.3
-
diff --git a/SOURCES/0083-BUILD-Install-krb5_child-as-suid-if-running-under-no.patch b/SOURCES/0083-BUILD-Install-krb5_child-as-suid-if-running-under-no.patch
new file mode 100644
index 0000000..26f66d8
--- /dev/null
+++ b/SOURCES/0083-BUILD-Install-krb5_child-as-suid-if-running-under-no.patch
@@ -0,0 +1,51 @@
+From f28c0df2ba8d3ba4632e3fa5cb395635470d3639 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 24 Oct 2014 22:44:17 +0200
+Subject: [PATCH 83/92] BUILD: Install krb5_child as suid if running under
+ non-privileged user
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If sssd_be is running unprivileged, then krb5_child must be setuid to be
+able to access the keytab and become arbitrary user.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am          | 2 ++
+ contrib/sssd.spec.in | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index b85341f5845c3cffab8a2c95b1be1d32517316e8..5f265dcefd16ce4efdde4d62f3cd5d02dbce255f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2872,6 +2872,8 @@ endif
+ if SSSD_USER
+ 	chgrp $(SSSD_USER) $(sssdlibexecdir)/ldap_child
+ 	chmod 4750 $(sssdlibexecdir)/ldap_child
++	chgrp $(SSSD_USER) $(sssdlibexecdir)/krb5_child
++	chmod 4750 $(sssdlibexecdir)/krb5_child
+ if BUILD_SEMANAGE
+ 	chgrp $(SSSD_USER) $(sssdlibexecdir)/selinux_child
+ 	chmod 4750 $(sssdlibexecdir)/selinux_child
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index 5bfb16707c22dc65376581c88b8eb898949e726f..4734d124817cac860b7f6d9633b043df5aa591e8 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -646,7 +646,7 @@ rm -rf $RPM_BUILD_ROOT
+ %doc COPYING
+ %{_libdir}/%{name}/libsss_krb5_common.so
+ %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child
+-%{_libexecdir}/%{servicename}/krb5_child
++%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child
+ 
+ %files krb5 -f sssd_krb5.lang
+ %defattr(-,root,root,-)
+-- 
+1.9.3
+
diff --git a/SOURCES/0084-KRB5-Drop-privileges-in-the-child-not-the-back-end.patch b/SOURCES/0084-KRB5-Drop-privileges-in-the-child-not-the-back-end.patch
new file mode 100644
index 0000000..9168a2d
--- /dev/null
+++ b/SOURCES/0084-KRB5-Drop-privileges-in-the-child-not-the-back-end.patch
@@ -0,0 +1,142 @@
+From 6422e4a1fea8176fab2f92711cd593904d549cfe Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 13 Oct 2014 21:13:38 +0200
+Subject: [PATCH 84/92] KRB5: Drop privileges in the child, not the back end
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In future patches, sssd_be will be running as a non-privileged user, who
+will execute the setuid krb5_child. In this case, the child will start
+as root and drop the privileges as soon as possible.
+
+However, we need to also remove the privilege drop in sssd_be, because
+if we dropped to the user who is authenticating, we wouldn't be even
+allowed to execute krb5_child. The krb5_child permissions should be
+4750, owned by root.sssd, to make sure only root and sssd can execute
+the child and if executed by sssd, the child will run as root.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/krb5/krb5_child.c         | 71 ++++++++++++++++++++++++++-------
+ src/providers/krb5/krb5_child_handler.c |  8 ----
+ 2 files changed, 57 insertions(+), 22 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 3234a4e6c740db5e05f7db8eb7f4ea0cc126e7ce..b0bf76fb3b8a77831b114c47acff8cd0d3fd780d 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -1840,11 +1840,60 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
+     return EOK;
+ }
+ 
+-static int k5c_setup(struct krb5_req *kr, uint32_t offline)
++enum k5c_fast_opt {
++    K5C_FAST_NEVER,
++    K5C_FAST_TRY,
++    K5C_FAST_DEMAND,
++};
++
++static errno_t check_use_fast(enum k5c_fast_opt *_fast_val)
+ {
+-    krb5_error_code kerr;
+     char *use_fast_str;
++    enum k5c_fast_opt fast_val;
++
++    use_fast_str = getenv(SSSD_KRB5_USE_FAST);
++    if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) {
++        DEBUG(SSSDBG_CONF_SETTINGS, "Not using FAST.\n");
++        fast_val = K5C_FAST_NEVER;
++    } else if (strcasecmp(use_fast_str, "try") == 0) {
++        fast_val = K5C_FAST_TRY;
++    } else if (strcasecmp(use_fast_str, "demand") == 0) {
++        fast_val = K5C_FAST_DEMAND;
++    } else {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++                "Unsupported value [%s] for krb5_use_fast.\n",
++                use_fast_str);
++        return EINVAL;
++    }
++
++    *_fast_val = fast_val;
++    return EOK;
++}
++
++static int k5c_setup(struct krb5_req *kr, uint32_t offline)
++{
++    krb5_error_code kerr;
+     int parse_flags;
++    enum k5c_fast_opt fast_val;
++
++    kerr = check_use_fast(&fast_val);
++    if (kerr != EOK) {
++        return kerr;
++    }
++
++    if (offline || (fast_val == K5C_FAST_NEVER && kr->validate == false)) {
++        /* If krb5_child was started as setuid, but we don't need to
++         * perform either validation or FAST, just drop privileges to
++         * the user who is logging in. The same applies to the offline case
++         */
++        kerr = become_user(kr->uid, kr->gid);
++        if (kerr != 0) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
++            return kerr;
++        }
++    }
++    DEBUG(SSSDBG_TRACE_INTERNAL,
++          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
+ 
+     kr->realm = getenv(SSSD_KRB5_REALM);
+     if (kr->realm == NULL) {
+@@ -1931,18 +1980,12 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+     if (!offline) {
+         set_canonicalize_option(kr->options);
+ 
+-        use_fast_str = getenv(SSSD_KRB5_USE_FAST);
+-        if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) {
+-            DEBUG(SSSDBG_CONF_SETTINGS, "Not using FAST.\n");
+-        } else if (strcasecmp(use_fast_str, "try") == 0) {
+-            kerr = k5c_setup_fast(kr, false);
+-        } else if (strcasecmp(use_fast_str, "demand") == 0) {
+-            kerr = k5c_setup_fast(kr, true);
+-        } else {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Unsupported value [%s] for krb5_use_fast.\n",
+-                   use_fast_str);
+-            return EINVAL;
++        if (fast_val != K5C_FAST_NEVER) {
++            kerr = k5c_setup_fast(kr, fast_val == K5C_FAST_DEMAND);
++            if (kerr != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "Cannot set up FAST\n");
++                return kerr;
++            }
+         }
+     }
+ 
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 4ba939deb3e0e282b3ca9b2b21226ea7e64e311b..71c7f9c9f662e16b94afda0c8c0ae24666f0ba15 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -284,14 +284,6 @@ static errno_t fork_child(struct tevent_req *req)
+     pid = fork();
+ 
+     if (pid == 0) { /* child */
+-        if (state->kr->run_as_user) {
+-            ret = become_user(state->kr->uid, state->kr->gid);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
+-                return ret;
+-            }
+-        }
+-
+         err = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+                          KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd);
+-- 
+1.9.3
+
diff --git a/SOURCES/0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch b/SOURCES/0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch
deleted file mode 100644
index 88049e5..0000000
--- a/SOURCES/0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From 97616c8e1ab41c72c509a31626fafcfb07241a46 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 11 Feb 2014 12:23:51 +0100
-Subject: [PATCH 84/84] LDAP: Handle errors from sdap_id_op properly in enum
- code
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 93dabb2fe0a798f22bb802b9c6521ab9e6a4ac36)
----
- src/providers/ldap/sdap_async_enum.c | 42 +++++++++++++++++++++++++++++++++++-
- 1 file changed, 41 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index 0c20afa9d7a1b0198bb71cffdafcb14763c1dafb..0431d03c38098080847035d522ab5f1f494b8bfe 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -235,7 +235,7 @@ static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq)
- 
-     ret = sdap_posix_check_recv(subreq, &has_posix);
-     talloc_zfree(subreq);
--    if (ret != EOK) {
-+    if (ret != EOK && ret != ERR_NO_POSIX) {
-         /* We can only finish the id_op on error as the connection
-          * is re-used by the user search
-          */
-@@ -248,6 +248,16 @@ static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq)
-                 tevent_req_error(req, ret);
-             }
-             return;
-+        } else if (dp_error == DP_ERR_OFFLINE) {
-+            DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n"));
-+            tevent_req_done(req);
-+            return;
-+        } else {
-+            /* Non-recoverable error */
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                ("POSIX check failed: %d: %s\n", ret, sss_strerror(ret)));
-+            tevent_req_error(req, ret);
-+            return;
-         }
-     }
- 
-@@ -306,6 +316,16 @@ static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)
-             return;
-         }
-         return;
-+    } else if (dp_error == DP_ERR_OFFLINE) {
-+        DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n"));
-+        tevent_req_done(req);
-+        return;
-+    } else if (ret != EOK && ret != ENOENT) {
-+        /* Non-recoverable error */
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("User enumeration failed: %d: %s\n", ret, sss_strerror(ret)));
-+        tevent_req_error(req, ret);
-+        return;
-     }
- 
-     state->group_op = sdap_id_op_create(state, state->group_conn->conn_cache);
-@@ -367,6 +387,16 @@ static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq)
-             return;
-         }
-         return;
-+    } else if (dp_error == DP_ERR_OFFLINE) {
-+        DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n"));
-+        tevent_req_done(req);
-+        return;
-+    } else if (ret != EOK && ret != ENOENT) {
-+        /* Non-recoverable error */
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Group enumeration failed: %d: %s\n", ret, sss_strerror(ret)));
-+        tevent_req_error(req, ret);
-+        return;
-     }
- 
- 
-@@ -426,6 +456,16 @@ static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq)
-             return;
-         }
-         return;
-+    } else if (dp_error == DP_ERR_OFFLINE) {
-+        DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n"));
-+        tevent_req_done(req);
-+        return;
-+    } else if (ret != EOK && ret != ENOENT) {
-+        /* Non-recoverable error */
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Service enumeration failed: %d: %s\n", ret, sss_strerror(ret)));
-+        tevent_req_error(req, ret);
-+        return;
-     }
- 
-     /* Ok, we've completed an enumeration. Save this to the
--- 
-1.8.5.3
-
diff --git a/SOURCES/0085-KRB5-Move-ccache-related-functions-to-krb5_ccache.c.patch b/SOURCES/0085-KRB5-Move-ccache-related-functions-to-krb5_ccache.c.patch
new file mode 100644
index 0000000..73c0db0
--- /dev/null
+++ b/SOURCES/0085-KRB5-Move-ccache-related-functions-to-krb5_ccache.c.patch
@@ -0,0 +1,1794 @@
+From b53c6d5adcd51869fe2d84b6149b4894fa18a436 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 18 Oct 2014 20:52:43 +0200
+Subject: [PATCH 85/92] KRB5: Move ccache-related functions to krb5_ccache.c
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a new module krb5_ccache.c that contains all ccache-related
+operations. The only user of this module shall be krb5_child.c as the
+other modules will run unprivileged and accessing the ccache requires
+either privileges of root or the ccache owner.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am                                        |   4 +
+ src/providers/krb5/krb5_auth.c                     |  16 +-
+ src/providers/krb5/krb5_auth.h                     |   1 +
+ src/providers/krb5/{krb5_utils.c => krb5_ccache.c} | 720 +++++----------------
+ src/providers/krb5/{krb5_utils.h => krb5_ccache.h} |  49 +-
+ src/providers/krb5/krb5_child.c                    |   1 +
+ src/providers/krb5/krb5_common.h                   |   7 -
+ src/providers/krb5/krb5_renew_tgt.c                |   1 +
+ src/providers/krb5/krb5_utils.c                    | 674 +------------------
+ src/providers/krb5/krb5_utils.h                    |  15 -
+ src/tests/krb5_child-test.c                        |   1 +
+ src/tests/krb5_utils-tests.c                       |   1 +
+ 12 files changed, 198 insertions(+), 1292 deletions(-)
+ copy src/providers/krb5/{krb5_utils.c => krb5_ccache.c} (57%)
+ copy src/providers/krb5/{krb5_utils.h => krb5_ccache.h} (53%)
+
+diff --git a/Makefile.am b/Makefile.am
+index 5f265dcefd16ce4efdde4d62f3cd5d02dbce255f..4a69ecb0cfe48e20bde958c9351c2a5ece5ffffa 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -568,6 +568,7 @@ dist_noinst_HEADERS = \
+     src/providers/krb5/krb5_utils.h \
+     src/providers/krb5/krb5_init_shared.h \
+     src/providers/krb5/krb5_opts.h \
++    src/providers/krb5/krb5_ccache.h \
+     src/providers/ldap/ldap_common.h \
+     src/providers/ldap/sdap.h \
+     src/providers/ldap/sdap_access.h \
+@@ -1322,6 +1323,7 @@ strtonum_tests_LDADD = \
+ krb5_utils_tests_SOURCES = \
+     src/tests/krb5_utils-tests.c \
+     src/providers/krb5/krb5_utils.c \
++    src/providers/krb5/krb5_ccache.c \
+     src/providers/krb5/krb5_common.c \
+     src/util/sss_krb5.c \
+     src/providers/data_provider_fo.c \
+@@ -1603,6 +1605,7 @@ stress_tests_LDADD = \
+ krb5_child_test_SOURCES = \
+     src/tests/krb5_child-test.c \
+     src/providers/krb5/krb5_utils.c \
++    src/providers/krb5/krb5_ccache.c \
+     src/providers/krb5/krb5_child_handler.c \
+     src/providers/krb5/krb5_common.c \
+     src/util/sss_krb5.c \
+@@ -2306,6 +2309,7 @@ libsss_krb5_common_la_SOURCES = \
+     src/providers/krb5/krb5_access.c \
+     src/providers/krb5/krb5_child_handler.c \
+     src/providers/krb5/krb5_init_shared.c \
++    src/providers/krb5/krb5_ccache.c \
+     src/util/sss_krb5.c \
+     src/util/become_user.c \
+     $(NULL)
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index c96b7aee99da8c3d43a67a04bb1f67ee048d4705..bd8b51f47462f1eaef8da61b42caedda3475a4e7 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -39,21 +39,7 @@
+ #include "util/child_common.h"
+ #include "providers/krb5/krb5_auth.h"
+ #include "providers/krb5/krb5_utils.h"
+-
+-static errno_t safe_remove_old_ccache_file(const char *old_ccache,
+-                                           const char *new_ccache,
+-                                           uid_t uid, gid_t gid)
+-{
+-    if ((old_ccache == new_ccache)
+-        || (old_ccache && new_ccache
+-            && (strcmp(old_ccache, new_ccache) == 0))) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "New and old ccache file are the same, "
+-                                  "none will be deleted.\n");
+-        return EOK;
+-    }
+-
+-    return sss_krb5_cc_destroy(old_ccache, uid, gid);
+-}
++#include "providers/krb5/krb5_ccache.h"
+ 
+ static errno_t
+ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
+index 022dc9b7645f18d01a8a334371e178aa470d92a1..00cb658c418ade2e6a1d9b5362a40f97e0dc6c6b 100644
+--- a/src/providers/krb5/krb5_auth.h
++++ b/src/providers/krb5/krb5_auth.h
+@@ -32,6 +32,7 @@
+ #include "providers/dp_backend.h"
+ #include "util/child_common.h"
+ #include "providers/krb5/krb5_common.h"
++#include "providers/krb5/krb5_ccache.h"
+ 
+ #define CCACHE_ENV_NAME "KRB5CCNAME"
+ 
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_ccache.c
+similarity index 57%
+copy from src/providers/krb5/krb5_utils.c
+copy to src/providers/krb5/krb5_ccache.c
+index 0d2e281198390043068e21b412b57de04df6a12b..5586963338616519f36e5d75e796a597d3ac2f22 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_ccache.c
+@@ -1,12 +1,13 @@
+ /*
+     SSSD
+ 
+-    Kerberos 5 Backend Module -- Utilities
++    Kerberos 5 Backend Module -- ccache related utilities
+ 
+     Authors:
+         Sumit Bose <sbose@redhat.com>
++        Jakub Hrozek <jhrozek@redhat.com>
+ 
+-    Copyright (C) 2009 Red Hat
++    Copyright (C) 2014 Red Hat
+ 
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+@@ -21,427 +22,37 @@
+     You should have received a copy of the GNU General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+-#include <string.h>
+-#include <stdlib.h>
+-#include <libgen.h>
+ 
+-#include "providers/krb5/krb5_utils.h"
+-#include "providers/krb5/krb5_auth.h"
+-#include "src/util/find_uid.h"
++#ifdef HAVE_KRB5_KRB5_H
++#include <krb5/krb5.h>
++#else
++#include <krb5.h>
++#endif
++
++#include "providers/krb5/krb5_ccache.h"
++#include "util/sss_krb5.h"
+ #include "util/util.h"
+ 
+-errno_t find_or_guess_upn(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+-                          struct krb5_ctx *krb5_ctx,
+-                          struct sss_domain_info *dom, const char *user,
+-                          const char *user_dom, char **_upn)
++static errno_t
++check_ccache_re(const char *filename, pcre *illegal_re)
+ {
+-    const char *upn = NULL;
+-    int ret;
++    errno_t ret;
+ 
+-    if (krb5_ctx == NULL || dom == NULL || user == NULL || _upn == NULL) {
+-        return EINVAL;
+-    }
+-
+-    if (msg != NULL) {
+-        upn = ldb_msg_find_attr_as_string(msg, SYSDB_CANONICAL_UPN, NULL);
+-        if (upn != NULL) {
+-            ret = EOK;
+-            goto done;
+-        }
+-
+-        upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);
+-        if (upn != NULL) {
+-            ret = EOK;
+-            goto done;
+-        }
+-    }
+-
+-    ret = krb5_get_simple_upn(mem_ctx, krb5_ctx, dom, user,
+-                              user_dom, _upn);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "krb5_get_simple_upn failed.\n");
+-        return ret;
+-    }
+-
+-done:
+-    if (ret == EOK && upn != NULL) {
+-        *_upn = talloc_strdup(mem_ctx, upn);
+-        if (*_upn == NULL) {
+-            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+-            return ENOMEM;
+-        }
+-    }
+-
+-    return ret;
+-}
+-
+-errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+-                                         struct sss_domain_info *domain,
+-                                         const char *user,
+-                                         const char *upn)
+-{
+-    TALLOC_CTX *tmp_ctx;
+-    int ret;
+-    int sret;
+-    const char *attrs[] = {SYSDB_UPN, SYSDB_CANONICAL_UPN, NULL};
+-    struct sysdb_attrs *new_attrs;
+-    struct ldb_result *res;
+-    bool in_transaction = false;
+-    const char *cached_upn;
+-    const char *cached_canonical_upn;
+-
+-    if (sysdb == NULL || user == NULL || upn == NULL) {
+-        return EINVAL;
+-    }
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = sysdb_get_user_attr(tmp_ctx, domain, user, attrs, &res);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_user_attr failed.\n");
+-        goto done;
+-    }
+-
+-    if (res->count != 1) {
+-        DEBUG(SSSDBG_OP_FAILURE, "[%d] user objects for name [%s] found, " \
+-                                  "expected 1.\n", res->count, user);
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    cached_upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL);
+-
+-    if (cached_upn != NULL && strcmp(cached_upn, upn) == 0) {
+-        DEBUG(SSSDBG_TRACE_ALL, "Cached UPN and new one match, "
+-                                 "nothing to do.\n");
+-        ret = EOK;
+-        goto done;
+-    }
+-
+-    cached_canonical_upn = ldb_msg_find_attr_as_string(res->msgs[0],
+-                                                       SYSDB_CANONICAL_UPN,
+-                                                       NULL);
+-
+-    if (cached_canonical_upn != NULL
+-            && strcmp(cached_canonical_upn, upn) == 0) {
+-        DEBUG(SSSDBG_TRACE_ALL, "Cached canonical UPN and new one match, "
+-                                 "nothing to do.\n");
+-        ret = EOK;
+-        goto done;
+-    }
+-
+-    DEBUG(SSSDBG_TRACE_LIBS, "Replacing canonical UPN [%s] with [%s] " \
+-                              "for user [%s].\n",
+-                              cached_canonical_upn == NULL ?
+-                                                 "empty" : cached_canonical_upn,
+-                              upn, user);
+-
+-    new_attrs = sysdb_new_attrs(tmp_ctx);
+-    if (new_attrs == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    ret = sysdb_attrs_add_string(new_attrs, SYSDB_CANONICAL_UPN, upn);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+-        goto done;
+-    }
+-
+-    ret = sysdb_transaction_start(sysdb);
+-    if (ret != EOK) {
++    ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
++                    0, 0, NULL, 0);
++    if (ret == 0) {
+         DEBUG(SSSDBG_OP_FAILURE,
+-              "Error %d starting transaction (%s)\n", ret, strerror(ret));
+-        goto done;
+-    }
+-    in_transaction = true;
+-
+-    ret = sysdb_set_entry_attr(sysdb, res->msgs[0]->dn, new_attrs,
+-                               cached_canonical_upn == NULL ? SYSDB_MOD_ADD :
+-                                                              SYSDB_MOD_REP);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed [%d][%s].\n",
+-                                  ret, strerror(ret));
+-        goto done;
+-    }
+-
+-    ret = sysdb_transaction_commit(sysdb);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Failed to commit transaction!\n");
+-        goto done;
+-    }
+-    in_transaction = false;
+-
+-    ret = EOK;
+-
+-done:
+-    if (in_transaction) {
+-        sret = sysdb_transaction_cancel(sysdb);
+-        if (sret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
+-        }
+-    }
+-
+-    talloc_free(tmp_ctx);
+-
+-    return ret;
+-}
+-
+-#define S_EXP_UID "{uid}"
+-#define L_EXP_UID (sizeof(S_EXP_UID) - 1)
+-#define S_EXP_USERID "{USERID}"
+-#define L_EXP_USERID (sizeof(S_EXP_USERID) - 1)
+-#define S_EXP_EUID "{euid}"
+-#define L_EXP_EUID (sizeof(S_EXP_EUID) - 1)
+-#define S_EXP_USERNAME "{username}"
+-#define L_EXP_USERNAME (sizeof(S_EXP_USERNAME) - 1)
+-
+-char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+-                             const char *template, bool file_mode,
+-                             bool case_sensitive)
+-{
+-    char *copy;
+-    char *p;
+-    char *n;
+-    char *result = NULL;
+-    char *dummy;
+-    char *name;
+-    char *res = NULL;
+-    const char *cache_dir_tmpl;
+-    TALLOC_CTX *tmp_ctx = NULL;
+-    char action;
+-    bool rerun;
+-
+-    if (template == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing template.\n");
+-        return NULL;
+-    }
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (!tmp_ctx) return NULL;
+-
+-    copy = talloc_strdup(tmp_ctx, template);
+-    if (copy == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
+-        goto done;
+-    }
+-
+-    result = talloc_strdup(tmp_ctx, "");
+-    if (result == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
+-        goto done;
+-    }
+-
+-    p = copy;
+-    while ( (n = strchr(p, '%')) != NULL) {
+-        *n = '\0';
+-        n++;
+-        if ( *n == '\0' ) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "format error, single %% at the end of the template.\n");
+-            goto done;
+-        }
+-
+-        rerun = true;
+-        action = *n;
+-        while (rerun) {
+-            rerun = false;
+-            switch (action) {
+-            case 'u':
+-                if (kr->pd->user == NULL) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Cannot expand user name template "
+-                              "because user name is empty.\n");
+-                    goto done;
+-                }
+-                name = sss_get_cased_name(tmp_ctx, kr->pd->user,
+-                                          case_sensitive);
+-                if (!name) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "sss_get_cased_name failed\n");
+-                    goto done;
+-                }
+-
+-                result = talloc_asprintf_append(result, "%s%s", p,
+-                                                name);
+-                break;
+-            case 'U':
+-                if (kr->uid <= 0) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE, "Cannot expand uid template "
+-                              "because uid is invalid.\n");
+-                    goto done;
+-                }
+-                result = talloc_asprintf_append(result, "%s%"SPRIuid, p,
+-                                                kr->uid);
+-                break;
+-            case 'p':
+-                if (kr->upn == NULL) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Cannot expand user principal name template "
+-                              "because upn is empty.\n");
+-                    goto done;
+-                }
+-                result = talloc_asprintf_append(result, "%s%s", p, kr->upn);
+-                break;
+-            case '%':
+-                result = talloc_asprintf_append(result, "%s%%", p);
+-                break;
+-            case 'r':
+-                dummy = dp_opt_get_string(kr->krb5_ctx->opts, KRB5_REALM);
+-                if (dummy == NULL) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE, "Missing kerberos realm.\n");
+-                    goto done;
+-                }
+-                result = talloc_asprintf_append(result, "%s%s", p, dummy);
+-                break;
+-            case 'h':
+-                if (kr->homedir == NULL) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Cannot expand home directory template "
+-                              "because the path is not available.\n");
+-                    goto done;
+-                }
+-                result = talloc_asprintf_append(result, "%s%s", p, kr->homedir);
+-                break;
+-            case 'd':
+-                if (file_mode) {
+-                    cache_dir_tmpl = dp_opt_get_string(kr->krb5_ctx->opts,
+-                                                       KRB5_CCACHEDIR);
+-                    if (cache_dir_tmpl == NULL) {
+-                        DEBUG(SSSDBG_CRIT_FAILURE,
+-                              "Missing credential cache directory.\n");
+-                        goto done;
+-                    }
+-
+-                    dummy = expand_ccname_template(tmp_ctx, kr, cache_dir_tmpl,
+-                                                   false, case_sensitive);
+-                    if (dummy == NULL) {
+-                        DEBUG(SSSDBG_CRIT_FAILURE,
+-                              "Expanding credential cache directory "
+-                                  "template failed.\n");
+-                        goto done;
+-                    }
+-                    result = talloc_asprintf_append(result, "%s%s", p, dummy);
+-                    talloc_zfree(dummy);
+-                } else {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "'%%d' is not allowed in this template.\n");
+-                    goto done;
+-                }
+-                break;
+-            case 'P':
+-                if (!file_mode) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "'%%P' is not allowed in this template.\n");
+-                    goto done;
+-                }
+-                if (kr->pd->cli_pid == 0) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE, "Cannot expand PID template "
+-                              "because PID is not available.\n");
+-                    goto done;
+-                }
+-                result = talloc_asprintf_append(result, "%s%d", p,
+-                                                kr->pd->cli_pid);
+-                break;
+-
+-            /* Additional syntax from krb5.conf default_ccache_name */
+-            case '{':
+-                if (strncmp(n , S_EXP_UID, L_EXP_UID) == 0) {
+-                    action = 'U';
+-                    n += L_EXP_UID - 1;
+-                    rerun = true;
+-                    continue;
+-                } else if (strncmp(n , S_EXP_USERID, L_EXP_USERID) == 0) {
+-                    action = 'U';
+-                    n += L_EXP_USERID - 1;
+-                    rerun = true;
+-                    continue;
+-                } else if (strncmp(n , S_EXP_EUID, L_EXP_EUID) == 0) {
+-                    /* SSSD does not distinguish betwen uid and euid,
+-                     * so we treat both the same way */
+-                    action = 'U';
+-                    n += L_EXP_EUID - 1;
+-                    rerun = true;
+-                    continue;
+-                } else if (strncmp(n , S_EXP_USERNAME, L_EXP_USERNAME) == 0) {
+-                    action = 'u';
+-                    n += L_EXP_USERNAME - 1;
+-                    rerun = true;
+-                    continue;
+-                } else {
+-                    /* ignore any expansion variable we do not understand and
+-                     * let libkrb5 hndle it or fail */
+-                    name = n;
+-                    n = strchr(name, '}');
+-                    if (!n) {
+-                        DEBUG(SSSDBG_CRIT_FAILURE, 
+-                              "Invalid substitution sequence in cache "
+-                              "template. Missing closing '}' in [%s].\n",
+-                              template);
+-                        goto done;
+-                    }
+-                    result = talloc_asprintf_append(result, "%s%%%.*s", p,
+-                                                    (int)(n - name + 1), name);
+-                }
+-                break;
+-            default:
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "format error, unknown template [%%%c].\n", *n);
+-                goto done;
+-            }
+-        }
+-
+-        if (result == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append failed.\n");
+-            goto done;
+-        }
+-
+-        p = n + 1;
+-    }
+-
+-    result = talloc_asprintf_append(result, "%s", p);
+-    if (result == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append failed.\n");
+-        goto done;
+-    }
+-
+-    res = talloc_move(mem_ctx, &result);
+-done:
+-    talloc_zfree(tmp_ctx);
+-    return res;
+-}
+-
+-static errno_t check_parent_stat(struct stat *parent_stat, uid_t uid)
+-{
+-    if (parent_stat->st_uid != 0 && parent_stat->st_uid != uid) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Private directory can only be created below a directory "
+-              "belonging to root or to [%"SPRIuid"].\n", uid);
++              "Illegal pattern in ccache directory name [%s].\n", filename);
+         return EINVAL;
++    } else if (ret == PCRE_ERROR_NOMATCH) {
++        DEBUG(SSSDBG_TRACE_LIBS,
++              "Ccache directory name [%s] does not contain "
++               "illegal patterns.\n", filename);
++        return EOK;
+     }
+ 
+-    if (parent_stat->st_uid == uid) {
+-        if (!(parent_stat->st_mode & S_IXUSR)) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Parent directory does not have the search bit set for "
+-                   "the owner.\n");
+-            return EINVAL;
+-        }
+-    } else {
+-        if (!(parent_stat->st_mode & S_IXOTH)) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Parent directory does not have the search bit set for "
+-                   "others.\n");
+-            return EINVAL;
+-        }
+-    }
+-
+-    return EOK;
++    DEBUG(SSSDBG_CRIT_FAILURE, "pcre_exec failed [%d].\n", ret);
++    return EFAULT;
+ }
+ 
+ struct string_list {
+@@ -523,31 +134,37 @@ done:
+     return ret;
+ }
+ 
+-static errno_t
+-check_ccache_re(const char *filename, pcre *illegal_re)
++static errno_t check_parent_stat(struct stat *parent_stat, uid_t uid)
+ {
+-    errno_t ret;
+-
+-    ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
+-                    0, 0, NULL, 0);
+-    if (ret == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "Illegal pattern in ccache directory name [%s].\n", filename);
++    if (parent_stat->st_uid != 0 && parent_stat->st_uid != uid) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Private directory can only be created below a directory "
++              "belonging to root or to [%"SPRIuid"].\n", uid);
+         return EINVAL;
+-    } else if (ret == PCRE_ERROR_NOMATCH) {
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "Ccache directory name [%s] does not contain "
+-               "illegal patterns.\n", filename);
+-        return EOK;
+     }
+ 
+-    DEBUG(SSSDBG_CRIT_FAILURE, "pcre_exec failed [%d].\n", ret);
+-    return EFAULT;
++    if (parent_stat->st_uid == uid) {
++        if (!(parent_stat->st_mode & S_IXUSR)) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Parent directory does not have the search bit set for "
++                   "the owner.\n");
++            return EINVAL;
++        }
++    } else {
++        if (!(parent_stat->st_mode & S_IXOTH)) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Parent directory does not have the search bit set for "
++                   "others.\n");
++            return EINVAL;
++        }
++    }
++
++    return EOK;
+ }
+ 
+-errno_t
+-create_ccache_dir(const char *ccdirname, pcre *illegal_re,
+-                  uid_t uid, gid_t gid)
++errno_t create_ccache_dir(const char *ccdirname,
++                          pcre *illegal_re,
++                          uid_t uid, gid_t gid)
+ {
+     int ret = EFAULT;
+     struct stat parent_stat;
+@@ -625,113 +242,6 @@ done:
+     return ret;
+ }
+ 
+-errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+-                             struct tgt_times *tgtt)
+-{
+-    krb5_error_code kerr;
+-    krb5_context ctx = NULL;
+-    krb5_ccache cc = NULL;
+-    krb5_principal client_princ = NULL;
+-    krb5_principal server_princ = NULL;
+-    char *server_name;
+-    krb5_creds mcred;
+-    krb5_creds cred;
+-    const char *realm_name;
+-    int realm_length;
+-
+-    kerr = krb5_init_context(&ctx);
+-    if (kerr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_init_context failed.\n");
+-        goto done;
+-    }
+-
+-    kerr = krb5_parse_name(ctx, client_name, &client_princ);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
+-        goto done;
+-    }
+-
+-    sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
+-
+-    server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
+-                                  realm_length, realm_name,
+-                                  realm_length, realm_name);
+-    if (server_name == NULL) {
+-        kerr = KRB5_CC_NOMEM;
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
+-        goto done;
+-    }
+-
+-    kerr = krb5_parse_name(ctx, server_name, &server_princ);
+-    talloc_free(server_name);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
+-        goto done;
+-    }
+-
+-    kerr = krb5_cc_resolve(ctx, ccache_file, &cc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
+-        goto done;
+-    }
+-
+-    memset(&mcred, 0, sizeof(mcred));
+-    memset(&cred, 0, sizeof(mcred));
+-
+-    mcred.server = server_princ;
+-    mcred.client = client_princ;
+-
+-    kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed.\n");
+-        goto done;
+-    }
+-
+-    tgtt->authtime = cred.times.authtime;
+-    tgtt->starttime = cred.times.starttime;
+-    tgtt->endtime = cred.times.endtime;
+-    tgtt->renew_till = cred.times.renew_till;
+-
+-    krb5_free_cred_contents(ctx, &cred);
+-
+-    kerr = krb5_cc_close(ctx, cc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_close failed.\n");
+-        goto done;
+-    }
+-    cc = NULL;
+-
+-    kerr = 0;
+-
+-done:
+-    if (cc != NULL) {
+-        krb5_cc_close(ctx, cc);
+-    }
+-
+-    if (client_princ != NULL) {
+-        krb5_free_principal(ctx, client_princ);
+-    }
+-
+-    if (server_princ != NULL) {
+-        krb5_free_principal(ctx, server_princ);
+-    }
+-
+-    if (ctx != NULL) {
+-        krb5_free_context(ctx);
+-    }
+-
+-    if (kerr != 0) {
+-        return EIO;
+-    }
+-
+-    return EOK;
+-}
+-
+ errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+                                   uid_t uid, gid_t gid)
+ {
+@@ -783,7 +293,6 @@ done:
+     return ret;
+ }
+ 
+-
+ struct sss_krb5_ccache {
+     struct sss_creds *creds;
+     krb5_context context;
+@@ -895,7 +404,6 @@ done:
+     return ret;
+ }
+ 
+-
+ /* This function is called only as a way to validate that we have the
+  * right cache */
+ errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+@@ -1086,22 +594,124 @@ done:
+     return ret;
+ }
+ 
+-
+-errno_t get_domain_or_subdomain(struct be_ctx *be_ctx,
+-                                char *domain_name,
+-                                struct sss_domain_info **dom)
++errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
++                             struct tgt_times *tgtt)
+ {
++    krb5_error_code kerr;
++    krb5_context ctx = NULL;
++    krb5_ccache cc = NULL;
++    krb5_principal client_princ = NULL;
++    krb5_principal server_princ = NULL;
++    char *server_name;
++    krb5_creds mcred;
++    krb5_creds cred;
++    const char *realm_name;
++    int realm_length;
+ 
+-    if (domain_name != NULL &&
+-        strcasecmp(domain_name, be_ctx->domain->name) != 0) {
+-        *dom = find_domain_by_name(be_ctx->domain, domain_name, true);
+-        if (*dom == NULL) {
+-            DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
+-            return ENOMEM;
+-        }
+-    } else {
+-        *dom = be_ctx->domain;
++    kerr = krb5_init_context(&ctx);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_init_context failed.\n");
++        goto done;
++    }
++
++    kerr = krb5_parse_name(ctx, client_name, &client_princ);
++    if (kerr != 0) {
++        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
++        goto done;
++    }
++
++    sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
++
++    server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
++                                  realm_length, realm_name,
++                                  realm_length, realm_name);
++    if (server_name == NULL) {
++        kerr = KRB5_CC_NOMEM;
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
++        goto done;
++    }
++
++    kerr = krb5_parse_name(ctx, server_name, &server_princ);
++    talloc_free(server_name);
++    if (kerr != 0) {
++        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
++        goto done;
++    }
++
++    kerr = krb5_cc_resolve(ctx, ccache_file, &cc);
++    if (kerr != 0) {
++        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
++        goto done;
++    }
++
++    memset(&mcred, 0, sizeof(mcred));
++    memset(&cred, 0, sizeof(mcred));
++
++    mcred.server = server_princ;
++    mcred.client = client_princ;
++
++    kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
++    if (kerr != 0) {
++        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed.\n");
++        goto done;
++    }
++
++    tgtt->authtime = cred.times.authtime;
++    tgtt->starttime = cred.times.starttime;
++    tgtt->endtime = cred.times.endtime;
++    tgtt->renew_till = cred.times.renew_till;
++
++    krb5_free_cred_contents(ctx, &cred);
++
++    kerr = krb5_cc_close(ctx, cc);
++    if (kerr != 0) {
++        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_close failed.\n");
++        goto done;
++    }
++    cc = NULL;
++
++    kerr = 0;
++
++done:
++    if (cc != NULL) {
++        krb5_cc_close(ctx, cc);
++    }
++
++    if (client_princ != NULL) {
++        krb5_free_principal(ctx, client_princ);
++    }
++
++    if (server_princ != NULL) {
++        krb5_free_principal(ctx, server_princ);
++    }
++
++    if (ctx != NULL) {
++        krb5_free_context(ctx);
++    }
++
++    if (kerr != 0) {
++        return EIO;
+     }
+ 
+     return EOK;
+ }
++
++errno_t safe_remove_old_ccache_file(const char *old_ccache,
++                                    const char *new_ccache,
++                                    uid_t uid, gid_t gid)
++{
++    if ((old_ccache == new_ccache)
++        || (old_ccache && new_ccache
++            && (strcmp(old_ccache, new_ccache) == 0))) {
++        DEBUG(SSSDBG_TRACE_FUNC, "New and old ccache file are the same, "
++                                  "none will be deleted.\n");
++        return EOK;
++    }
++
++    return sss_krb5_cc_destroy(old_ccache, uid, gid);
++}
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_ccache.h
+similarity index 53%
+copy from src/providers/krb5/krb5_utils.h
+copy to src/providers/krb5/krb5_ccache.h
+index f54a07f7936a361c21ca933026ee753a89fe5808..9f0b3ac84b7af118c315ca00a7c52f200534d97e 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_ccache.h
+@@ -1,13 +1,13 @@
+ /*
+     SSSD
+ 
+-    Kerberos Backend, header file for utilities
++    Kerberos 5 Backend Module -- ccache related utilities
+ 
+     Authors:
+         Sumit Bose <sbose@redhat.com>
++        Jakub Hrozek <jhrozek@redhat.com>
+ 
+-    Copyright (C) 2009 Red Hat
+-
++    Copyright (C) 2014 Red Hat
+ 
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+@@ -23,45 +23,38 @@
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+ 
+-#ifndef __KRB5_UTILS_H__
+-#define __KRB5_UTILS_H__
++#ifndef __KRB5_CCACHE_H__
++#define __KRB5_CCACHE_H__
+ 
+-#include <talloc.h>
+-#include "config.h"
++#include "util/util.h"
+ 
+-#include "providers/krb5/krb5_auth.h"
+-#include "providers/data_provider.h"
++struct tgt_times {
++    time_t authtime;
++    time_t starttime;
++    time_t endtime;
++    time_t renew_till;
++};
+ 
+-errno_t find_or_guess_upn(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+-                          struct krb5_ctx *krb5_ctx,
+-                          struct sss_domain_info *dom, const char *user,
+-                          const char *user_dom, char **_upn);
+-
+-errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+-                                         struct sss_domain_info *domain,
+-                                         const char *user,
+-                                         const char *upn);
+-
+-errno_t create_ccache_dir(const char *dirname, pcre *illegal_re,
++errno_t create_ccache_dir(const char *ccdirname,
++                          pcre *illegal_re,
+                           uid_t uid, gid_t gid);
+ 
+-char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+-                             const char *template, bool file_mode,
+-                             bool case_sensitive);
+-
+ errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+                                   uid_t uid, gid_t gid);
++
+ errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
++
+ errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+                                     const char *ccname, const char *principal);
++
+ errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+                                   const char *realm, const char *principal);
+ 
+ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+                              struct tgt_times *tgtt);
+ 
++errno_t safe_remove_old_ccache_file(const char *old_ccache,
++                                    const char *new_ccache,
++                                    uid_t uid, gid_t gid);
+ 
+-errno_t get_domain_or_subdomain(struct be_ctx *be_ctx,
+-                                char *domain_name,
+-                                struct sss_domain_info **dom);
+-#endif /* __KRB5_UTILS_H__ */
++#endif /* __KRB5_CCACHE_H__ */
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index b0bf76fb3b8a77831b114c47acff8cd0d3fd780d..7fa5f0c344a4afe110afa08f479f283aefce8d23 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -1885,6 +1885,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+         /* If krb5_child was started as setuid, but we don't need to
+          * perform either validation or FAST, just drop privileges to
+          * the user who is logging in. The same applies to the offline case
++         * the user who is logging in. The same applies to the offline case.
+          */
+         kerr = become_user(kr->uid, kr->gid);
+         if (kerr != 0) {
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index eac0d6b1f0c0fec4a107a7b830d8b0c927f4fe42..a5cee6497e4930b16b1102a525d9fa3452845a58 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -73,13 +73,6 @@ enum krb5_opts {
+ 
+ typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
+ 
+-struct tgt_times {
+-    time_t authtime;
+-    time_t starttime;
+-    time_t endtime;
+-    time_t renew_till;
+-};
+-
+ struct krb5_service {
+     char *name;
+     char *realm;
+diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c
+index 12963549829c4bbb0f799c5d00b9b8986ccfd485..5277c0f7691dd272a69b3024cb2c0bd7545a8fbd 100644
+--- a/src/providers/krb5/krb5_renew_tgt.c
++++ b/src/providers/krb5/krb5_renew_tgt.c
+@@ -27,6 +27,7 @@
+ #include "providers/krb5/krb5_common.h"
+ #include "providers/krb5/krb5_auth.h"
+ #include "providers/krb5/krb5_utils.h"
++#include "providers/krb5/krb5_ccache.h"
+ 
+ #define INITIAL_TGT_TABLE_SIZE 10
+ 
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 0d2e281198390043068e21b412b57de04df6a12b..ae72b04be236cfce9b6f794c602887491ba487a9 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -26,6 +26,7 @@
+ #include <libgen.h>
+ 
+ #include "providers/krb5/krb5_utils.h"
++#include "providers/krb5/krb5_ccache.h"
+ #include "providers/krb5/krb5_auth.h"
+ #include "src/util/find_uid.h"
+ #include "util/util.h"
+@@ -379,7 +380,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+                     name = n;
+                     n = strchr(name, '}');
+                     if (!n) {
+-                        DEBUG(SSSDBG_CRIT_FAILURE, 
++                        DEBUG(SSSDBG_CRIT_FAILURE,
+                               "Invalid substitution sequence in cache "
+                               "template. Missing closing '}' in [%s].\n",
+                               template);
+@@ -416,677 +417,6 @@ done:
+     return res;
+ }
+ 
+-static errno_t check_parent_stat(struct stat *parent_stat, uid_t uid)
+-{
+-    if (parent_stat->st_uid != 0 && parent_stat->st_uid != uid) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Private directory can only be created below a directory "
+-              "belonging to root or to [%"SPRIuid"].\n", uid);
+-        return EINVAL;
+-    }
+-
+-    if (parent_stat->st_uid == uid) {
+-        if (!(parent_stat->st_mode & S_IXUSR)) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Parent directory does not have the search bit set for "
+-                   "the owner.\n");
+-            return EINVAL;
+-        }
+-    } else {
+-        if (!(parent_stat->st_mode & S_IXOTH)) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Parent directory does not have the search bit set for "
+-                   "others.\n");
+-            return EINVAL;
+-        }
+-    }
+-
+-    return EOK;
+-}
+-
+-struct string_list {
+-    struct string_list *next;
+-    struct string_list *prev;
+-    char *s;
+-};
+-
+-static errno_t find_ccdir_parent_data(TALLOC_CTX *mem_ctx,
+-                                      const char *ccdirname,
+-                                      struct stat *parent_stat,
+-                                      struct string_list **missing_parents)
+-{
+-    int ret = EFAULT;
+-    char *parent = NULL;
+-    char *end;
+-    struct string_list *li;
+-
+-    ret = stat(ccdirname, parent_stat);
+-    if (ret == EOK) {
+-        if ( !S_ISDIR(parent_stat->st_mode) ) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "[%s] is not a directory.\n", ccdirname);
+-            return EINVAL;
+-        }
+-        return EOK;
+-    } else {
+-        if (errno != ENOENT) {
+-            ret = errno;
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "stat for [%s] failed: [%d][%s].\n", ccdirname, ret,
+-                   strerror(ret));
+-            return ret;
+-        }
+-    }
+-
+-    li = talloc_zero(mem_ctx, struct string_list);
+-    if (li == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "talloc_zero failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    li->s = talloc_strdup(li, ccdirname);
+-    if (li->s == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "talloc_strdup failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    DLIST_ADD(*missing_parents, li);
+-
+-    parent = talloc_strdup(mem_ctx, ccdirname);
+-    if (parent == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "talloc_strdup failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    /* We'll remove all trailing slashes from the back so that
+-     * we only pass /some/path to find_ccdir_parent_data, not
+-     * /some/path */
+-    do {
+-        end = strrchr(parent, '/');
+-        if (end == NULL || end == parent) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Cannot find parent directory of [%s], / is not allowed.\n",
+-                   ccdirname);
+-            ret = EINVAL;
+-            goto done;
+-        }
+-        *end = '\0';
+-    } while (*(end+1) == '\0');
+-
+-    ret = find_ccdir_parent_data(mem_ctx, parent, parent_stat, missing_parents);
+-
+-done:
+-    talloc_free(parent);
+-    return ret;
+-}
+-
+-static errno_t
+-check_ccache_re(const char *filename, pcre *illegal_re)
+-{
+-    errno_t ret;
+-
+-    ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
+-                    0, 0, NULL, 0);
+-    if (ret == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "Illegal pattern in ccache directory name [%s].\n", filename);
+-        return EINVAL;
+-    } else if (ret == PCRE_ERROR_NOMATCH) {
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "Ccache directory name [%s] does not contain "
+-               "illegal patterns.\n", filename);
+-        return EOK;
+-    }
+-
+-    DEBUG(SSSDBG_CRIT_FAILURE, "pcre_exec failed [%d].\n", ret);
+-    return EFAULT;
+-}
+-
+-errno_t
+-create_ccache_dir(const char *ccdirname, pcre *illegal_re,
+-                  uid_t uid, gid_t gid)
+-{
+-    int ret = EFAULT;
+-    struct stat parent_stat;
+-    struct string_list *missing_parents = NULL;
+-    struct string_list *li = NULL;
+-    mode_t old_umask;
+-    mode_t new_dir_mode;
+-    TALLOC_CTX *tmp_ctx = NULL;
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    if (*ccdirname != '/') {
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Only absolute paths are allowed, not [%s] .\n", ccdirname);
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    if (illegal_re != NULL) {
+-        ret = check_ccache_re(ccdirname, illegal_re);
+-        if (ret != EOK) {
+-            goto done;
+-        }
+-    }
+-
+-    ret = find_ccdir_parent_data(tmp_ctx, ccdirname, &parent_stat,
+-                                 &missing_parents);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "find_ccdir_parent_data failed.\n");
+-        goto done;
+-    }
+-
+-    ret = check_parent_stat(&parent_stat, uid);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,
+-              "Check the ownership and permissions of krb5_ccachedir: [%s].\n",
+-              ccdirname);
+-        goto done;
+-    }
+-
+-    DLIST_FOR_EACH(li, missing_parents) {
+-        DEBUG(SSSDBG_TRACE_INTERNAL,
+-              "Creating directory [%s].\n", li->s);
+-        new_dir_mode = 0700;
+-
+-        old_umask = umask(0000);
+-        ret = mkdir(li->s, new_dir_mode);
+-        umask(old_umask);
+-        if (ret != EOK) {
+-            ret = errno;
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "mkdir [%s] failed: [%d][%s].\n", li->s, ret,
+-                   strerror(ret));
+-            goto done;
+-        }
+-        ret = chown(li->s, uid, gid);
+-        if (ret != EOK) {
+-            ret = errno;
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "chown failed [%d][%s].\n", ret, strerror(ret));
+-            goto done;
+-        }
+-    }
+-
+-    ret = EOK;
+-
+-done:
+-    talloc_free(tmp_ctx);
+-    return ret;
+-}
+-
+-errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+-                             struct tgt_times *tgtt)
+-{
+-    krb5_error_code kerr;
+-    krb5_context ctx = NULL;
+-    krb5_ccache cc = NULL;
+-    krb5_principal client_princ = NULL;
+-    krb5_principal server_princ = NULL;
+-    char *server_name;
+-    krb5_creds mcred;
+-    krb5_creds cred;
+-    const char *realm_name;
+-    int realm_length;
+-
+-    kerr = krb5_init_context(&ctx);
+-    if (kerr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_init_context failed.\n");
+-        goto done;
+-    }
+-
+-    kerr = krb5_parse_name(ctx, client_name, &client_princ);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
+-        goto done;
+-    }
+-
+-    sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
+-
+-    server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
+-                                  realm_length, realm_name,
+-                                  realm_length, realm_name);
+-    if (server_name == NULL) {
+-        kerr = KRB5_CC_NOMEM;
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
+-        goto done;
+-    }
+-
+-    kerr = krb5_parse_name(ctx, server_name, &server_princ);
+-    talloc_free(server_name);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
+-        goto done;
+-    }
+-
+-    kerr = krb5_cc_resolve(ctx, ccache_file, &cc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
+-        goto done;
+-    }
+-
+-    memset(&mcred, 0, sizeof(mcred));
+-    memset(&cred, 0, sizeof(mcred));
+-
+-    mcred.server = server_princ;
+-    mcred.client = client_princ;
+-
+-    kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed.\n");
+-        goto done;
+-    }
+-
+-    tgtt->authtime = cred.times.authtime;
+-    tgtt->starttime = cred.times.starttime;
+-    tgtt->endtime = cred.times.endtime;
+-    tgtt->renew_till = cred.times.renew_till;
+-
+-    krb5_free_cred_contents(ctx, &cred);
+-
+-    kerr = krb5_cc_close(ctx, cc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_close failed.\n");
+-        goto done;
+-    }
+-    cc = NULL;
+-
+-    kerr = 0;
+-
+-done:
+-    if (cc != NULL) {
+-        krb5_cc_close(ctx, cc);
+-    }
+-
+-    if (client_princ != NULL) {
+-        krb5_free_principal(ctx, client_princ);
+-    }
+-
+-    if (server_princ != NULL) {
+-        krb5_free_principal(ctx, server_princ);
+-    }
+-
+-    if (ctx != NULL) {
+-        krb5_free_context(ctx);
+-    }
+-
+-    if (kerr != 0) {
+-        return EIO;
+-    }
+-
+-    return EOK;
+-}
+-
+-errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+-                                  uid_t uid, gid_t gid)
+-{
+-    TALLOC_CTX *tmp_ctx = NULL;
+-    const char *filename;
+-    char *ccdirname;
+-    char *end;
+-    errno_t ret;
+-
+-    if (ccname[0] == '/') {
+-        filename = ccname;
+-    } else if (strncmp(ccname, "FILE:", 5) == 0) {
+-        filename = ccname + 5;
+-    } else if (strncmp(ccname, "DIR:", 4) == 0) {
+-        filename = ccname + 4;
+-    } else {
+-        /* only FILE and DIR types need precreation so far, we ignore any
+-         * other type */
+-        return EOK;
+-    }
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (!tmp_ctx) return ENOMEM;
+-
+-    ccdirname = talloc_strdup(tmp_ctx, filename);
+-    if (ccdirname == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    /* We'll remove all trailing slashes from the back so that
+-     * we only pass /some/path to find_ccdir_parent_data, not
+-     * /some/path/ */
+-    do {
+-        end = strrchr(ccdirname, '/');
+-        if (end == NULL || end == ccdirname) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find parent directory of [%s], "
+-                  "/ is not allowed.\n", ccdirname);
+-            ret = EINVAL;
+-            goto done;
+-        }
+-        *end = '\0';
+-    } while (*(end+1) == '\0');
+-
+-    ret = create_ccache_dir(ccdirname, illegal_re, uid, gid);
+-done:
+-    talloc_free(tmp_ctx);
+-    return ret;
+-}
+-
+-
+-struct sss_krb5_ccache {
+-    struct sss_creds *creds;
+-    krb5_context context;
+-    krb5_ccache ccache;
+-};
+-
+-static int sss_free_krb5_ccache(void *mem)
+-{
+-    struct sss_krb5_ccache *cc = talloc_get_type(mem, struct sss_krb5_ccache);
+-
+-    if (cc->ccache) {
+-        krb5_cc_close(cc->context, cc->ccache);
+-    }
+-    krb5_free_context(cc->context);
+-    restore_creds(cc->creds);
+-    return 0;
+-}
+-
+-static errno_t sss_open_ccache_as_user(TALLOC_CTX *mem_ctx,
+-                                       const char *ccname,
+-                                       uid_t uid, gid_t gid,
+-                                       struct sss_krb5_ccache **ccache)
+-{
+-    struct sss_krb5_ccache *cc;
+-    krb5_error_code kerr;
+-    errno_t ret;
+-
+-    cc = talloc_zero(mem_ctx, struct sss_krb5_ccache);
+-    if (!cc) {
+-        return ENOMEM;
+-    }
+-    talloc_set_destructor((TALLOC_CTX *)cc, sss_free_krb5_ccache);
+-
+-    ret = switch_creds(cc, uid, gid, 0, NULL, &cc->creds);
+-    if (ret) {
+-        goto done;
+-    }
+-
+-    kerr = krb5_init_context(&cc->context);
+-    if (kerr) {
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    kerr = krb5_cc_resolve(cc->context, ccname, &cc->ccache);
+-    if (kerr == KRB5_FCC_NOFILE || cc->ccache == NULL) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "ccache %s is missing or empty\n", ccname);
+-        ret = ERR_NOT_FOUND;
+-        goto done;
+-    } else if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
+-        ret = ERR_INTERNAL;
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-
+-done:
+-    if (ret) {
+-        talloc_free(cc);
+-    } else {
+-        *ccache = cc;
+-    }
+-    return ret;
+-}
+-
+-static errno_t sss_destroy_ccache(struct sss_krb5_ccache *cc)
+-{
+-    krb5_error_code kerr;
+-    errno_t ret;
+-
+-    kerr = krb5_cc_destroy(cc->context, cc->ccache);
+-    if (kerr) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_destroy failed.\n");
+-        ret = EIO;
+-    } else {
+-        ret = EOK;
+-    }
+-
+-    /* krb5_cc_destroy frees cc->ccache in all events */
+-    cc->ccache = NULL;
+-
+-    return ret;
+-}
+-
+-errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid)
+-{
+-    struct sss_krb5_ccache *cc = NULL;
+-    TALLOC_CTX *tmp_ctx;
+-    errno_t ret;
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
+-    if (ret) {
+-        goto done;
+-    }
+-
+-    ret = sss_destroy_ccache(cc);
+-
+-done:
+-    talloc_free(tmp_ctx);
+-    return ret;
+-}
+-
+-
+-/* This function is called only as a way to validate that we have the
+- * right cache */
+-errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+-                                    const char *ccname, const char *principal)
+-{
+-    struct sss_krb5_ccache *cc = NULL;
+-    krb5_principal ccprinc = NULL;
+-    krb5_principal kprinc = NULL;
+-    krb5_error_code kerr;
+-    const char *cc_type;
+-    TALLOC_CTX *tmp_ctx;
+-    errno_t ret;
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
+-    if (ret) {
+-        goto done;
+-    }
+-
+-    cc_type = krb5_cc_get_type(cc->context, cc->ccache);
+-
+-    DEBUG(SSSDBG_TRACE_INTERNAL,
+-          "Searching for [%s] in cache of type [%s]\n", principal, cc_type);
+-
+-    kerr = krb5_parse_name(cc->context, principal, &kprinc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
+-        ret = ERR_INTERNAL;
+-        goto done;
+-    }
+-
+-    kerr = krb5_cc_get_principal(cc->context, cc->ccache, &ccprinc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_get_principal failed.\n");
+-    }
+-
+-    if (ccprinc) {
+-        if (krb5_principal_compare(cc->context, kprinc, ccprinc) == TRUE) {
+-            /* found in the primary ccache */
+-            ret = EOK;
+-            goto done;
+-        }
+-    }
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+-
+-    if (krb5_cc_support_switch(cc->context, cc_type)) {
+-
+-        krb5_cc_close(cc->context, cc->ccache);
+-        cc->ccache = NULL;
+-
+-        kerr = krb5_cc_set_default_name(cc->context, ccname);
+-        if (kerr != 0) {
+-            KRB5_DEBUG(SSSDBG_MINOR_FAILURE, cc->context, kerr);
+-            /* try to continue despite failure */
+-        }
+-
+-        kerr = krb5_cc_cache_match(cc->context, kprinc, &cc->ccache);
+-        if (kerr == 0) {
+-            ret = EOK;
+-            goto done;
+-        }
+-        KRB5_DEBUG(SSSDBG_TRACE_INTERNAL, cc->context, kerr);
+-    }
+-
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+-    ret = ERR_NOT_FOUND;
+-
+-done:
+-    if (cc) {
+-        krb5_free_principal(cc->context, ccprinc);
+-        krb5_free_principal(cc->context, kprinc);
+-    }
+-    talloc_free(tmp_ctx);
+-    return ret;
+-}
+-
+-static errno_t sss_low_level_path_check(const char *ccname)
+-{
+-    const char *filename;
+-    struct stat buf;
+-    int ret;
+-
+-    if (ccname[0] == '/') {
+-        filename = ccname;
+-    } else if (strncmp(ccname, "FILE:", 5) == 0) {
+-        filename = ccname + 5;
+-    } else if (strncmp(ccname, "DIR:", 4) == 0) {
+-        filename = ccname + 4;
+-        if (filename[0] == ':') filename += 1;
+-    } else {
+-        /* only FILE and DIR types need file checks so far, we ignore any
+-         * other type */
+-        return EOK;
+-    }
+-
+-    ret = stat(filename, &buf);
+-    if (ret == -1) return errno;
+-    return EOK;
+-}
+-
+-errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+-                                  const char *realm, const char *principal)
+-{
+-    struct sss_krb5_ccache *cc = NULL;
+-    TALLOC_CTX *tmp_ctx = NULL;
+-    krb5_principal tgt_princ = NULL;
+-    krb5_principal princ = NULL;
+-    char *tgt_name;
+-    krb5_creds mcred = { 0 };
+-    krb5_creds cred = { 0 };
+-    krb5_error_code kerr;
+-    errno_t ret;
+-
+-    /* first of all verify if the old ccache file/dir exists as we may be
+-     * trying to verify if an old ccache exists at all. If no file/dir
+-     * exists bail out immediately otherwise a following krb5_cc_resolve()
+-     * call may actually create paths and files we do not want to have
+-     * around */
+-    ret = sss_low_level_path_check(ccname);
+-    if (ret) {
+-        return ret;
+-    }
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
+-    if (ret) {
+-        goto done;
+-    }
+-
+-    tgt_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
+-    if (!tgt_name) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    kerr = krb5_parse_name(cc->context, tgt_name, &tgt_princ);
+-    if (kerr) {
+-        KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
+-        if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
+-        else ret = ERR_INTERNAL;
+-        goto done;
+-    }
+-
+-    kerr = krb5_parse_name(cc->context, principal, &princ);
+-    if (kerr) {
+-        KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
+-        if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
+-        else ret = ERR_INTERNAL;
+-        goto done;
+-    }
+-
+-    mcred.client = princ;
+-    mcred.server = tgt_princ;
+-    mcred.times.endtime = time(NULL);
+-
+-    kerr = krb5_cc_retrieve_cred(cc->context, cc->ccache,
+-                                 KRB5_TC_MATCH_TIMES, &mcred, &cred);
+-    if (kerr) {
+-        if (kerr == KRB5_CC_NOTFOUND || kerr == KRB5_FCC_NOFILE) {
+-            DEBUG(SSSDBG_TRACE_INTERNAL, "TGT not found or expired.\n");
+-            ret = EINVAL;
+-        } else {
+-            KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
+-            ret = ERR_INTERNAL;
+-        }
+-    }
+-    krb5_free_cred_contents(cc->context, &cred);
+-
+-done:
+-    if (tgt_princ) krb5_free_principal(cc->context, tgt_princ);
+-    if (princ) krb5_free_principal(cc->context, princ);
+-    talloc_free(tmp_ctx);
+-    return ret;
+-}
+-
+-
+ errno_t get_domain_or_subdomain(struct be_ctx *be_ctx,
+                                 char *domain_name,
+                                 struct sss_domain_info **dom)
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index f54a07f7936a361c21ca933026ee753a89fe5808..ce5ce1ebcf6db14579191840600e684d41a2fdbe 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -42,25 +42,10 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+                                          const char *user,
+                                          const char *upn);
+ 
+-errno_t create_ccache_dir(const char *dirname, pcre *illegal_re,
+-                          uid_t uid, gid_t gid);
+-
+ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+                              const char *template, bool file_mode,
+                              bool case_sensitive);
+ 
+-errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+-                                  uid_t uid, gid_t gid);
+-errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
+-errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+-                                    const char *ccname, const char *principal);
+-errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+-                                  const char *realm, const char *principal);
+-
+-errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+-                             struct tgt_times *tgtt);
+-
+-
+ errno_t get_domain_or_subdomain(struct be_ctx *be_ctx,
+                                 char *domain_name,
+                                 struct sss_domain_info **dom);
+diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
+index 63caa5f6c97f3e5c0df459b7549e681e51fcc108..09f23d5386e3c70efc5ce54fa199c1a6e8656eec 100644
+--- a/src/tests/krb5_child-test.c
++++ b/src/tests/krb5_child-test.c
+@@ -37,6 +37,7 @@
+ #include "providers/krb5/krb5_auth.h"
+ #include "providers/krb5/krb5_common.h"
+ #include "providers/krb5/krb5_utils.h"
++#include "providers/krb5/krb5_ccache.h"
+ 
+ extern struct dp_option default_krb5_opts[];
+ 
+diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
+index 18d2bd230ab1170da2caf685cead46c1390c0851..52d8a18576b23c627c7ef3358bd34f4b2dbae6f7 100644
+--- a/src/tests/krb5_utils-tests.c
++++ b/src/tests/krb5_utils-tests.c
+@@ -27,6 +27,7 @@
+ #include <check.h>
+ 
+ #include "providers/krb5/krb5_utils.h"
++#include "providers/krb5/krb5_ccache.h"
+ #include "providers/krb5/krb5_auth.h"
+ #include "tests/common.h"
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch b/SOURCES/0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch
deleted file mode 100644
index 684c1e6..0000000
--- a/SOURCES/0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From a5910c05a1013c9a050f6df3d4c6884e894bf2d9 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 11 Feb 2014 22:51:48 +0100
-Subject: [PATCH 85/88] SSS_CACHE: Reset the initgroups attribute when
- resetting users
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-(cherry picked from commit 30ee051025753b63ceb19d3b83c44019a19554a1)
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
----
- src/tools/sss_cache.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
-index 56dc47afdcb92b71dc1ef71d7f26fdf276a1c45f..59b36db3e25333f4ca5da241b607edda226b929f 100644
---- a/src/tools/sss_cache.c
-+++ b/src/tools/sss_cache.c
-@@ -424,6 +424,12 @@ static errno_t invalidate_entry(TALLOC_CTX *ctx, struct sysdb_ctx *sysdb,
-         if (ret == EOK) {
-             switch (entry_type) {
-                 case TYPE_USER:
-+                    /* For users, we also need to reset the initgroups
-+                     * cache expiry */
-+                    ret = sysdb_attrs_add_time_t(sys_attrs,
-+                            SYSDB_INITGR_EXPIRE, 1);
-+                    if (ret != EOK) return ret;
-+
-                     ret = sysdb_set_user_attr(sysdb, domain, name, sys_attrs,
-                                               SYSDB_MOD_REP);
-                     break;
--- 
-1.8.5.3
-
diff --git a/SOURCES/0086-IPA-Default-to-krb5_use_fast-try.patch b/SOURCES/0086-IPA-Default-to-krb5_use_fast-try.patch
deleted file mode 100644
index 724e723..0000000
--- a/SOURCES/0086-IPA-Default-to-krb5_use_fast-try.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 529c7ade2f7f633fdb80e2f5b2055afd5a017d2f Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 11 Feb 2014 15:36:04 +0100
-Subject: [PATCH 86/88] IPA: Default to krb5_use_fast=try
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Nathaniel McCallum <npmccallum@redhat.com>
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
----
- src/providers/ipa/ipa_common.c | 27 +++++++++++++++++++++++++++
- src/providers/ipa/ipa_opts.h   |  2 +-
- 2 files changed, 28 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
-index 671374098afa1f2e00fc9cf1788ba4383b600a1b..e0abd169302406a555728589185b67e0fbbcfe94 100644
---- a/src/providers/ipa/ipa_common.c
-+++ b/src/providers/ipa/ipa_common.c
-@@ -664,6 +664,33 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts,
-                   dp_opt_get_string(ipa_opts->auth, KRB5_REALM)));
-     }
- 
-+    /* If krb5_fast_principal was not set explicitly, default to
-+     * host/$client_hostname
-+     */
-+    value = dp_opt_get_string(ipa_opts->auth, KRB5_FAST_PRINCIPAL);
-+    if (value == NULL) {
-+        value = talloc_asprintf(ipa_opts->auth, "host/%s",
-+                                    dp_opt_get_string(ipa_opts->basic,
-+                                                      IPA_HOSTNAME));
-+        if (value == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot set %s!\n",
-+                     ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name));
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        ret = dp_opt_set_string(ipa_opts->auth, KRB5_FAST_PRINCIPAL,
-+                                value);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot set %s!\n",
-+                     ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name));
-+            goto done;
-+        }
-+
-+        DEBUG(SSSDBG_CONF_SETTINGS, ("Option %s set to %s\n",
-+              ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name, value));
-+    }
-+
-     /* Set flag that controls whether we want to write the
-      * kdcinfo files at all
-      */
-diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
-index 27dc3e2f977383836c18cb824abceb03c9e9056c..c46d421ad0bfb9272cbdadbfeea5ebcf65a7deb1 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -274,7 +274,7 @@ struct dp_option ipa_def_krb5_opts[] = {
-     { "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-     { "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-     { "krb5_renew_interval", DP_OPT_STRING, NULL_STRING, NULL_STRING },
--    { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-+    { "krb5_use_fast", DP_OPT_STRING, { "try" }, NULL_STRING },
-     { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
-     { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
--- 
-1.8.5.3
-
diff --git a/SOURCES/0086-KRB5-Move-checking-for-illegal-RE-to-krb5_utils.c.patch b/SOURCES/0086-KRB5-Move-checking-for-illegal-RE-to-krb5_utils.c.patch
new file mode 100644
index 0000000..f8e95e4
--- /dev/null
+++ b/SOURCES/0086-KRB5-Move-checking-for-illegal-RE-to-krb5_utils.c.patch
@@ -0,0 +1,487 @@
+From f72856736ac39c7e926c02c11f854f43400366d4 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 18 Oct 2014 22:03:01 +0200
+Subject: [PATCH 86/92] KRB5: Move checking for illegal RE to krb5_utils.c
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Otherwise we would have to link krb5_child with pcre and transfer the
+regex, which would be cumbersome. Check for illegal patterns when
+expanding the template instead.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/krb5/krb5_auth.c   |  5 +--
+ src/providers/krb5/krb5_ccache.c | 38 ++------------------
+ src/providers/krb5/krb5_ccache.h |  7 +---
+ src/providers/krb5/krb5_utils.c  | 36 +++++++++++++++++--
+ src/providers/krb5/krb5_utils.h  |  4 +--
+ src/tests/krb5_child-test.c      |  2 +-
+ src/tests/krb5_utils-tests.c     | 78 ++++++++++++++++------------------------
+ 7 files changed, 73 insertions(+), 97 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index bd8b51f47462f1eaef8da61b42caedda3475a4e7..5ed561601ac80e53ee795b458c5bf0ca410951bc 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -302,7 +302,9 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
+             DEBUG(SSSDBG_TRACE_ALL, "Recreating  ccache file.\n");
+             ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts,
+                                                  KRB5_CCNAME_TMPL);
+-            kr->ccname = expand_ccname_template(kr, kr, ccname_template, true,
++            kr->ccname = expand_ccname_template(kr, kr, ccname_template,
++                                                kr->krb5_ctx->illegal_path_re,
++                                                true,
+                                                 be_ctx->domain->case_sensitive);
+             if (kr->ccname == NULL) {
+                 DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
+@@ -310,7 +312,6 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
+             }
+ 
+             ret = sss_krb5_precreate_ccache(kr->ccname,
+-                                            kr->krb5_ctx->illegal_path_re,
+                                             kr->uid, kr->gid);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE, "ccache creation failed.\n");
+diff --git a/src/providers/krb5/krb5_ccache.c b/src/providers/krb5/krb5_ccache.c
+index 5586963338616519f36e5d75e796a597d3ac2f22..c0f5b7b8ced3fd2d6d8cbbf4e3339caba60888ff 100644
+--- a/src/providers/krb5/krb5_ccache.c
++++ b/src/providers/krb5/krb5_ccache.c
+@@ -33,28 +33,6 @@
+ #include "util/sss_krb5.h"
+ #include "util/util.h"
+ 
+-static errno_t
+-check_ccache_re(const char *filename, pcre *illegal_re)
+-{
+-    errno_t ret;
+-
+-    ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
+-                    0, 0, NULL, 0);
+-    if (ret == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "Illegal pattern in ccache directory name [%s].\n", filename);
+-        return EINVAL;
+-    } else if (ret == PCRE_ERROR_NOMATCH) {
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "Ccache directory name [%s] does not contain "
+-               "illegal patterns.\n", filename);
+-        return EOK;
+-    }
+-
+-    DEBUG(SSSDBG_CRIT_FAILURE, "pcre_exec failed [%d].\n", ret);
+-    return EFAULT;
+-}
+-
+ struct string_list {
+     struct string_list *next;
+     struct string_list *prev;
+@@ -162,9 +140,7 @@ static errno_t check_parent_stat(struct stat *parent_stat, uid_t uid)
+     return EOK;
+ }
+ 
+-errno_t create_ccache_dir(const char *ccdirname,
+-                          pcre *illegal_re,
+-                          uid_t uid, gid_t gid)
++static errno_t create_ccache_dir(const char *ccdirname, uid_t uid, gid_t gid)
+ {
+     int ret = EFAULT;
+     struct stat parent_stat;
+@@ -188,13 +164,6 @@ errno_t create_ccache_dir(const char *ccdirname,
+         goto done;
+     }
+ 
+-    if (illegal_re != NULL) {
+-        ret = check_ccache_re(ccdirname, illegal_re);
+-        if (ret != EOK) {
+-            goto done;
+-        }
+-    }
+-
+     ret = find_ccdir_parent_data(tmp_ctx, ccdirname, &parent_stat,
+                                  &missing_parents);
+     if (ret != EOK) {
+@@ -242,8 +211,7 @@ done:
+     return ret;
+ }
+ 
+-errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+-                                  uid_t uid, gid_t gid)
++errno_t sss_krb5_precreate_ccache(const char *ccname, uid_t uid, gid_t gid)
+ {
+     TALLOC_CTX *tmp_ctx = NULL;
+     const char *filename;
+@@ -287,7 +255,7 @@ errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+         *end = '\0';
+     } while (*(end+1) == '\0');
+ 
+-    ret = create_ccache_dir(ccdirname, illegal_re, uid, gid);
++    ret = create_ccache_dir(ccdirname, uid, gid);
+ done:
+     talloc_free(tmp_ctx);
+     return ret;
+diff --git a/src/providers/krb5/krb5_ccache.h b/src/providers/krb5/krb5_ccache.h
+index 9f0b3ac84b7af118c315ca00a7c52f200534d97e..e39f96cad6f46c4003103dce4eadf007bc0f8920 100644
+--- a/src/providers/krb5/krb5_ccache.h
++++ b/src/providers/krb5/krb5_ccache.h
+@@ -35,12 +35,7 @@ struct tgt_times {
+     time_t renew_till;
+ };
+ 
+-errno_t create_ccache_dir(const char *ccdirname,
+-                          pcre *illegal_re,
+-                          uid_t uid, gid_t gid);
+-
+-errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
+-                                  uid_t uid, gid_t gid);
++errno_t sss_krb5_precreate_ccache(const char *ccname, uid_t uid, gid_t gid);
+ 
+ errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
+ 
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index ae72b04be236cfce9b6f794c602887491ba487a9..de2d94503744b80b0a3365efb227cd05434579ff 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -202,9 +202,31 @@ done:
+ #define S_EXP_USERNAME "{username}"
+ #define L_EXP_USERNAME (sizeof(S_EXP_USERNAME) - 1)
+ 
++static errno_t
++check_ccache_re(const char *filename, pcre *illegal_re)
++{
++    errno_t ret;
++
++    ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
++                    0, 0, NULL, 0);
++    if (ret == 0) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Illegal pattern in ccache directory name [%s].\n", filename);
++        return EINVAL;
++    } else if (ret == PCRE_ERROR_NOMATCH) {
++        DEBUG(SSSDBG_TRACE_LIBS,
++              "Ccache directory name [%s] does not contain "
++               "illegal patterns.\n", filename);
++        return EOK;
++    }
++
++    DEBUG(SSSDBG_CRIT_FAILURE, "pcre_exec failed [%d].\n", ret);
++    return EFAULT;
++}
++
+ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+-                             const char *template, bool file_mode,
+-                             bool case_sensitive)
++                             const char *template, pcre *illegal_re,
++                             bool file_mode, bool case_sensitive)
+ {
+     char *copy;
+     char *p;
+@@ -217,6 +239,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+     TALLOC_CTX *tmp_ctx = NULL;
+     char action;
+     bool rerun;
++    int ret;
+ 
+     if (template == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Missing template.\n");
+@@ -320,7 +343,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+                     }
+ 
+                     dummy = expand_ccname_template(tmp_ctx, kr, cache_dir_tmpl,
+-                                                   false, case_sensitive);
++                                                   illegal_re, false, case_sensitive);
+                     if (dummy == NULL) {
+                         DEBUG(SSSDBG_CRIT_FAILURE,
+                               "Expanding credential cache directory "
+@@ -411,6 +434,13 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+         goto done;
+     }
+ 
++    if (illegal_re != NULL) {
++        ret = check_ccache_re(result, illegal_re);
++        if (ret != EOK) {
++            goto done;
++        }
++    }
++
+     res = talloc_move(mem_ctx, &result);
+ done:
+     talloc_zfree(tmp_ctx);
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index ce5ce1ebcf6db14579191840600e684d41a2fdbe..0155905b5bc7469d09aecbd51cae0e8cc61b3952 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -43,8 +43,8 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+                                          const char *upn);
+ 
+ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+-                             const char *template, bool file_mode,
+-                             bool case_sensitive);
++                             const char *template, pcre *illegal_re,
++                             bool file_mode, bool case_sensitive);
+ 
+ errno_t get_domain_or_subdomain(struct be_ctx *be_ctx,
+                                 char *domain_name,
+diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
+index 09f23d5386e3c70efc5ce54fa199c1a6e8656eec..8826a28ed5ea064317c62682003dc0e9a6df01b6 100644
+--- a/src/tests/krb5_child-test.c
++++ b/src/tests/krb5_child-test.c
+@@ -239,6 +239,7 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
+         kr->ccname = expand_ccname_template(kr, kr,
+                                         dp_opt_get_cstring(kr->krb5_ctx->opts,
+                                                            KRB5_CCNAME_TMPL),
++                                            kr->krb5_ctx->illegal_path_re,
+                                             true, true);
+         if (!kr->ccname) goto fail;
+ 
+@@ -254,7 +255,6 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
+             kr->ccname, kr->uid, kr->gid);
+ 
+     ret = sss_krb5_precreate_ccache(kr->ccname,
+-                                    kr->krb5_ctx->illegal_path_re,
+                                     kr->uid, kr->gid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "create_ccache_dir failed.\n");
+diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
+index 52d8a18576b23c627c7ef3358bd34f4b2dbae6f7..409c0f01d2cce9c24a648306007b9fa7f5bc8372 100644
+--- a/src/tests/krb5_utils-tests.c
++++ b/src/tests/krb5_utils-tests.c
+@@ -131,13 +131,13 @@ START_TEST(test_private_ccache_dir_in_user_dir)
+ 
+     ret = chmod(user_dir, 0600);
+     fail_unless(ret == EOK, "chmod failed.");
+-    ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid);
++    ret = sss_krb5_precreate_ccache(filename, uid, gid);
+     fail_unless(ret == EINVAL, "sss_krb5_precreate_ccache does not return EINVAL "
+                                "while x-bit is missing.");
+ 
+     ret = chmod(user_dir, 0700);
+     fail_unless(ret == EOK, "chmod failed.");
+-    ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid);
++    ret = sss_krb5_precreate_ccache(filename, uid, gid);
+     fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed.");
+ 
+     check_dir(dn3, uid, gid, 0700);
+@@ -175,7 +175,7 @@ START_TEST(test_private_ccache_dir_in_wrong_user_dir)
+     filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname);
+     fail_unless(filename != NULL, "talloc_asprintf failed.");
+ 
+-    ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345);
++    ret = sss_krb5_precreate_ccache(filename, 12345, 12345);
+     fail_unless(ret == EINVAL, "Creating private ccache dir in wrong user "
+                                "dir does not failed with EINVAL.");
+ 
+@@ -185,16 +185,14 @@ END_TEST
+ 
+ START_TEST(test_illegal_patterns)
+ {
+-    int ret;
+     char *cwd;
+     char *dirname;
+     char *filename;
+-    uid_t uid = getuid();
+-    gid_t gid = getgid();
+     pcre *illegal_re;
+     const char *errstr;
+     int errval;
+     int errpos;
++    char *result = NULL;
+ 
+     illegal_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
+                                &errval, &errstr, &errpos, NULL);
+@@ -209,33 +207,28 @@ START_TEST(test_illegal_patterns)
+     free(cwd);
+     fail_unless(dirname != NULL, "talloc_asprintf failed.");
+ 
+-
+-    filename = talloc_asprintf(tmp_ctx, "abc/./ccfile");
+-    fail_unless(filename != NULL, "talloc_asprintf failed.");
+-    ret = create_ccache_dir(filename, illegal_re, uid, gid);
+-    fail_unless(ret == EINVAL, "create_ccache_dir allowed relative path [%s].",
+-                               filename);
++    result = expand_ccname_template(tmp_ctx, kr, "abc/./ccfile", illegal_re, true, true);
++    fail_unless(result == NULL, "expand_ccname_template allowed relative path\n");
+ 
+     filename = talloc_asprintf(tmp_ctx, "%s/abc/./ccfile", dirname);
+     fail_unless(filename != NULL, "talloc_asprintf failed.");
+-    ret = create_ccache_dir(filename, illegal_re, uid, gid);
+-    fail_unless(ret == EINVAL, "create_ccache_dir allowed "
+-                               "illegal pattern '/./' in filename [%s].",
+-                               filename);
++    result = expand_ccname_template(tmp_ctx, kr, filename, illegal_re, true, true);
++    fail_unless(result == NULL, "expand_ccname_template allowed "
++                                "illegal pattern '/./'\n");
+ 
+     filename = talloc_asprintf(tmp_ctx, "%s/abc/../ccfile", dirname);
+     fail_unless(filename != NULL, "talloc_asprintf failed.");
+-    ret = create_ccache_dir(filename, illegal_re, uid, gid);
+-    fail_unless(ret == EINVAL, "create_ccache_dir allowed "
+-                               "illegal pattern '/../' in filename [%s].",
+-                               filename);
++    result = expand_ccname_template(tmp_ctx, kr, filename, illegal_re, true, true);
++    fail_unless(result == NULL, "expand_ccname_template allowed "
++                                "illegal pattern '/../' in filename [%s].",
++                                filename);
+ 
+     filename = talloc_asprintf(tmp_ctx, "%s/abc//ccfile", dirname);
+     fail_unless(filename != NULL, "talloc_asprintf failed.");
+-    ret = create_ccache_dir(filename, illegal_re, uid, gid);
+-    fail_unless(ret == EINVAL, "create_ccache_dir allowed "
+-                               "illegal pattern '//' in filename [%s].",
+-                               filename);
++    result = expand_ccname_template(tmp_ctx, kr, filename, illegal_re, true, true);
++    fail_unless(result == NULL, "expand_ccname_template allowed "
++                                "illegal pattern '//' in filename [%s].",
++                                filename);
+ 
+     pcre_free(illegal_re);
+ }
+@@ -248,17 +241,7 @@ START_TEST(test_cc_dir_create)
+     char *cwd;
+     uid_t uid = getuid();
+     gid_t gid = getgid();
+-    pcre *illegal_re;
+     errno_t ret;
+-    const char *errstr;
+-    int errval;
+-    int errpos;
+-
+-    illegal_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
+-                               &errval, &errstr, &errpos, NULL);
+-    fail_unless(illegal_re != NULL, "Invalid Regular Expression pattern at "
+-                                    " position %d. (Error: %d [%s])\n",
+-                                    errpos, errval, errstr);
+ 
+     cwd = getcwd(NULL, 0);
+     fail_unless(cwd != NULL, "getcwd failed.");
+@@ -269,7 +252,7 @@ START_TEST(test_cc_dir_create)
+     residual = talloc_asprintf(tmp_ctx, "DIR:%s/%s", dirname, "ccdir");
+     fail_unless(residual != NULL, "talloc_asprintf failed.");
+ 
+-    ret = sss_krb5_precreate_ccache(residual, illegal_re, uid, gid);
++    ret = sss_krb5_precreate_ccache(residual, uid, gid);
+     fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed\n");
+     ret = rmdir(dirname);
+     if (ret < 0) ret = errno;
+@@ -282,14 +265,13 @@ START_TEST(test_cc_dir_create)
+     residual = talloc_asprintf(tmp_ctx, "DIR:%s/%s", dirname, "ccdir/");
+     fail_unless(residual != NULL, "talloc_asprintf failed.");
+ 
+-    ret = sss_krb5_precreate_ccache(residual, illegal_re, uid, gid);
++    ret = sss_krb5_precreate_ccache(residual, uid, gid);
+     fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed\n");
+     ret = rmdir(dirname);
+     if (ret < 0) ret = errno;
+     fail_unless(ret == 0, "Cannot remove %s: %s\n", dirname, strerror(ret));
+     talloc_free(residual);
+     free(cwd);
+-    pcre_free(illegal_re);
+ }
+ END_TEST
+ 
+@@ -356,7 +338,7 @@ static void do_test(const char *file_template, const char *dir_template,
+     ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, dir_template);
+     fail_unless(ret == EOK, "Failed to set Ccache dir");
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, file_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, file_template, NULL, true, true);
+ 
+     fail_unless(result != NULL, "Cannot expand template [%s].", file_template);
+     fail_unless(strcmp(result, expected) == 0,
+@@ -391,14 +373,14 @@ START_TEST(test_case_sensitive)
+     ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, CCACHE_DIR);
+     fail_unless(ret == EOK, "Failed to set Ccache dir");
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, file_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, file_template, NULL, true, true);
+ 
+     fail_unless(result != NULL, "Cannot expand template [%s].", file_template);
+     fail_unless(strcmp(result, expected_cs) == 0,
+                 "Expansion failed, result [%s], expected [%s].",
+                 result, expected_cs);
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, file_template, true, false);
++    result = expand_ccname_template(tmp_ctx, kr, file_template, NULL, true, false);
+ 
+     fail_unless(result != NULL, "Cannot expand template [%s].", file_template);
+     fail_unless(strcmp(result, expected_ci) == 0,
+@@ -445,7 +427,7 @@ START_TEST(test_ccache_dir)
+     ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, BASE"_%d");
+     fail_unless(ret == EOK, "Failed to set Ccache dir");
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, "%d/"FILENAME, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, "%d/"FILENAME, NULL, true, true);
+ 
+     fail_unless(result == NULL, "Using %%d in ccache dir should fail.");
+ }
+@@ -461,7 +443,7 @@ START_TEST(test_pid)
+     ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, BASE"_%P");
+     fail_unless(ret == EOK, "Failed to set Ccache dir");
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, "%d/"FILENAME, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, "%d/"FILENAME, NULL, true, true);
+ 
+     fail_unless(result == NULL, "Using %%P in ccache dir should fail.");
+ }
+@@ -480,7 +462,7 @@ START_TEST(test_unknown_template)
+     char *result;
+     int ret;
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, test_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, test_template, NULL, true, true);
+ 
+     fail_unless(result == NULL, "Unknown template [%s] should fail.",
+                 test_template);
+@@ -488,7 +470,7 @@ START_TEST(test_unknown_template)
+     ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, BASE"_%X");
+     fail_unless(ret == EOK, "Failed to set Ccache dir");
+     test_template = "%d/"FILENAME;
+-    result = expand_ccname_template(tmp_ctx, kr, test_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, test_template, NULL, true, true);
+ 
+     fail_unless(result == NULL, "Unknown template [%s] should fail.",
+                 test_template);
+@@ -500,7 +482,7 @@ START_TEST(test_NULL)
+     char *test_template = NULL;
+     char *result;
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, test_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, test_template, NULL, true, true);
+ 
+     fail_unless(result == NULL, "Expected NULL as a result for an empty input.",
+                 test_template);
+@@ -512,7 +494,7 @@ START_TEST(test_no_substitution)
+     const char *test_template = BASE;
+     char *result;
+ 
+-    result = expand_ccname_template(tmp_ctx, kr, test_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, test_template, NULL, true, true);
+ 
+     fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+     fail_unless(strcmp(result, test_template) == 0,
+@@ -529,7 +511,7 @@ START_TEST(test_krb5_style_expansion)
+ 
+     file_template = BASE"/%{uid}/%{USERID}/%{euid}/%{username}";
+     expected = BASE"/"UID"/"UID"/"UID"/"USERNAME;
+-    result = expand_ccname_template(tmp_ctx, kr, file_template, true, true);
++    result = expand_ccname_template(tmp_ctx, kr, file_template, NULL, true, true);
+ 
+     fail_unless(result != NULL, "Cannot expand template [%s].", file_template);
+     fail_unless(strcmp(result, expected) == 0,
+@@ -538,7 +520,7 @@ START_TEST(test_krb5_style_expansion)
+ 
+     file_template = BASE"/%{unknown}";
+     expected = BASE"/%{unknown}";
+-    result = expand_ccname_template(tmp_ctx, kr, file_template, true, false);
++    result = expand_ccname_template(tmp_ctx, kr, file_template, NULL, true, true);
+ 
+     fail_unless(result != NULL, "Cannot expand template [%s].", file_template);
+     fail_unless(strcmp(result, expected) == 0,
+-- 
+1.9.3
+
diff --git a/SOURCES/0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch b/SOURCES/0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch
deleted file mode 100644
index ca8a886..0000000
--- a/SOURCES/0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 920e81404bc37e57f2d7613ca9031e2337c1edd0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 14 Feb 2014 11:45:50 +0100
-Subject: [PATCH 87/88] IPA: default krb5_fast_principal to host/$client@$realm
-
-If krb5_fast_principal is not set in sssd.conf it was set to host/$client,
-KRB5 default realm was used which doesn't have to be the same as realm
-used for IPA, thus authentication failed when using FAST.
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-(cherry picked from commit e325cabe762fad7d696e014a7fdbb47a5cb8174a)
----
- src/providers/ipa/ipa_common.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
-index e0abd169302406a555728589185b67e0fbbcfe94..d4db1549b3657268381d0e425615c1b389fed23e 100644
---- a/src/providers/ipa/ipa_common.c
-+++ b/src/providers/ipa/ipa_common.c
-@@ -665,13 +665,15 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts,
-     }
- 
-     /* If krb5_fast_principal was not set explicitly, default to
--     * host/$client_hostname
-+     * host/$client_hostname@REALM
-      */
-     value = dp_opt_get_string(ipa_opts->auth, KRB5_FAST_PRINCIPAL);
-     if (value == NULL) {
--        value = talloc_asprintf(ipa_opts->auth, "host/%s",
-+        value = talloc_asprintf(ipa_opts->auth, "host/%s@%s",
-                                     dp_opt_get_string(ipa_opts->basic,
--                                                      IPA_HOSTNAME));
-+                                                      IPA_HOSTNAME),
-+                                    dp_opt_get_string(ipa_opts->auth,
-+                                                      KRB5_REALM));
-         if (value == NULL) {
-             DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot set %s!\n",
-                      ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name));
--- 
-1.8.5.3
-
diff --git a/SOURCES/0087-KRB5-Move-all-ccache-operations-to-krb5_child.c.patch b/SOURCES/0087-KRB5-Move-all-ccache-operations-to-krb5_child.c.patch
new file mode 100644
index 0000000..da6bae6
--- /dev/null
+++ b/SOURCES/0087-KRB5-Move-all-ccache-operations-to-krb5_child.c.patch
@@ -0,0 +1,889 @@
+From 663c5a61e6ab5aeee901684b8b43176711d5554e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 18 Oct 2014 22:03:13 +0200
+Subject: [PATCH 87/92] KRB5: Move all ccache operations to krb5_child.c
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The credential cache operations must be now performed by the krb5_child
+completely, because the sssd_be process might be running as the sssd
+user who doesn't have access to the ccaches.
+
+src/providers/krb5/krb5_ccache.c is still linked against libsss_krb5
+until we fix Kerberos ticket renewal as non-root.
+
+Also includes a new error code that indicates that the back end should
+remove the old ccache attribute -- the child can't do that if it's
+running as the user.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am                             |  13 +-
+ src/providers/krb5/krb5_auth.c          | 223 ++++----------------------------
+ src/providers/krb5/krb5_ccache.c        |  62 ++++-----
+ src/providers/krb5/krb5_ccache.h        |   5 +-
+ src/providers/krb5/krb5_child.c         | 208 +++++++++++++++++++++++++++--
+ src/providers/krb5/krb5_child_handler.c |  13 ++
+ src/tests/krb5_child-test.c             |   3 +-
+ src/util/util_errors.c                  |   1 +
+ src/util/util_errors.h                  |   1 +
+ 9 files changed, 281 insertions(+), 248 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 4a69ecb0cfe48e20bde958c9351c2a5ece5ffffa..5325d51e7240ae39a546e68b2a2aea202b3dfdfa 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2496,27 +2496,36 @@ libsss_ad_la_LDFLAGS = \
+ 
+ krb5_child_SOURCES = \
+     src/providers/krb5/krb5_child.c \
++    src/providers/krb5/krb5_ccache.c \
+     src/providers/dp_pam_data_util.c \
+     src/util/user_info_msg.c \
+     src/util/sss_krb5.c \
++    src/util/find_uid.c \
+     src/util/atomic_io.c \
+     src/util/authtok.c \
+     src/util/util.c \
+     src/util/signal.c \
++    src/util/strtonum.c \
+     src/util/become_user.c \
+     src/sss_client/common.c \
+     $(NULL)
+ krb5_child_CFLAGS = \
+     $(AM_CFLAGS) \
+     $(POPT_CFLAGS) \
+-    $(KRB5_CFLAGS)
++    $(KRB5_CFLAGS) \
++    $(PCRE_CFLAGS) \
++    $(SYSTEMD_LOGIN_CFLAGS) \
++    $(NULL)
+ krb5_child_LDADD = \
+     libsss_debug.la \
+     $(TALLOC_LIBS) \
+     $(POPT_LIBS) \
+     $(DHASH_LIBS) \
+     $(KRB5_LIBS) \
+-    $(CLIENT_LIBS)
++    $(CLIENT_LIBS) \
++    $(PCRE_LIBS) \
++    $(SYSTEMD_LOGIN_LIBS) \
++    $(NULL)
+ 
+ ldap_child_SOURCES = \
+     src/providers/ldap/ldap_child.c \
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index 5ed561601ac80e53ee795b458c5bf0ca410951bc..e791aee1c2d83f84ba617db1d5d93948c0e4e2a1 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -41,45 +41,6 @@
+ #include "providers/krb5/krb5_utils.h"
+ #include "providers/krb5/krb5_ccache.h"
+ 
+-static errno_t
+-check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+-                 const char *realm, bool *active, bool *valid)
+-{
+-    errno_t ret;
+-
+-    *active = false;
+-    *valid = false;
+-
+-    ret = sss_krb5_cc_verify_ccache(old_ccache,
+-                                    kr->uid, kr->gid,
+-                                    realm, kr->upn);
+-    switch (ret) {
+-    case ERR_NOT_FOUND:
+-    case ENOENT:
+-        DEBUG(SSSDBG_TRACE_FUNC,
+-              "Saved ccache %s doesn't exist.\n", old_ccache);
+-        return ENOENT;
+-    case EINVAL:
+-        /* cache found but no tgt or expired */
+-    case EOK:
+-        *valid = true;
+-        break;
+-    default:
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "Cannot check if saved ccache %s is valid\n",
+-               old_ccache);
+-        return ret;
+-    }
+-
+-    ret = check_if_uid_is_active(kr->uid, active);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "check_if_uid_is_active failed.\n");
+-        return ret;
+-    }
+-
+-    return EOK;
+-}
+-
+ static int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
+                            struct sysdb_ctx *sysdb,
+                            struct sss_domain_info *domain,
+@@ -225,7 +186,6 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
+         return ENOMEM;
+     }
+     kr->is_offline = false;
+-    kr->active_ccache = true;
+     kr->run_as_user = true;
+     talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
+ 
+@@ -276,47 +236,26 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
+ }
+ 
+ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
++                                             struct ldb_message *user_msg,
+                                              struct be_ctx *be_ctx)
+ {
+     const char *ccname_template;
+-    errno_t ret;
+ 
+-    if (!kr->is_offline) {
+-        kr->is_offline = be_is_offline(be_ctx);
++    ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
++
++    kr->ccname = expand_ccname_template(kr, kr, ccname_template,
++                                        kr->krb5_ctx->illegal_path_re, true,
++                                        be_ctx->domain->case_sensitive);
++    if (kr->ccname == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
++        return ENOMEM;
+     }
+ 
+-    /* The ccache file should be (re)created if one of the following conditions
+-     * is true:
+-     * - it doesn't exist (kr->ccname == NULL)
+-     * - the backend is online and the current ccache file is not used, i.e
+-     *   the related user is currently not logged in and it is not a renewal
+-     *   request
+-     *   (!kr->is_offline && !kr->active_ccache && kr->pd->cmd != SSS_CMD_RENEW)
+-     * - the backend is offline and the current cache file not used and
+-     *   it does not contain a valid tgt
+-     *   (kr->is_offline && !kr->active_ccache && !kr->valid_tgt)
+-     */
+-    if (kr->ccname == NULL ||
+-        (kr->is_offline && !kr->active_ccache && !kr->valid_tgt) ||
+-        (!kr->is_offline && !kr->active_ccache && kr->pd->cmd != SSS_CMD_RENEW)) {
+-            DEBUG(SSSDBG_TRACE_ALL, "Recreating  ccache file.\n");
+-            ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts,
+-                                                 KRB5_CCNAME_TMPL);
+-            kr->ccname = expand_ccname_template(kr, kr, ccname_template,
+-                                                kr->krb5_ctx->illegal_path_re,
+-                                                true,
+-                                                be_ctx->domain->case_sensitive);
+-            if (kr->ccname == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
+-                return ENOMEM;
+-            }
+-
+-            ret = sss_krb5_precreate_ccache(kr->ccname,
+-                                            kr->uid, kr->gid);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "ccache creation failed.\n");
+-                return ret;
+-            }
++    kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
++                                                 SYSDB_CCACHE_FILE, NULL);
++    if (kr->old_ccname == NULL) {
++        DEBUG(SSSDBG_TRACE_LIBS,
++                "No ccache file for user [%s] found.\n", kr->pd->user);
+     }
+ 
+     return EOK;
+@@ -402,7 +341,6 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+     struct krb5_auth_state *state;
+     struct ldb_result *res;
+     struct krb5child_req *kr = NULL;
+-    const char *ccache_file = NULL;
+     const char *realm;
+     struct tevent_req *req;
+     struct tevent_req *subreq;
+@@ -588,45 +526,10 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+ 
+-        ccache_file = ldb_msg_find_attr_as_string(res->msgs[0],
+-                                                  SYSDB_CCACHE_FILE,
+-                                                  NULL);
+-        if (ccache_file != NULL) {
+-            ret = check_old_ccache(ccache_file, kr, realm,
+-                                   &kr->active_ccache,
+-                                   &kr->valid_tgt);
+-            if (ret == ENOENT) {
+-                DEBUG(SSSDBG_FUNC_DATA,
+-                      "Ignoring ccache attribute [%s], because it doesn't"
+-                       "exist.\n", ccache_file);
+-                ccache_file = NULL;
+-            } else if (ret != EOK) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "check_if_ccache_file_is_used failed.\n");
+-                ccache_file = NULL;
+-            }
+-        } else {
+-            kr->active_ccache = false;
+-            kr->valid_tgt = false;
+-            DEBUG(SSSDBG_CONF_SETTINGS,
+-                  "No ccache file for user [%s] found.\n", pd->user);
+-        }
+-        DEBUG(SSSDBG_TRACE_ALL,
+-              "Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
+-                  ccache_file ? ccache_file : "not set",
+-                  kr->active_ccache ? "" : "not",
+-                  kr->valid_tgt ? "" : "not");
+-        if (ccache_file != NULL) {
+-            kr->ccname = ccache_file;
+-            kr->old_ccname = talloc_strdup(kr, ccache_file);
+-            if (kr->old_ccname == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
+-                ret = ENOMEM;
+-                goto done;
+-            }
+-        } else {
+-            kr->ccname = NULL;
+-            kr->old_ccname = NULL;
++        ret = krb5_auth_prepare_ccache_name(kr, res->msgs[0], state->be_ctx);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot prepare ccache names!\n");
++            goto done;
+         }
+         break;
+ 
+@@ -669,7 +572,6 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
+     struct krb5child_req *kr = state->kr;
+-    char *msg;
+     int ret;
+ 
+     if (!state->search_kpasswd) {
+@@ -728,45 +630,8 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
+         }
+     }
+ 
+-    ret = krb5_auth_prepare_ccache_name(kr, state->be_ctx);
+-    if (ret) {
+-        goto done;
+-    }
+-
+-    if (kr->is_offline) {
+-        DEBUG(SSSDBG_TRACE_ALL, "Preparing for offline operation.\n");
+-
+-        if (kr->valid_tgt || kr->active_ccache) {
+-            DEBUG(SSSDBG_TRACE_ALL, "Valid TGT available or "
+-                      "ccache file is already in use.\n");
+-            kr->ccname = kr->old_ccname;
+-            msg = talloc_asprintf(kr->pd,
+-                                  "%s=%s", CCACHE_ENV_NAME, kr->ccname);
+-            if (msg == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
+-            } else {
+-                ret = pam_add_response(kr->pd, SSS_PAM_ENV_ITEM,
+-                                       strlen(msg) + 1, (uint8_t *) msg);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
+-                }
+-            }
+-
+-            if (dp_opt_get_bool(kr->krb5_ctx->opts,
+-                                KRB5_STORE_PASSWORD_IF_OFFLINE)) {
+-                krb5_auth_cache_creds(state->kr->krb5_ctx,
+-                                      state->domain,
+-                                      state->be_ctx->cdb,
+-                                      kr->pd, kr->uid,
+-                                      &state->pam_status, &state->dp_err);
+-            } else {
+-                state->pam_status = PAM_AUTHINFO_UNAVAIL;
+-                state->dp_err = DP_ERR_OFFLINE;
+-            }
+-            ret = EOK;
+-            goto done;
+-
+-        }
++    if (!kr->is_offline) {
++        kr->is_offline = be_is_offline(state->be_ctx);
+     }
+ 
+     /* We need to keep the root privileges to read the keytab file if
+@@ -814,7 +679,6 @@ static void krb5_auth_done(struct tevent_req *subreq)
+     char *renew_interval_str;
+     time_t renew_interval_time = 0;
+     bool use_enterprise_principal;
+-    uint32_t user_info_type;
+ 
+     ret = handle_child_recv(subreq, pd, &buf, &len);
+     talloc_zfree(subreq);
+@@ -974,6 +838,14 @@ static void krb5_auth_done(struct tevent_req *subreq)
+         }
+         break;
+ 
++    case ERR_CREDS_EXPIRED_CCACHE:
++        ret = krb5_delete_ccname(state, state->sysdb, state->domain,
++                pd->user, kr->old_ccname);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "krb5_delete_ccname failed.\n");
++        }
++        /* FALLTHROUGH */
++
+     case ERR_CREDS_EXPIRED:
+         /* If the password is expired we can safely remove the ccache from the
+          * cache and disk if it is not actively used anymore. This will allow
+@@ -981,14 +853,6 @@ static void krb5_auth_done(struct tevent_req *subreq)
+          * used. */
+         if (pd->cmd == SSS_PAM_AUTHENTICATE && !kr->active_ccache) {
+             if (kr->old_ccname != NULL) {
+-                ret = safe_remove_old_ccache_file(kr->old_ccname, NULL,
+-                                                  kr->uid, kr->gid);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Failed to remove old ccache file [%s], "
+-                              "please remove it manually.\n", kr->old_ccname);
+-                }
+-
+                 ret = krb5_delete_ccname(state, state->sysdb, state->domain,
+                                          pd->user, kr->old_ccname);
+                 if (ret != EOK) {
+@@ -1062,37 +926,6 @@ static void krb5_auth_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
+-    ret = sss_krb5_check_ccache_princ(kr->uid, kr->gid, kr->ccname, kr->upn);
+-    if (ret) {
+-        if (res->otp == true && pd->cmd == SSS_PAM_CHAUTHTOK) {
+-            DEBUG(SSSDBG_IMPORTANT_INFO,
+-                  "Password change succeeded but currently "
+-                  "post-chpass kinit is not implemented\n");
+-
+-            user_info_type = SSS_PAM_USER_INFO_OTP_CHPASS;
+-            ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
+-                                   (const uint8_t *) &user_info_type);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
+-                /* Not fatal */
+-            }
+-        } else {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "No ccache for %s in %s?\n", kr->upn, kr->ccname);
+-            goto done;
+-        }
+-    }
+-
+-    if (kr->old_ccname) {
+-        ret = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname,
+-                                          kr->uid, kr->gid);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Failed to remove old ccache file [%s], "
+-                   "please remove it manually.\n", kr->old_ccname);
+-        }
+-    }
+-
+     ret = krb5_save_ccname(state, state->sysdb, state->domain,
+                            pd->user, kr->ccname);
+     if (ret) {
+diff --git a/src/providers/krb5/krb5_ccache.c b/src/providers/krb5/krb5_ccache.c
+index c0f5b7b8ced3fd2d6d8cbbf4e3339caba60888ff..7aa36b744ddcf7e46edcc26405a5101645b8b546 100644
+--- a/src/providers/krb5/krb5_ccache.c
++++ b/src/providers/krb5/krb5_ccache.c
+@@ -374,49 +374,32 @@ done:
+ 
+ /* This function is called only as a way to validate that we have the
+  * right cache */
+-errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+-                                    const char *ccname, const char *principal)
++errno_t sss_krb5_check_ccache_princ(krb5_context kctx,
++                                    const char *ccname,
++                                    krb5_principal user_princ)
+ {
+-    struct sss_krb5_ccache *cc = NULL;
++    krb5_ccache kcc = NULL;
+     krb5_principal ccprinc = NULL;
+-    krb5_principal kprinc = NULL;
+     krb5_error_code kerr;
+     const char *cc_type;
+-    TALLOC_CTX *tmp_ctx;
+     errno_t ret;
+ 
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
+-    if (ret) {
+-        goto done;
+-    }
+-
+-    cc_type = krb5_cc_get_type(cc->context, cc->ccache);
+-
+-    DEBUG(SSSDBG_TRACE_INTERNAL,
+-          "Searching for [%s] in cache of type [%s]\n", principal, cc_type);
+-
+-    kerr = krb5_parse_name(cc->context, principal, &kprinc);
+-    if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
++    kerr = krb5_cc_resolve(kctx, ccname, &kcc);
++    if (kerr) {
+         ret = ERR_INTERNAL;
+         goto done;
+     }
+ 
+-    kerr = krb5_cc_get_principal(cc->context, cc->ccache, &ccprinc);
++    cc_type = krb5_cc_get_type(kctx, kcc);
++
++    kerr = krb5_cc_get_principal(kctx, kcc, &ccprinc);
+     if (kerr != 0) {
+-        KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
++        KRB5_DEBUG(SSSDBG_OP_FAILURE, kctx, kerr);
+         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_get_principal failed.\n");
+     }
+ 
+     if (ccprinc) {
+-        if (krb5_principal_compare(cc->context, kprinc, ccprinc) == TRUE) {
++        if (krb5_principal_compare(kctx, user_princ, ccprinc) == TRUE) {
+             /* found in the primary ccache */
+             ret = EOK;
+             goto done;
+@@ -425,23 +408,23 @@ errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+ 
+ #ifdef HAVE_KRB5_CC_COLLECTION
+ 
+-    if (krb5_cc_support_switch(cc->context, cc_type)) {
++    if (krb5_cc_support_switch(kctx, cc_type)) {
+ 
+-        krb5_cc_close(cc->context, cc->ccache);
+-        cc->ccache = NULL;
++        krb5_cc_close(kctx, kcc);
++        kcc = NULL;
+ 
+-        kerr = krb5_cc_set_default_name(cc->context, ccname);
++        kerr = krb5_cc_set_default_name(kctx, ccname);
+         if (kerr != 0) {
+-            KRB5_DEBUG(SSSDBG_MINOR_FAILURE, cc->context, kerr);
++            KRB5_DEBUG(SSSDBG_MINOR_FAILURE, kctx, kerr);
+             /* try to continue despite failure */
+         }
+ 
+-        kerr = krb5_cc_cache_match(cc->context, kprinc, &cc->ccache);
++        kerr = krb5_cc_cache_match(kctx, user_princ, &kcc);
+         if (kerr == 0) {
+             ret = EOK;
+             goto done;
+         }
+-        KRB5_DEBUG(SSSDBG_TRACE_INTERNAL, cc->context, kerr);
++        KRB5_DEBUG(SSSDBG_TRACE_INTERNAL, kctx, kerr);
+     }
+ 
+ #endif /* HAVE_KRB5_CC_COLLECTION */
+@@ -449,11 +432,12 @@ errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+     ret = ERR_NOT_FOUND;
+ 
+ done:
+-    if (cc) {
+-        krb5_free_principal(cc->context, ccprinc);
+-        krb5_free_principal(cc->context, kprinc);
++    if (ccprinc) {
++        krb5_free_principal(kctx, ccprinc);
++    }
++    if (kcc) {
++        krb5_cc_close(kctx, kcc);
+     }
+-    talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
+diff --git a/src/providers/krb5/krb5_ccache.h b/src/providers/krb5/krb5_ccache.h
+index e39f96cad6f46c4003103dce4eadf007bc0f8920..e47df3665e3f325cc56d34767b416662577cc048 100644
+--- a/src/providers/krb5/krb5_ccache.h
++++ b/src/providers/krb5/krb5_ccache.h
+@@ -39,8 +39,9 @@ errno_t sss_krb5_precreate_ccache(const char *ccname, uid_t uid, gid_t gid);
+ 
+ errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
+ 
+-errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+-                                    const char *ccname, const char *principal);
++errno_t sss_krb5_check_ccache_princ(krb5_context kctx,
++                                    const char *ccname,
++                                    krb5_principal user_princ);
+ 
+ errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+                                   const char *realm, const char *principal);
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 7fa5f0c344a4afe110afa08f479f283aefce8d23..94cd34e433cf6a197860d233fbf9ca30cd3eb535 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -33,6 +33,7 @@
+ #include "util/sss_krb5.h"
+ #include "util/user_info_msg.h"
+ #include "util/child_common.h"
++#include "util/find_uid.h"
+ #include "providers/dp_backend.h"
+ #include "providers/krb5/krb5_auth.h"
+ #include "providers/krb5/krb5_utils.h"
+@@ -61,6 +62,10 @@ struct krb5_req {
+     const char *upn;
+     uid_t uid;
+     gid_t gid;
++
++    char *old_ccname;
++    bool old_cc_valid;
++    bool old_cc_active;
+ };
+ 
+ static krb5_context krb5_error_ctx;
+@@ -1021,6 +1026,24 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
+         goto done;
+     }
+ 
++    /* Successfull authentication! Check if ccache contains the
++     * right principal...
++     */
++    kerr = sss_krb5_check_ccache_princ(kr->ctx, kr->ccname, kr->creds->client);
++    if (kerr) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "No ccache for %s in %s?\n", kr->upn, kr->ccname);
++        goto done;
++    }
++
++    kerr = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname,
++                                       kr->uid, kr->gid);
++    if (kerr != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Failed to remove old ccache file [%s], "
++              "please remove it manually.\n", kr->old_ccname);
++    }
++
+     kerr = add_ticket_times_and_upn_to_response(kr);
+     if (kerr != 0) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+@@ -1094,6 +1117,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
+     int realm_length;
+     size_t msg_len;
+     uint8_t *msg;
++    uint32_t user_info_type;
+ 
+     DEBUG(SSSDBG_TRACE_LIBS, "Password change operation\n");
+ 
+@@ -1222,6 +1246,14 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
+     krb5_free_cred_contents(kr->ctx, kr->creds);
+ 
+     if (kr->otp == true) {
++        user_info_type = SSS_PAM_USER_INFO_OTP_CHPASS;
++        ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
++                               (const uint8_t *) &user_info_type);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
++            /* Not fatal */
++        }
++
+         sss_authtok_set_empty(kr->pd->newauthtok);
+         return map_krb5_error(kerr);
+     }
+@@ -1298,6 +1330,21 @@ static errno_t tgt_req_child(struct krb5_req *kr)
+     krb5_free_cred_contents(kr->ctx, kr->creds);
+     if (kerr == 0) {
+         ret = ERR_CREDS_EXPIRED;
++
++        /* If the password is expired we can safely remove the ccache from the
++         * cache and disk if it is not actively used anymore. This will allow
++         * to create a new random ccache if sshd with privilege separation is
++         * used. */
++        if (kr->old_cc_active == false && kr->old_ccname) {
++            ret = safe_remove_old_ccache_file(kr->old_ccname, NULL,
++                    kr->uid, kr->gid);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                        "Failed to remove old ccache file [%s], "
++                        "please remove it manually.\n", kr->old_ccname);
++            }
++            ret = ERR_CREDS_EXPIRED_CCACHE;
++        }
+     } else {
+         ret = map_krb5_error(kerr);
+     }
+@@ -1423,12 +1470,17 @@ static errno_t create_empty_ccache(struct krb5_req *kr)
+     krb5_creds *creds = NULL;
+     krb5_error_code kerr;
+ 
+-    DEBUG(SSSDBG_TRACE_LIBS, "Creating empty ccache\n");
+-
+-    kerr = create_empty_cred(kr->ctx, kr->princ, &creds);
+-    if (kerr == 0) {
+-        kerr = create_ccache(kr->ccname, creds);
++    if (kr->old_cc_valid == false) {
++        DEBUG(SSSDBG_TRACE_LIBS, "Creating empty ccache\n");
++        kerr = create_empty_cred(kr->ctx, kr->princ, &creds);
++        if (kerr == 0) {
++            kerr = create_ccache(kr->ccname, creds);
++        }
++    } else {
++        DEBUG(SSSDBG_TRACE_LIBS, "Existing ccache still valid, reusing\n");
++        kerr = 0;
+     }
++
+     if (kerr != 0) {
+         KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+     } else {
+@@ -1529,6 +1581,17 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
+ 
+         SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
+         if ((p + len ) > size) return EINVAL;
++
++        if (len > 0) {
++            kr->old_ccname = talloc_strndup(pd, (char *)(buf + p), len);
++            if (kr->old_ccname == NULL) return ENOMEM;
++            p += len;
++        } else {
++            DEBUG(SSSDBG_TRACE_INTERNAL, "No old ccache\n");
++        }
++
++        SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
++        if ((p + len ) > size) return EINVAL;
+         kr->keytab = talloc_strndup(pd, (char *)(buf + p), len);
+         if (kr->keytab == NULL) return ENOMEM;
+         p += len;
+@@ -1538,10 +1601,14 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
+             return ret;
+         }
+ 
+-        DEBUG(SSSDBG_CONF_SETTINGS, "ccname: [%s] keytab: [%s]\n",
+-              kr->ccname, kr->keytab);
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "ccname: [%s] old_ccname: [%s] keytab: [%s]\n",
++              kr->ccname,
++              kr->old_ccname ? kr->old_ccname : "not set",
++              kr->keytab);
+     } else {
+         kr->ccname = NULL;
++        kr->old_ccname = NULL;
+         kr->keytab = NULL;
+         sss_authtok_set_empty(pd->authtok);
+     }
+@@ -1870,6 +1937,126 @@ static errno_t check_use_fast(enum k5c_fast_opt *_fast_val)
+     return EOK;
+ }
+ 
++static errno_t old_ccache_valid(struct krb5_req *kr, bool *_valid)
++{
++    errno_t ret;
++    bool valid;
++
++    valid = false;
++
++    ret = sss_krb5_cc_verify_ccache(kr->old_ccname,
++                                    kr->uid, kr->gid,
++                                    kr->realm, kr->upn);
++    switch (ret) {
++        case ERR_NOT_FOUND:
++        case ENOENT:
++            DEBUG(SSSDBG_TRACE_FUNC,
++                  "Saved ccache %s doesn't exist, ignoring\n", kr->old_ccname);
++            break;
++        case EINVAL:
++            /* cache found but no tgt or expired */
++        case EOK:
++            valid = true;
++            break;
++        default:
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "Cannot check if saved ccache %s is valid\n",
++                   kr->old_ccname);
++            return ret;
++    }
++
++    *_valid = valid;
++    return EOK;
++}
++
++static int k5c_check_old_ccache(struct krb5_req *kr)
++{
++    errno_t ret;
++
++    if (kr->old_ccname) {
++        ret = old_ccache_valid(kr, &kr->old_cc_valid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "old_ccache_valid failed.\n");
++            return ret;
++        }
++
++        ret = check_if_uid_is_active(kr->uid, &kr->old_cc_active);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "check_if_uid_is_active failed.\n");
++            return ret;
++        }
++
++        DEBUG(SSSDBG_TRACE_ALL,
++                "Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
++                kr->old_ccname ? kr->old_ccname : "not set",
++                kr->old_cc_active ? "" : "not",
++                kr->old_cc_valid ? "" : "not");
++    }
++
++    return EOK;
++}
++
++static int k5c_precreate_ccache(struct krb5_req *kr, uint32_t offline)
++{
++    errno_t ret;
++
++    /* The ccache file should be (re)created if one of the following conditions
++     * is true:
++     * - it doesn't exist (kr->old_ccname == NULL)
++     * - the backend is online and the current ccache file is not used, i.e
++     * the related user is currently not logged in and it is not a renewal
++     * request
++     * (offline && !kr->old_cc_active && kr->pd->cmd != SSS_CMD_RENEW)
++     * - the backend is offline and the current cache file not used and
++     * it does not contain a valid tgt
++     * (offline && !kr->old_cc_active && !kr->valid_tgt)
++     */
++    if (kr->old_ccname == NULL ||
++            (offline && !kr->old_cc_active && !kr->old_cc_valid) ||
++            (!offline && !kr->old_cc_active && kr->pd->cmd != SSS_CMD_RENEW)) {
++        DEBUG(SSSDBG_TRACE_ALL, "Recreating ccache\n");
++
++        ret = sss_krb5_precreate_ccache(kr->ccname, kr->uid, kr->gid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "ccache creation failed.\n");
++            return ret;
++        }
++    } else {
++        /* We can reuse the old ccache */
++        kr->ccname = kr->old_ccname;
++    }
++
++    return EOK;
++}
++
++static int k5c_ccache_setup(struct krb5_req *kr, uint32_t offline)
++{
++    errno_t ret;
++
++    if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
++        return EOK;
++    }
++
++    ret = k5c_check_old_ccache(kr);
++    if (ret != 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "Cannot check old ccache\n");
++        return ret;
++    }
++
++    /* Pre-creating the ccache must be done as root, otherwise we can't mkdir
++     * some of the DIR: cache components. One example is /run/user/$UID because
++     * logind doesn't create the directory until the session phase, whereas
++     * we need the directory during the auth phase already
++     */
++    ret = k5c_precreate_ccache(kr, offline);
++    if (ret != 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "Cannot precreate ccache\n");
++        return ret;
++    }
++
++    return EOK;
++}
++
+ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+ {
+     krb5_error_code kerr;
+@@ -1881,6 +2068,11 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+         return kerr;
+     }
+ 
++    kerr = k5c_ccache_setup(kr, offline);
++    if (kerr != EOK) {
++        return kerr;
++    }
++
+     if (offline || (fast_val == K5C_FAST_NEVER && kr->validate == false)) {
+         /* If krb5_child was started as setuid, but we don't need to
+          * perform either validation or FAST, just drop privileges to
+@@ -1974,7 +2166,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+ 
+     kerr = set_lifetime_options(kr->options);
+     if (kerr != 0) {
+-        DEBUG(SSSDBG_OP_FAILURE, ("set_lifetime_options failed.\n"));
++        DEBUG(SSSDBG_OP_FAILURE, "set_lifetime_options failed.\n");
+         return kerr;
+     }
+ 
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 71c7f9c9f662e16b94afda0c8c0ae24666f0ba15..93961172c7a3a5d8f2a4fb320370037f188b5909 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -144,6 +144,11 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
+         kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
+         buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
+                      sss_authtok_get_size(kr->pd->authtok);
++
++        buf->size += sizeof(uint32_t);
++        if (kr->old_ccname) {
++            buf->size += strlen(kr->old_ccname);
++        }
+     }
+ 
+     if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
+@@ -182,6 +187,14 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
+         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->ccname), &rp);
+         safealign_memcpy(&buf->data[rp], kr->ccname, strlen(kr->ccname), &rp);
+ 
++        if (kr->old_ccname) {
++            SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->old_ccname), &rp);
++            safealign_memcpy(&buf->data[rp], kr->old_ccname,
++                             strlen(kr->old_ccname), &rp);
++        } else {
++            SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
++        }
++
+         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp);
+         safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
+ 
+diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
+index 8826a28ed5ea064317c62682003dc0e9a6df01b6..a59863b4d8aa8bdcc241c87befd672a5e5c876a3 100644
+--- a/src/tests/krb5_child-test.c
++++ b/src/tests/krb5_child-test.c
+@@ -239,8 +239,7 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
+         kr->ccname = expand_ccname_template(kr, kr,
+                                         dp_opt_get_cstring(kr->krb5_ctx->opts,
+                                                            KRB5_CCNAME_TMPL),
+-                                            kr->krb5_ctx->illegal_path_re,
+-                                            true, true);
++                                            kr->krb5_ctx->illegal_path_re, true, true);
+         if (!kr->ccname) goto fail;
+ 
+         DEBUG(SSSDBG_FUNC_DATA, "ccname [%s] uid [%llu] gid [%llu]\n",
+diff --git a/src/util/util_errors.c b/src/util/util_errors.c
+index d5da64622eebe7f779816c7f2090da5b9a9b13f0..c1ed0fb634c447904b63335d1cd161b7e7914a08 100644
+--- a/src/util/util_errors.c
++++ b/src/util/util_errors.c
+@@ -31,6 +31,7 @@ struct err_string error_to_str[] = {
+     { "Invalid credential type" },  /* ERR_INVALID_CRED_TYPE */
+     { "No credentials available" }, /* ERR_NO_CREDS */
+     { "Credentials are expired" }, /* ERR_CREDS_EXPIRED */
++    { "Credentials are expired, old ccache was removed" }, /* ERR_CREDS_EXPIRED_CCACHE */
+     { "Failure setting user credentials"}, /* ERR_CREDS_INVALID */
+     { "No cached credentials available" }, /* ERR_NO_CACHED_CREDS */
+     { "Cached credentials are expired" }, /* ERR_CACHED_CREDS_EXPIRED */
+diff --git a/src/util/util_errors.h b/src/util/util_errors.h
+index 2bc576605e613d674d38b54aae1604c0b044635f..f71ede8d0fa000627a1bd994ec8bd94a632b35b2 100644
+--- a/src/util/util_errors.h
++++ b/src/util/util_errors.h
+@@ -56,6 +56,7 @@ enum sssd_errors {
+     ERR_CREDS_INVALID,
+     ERR_NO_CACHED_CREDS,
+     ERR_CACHED_CREDS_EXPIRED,
++    ERR_CREDS_EXPIRED_CCACHE,
+     ERR_AUTH_DENIED,
+     ERR_AUTH_FAILED,
+     ERR_CHPASS_DENIED,
+-- 
+1.9.3
+
diff --git a/SOURCES/0088-KRB5-Do-not-switch_creds-if-already-the-specified-us.patch b/SOURCES/0088-KRB5-Do-not-switch_creds-if-already-the-specified-us.patch
new file mode 100644
index 0000000..8f3e925
--- /dev/null
+++ b/SOURCES/0088-KRB5-Do-not-switch_creds-if-already-the-specified-us.patch
@@ -0,0 +1,124 @@
+From 458ab6652130ebea1f305b5d383e263a2fbbcedc Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 19 Oct 2014 12:28:13 +0200
+Subject: [PATCH 88/92] KRB5: Do not switch_creds() if already the specified
+ user
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The code didn't have to handle this case previously as sssd_be was always
+running as root and switching to the ccache as the user logging in.
+
+Also handle NULL creds on restore_creds() in case there was no switch.
+One less if-condition and fewer indentation levels.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/cwrap/test_become_user.c |  7 +++++++
+ src/util/become_user.c             | 29 +++++++++++++++++++++--------
+ 2 files changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/src/tests/cwrap/test_become_user.c b/src/tests/cwrap/test_become_user.c
+index 06d3ad425c4928e9e9bff661fbb8f7b4536b8896..7ecea5aac34bb73ca81d94ad481f05b338e65ed0 100644
+--- a/src/tests/cwrap/test_become_user.c
++++ b/src/tests/cwrap/test_become_user.c
+@@ -76,6 +76,7 @@ void test_switch_user(void **state)
+     struct passwd *sssd;
+     TALLOC_CTX *tmp_ctx;
+     struct sss_creds *saved_creds;
++    struct sss_creds *saved_creds2 = NULL;
+ 
+     check_leaks_push(global_talloc_context);
+     tmp_ctx = talloc_new(global_talloc_context);
+@@ -102,6 +103,12 @@ void test_switch_user(void **state)
+     assert_int_equal(saved_creds->uid, 0);
+     assert_int_equal(saved_creds->gid, 0);
+ 
++    /* Attempt to restore creds again */
++    ret = switch_creds(tmp_ctx, sssd->pw_uid, sssd->pw_gid,
++                       0, NULL, &saved_creds2);
++    assert_int_equal(ret, EOK);
++    assert_null(saved_creds2);
++
+     /* restore root */
+     ret = restore_creds(saved_creds);
+     assert_int_equal(ret, EOK);
+diff --git a/src/util/become_user.c b/src/util/become_user.c
+index b5f94f993cd2c23bd3340fc502d36a530aa729fa..7dd2c752b1d0f289e7d82feee6d93e5974823f95 100644
+--- a/src/util/become_user.c
++++ b/src/util/become_user.c
+@@ -90,9 +90,14 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+     struct sss_creds *ssc = NULL;
+     int size;
+     int ret;
++    uid_t myuid;
++    uid_t mygid;
+ 
+     DEBUG(SSSDBG_FUNC_DATA, "Switch user to [%d][%d].\n", uid, gid);
+ 
++    myuid = geteuid();
++    mygid = getegid();
++
+     if (saved_creds) {
+         /* save current user credentials */
+         size = getgroups(0, NULL);
+@@ -124,8 +129,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+         }
+ 
+         /* we care only about effective ids */
+-        ssc->uid = geteuid();
+-        ssc->gid = getegid();
++        ssc->uid = myuid;
++        ssc->gid = mygid;
+     }
+ 
+     /* if we are regaining root set euid first so that we have CAP_SETUID back,
+@@ -141,7 +146,12 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
+-    /* TODO: use prctl to get/set capabilities too ? */
++    /* TODO: use libcap-ng if we need to get/set capabilities too ? */
++
++    if (myuid == uid && mygid == gid) {
++        DEBUG(SSSDBG_FUNC_DATA, "Already user [%"SPRIuid"].\n", uid);
++        return EOK;
++    }
+ 
+     /* try to setgroups first should always work if CAP_SETUID is set,
+      * otherwise it will always fail, failure is not critical though as
+@@ -177,11 +187,9 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+ 
+ done:
+     if (ret) {
+-        if (ssc) {
+-            /* attempt to restore creds first */
+-            restore_creds(ssc);
+-            talloc_free(ssc);
+-        }
++        /* attempt to restore creds first */
++        restore_creds(ssc);
++        talloc_free(ssc);
+     } else if (saved_creds) {
+         *saved_creds = ssc;
+     }
+@@ -190,6 +198,11 @@ done:
+ 
+ errno_t restore_creds(struct sss_creds *saved_creds)
+ {
++    if (saved_creds == NULL) {
++        /* In case save_creds was saved with the UID already dropped */
++        return EOK;
++    }
++
+     return switch_creds(saved_creds,
+                         saved_creds->uid,
+                         saved_creds->gid,
+-- 
+1.9.3
+
diff --git a/SOURCES/0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch b/SOURCES/0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch
deleted file mode 100644
index a985a8c..0000000
--- a/SOURCES/0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 4d5cbad45245016747aa34f2271f2fe5214cf34a Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 17 Feb 2014 17:30:52 +0100
-Subject: [PATCH 88/88] MAN: Clarify the new krb5_use_fast IPA default
-
----
- src/man/sssd-ipa.5.xml  | 34 ++++++++++++++++++++++++++++++++++
- src/man/sssd-krb5.5.xml |  2 +-
- 2 files changed, 35 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
-index 28ac252abbeb508d62ca1a94f2440afc6b5b5c88..7ab59dc20cc43c7ed86c0e1a988a30813b9fe673 100644
---- a/src/man/sssd-ipa.5.xml
-+++ b/src/man/sssd-ipa.5.xml
-@@ -399,6 +399,40 @@
-                 </varlistentry>
- 
-                 <varlistentry>
-+                    <term>krb5_use_fast (string)</term>
-+                    <listitem>
-+                        <para>
-+                            Enables flexible authentication secure tunneling
-+                            (FAST) for Kerberos pre-authentication. The
-+                            following options are supported:
-+                        </para>
-+                        <para>
-+                            <emphasis>never</emphasis> use FAST.
-+                        </para>
-+                        <para>
-+                            <emphasis>try</emphasis> to use FAST. If the server
-+                            does not support FAST, continue the
-+                            authentication without it. This is
-+                            equivalent to not setting this option at all.
-+                        </para>
-+                        <para>
-+                            <emphasis>demand</emphasis> to use FAST. The
-+                            authentication fails if the server does not
-+                            require fast.
-+                        </para>
-+                        <para>
-+                            Default: try
-+                        </para>
-+                        <para>
-+                            NOTE: SSSD supports FAST only with
-+                            MIT Kerberos version 1.8 and later. If SSSD is used
-+                            with an older version of MIT Kerberos, using this
-+                            option is a configuration error.
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-+                <varlistentry>
-                     <term>ipa_hbac_refresh (integer)</term>
-                     <listitem>
-                         <para>
-diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml
-index 384d506616408c3f45f5b85621a8101ef4faa3e8..602c07e9c2e2b9c231c596d50be94b7d220c3257 100644
---- a/src/man/sssd-krb5.5.xml
-+++ b/src/man/sssd-krb5.5.xml
-@@ -502,7 +502,7 @@
-                         </para>
- 
-                         <para>
--                            Default: false (AD provide: true)
-+                            Default: false (AD provider: true)
-                         </para>
-                     </listitem>
-                 </varlistentry>
--- 
-1.8.5.3
-
diff --git a/SOURCES/0089-BUILD-Use-separate-chown-to-make-changing-ownership-.patch b/SOURCES/0089-BUILD-Use-separate-chown-to-make-changing-ownership-.patch
new file mode 100644
index 0000000..bdda2a6
--- /dev/null
+++ b/SOURCES/0089-BUILD-Use-separate-chown-to-make-changing-ownership-.patch
@@ -0,0 +1,88 @@
+From 29d7f951999d0c8aad33fd1d0cb25a9b50db693f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 5 Nov 2014 17:57:44 +0100
+Subject: [PATCH 89/92] BUILD: Use separate chown to make changing ownership to
+ the sssd user non-fatal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When the SSSD is built in the build system using a non-root user, the
+user doesn't exist in the build system and file ownership will be
+maintained by the downstream packaging instead.
+
+We need to make sure that setting the ownership to the sssd user is a
+separate step from creating the directories in this case in order to
+make failure to set the ownership non-fatal.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am | 35 ++++++++++++++++++-----------------
+ 1 file changed, 18 insertions(+), 17 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 5325d51e7240ae39a546e68b2a2aea202b3dfdfa..6ce3a42f3833fc9041efd908c2e3de4a85193d42 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -82,11 +82,6 @@ INSTALL = @INSTALL@
+ 
+ SSSD_USER = @SSSD_USER@
+ 
+-INSTALL_USER_DIR_FLAGS = -d
+-if SSSD_USER
+-INSTALL_USER_DIR_FLAGS += -o $(SSSD_USER) -g $(SSSD_USER)
+-endif
+-
+ AM_CFLAGS =
+ if WANT_AUX_INFO
+     AM_CFLAGS += -aux-info $@.X
+@@ -2798,6 +2793,18 @@ src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile
+ 	@$(MKDIR_P) src/sysv/systemd/
+ 	$(replace_script)
+ 
++SSSD_USER_DIRS = \
++    $(DESTDIR)$(dbpath) \
++    $(DESTDIR)$(mcpath) \
++    $(DESTDIR)$(pipepath) \
++    $(DESTDIR)$(pipepath)/private \
++    $(DESTDIR)$(pubconfpath) \
++    $(DESTDIR)$(pubconfpath)/krb5.include.d \
++    $(DESTDIR)$(gpocachepath) \
++    $(DESTDIR)$(sssdconfdir) \
++    $(DESTDIR)$(logpath) \
++    $(NULL)
++
+ installsssddirs::
+ 	$(MKDIR_P) \
+     $(DESTDIR)$(includedir) \
+@@ -2815,18 +2822,12 @@ installsssddirs::
+     $(DESTDIR)$(sssddatadir) \
+     $(DESTDIR)$(sudolibdir) \
+     $(DESTDIR)$(autofslibdir) \
+-    $(NULL); \
+-	$(INSTALL) $(INSTALL_USER_DIR_FLAGS) \
+-    $(DESTDIR)$(dbpath) \
+-    $(DESTDIR)$(mcpath) \
+-    $(DESTDIR)$(pipepath) \
+-    $(DESTDIR)$(pipepath)/private \
+-    $(DESTDIR)$(pubconfpath) \
+-    $(DESTDIR)$(pubconfpath)/krb5.include.d \
+-    $(DESTDIR)$(gpocachepath) \
+-    $(DESTDIR)$(sssdconfdir) \
+-    $(DESTDIR)$(logpath) \
+-    $(NULL)
++    $(SSSD_USER_DIRS) \
++    $(NULL);
++if SSSD_USER
++	-chown $(SSSD_USER):$(SSSD_USER) \
++	$(SSSD_USER_DIRS)
++endif
+ 
+ if HAVE_DOXYGEN
+ docs:
+-- 
+1.9.3
+
diff --git a/SOURCES/0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch b/SOURCES/0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch
deleted file mode 100644
index ac3ca2d..0000000
--- a/SOURCES/0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 4b1c7fee8fd597660e77436fd205802e353b2e97 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 19 Feb 2014 15:00:15 +0100
-Subject: [PATCH 89/90] IPA: Don't call tevent_req_post outside _send
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 6d4574a8dd1a9cafbb15631e7d01bdf6e67f821b)
----
- src/providers/ipa/ipa_subdomains_id.c | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index b61c6a5f4d7605f0cdfa182bbc933d35c4613a79..c15bdaa703835ab07a9b3b21d1304220a01eac10 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -580,7 +580,6 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
- fail:
-     state->dp_error = DP_ERR_FATAL;
-     tevent_req_error(req, ret);
--    tevent_req_post(req, state->ev);
-     return;
- }
- 
--- 
-1.8.5.3
-
diff --git a/SOURCES/0090-BUILD-Make-chown-of-files-to-sssd-user-non-fatal.patch b/SOURCES/0090-BUILD-Make-chown-of-files-to-sssd-user-non-fatal.patch
new file mode 100644
index 0000000..d6262bb
--- /dev/null
+++ b/SOURCES/0090-BUILD-Make-chown-of-files-to-sssd-user-non-fatal.patch
@@ -0,0 +1,44 @@
+From f716f3b0876edfd94be6f46f6390d7286fcf8443 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 11 Nov 2014 15:39:57 +0100
+Subject: [PATCH 90/92] BUILD: Make chown of files to sssd user non-fatal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In build environments, we can't assume the sssd user will be created
+prior to installing the package, so we can't chown the files.
+
+RPM will own the files instead in this case.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 6ce3a42f3833fc9041efd908c2e3de4a85193d42..d58fcb9501c44ccf0d5814e1f2070cd82fa8be61 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2884,12 +2884,12 @@ else
+ endif
+ 
+ if SSSD_USER
+-	chgrp $(SSSD_USER) $(sssdlibexecdir)/ldap_child
++	-chgrp $(SSSD_USER) $(sssdlibexecdir)/ldap_child
+ 	chmod 4750 $(sssdlibexecdir)/ldap_child
+-	chgrp $(SSSD_USER) $(sssdlibexecdir)/krb5_child
++	-chgrp $(SSSD_USER) $(sssdlibexecdir)/krb5_child
+ 	chmod 4750 $(sssdlibexecdir)/krb5_child
+ if BUILD_SEMANAGE
+-	chgrp $(SSSD_USER) $(sssdlibexecdir)/selinux_child
++	-chgrp $(SSSD_USER) $(sssdlibexecdir)/selinux_child
+ 	chmod 4750 $(sssdlibexecdir)/selinux_child
+ endif
+ endif
+-- 
+1.9.3
+
diff --git a/SOURCES/0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch b/SOURCES/0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch
deleted file mode 100644
index c09b52e..0000000
--- a/SOURCES/0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From da729f6765e11fec980fbb9ec1291e2a7ef533fe Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 19 Feb 2014 15:34:34 +0100
-Subject: [PATCH 90/90] IPA: Don't fail if apply_subdomain_homedir returns
- ENOENT
-
-Reviewed-by: Pavel Reichl <preichl@redhat.com>
-(cherry picked from commit 26786da26706aeedbda4caea0383c143ed4e59dc)
----
- src/providers/ipa/ipa_subdomains_id.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index c15bdaa703835ab07a9b3b21d1304220a01eac10..637dd61f9f272eb4ac4ecb8368d2210801bb0373 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -550,7 +550,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
-     ret = apply_subdomain_homedir(state, state->user_dom,
-                                   state->ar->filter_type,
-                                   state->ar->filter_value);
--    if (ret != EOK) {
-+    if (ret != EOK && ret != ENOENT) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("apply_subdomain_homedir failed: [%d]: [%s].\n",
-                ret, sss_strerror(ret)));
--- 
-1.8.5.3
-
diff --git a/SOURCES/0091-BUILD-Touch-files-in-DESTDIR.patch b/SOURCES/0091-BUILD-Touch-files-in-DESTDIR.patch
new file mode 100644
index 0000000..0fb4940
--- /dev/null
+++ b/SOURCES/0091-BUILD-Touch-files-in-DESTDIR.patch
@@ -0,0 +1,43 @@
+From 6686822567fba8dd25ed0bd2e235c30c60eeccf2 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 11 Nov 2014 15:59:22 +0100
+Subject: [PATCH 91/92] BUILD: Touch files in DESTDIR
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index d58fcb9501c44ccf0d5814e1f2070cd82fa8be61..156ef3c4eab1510126d2bfb47c06163885b8acfe 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2884,13 +2884,13 @@ else
+ endif
+ 
+ if SSSD_USER
+-	-chgrp $(SSSD_USER) $(sssdlibexecdir)/ldap_child
+-	chmod 4750 $(sssdlibexecdir)/ldap_child
+-	-chgrp $(SSSD_USER) $(sssdlibexecdir)/krb5_child
+-	chmod 4750 $(sssdlibexecdir)/krb5_child
++	-chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/ldap_child
++	chmod 4750 $(DESTDIR)$(sssdlibexecdir)/ldap_child
++	-chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/krb5_child
++	chmod 4750 $(DESTDIR)$(sssdlibexecdir)/krb5_child
+ if BUILD_SEMANAGE
+-	-chgrp $(SSSD_USER) $(sssdlibexecdir)/selinux_child
+-	chmod 4750 $(sssdlibexecdir)/selinux_child
++	-chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/selinux_child
++	chmod 4750 $(DESTDIR)$(sssdlibexecdir)/selinux_child
+ endif
+ endif
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0091-LDAP-Setup-periodic-task-only-once.patch b/SOURCES/0091-LDAP-Setup-periodic-task-only-once.patch
deleted file mode 100644
index 00b4633..0000000
--- a/SOURCES/0091-LDAP-Setup-periodic-task-only-once.patch
+++ /dev/null
@@ -1,132 +0,0 @@
-From f7a7a583c475eb22a6d762e74c67ffcfa7ba32d0 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 12 Feb 2014 14:33:49 +0100
-Subject: [PATCH 91/92] LDAP: Setup periodic task only once.
-
-If id provider is {ipa, ad} periodic task will be stared in sssm_{ipa,ad}_init
-If you enable enumeration and use different providers for id and sudo(autofs)
-then another periodic task will be scheduled.
-This can cause weird behaviour (e.g. missing members of group)
-
-Perodic tasks will be started only by id_provider.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2153
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 057cb583f02bf47678c393cb8f1f74861c2b960b)
----
- src/providers/ldap/ldap_init.c | 54 ++++++++++++++++++++++++++++++++----------
- 1 file changed, 41 insertions(+), 13 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
-index 15615b2891f2e3104c11e8610c081adcd1d1ee8e..cf4ab5598e2b6eb00c188edabb61e22605e7dc82 100644
---- a/src/providers/ldap/ldap_init.c
-+++ b/src/providers/ldap/ldap_init.c
-@@ -84,9 +84,9 @@ errno_t check_order_list_for_duplicates(char **list,
-     return EOK;
- }
- 
--int sssm_ldap_id_init(struct be_ctx *bectx,
--                      struct bet_ops **ops,
--                      void **pvt_data)
-+static int ldap_id_init_internal(struct be_ctx *bectx,
-+                                 struct bet_ops **ops,
-+                                 void **pvt_data)
- {
-     struct sdap_id_ctx *ctx = NULL;
-     const char *urls;
-@@ -160,11 +160,6 @@ int sssm_ldap_id_init(struct be_ctx *bectx,
-     ret = sdap_idmap_init(ctx, ctx, &ctx->opts->idmap_ctx);
-     if (ret != EOK) goto done;
- 
--    ret = ldap_id_setup_tasks(ctx);
--    if (ret != EOK) {
--        goto done;
--    }
--
-     ret = sdap_setup_child();
-     if (ret != EOK) {
-         DEBUG(1, ("setup_child failed [%d][%s].\n",
-@@ -202,6 +197,39 @@ done:
-     return ret;
- }
- 
-+int sssm_ldap_id_init(struct be_ctx *bectx,
-+                      struct bet_ops **ops,
-+                      void **pvt_data)
-+{
-+    int ret;
-+    struct sdap_id_ctx *ctx = NULL;
-+
-+    ret = ldap_id_init_internal(bectx, ops, (void **) &ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              ("ldap_id_init_internal failed [%d][%s].\n",
-+              ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    ret = ldap_id_setup_tasks(ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              ("sdap_id_setup_tasks failed [%d][%s].\n",
-+              ret, strerror(ret)));
-+        goto done;
-+    }
-+
-+    *pvt_data = ctx;
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(ctx);
-+    }
-+    return ret;
-+}
-+
- int sssm_ldap_auth_init(struct be_ctx *bectx,
-                         struct bet_ops **ops,
-                         void **pvt_data)
-@@ -211,7 +239,7 @@ int sssm_ldap_auth_init(struct be_ctx *bectx,
-     struct sdap_auth_ctx *ctx;
-     int ret;
- 
--    ret = sssm_ldap_id_init(bectx, ops, &data);
-+    ret = ldap_id_init_internal(bectx, ops, &data);
-     if (ret == EOK) {
-         id_ctx = talloc_get_type(data, struct sdap_id_ctx);
- 
-@@ -302,9 +330,9 @@ int sssm_ldap_access_init(struct be_ctx *bectx,
-         goto done;
-     }
- 
--    ret = sssm_ldap_id_init(bectx, ops, (void **)&access_ctx->id_ctx);
-+    ret = ldap_id_init_internal(bectx, ops, (void **)&access_ctx->id_ctx);
-     if (ret != EOK) {
--        DEBUG(1, ("sssm_ldap_id_init failed.\n"));
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("ldap_id_init_internal failed.\n"));
-         goto done;
-     }
- 
-@@ -417,7 +445,7 @@ int sssm_ldap_sudo_init(struct be_ctx *be_ctx,
-     void *data;
-     int ret;
- 
--    ret = sssm_ldap_id_init(be_ctx, ops, &data);
-+    ret = ldap_id_init_internal(be_ctx, ops, &data);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot init LDAP ID provider [%d]: %s\n",
-                                     ret, strerror(ret)));
-@@ -447,7 +475,7 @@ int sssm_ldap_autofs_init(struct be_ctx *be_ctx,
-     void *data;
-     int ret;
- 
--    ret = sssm_ldap_id_init(be_ctx, ops, &data);
-+    ret = ldap_id_init_internal(be_ctx, ops, &data);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot init LDAP ID provider [%d]: %s\n",
-                                     ret, strerror(ret)));
--- 
-1.8.5.3
-
diff --git a/SOURCES/0092-BE-Become-a-regular-user-after-initialization.patch b/SOURCES/0092-BE-Become-a-regular-user-after-initialization.patch
new file mode 100644
index 0000000..c6df42f
--- /dev/null
+++ b/SOURCES/0092-BE-Become-a-regular-user-after-initialization.patch
@@ -0,0 +1,44 @@
+From edd6a6f65c1f1472632c263bdbd0946ff7fa8849 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 27 Oct 2014 16:14:51 +0100
+Subject: [PATCH 92/92] BE: Become a regular user after initialization
+
+Some parts of initialization (Kerberos ticket renewal, checking the
+keytab for the right principal) still require the root privileges. Drop
+privileges after initializing the back ends.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2370
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/data_provider_be.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 2716e4a8b38f3ff9a5b48a861ecc31f18f9fcbce..267f5f1d89cdfd0d8c69f90bc44b0f06f7e007ff 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -2886,6 +2886,19 @@ int main(int argc, const char *argv[])
+         return 3;
+     }
+ 
++    ret = chown_debug_file(NULL, uid, gid);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot chown the debug files, debugging might not work!\n");
++    }
++
++    ret = become_user(uid, gid);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FUNC_DATA,
++              "Cannot become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid);
++        return ret;
++    }
++
+     DEBUG(SSSDBG_TRACE_FUNC, "Backend provider (%s) started!\n", be_domain);
+ 
+     /* loop on main */
+-- 
+1.9.3
+
diff --git a/SOURCES/0092-UTIL-Sanitize-whitespaces.patch b/SOURCES/0092-UTIL-Sanitize-whitespaces.patch
deleted file mode 100644
index 09cdfa0..0000000
--- a/SOURCES/0092-UTIL-Sanitize-whitespaces.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 1c4109bf7f16016cf0b53cd73e7b80e0d87be660 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 24 Feb 2014 11:37:52 +0100
-Subject: [PATCH 92/92] UTIL: Sanitize whitespaces.
-
-Original patches submitted by: mpesari(Thanks!!)
-
-It can cause problems if user will hit spaces before entering username.
-(e.g in gdm). Spaces are ignored by LDAP; it's better to escape them.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/1955
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2b8208b45feb2aab64d560d3e12e01e7b6d00d39)
----
- src/util/util.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/src/util/util.c b/src/util/util.c
-index fb3bed146e2c634375a1133ef512673dee16718a..1ec5c2a9474b0cd2d19a50b495e218d1da7da6c8 100644
---- a/src/util/util.c
-+++ b/src/util/util.c
-@@ -537,6 +537,16 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
- 
-     while (input[i]) {
-         switch(input[i]) {
-+        case '\t':
-+            output[j++] = '\\';
-+            output[j++] = '0';
-+            output[j++] = '9';
-+            break;
-+        case ' ':
-+            output[j++] = '\\';
-+            output[j++] = '2';
-+            output[j++] = '0';
-+            break;
-         case '*':
-             output[j++] = '\\';
-             output[j++] = '2';
--- 
-1.8.5.3
-
diff --git a/SOURCES/0093-IDMAP-add-sss_idmap_check_collision-_ex.patch b/SOURCES/0093-IDMAP-add-sss_idmap_check_collision-_ex.patch
deleted file mode 100644
index fe6caa9..0000000
--- a/SOURCES/0093-IDMAP-add-sss_idmap_check_collision-_ex.patch
+++ /dev/null
@@ -1,362 +0,0 @@
-From 4206e5dbe37277a4002010e85438fe376b5b1812 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 3 Feb 2014 13:30:35 +0100
-Subject: [PATCH 93/97] IDMAP: add sss_idmap_check_collision(_ex)
-
----
- src/lib/idmap/sss_idmap.c         | 129 ++++++++++++++++++++++++++------------
- src/lib/idmap/sss_idmap.h         |  65 +++++++++++++++++++
- src/tests/cmocka/test_sss_idmap.c |  93 +++++++++++++++++++++++++++
- 3 files changed, 247 insertions(+), 40 deletions(-)
-
-diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
-index 3f1e7a58f390a3c10999251e2155ef513ba69bd7..4c453120539a549807e9b6bb4db2dc396c1b3152 100644
---- a/src/lib/idmap/sss_idmap.c
-+++ b/src/lib/idmap/sss_idmap.c
-@@ -380,55 +380,104 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
-     return IDMAP_SUCCESS;
- }
- 
-+enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name,
-+                                                const char *o_sid,
-+                                                struct sss_idmap_range *o_range,
-+                                                uint32_t o_first_rid,
-+                                                const char *o_range_id,
-+                                                bool o_external_mapping,
-+                                                const char *n_name,
-+                                                const char *n_sid,
-+                                                struct sss_idmap_range *n_range,
-+                                                uint32_t n_first_rid,
-+                                                const char *n_range_id,
-+                                                bool n_external_mapping)
-+{
-+    bool names_equal;
-+    bool sids_equal;
-+
-+    /* TODO: if both ranges have the same ID check if an update is
-+     * needed. */
-+
-+    /* Check if ID ranges overlap.
-+     * ID ranges with external mapping may overlap. */
-+    if ((!n_external_mapping && !o_external_mapping)
-+        && ((n_range->min >= o_range->min
-+                && n_range->min <= o_range->max)
-+            || (n_range->max >= o_range->min
-+                && n_range->max <= o_range->max))) {
-+        return IDMAP_COLLISION;
-+    }
-+
-+    names_equal = (strcasecmp(n_name, o_name) == 0);
-+    sids_equal = ((n_sid == NULL && o_sid == NULL)
-+                    || (n_sid != NULL && o_sid != NULL
-+                        && strcasecmp(n_sid, o_sid) == 0));
-+
-+    /* check if domain name and SID are consistent */
-+    if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) {
-+        return IDMAP_COLLISION;
-+    }
-+
-+    /* check if external_mapping is consistent */
-+    if (names_equal && sids_equal
-+            && n_external_mapping != o_external_mapping) {
-+        return IDMAP_COLLISION;
-+    }
-+
-+    /* check if RID ranges overlap */
-+    if (names_equal && sids_equal
-+            && n_external_mapping == false
-+            && n_first_rid >= o_first_rid
-+            && n_first_rid <= o_first_rid + (o_range->max - o_range->min)) {
-+        return IDMAP_COLLISION;
-+    }
-+
-+    return IDMAP_SUCCESS;
-+}
-+
-+enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
-+                                                char *n_name, char *n_sid,
-+                                                struct sss_idmap_range *n_range,
-+                                                uint32_t n_first_rid,
-+                                                char *n_range_id,
-+                                                bool n_external_mapping)
-+{
-+    struct idmap_domain_info *dom;
-+    enum idmap_error_code err;
-+
-+    for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
-+        err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
-+                                           dom->first_rid, dom->range_id,
-+                                           dom->external_mapping,
-+                                           n_name, n_sid, n_range, n_first_rid,
-+                                           n_range_id, n_external_mapping);
-+        if (err != IDMAP_SUCCESS) {
-+            return err;
-+        }
-+    }
-+    return IDMAP_SUCCESS;
-+}
-+
- static enum idmap_error_code dom_check_collision(
-                                              struct idmap_domain_info *dom_list,
-                                              struct idmap_domain_info *new_dom)
- {
-     struct idmap_domain_info *dom;
--    bool names_equal;
--    bool sids_equal;
-+    enum idmap_error_code err;
- 
-     for (dom = dom_list; dom != NULL; dom = dom->next) {
--
--        /* TODO: if both ranges have the same ID check if an update is
--         * needed. */
--
--        /* Check if ID ranges overlap.
--         * ID ranges with external mapping may overlap. */
--        if ((!new_dom->external_mapping && !dom->external_mapping)
--            && ((new_dom->range->min >= dom->range->min
--                    && new_dom->range->min <= dom->range->max)
--                || (new_dom->range->max >= dom->range->min
--                    && new_dom->range->max <= dom->range->max))) {
--            return IDMAP_COLLISION;
--        }
--
--        names_equal = (strcasecmp(new_dom->name, dom->name) == 0);
--        sids_equal = ((new_dom->sid == NULL && dom->sid == NULL)
--                        || (new_dom->sid != NULL && dom->sid != NULL
--                            && strcasecmp(new_dom->sid, dom->sid) == 0));
--
--        /* check if domain name and SID are consistent */
--        if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) {
--            return IDMAP_COLLISION;
--        }
--
--        /* check if external_mapping is consistent */
--        if (names_equal && sids_equal
--                && new_dom->external_mapping != dom->external_mapping) {
--            return IDMAP_COLLISION;
--        }
--
--        /* check if RID ranges overlap */
--        if (names_equal && sids_equal
--                && new_dom->external_mapping == false
--                && new_dom->first_rid >= dom->first_rid
--                && new_dom->first_rid <=
--                    dom->first_rid + (dom->range->max - dom->range->min)) {
--            return IDMAP_COLLISION;
-+        err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
-+                                           dom->first_rid, dom->range_id,
-+                                           dom->external_mapping,
-+                                           new_dom->name, new_dom->sid,
-+                                           new_dom->range, new_dom->first_rid,
-+                                           new_dom->range_id,
-+                                           new_dom->external_mapping);
-+        if (err != IDMAP_SUCCESS) {
-+            return err;
-         }
-     }
--
-     return IDMAP_SUCCESS;
- }
- 
-diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
-index 1e1c9a5cfe490301d0e633db808589f1bc0ef857..ccc63f7f760b877cdb17696325731f8e540b2736 100644
---- a/src/lib/idmap/sss_idmap.h
-+++ b/src/lib/idmap/sss_idmap.h
-@@ -289,6 +289,71 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
-                                               const char *range_id,
-                                               uint32_t rid,
-                                               bool external_mapping);
-+
-+/**
-+ * @brief Check if a new range would collide with any existing one
-+ *
-+ * @param[in] ctx         Idmap context
-+ * @param[in] n_name      Zero-terminated string with the domain name the new
-+ *                        range should belong to
-+ * @param[in] n_sid       Zero-terminated string representation of the domain
-+ *                        SID (S-1-15-.....) the new range sould belong to
-+ * @param[in] n_range     The new id range
-+ * @param[in] n_range_id  unique identifier of the new range, it is needed
-+ *                        to allow updates at runtime, may be NULL
-+ * @param[in] n_first_rid The RID that should be mapped to the first ID of the
-+ *                        new range.
-+ * @param[in] n_external_mapping Mapping type of the new range
-+ *
-+ * @return
-+ *  - #IDMAP_COLLISION:     New range collides with existing one
-+ */
-+enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
-+                                                char *n_name, char *n_sid,
-+                                                struct sss_idmap_range *n_range,
-+                                                uint32_t n_first_rid,
-+                                                char *n_range_id,
-+                                                bool n_external_mapping);
-+
-+/**
-+ * @brief Check if two ranges would collide
-+ *
-+ * @param[in] o_name      Zero-terminated string with the domain name the
-+ *                        first range should belong to
-+ * @param[in] o_sid       Zero-terminated string representation of the domain
-+ *                        SID (S-1-15-.....) the first range sould belong to
-+ * @param[in] o_range     The first id range
-+ * @param[in] o_range_id  unique identifier of the first range, it is needed
-+ *                        to allow updates at runtime, may be NULL
-+ * @param[in] o_first_rid The RID that should be mapped to the first ID of the
-+ *                        first range.
-+ * @param[in] o_external_mapping Mapping type of the first range
-+ * @param[in] n_name      Zero-terminated string with the domain name the
-+ *                        second range should belong to
-+ * @param[in] n_sid       Zero-terminated string representation of the domain
-+ *                        SID (S-1-15-.....) the second range sould belong to
-+ * @param[in] n_range     The second id range
-+ * @param[in] n_range_id  unique identifier of the second range, it is needed
-+ *                        to allow updates at runtime, may be NULL
-+ * @param[in] n_first_rid The RID that should be mapped to the first ID of the
-+ *                        second range.
-+ * @param[in] n_external_mapping Mapping type of the second range
-+ *
-+ * @return
-+ *  - #IDMAP_COLLISION:     New range collides with existing one
-+ */
-+enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name,
-+                                                const char *o_sid,
-+                                                struct sss_idmap_range *o_range,
-+                                                uint32_t o_first_rid,
-+                                                const char *o_range_id,
-+                                                bool o_external_mapping,
-+                                                const char *n_name,
-+                                                const char *n_sid,
-+                                                struct sss_idmap_range *n_range,
-+                                                uint32_t n_first_rid,
-+                                                const char *n_range_id,
-+                                                bool n_external_mapping);
- /**
-  * @brief Translate SID to a unix UID or GID
-  *
-diff --git a/src/tests/cmocka/test_sss_idmap.c b/src/tests/cmocka/test_sss_idmap.c
-index 019b4618ef0e14e87cb86d64989e8f5ca9dfdfd8..ff933216416b61618bf764d8c2554b273706c787 100644
---- a/src/tests/cmocka/test_sss_idmap.c
-+++ b/src/tests/cmocka/test_sss_idmap.c
-@@ -30,11 +30,15 @@
- #define TEST_RANGE_MAX 399999
- #define TEST_DOM_NAME "test.dom"
- #define TEST_DOM_SID "S-1-5-21-123-456-789"
-+#define TEST_FIRST_RID 0
-+#define TEST_EXT_MAPPING true
- 
- #define TEST_2_RANGE_MIN 600000
- #define TEST_2_RANGE_MAX 799999
- #define TEST_2_DOM_NAME "test2.dom"
- #define TEST_2_DOM_SID "S-1-5-21-987-654-321"
-+#define TEST_2_FIRST_RID 1000000
-+#define TEST_2_EXT_MAPPING true
- 
- #define TEST_OFFSET 1000000
- #define TEST_OFFSET_STR "1000000"
-@@ -408,6 +412,94 @@ void test_has_algorithmic_by_name(void **state)
-     assert_false(use_id_mapping);
- }
- 
-+void test_sss_idmap_check_collision_ex(void **state)
-+{
-+    enum idmap_error_code err;
-+    struct sss_idmap_range r1 = {TEST_RANGE_MIN, TEST_RANGE_MAX};
-+    struct sss_idmap_range r2 = {TEST_2_RANGE_MIN, TEST_2_RANGE_MAX};
-+
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       TEST_EXT_MAPPING,
-+                                       TEST_2_DOM_NAME, TEST_2_DOM_SID, &r2,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       TEST_2_EXT_MAPPING);
-+    assert_int_equal(err, IDMAP_SUCCESS);
-+
-+    /* Same name, different SID */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       TEST_EXT_MAPPING,
-+                                       TEST_DOM_NAME, TEST_2_DOM_SID, &r2,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       TEST_2_EXT_MAPPING);
-+    assert_int_equal(err, IDMAP_COLLISION);
-+
-+    /* Same SID, different name */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       TEST_EXT_MAPPING,
-+                                       TEST_2_DOM_NAME, TEST_DOM_SID, &r2,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       TEST_2_EXT_MAPPING);
-+    assert_int_equal(err, IDMAP_COLLISION);
-+
-+    /* Same SID and name, no overlaps */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       TEST_EXT_MAPPING,
-+                                       TEST_DOM_NAME, TEST_DOM_SID, &r2,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       TEST_2_EXT_MAPPING);
-+    assert_int_equal(err, IDMAP_SUCCESS);
-+
-+    /* Same SID and name, different mappings */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       TEST_EXT_MAPPING,
-+                                       TEST_DOM_NAME, TEST_DOM_SID, &r2,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       !TEST_EXT_MAPPING);
-+    assert_int_equal(err, IDMAP_COLLISION);
-+
-+    /* Same SID and name, Overlapping RID range */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       false,
-+                                       TEST_DOM_NAME, TEST_DOM_SID, &r2,
-+                                       TEST_FIRST_RID, NULL,
-+                                       false);
-+    assert_int_equal(err, IDMAP_COLLISION);
-+
-+    /* Different SID and name, Overlapping RID range */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       false,
-+                                       TEST_2_DOM_NAME, TEST_2_DOM_SID, &r2,
-+                                       TEST_FIRST_RID, NULL,
-+                                       false);
-+    assert_int_equal(err, IDMAP_SUCCESS);
-+
-+
-+    /* Overlapping ranges with no external mapping */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       false,
-+                                       TEST_2_DOM_NAME, TEST_2_DOM_SID, &r1,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       false);
-+    assert_int_equal(err, IDMAP_COLLISION);
-+
-+    /* Overlapping ranges with external mapping */
-+    err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1,
-+                                       TEST_FIRST_RID, NULL,
-+                                       true,
-+                                       TEST_2_DOM_NAME, TEST_2_DOM_SID, &r1,
-+                                       TEST_2_FIRST_RID, NULL,
-+                                       true);
-+    assert_int_equal(err, IDMAP_SUCCESS);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -439,6 +531,7 @@ int main(int argc, const char *argv[])
-         unit_test_setup_teardown(test_has_algorithmic_by_name,
-                                  test_sss_idmap_setup_with_both,
-                                  test_sss_idmap_teardown),
-+        unit_test(test_sss_idmap_check_collision_ex),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-1.8.5.3
-
diff --git a/SOURCES/0093-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-speci.patch b/SOURCES/0093-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-speci.patch
new file mode 100644
index 0000000..f24afe3
--- /dev/null
+++ b/SOURCES/0093-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-speci.patch
@@ -0,0 +1,26 @@
+From 8d38a4b28ab7af15406b244910f369ba1aff02db Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 30 Oct 2014 15:59:17 +0100
+Subject: [PATCH 93/93] NOUPSTREAM: Default to root if sssd user is not
+ specified
+
+---
+ src/monitor/monitor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 0dea327213a1ad04b6f69c0ffb0fb87254420796..20b4aef4ee94fd42de1585d7d7c2e01ea01845ac 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -925,7 +925,7 @@ static int get_service_user(struct mt_ctx *ctx)
+ 
+     ret = confdb_get_string(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
+                             CONFDB_MONITOR_USER_RUNAS,
+-                            SSSD_USER, &user_str);
++                            "root", &user_str);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get the user to run as\n");
+         return ret;
+-- 
+1.9.3
+
diff --git a/SOURCES/0094-IPA-refactor-idmap-code-and-add-test.patch b/SOURCES/0094-IPA-refactor-idmap-code-and-add-test.patch
deleted file mode 100644
index c648a76..0000000
--- a/SOURCES/0094-IPA-refactor-idmap-code-and-add-test.patch
+++ /dev/null
@@ -1,630 +0,0 @@
-From 5ec1d31f32583761c05691c951576b6213037393 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Feb 2014 15:54:30 +0100
-Subject: [PATCH 94/97] IPA: refactor idmap code and add test
-
----
- Makefile.am                       |  15 +++
- src/providers/ipa/ipa_common.h    |  10 ++
- src/providers/ipa/ipa_idmap.c     | 248 +++++++++++++++----------------------
- src/tests/cmocka/test_ipa_idmap.c | 249 ++++++++++++++++++++++++++++++++++++++
- 4 files changed, 374 insertions(+), 148 deletions(-)
- create mode 100644 src/tests/cmocka/test_ipa_idmap.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 16648f9aa2275b60ec84a95ff8a26b1225b97918..2e1a1e6bacfb79e4ef7068a22a64c21d23858cb9 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -150,6 +150,7 @@ if HAVE_CMOCKA
-         dyndns-tests \
-         fqnames-tests \
-         test_sss_idmap \
-+        test_ipa_idmap \
-         test_utils \
-         ad_access_filter_tests \
-         ad_common_tests \
-@@ -1359,6 +1360,20 @@ test_sss_idmap_LDADD = \
-     $(SSSD_INTERNAL_LTLIBS) \
-     libsss_test_common.la
- 
-+test_ipa_idmap_SOURCES = \
-+    src/tests/cmocka/test_ipa_idmap.c \
-+    src/providers/ipa/ipa_idmap.c
-+test_ipa_idmap_CFLAGS = \
-+    $(AM_CFLAGS)
-+test_ipa_idmap_LDFLAGS = \
-+    -Wl,-wrap,sysdb_get_ranges
-+test_ipa_idmap_LDADD = \
-+    $(CMOCKA_LIBS) \
-+    $(POPT_LIBS) \
-+    libsss_idmap.la \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    libsss_test_common.la
-+
- test_utils_SOURCES = \
-     src/tests/cmocka/test_utils.c
- test_utils_CFLAGS = \
-diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
-index 02f0baf55f0d226eeb8956076b9bbcce285d4a94..0b8a17c532b7b0081dc749dcef1e6c0e684a7ed2 100644
---- a/src/providers/ipa/ipa_common.h
-+++ b/src/providers/ipa/ipa_common.h
-@@ -195,6 +195,16 @@ int ipa_sudo_init(struct be_ctx *be_ctx,
-                   struct bet_ops **ops,
-                   void **pvt_data);
- 
-+errno_t get_idmap_data_from_range(struct range_info *r, char *domain_name,
-+                                  char **_name, char **_sid, uint32_t *_rid,
-+                                  struct sss_idmap_range *_range,
-+                                  bool *_external_mapping);
-+
-+errno_t ipa_idmap_get_ranges_from_sysdb(struct sdap_idmap_ctx *idmap_ctx,
-+                                        const char *dom_name,
-+                                        const char *dom_sid_str,
-+                                        bool allow_collisions);
-+
- errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx,
-                        struct sdap_id_ctx *id_ctx,
-                        struct sdap_idmap_ctx **_idmap_ctx);
-diff --git a/src/providers/ipa/ipa_idmap.c b/src/providers/ipa/ipa_idmap.c
-index eaca0ed3c3ce2622fbf80dff13d22e2e521f54fe..a65086af4cb4bec7ab85774f3ca1a3555056cee0 100644
---- a/src/providers/ipa/ipa_idmap.c
-+++ b/src/providers/ipa/ipa_idmap.c
-@@ -156,9 +156,68 @@ done:
-     return ret;
- }
- 
--errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx,
--                                  const char *dom_name,
--                                  const char *dom_sid_str)
-+errno_t get_idmap_data_from_range(struct range_info *r, char *domain_name,
-+                                  char **_name, char **_sid, uint32_t *_rid,
-+                                  struct sss_idmap_range *_range,
-+                                  bool *_external_mapping)
-+{
-+    if (r->range_type == NULL) {
-+        /* Older IPA servers might not have the range_type attribute, but
-+         * only support local ranges and trusts with algorithmic mapping. */
-+
-+        if (r->trusted_dom_sid == NULL && r->secondary_base_rid != 0) {
-+            /* local IPA domain */
-+            *_rid = 0;
-+            *_external_mapping = true;
-+            *_name = domain_name;
-+            *_sid = NULL;
-+        } else if (r->trusted_dom_sid != NULL
-+                && r->secondary_base_rid == 0) {
-+            /* trusted domain */
-+            *_rid = r->base_rid;
-+            *_external_mapping = false;
-+            *_name = r->trusted_dom_sid;
-+            *_sid = r->trusted_dom_sid;
-+        } else {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot determine range type, " \
-+                                         "for id range [%s].\n",
-+                                         r->name));
-+            return EINVAL;
-+        }
-+    } else {
-+        if (strcmp(r->range_type, IPA_RANGE_LOCAL) == 0) {
-+            *_rid = 0;
-+            *_external_mapping = true;
-+            *_name = domain_name;
-+            *_sid = NULL;
-+        } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST_POSIX) == 0) {
-+            *_rid = 0;
-+            *_external_mapping = true;
-+            *_name = r->trusted_dom_sid;
-+            *_sid = r->trusted_dom_sid;
-+        } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST) == 0) {
-+            *_rid = r->base_rid;
-+            *_external_mapping = false;
-+            *_name = r->trusted_dom_sid;
-+            *_sid = r->trusted_dom_sid;
-+        } else {
-+            DEBUG(SSSDBG_MINOR_FAILURE, ("Range type [%s] of id range " \
-+                                         "[%s] not supported.\n", \
-+                                         r->range_type, r->name));
-+            return EINVAL;
-+        }
-+    }
-+
-+    _range->min = r->base_id;
-+    _range->max = r->base_id + r->id_range_size -1;
-+
-+    return EOK;
-+}
-+
-+errno_t ipa_idmap_get_ranges_from_sysdb(struct sdap_idmap_ctx *idmap_ctx,
-+                                        const char *dom_name,
-+                                        const char *dom_sid_str,
-+                                        bool allow_collisions)
- {
-     int ret;
-     size_t range_count;
-@@ -166,7 +225,6 @@ errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx,
-     TALLOC_CTX *tmp_ctx;
-     size_t c;
-     enum idmap_error_code err;
--    struct range_info *r;
-     struct sss_idmap_range range;
-     uint32_t rid;
-     bool external_mapping;
-@@ -187,74 +245,39 @@ errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx,
-     }
- 
-     for (c = 0; c < range_count; c++) {
--        r = range_list[c];
--
--        if (r->range_type == NULL) {
--            /* Older IPA servers might not have the range_type attribute, but
--             * only support local ranges and trusts with algorithmic mapping. */
--
--            if (r->trusted_dom_sid == NULL && r->secondary_base_rid != 0) {
--                /* local IPA domain */
--                rid = 0;
--                external_mapping = true;
--                name = idmap_ctx->id_ctx->be->domain->name;
--                sid = NULL;
--            } else if (r->trusted_dom_sid != NULL
--                    && r->secondary_base_rid == 0) {
--                /* trusted domain */
--                rid = r->base_rid;
--                external_mapping = false;
--                name = r->trusted_dom_sid;
--                sid = r->trusted_dom_sid;
--            } else {
--                DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot determine range type, " \
--                                             "skipping id ange [%s].\n",
--                                             r->name));
--                continue;
--            }
--        } else {
--            if (strcmp(r->range_type, IPA_RANGE_LOCAL) == 0) {
--                rid = 0;
--                external_mapping = true;
--                name = idmap_ctx->id_ctx->be->domain->name;
--                sid = NULL;
--            } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST_POSIX) == 0) {
--                rid = 0;
--                external_mapping = true;
--                name = r->trusted_dom_sid;
--                sid = r->trusted_dom_sid;
--            } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST) == 0) {
--                rid = r->base_rid;
--                external_mapping = false;
--                name = r->trusted_dom_sid;
--                sid = r->trusted_dom_sid;
--            } else {
--                DEBUG(SSSDBG_MINOR_FAILURE, ("Range type [%s] not supported, " \
--                                             "skipping id range [%s].\n",
--                                             r->range_type, r->name));
--                continue;
--            }
-+        ret = get_idmap_data_from_range(range_list[c],
-+                                        idmap_ctx->id_ctx->be->domain->name,
-+                                        &name, &sid, &rid, &range,
-+                                        &external_mapping);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("get_idmap_data_from_range failed for " \
-+                                      "id range [%s], skipping.\n",
-+                                      range_list[c]->name));
-+            continue;
-         }
- 
--        range.min = r->base_id;
--        range.max = r->base_id + r->id_range_size -1;
-         err = sss_idmap_add_domain_ex(idmap_ctx->map, name, sid, &range,
--                                      r->name, rid, external_mapping);
--        if (err != IDMAP_SUCCESS && err != IDMAP_COLLISION) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not add range [%s] to ID map\n",
--                                        r->name));
--            ret = EIO;
-+                                      range_list[c]->name, rid,
-+                                      external_mapping);
-+        if (err != IDMAP_SUCCESS) {
-+            if (!allow_collisions || err != IDMAP_COLLISION) {
-+                DEBUG(SSSDBG_CRIT_FAILURE, ("Could not add range [%s] to ID map\n",
-+                                            range_list[c]->name));
-+                ret = EIO;
-+                goto done;
-+            }
-+        }
-+    }
-+
-+    if (dom_name != NULL || dom_sid_str != NULL) {
-+        ret = ipa_idmap_check_posix_child(idmap_ctx, dom_name, dom_sid_str,
-+                                          range_count, range_list);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("ipa_idmap_check_posix_child failed.\n"));
-             goto done;
-         }
-     }
- 
--    ret = ipa_idmap_check_posix_child(idmap_ctx, dom_name, dom_sid_str,
--                                      range_count, range_list);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, ("ipa_idmap_check_posix_child failed.\n"));
--        goto done;
--    }
--
-     ret = EOK;
- 
- done:
-@@ -263,6 +286,14 @@ done:
-     return ret;
- }
- 
-+errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx,
-+                                  const char *dom_name,
-+                                  const char *dom_sid_str)
-+{
-+    return ipa_idmap_get_ranges_from_sysdb(idmap_ctx, dom_name, dom_sid_str,
-+                                           true);
-+}
-+
- errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx,
-                        struct sdap_id_ctx *id_ctx,
-                        struct sdap_idmap_ctx **_idmap_ctx)
-@@ -270,17 +301,7 @@ errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx,
-     errno_t ret;
-     TALLOC_CTX *tmp_ctx;
-     enum idmap_error_code err;
--    size_t c;
-     struct sdap_idmap_ctx *idmap_ctx = NULL;
--    struct sysdb_ctx *sysdb = id_ctx->be->domain->sysdb;
--    size_t range_count;
--    struct range_info **range_list;
--    struct range_info *r;
--    struct sss_idmap_range range;
--    uint32_t rid;
--    bool external_mapping;
--    char *name;
--    char *sid;
- 
-     tmp_ctx = talloc_new(NULL);
-     if (!tmp_ctx) return ENOMEM;
-@@ -309,82 +330,13 @@ errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--
--    /* Read in any existing mappings from the cache */
--    ret = sysdb_get_ranges(tmp_ctx, sysdb, &range_count, &range_list);
--    if (ret != EOK && ret != ENOENT) {
--        DEBUG(SSSDBG_FATAL_FAILURE,
--              ("Could not read ranges from the cache: [%s]\n",
--               strerror(ret)));
-+    ret = ipa_idmap_get_ranges_from_sysdb(idmap_ctx, NULL, NULL, false);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("ipa_idmap_get_ranges_from_sysdb failed.\n"));
-         goto done;
-     }
- 
--    DEBUG(SSSDBG_CONF_SETTINGS,
--          ("Initializing [%zu] domains for ID-mapping\n", range_count));
--
--    for (c = 0; c < range_count; c++) {
--
--        r = range_list[c];
--
--        if (r->range_type == NULL) {
--            /* Older IPA servers might not have the range_type attribute, but
--             * only support local ranges and trusts with algorithmic mapping. */
--
--            if (r->trusted_dom_sid == NULL && r->secondary_base_rid != 0) {
--                /* local IPA domain */
--                rid = 0;
--                external_mapping = true;
--                sid = NULL;
--                name = id_ctx->be->domain->name;
--            } else if (r->trusted_dom_sid != NULL
--                    && r->secondary_base_rid == 0) {
--                /* trusted domain */
--                rid = r->base_rid;
--                external_mapping = false;
--                sid = r->trusted_dom_sid;
--                name = sid;
--            } else {
--                DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot determine range type, " \
--                                             "skipping id ange [%s].\n",
--                                             r->name));
--                continue;
--            }
--        } else {
--            if (strcmp(r->range_type, IPA_RANGE_LOCAL) == 0) {
--                rid = 0;
--                external_mapping = true;
--                sid = NULL;
--                name = id_ctx->be->domain->name;
--            } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST_POSIX) == 0) {
--                rid = 0;
--                external_mapping = true;
--                sid = r->trusted_dom_sid;
--                name = sid;
--            } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST) == 0) {
--                rid = r->base_rid;
--                external_mapping = false;
--                sid = r->trusted_dom_sid;
--                name = sid;
--            } else {
--                DEBUG(SSSDBG_MINOR_FAILURE, ("Range type [%s] not supported, " \
--                                             "skipping id range [%s].\n",
--                                             r->range_type, r->name));
--                continue;
--            }
--        }
--
--        range.min = r->base_id;
--        range.max = r->base_id + r->id_range_size -1;
--        err = sss_idmap_add_domain_ex(idmap_ctx->map, name, sid, &range,
--                                      r->name, rid, external_mapping);
--        if (err != IDMAP_SUCCESS) {
--            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not add range [%s] to ID map\n",
--                                        r->name));
--            ret = EIO;
--            goto done;
--        }
--    }
--
-     *_idmap_ctx = talloc_steal(mem_ctx, idmap_ctx);
-     ret = EOK;
- 
-diff --git a/src/tests/cmocka/test_ipa_idmap.c b/src/tests/cmocka/test_ipa_idmap.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..2fb2cde2f9a7f1172fb69b268d19b559ff9d2f32
---- /dev/null
-+++ b/src/tests/cmocka/test_ipa_idmap.c
-@@ -0,0 +1,249 @@
-+/*
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2014 Red Hat
-+
-+    SSSD tests: Unit tests for id-mapping in the IPA provider
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include <popt.h>
-+
-+#include "tests/cmocka/common_mock.h"
-+#include "lib/idmap/sss_idmap.h"
-+#include "providers/ipa/ipa_common.h"
-+#include "providers/ldap/sdap_idmap.h"
-+
-+#define RANGE_NAME discard_const("range1")
-+#define DOMAIN_SID discard_const("S-1-5-21-2-3-4")
-+#define DOMAIN_NAME discard_const("dom.test")
-+#define BASE_RID 111
-+#define SECONDARY_BASE_RID 11223344
-+#define BASE_ID 123456
-+#define RANGE_SIZE 222222
-+#define RANGE_MAX (BASE_ID + RANGE_SIZE - 1)
-+
-+void test_get_idmap_data_from_range(void **state)
-+{
-+    char *dom_name;
-+    char *sid;
-+    uint32_t rid;
-+    struct sss_idmap_range range;
-+    bool external_mapping;
-+    size_t c;
-+    errno_t ret;
-+
-+    struct test_data {
-+        struct range_info r;
-+        errno_t exp_ret;
-+        char *exp_dom_name;
-+        char *exp_sid;
-+        uint32_t exp_rid;
-+        struct sss_idmap_range exp_range;
-+        bool exp_external_mapping;
-+    } d[] = {
-+        /* working IPA_RANGE_LOCAL range */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, SECONDARY_BASE_RID,
-+          NULL, discard_const(IPA_RANGE_LOCAL)},
-+         EOK, DOMAIN_NAME, NULL, 0, {BASE_ID, RANGE_MAX}, true},
-+        /* working old-style IPA_RANGE_LOCAL range without range type */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, SECONDARY_BASE_RID,
-+          NULL, NULL},
-+         EOK, DOMAIN_NAME, NULL, 0, {BASE_ID, RANGE_MAX}, true},
-+        /* old-style IPA_RANGE_LOCAL without SID and secondary base rid */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, NULL, NULL},
-+         EINVAL, NULL, NULL, 0, {0, 0}, false},
-+        /* old-style range with SID and secondary base rid */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, SECONDARY_BASE_RID,
-+          DOMAIN_SID, NULL},
-+         EINVAL, NULL, NULL, 0, {0, 0}, false},
-+        /* working IPA_RANGE_AD_TRUST range */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, DOMAIN_SID,
-+          discard_const(IPA_RANGE_AD_TRUST)},
-+         EOK, DOMAIN_SID, DOMAIN_SID, BASE_RID, {BASE_ID, RANGE_MAX}, false},
-+        /* working old-style IPA_RANGE_AD_TRUST range without range type */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, DOMAIN_SID, NULL},
-+         EOK, DOMAIN_SID, DOMAIN_SID, BASE_RID, {BASE_ID, RANGE_MAX}, false},
-+        /* working IPA_RANGE_AD_TRUST_POSIX range */
-+        {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, DOMAIN_SID,
-+          discard_const(IPA_RANGE_AD_TRUST_POSIX)},
-+         EOK, DOMAIN_SID, DOMAIN_SID, 0, {BASE_ID, RANGE_MAX}, true},
-+        {{0}, 0, NULL, NULL, 0, {0, 0}, false}
-+    };
-+
-+    for (c = 0; d[c].exp_dom_name != NULL; c++) {
-+        ret = get_idmap_data_from_range(&d[c].r, DOMAIN_NAME, &dom_name, &sid,
-+                                        &rid, &range, &external_mapping);
-+        assert_int_equal(ret, d[c].exp_ret);
-+        assert_string_equal(dom_name, d[c].exp_dom_name);
-+        if (d[c].exp_sid == NULL) {
-+            assert_null(sid);
-+        } else {
-+            assert_string_equal(sid, d[c].exp_sid);
-+        }
-+        assert_int_equal(rid, d[c].exp_rid);
-+        assert_int_equal(range.min, d[c].exp_range.min);
-+        assert_int_equal(range.max, d[c].exp_range.max);
-+        assert_true(external_mapping == d[c].exp_external_mapping);
-+    }
-+}
-+
-+errno_t __wrap_sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-+                                size_t *range_count,
-+                                struct range_info ***range_list)
-+{
-+
-+    *range_count = sss_mock_type(size_t);
-+    *range_list = talloc_steal(mem_ctx,
-+                               sss_mock_ptr_type(struct range_info **));
-+    return EOK;
-+}
-+
-+struct test_ctx {
-+    struct sdap_idmap_ctx *idmap_ctx;
-+    struct sdap_id_ctx *sdap_id_ctx;
-+};
-+
-+static struct range_info **get_range_list(TALLOC_CTX *mem_ctx)
-+{
-+    struct range_info **range_list;
-+
-+    range_list = talloc_array(mem_ctx, struct range_info *, 2);
-+    assert_non_null(range_list);
-+
-+    range_list[0] = talloc_zero(range_list, struct range_info);
-+    assert_non_null(range_list[0]);
-+
-+    range_list[0]->name = talloc_strdup(range_list[0], RANGE_NAME);
-+    assert_non_null( range_list[0]->name);
-+    range_list[0]->base_id = BASE_ID;
-+    range_list[0]->id_range_size = RANGE_SIZE;
-+    range_list[0]->base_rid = BASE_RID;
-+    range_list[0]->secondary_base_rid = 0;
-+    range_list[0]->trusted_dom_sid = talloc_strdup(range_list[0], DOMAIN_SID);
-+    assert_non_null(range_list[0]->trusted_dom_sid);
-+    range_list[0]->range_type = talloc_strdup(range_list[0],
-+                                              IPA_RANGE_AD_TRUST);
-+    assert_non_null(range_list[0]->range_type);
-+
-+    return range_list;
-+}
-+
-+void setup_idmap_ctx(void **state)
-+{
-+    int ret;
-+    struct test_ctx *test_ctx;
-+
-+    assert_true(leak_check_setup());
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    test_ctx->sdap_id_ctx = talloc_zero(test_ctx,
-+                                        struct sdap_id_ctx);
-+    assert_non_null(test_ctx->sdap_id_ctx);
-+
-+    test_ctx->sdap_id_ctx->be = talloc_zero(test_ctx->sdap_id_ctx,
-+                                            struct be_ctx);
-+    assert_non_null(test_ctx->sdap_id_ctx->be);
-+
-+    test_ctx->sdap_id_ctx->be->domain = talloc_zero(test_ctx->sdap_id_ctx->be,
-+                                                    struct sss_domain_info);
-+    assert_non_null(test_ctx->sdap_id_ctx->be->domain);
-+
-+    test_ctx->sdap_id_ctx->be->domain->name =
-+                  talloc_strdup(test_ctx->sdap_id_ctx->be->domain, DOMAIN_NAME);
-+    assert_non_null(test_ctx->sdap_id_ctx->be->domain->name);
-+
-+    will_return(__wrap_sysdb_get_ranges, 1);
-+    will_return(__wrap_sysdb_get_ranges, get_range_list(global_talloc_context));
-+
-+    ret = ipa_idmap_init(test_ctx, test_ctx->sdap_id_ctx,
-+                         &test_ctx->idmap_ctx);
-+    assert_int_equal(ret, EOK);
-+
-+    check_leaks_push(test_ctx);
-+    *state = test_ctx;
-+}
-+
-+void teardown_idmap_ctx(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
-+
-+    assert_non_null(test_ctx);
-+
-+    assert_true(check_leaks_pop(test_ctx) == true);
-+
-+    talloc_free(test_ctx);
-+    assert_true(leak_check_teardown());
-+}
-+
-+void test_ipa_idmap_get_ranges_from_sysdb(void **state)
-+{
-+    int ret;
-+    struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    will_return(__wrap_sysdb_get_ranges, 1);
-+    will_return(__wrap_sysdb_get_ranges, get_range_list(test_ctx->idmap_ctx));
-+    ret = ipa_idmap_get_ranges_from_sysdb(test_ctx->idmap_ctx,
-+                                          DOMAIN_NAME, DOMAIN_SID, true);
-+    assert_int_equal(ret, EOK);
-+
-+    will_return(__wrap_sysdb_get_ranges, 1);
-+    will_return(__wrap_sysdb_get_ranges, get_range_list(global_talloc_context));
-+    ret = ipa_idmap_get_ranges_from_sysdb(test_ctx->idmap_ctx,
-+                                          DOMAIN_NAME, DOMAIN_SID, false);
-+    assert_int_equal(ret, EIO);
-+}
-+
-+int main(int argc, const char *argv[])
-+{
-+    poptContext pc;
-+    int opt;
-+    struct poptOption long_options[] = {
-+        POPT_AUTOHELP
-+        SSSD_DEBUG_OPTS
-+        POPT_TABLEEND
-+    };
-+
-+    const UnitTest tests[] = {
-+        unit_test(test_get_idmap_data_from_range),
-+        unit_test_setup_teardown(test_ipa_idmap_get_ranges_from_sysdb,
-+                                 setup_idmap_ctx, teardown_idmap_ctx),
-+    };
-+
-+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
-+    debug_level = SSSDBG_INVALID;
-+
-+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
-+    while((opt = poptGetNextOpt(pc)) != -1) {
-+        switch(opt) {
-+        default:
-+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
-+                    poptBadOption(pc, 0), poptStrerror(opt));
-+            poptPrintUsage(pc, stderr, 0);
-+            return 1;
-+        }
-+    }
-+    poptFreeContext(pc);
-+
-+    DEBUG_INIT(debug_level);
-+
-+    tests_set_cwd();
-+
-+    return run_tests(tests);
-+}
--- 
-1.8.5.3
-
diff --git a/SOURCES/0094-MAN-page-edit-for-ldap_use_tokengroups.patch b/SOURCES/0094-MAN-page-edit-for-ldap_use_tokengroups.patch
new file mode 100644
index 0000000..1900f08
--- /dev/null
+++ b/SOURCES/0094-MAN-page-edit-for-ldap_use_tokengroups.patch
@@ -0,0 +1,44 @@
+From d3b1ed808665ba63bbb45cd4d9aa380916ed1b65 Mon Sep 17 00:00:00 2001
+From: Dan Lavu <dlavu@redhat.com>
+Date: Tue, 11 Nov 2014 15:46:51 -0500
+Subject: [PATCH 094/104] MAN: page edit for ldap_use_tokengroups
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2448
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/man/sssd-ldap.5.xml | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index d7a2a4ac9fa2497a4c347a2a7e77703e53b8a46c..5b36f69a679a1362290d8fea1f4c8fc29cc548d8 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -2482,7 +2482,18 @@ ldap_access_filter = (employeeType=admin)
+                     <term>ldap_group_search_base (string)</term>
+                     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/ldap_search_bases.xml" />
+                 </varlistentry>
+-
++            </variablelist>
++            <variablelist>
++                <note>
++                    <para>
++                        If the option <quote>ldap_use_tokengroups</quote> is
++                        enabled. The searches against Active Directory will
++                        not be restricted and return all groups memberships,
++                        even with no gid mapping. It is recommended to disable
++                        this feature, if group names are not being displayed
++                        correctly.
++                    </para>
++                </note>
+                 <varlistentry condition="with_sudo">
+                     <term>ldap_sudo_search_base (string)</term>
+                     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/ldap_search_bases.xml" />
+-- 
+1.9.3
+
diff --git a/SOURCES/0095-IPA-check-ranges-for-collisions-before-saving-them.patch b/SOURCES/0095-IPA-check-ranges-for-collisions-before-saving-them.patch
deleted file mode 100644
index b083bfd..0000000
--- a/SOURCES/0095-IPA-check-ranges-for-collisions-before-saving-them.patch
+++ /dev/null
@@ -1,193 +0,0 @@
-From 841fef45aef0a1424d4afbf3ea2bb40566155af9 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Feb 2014 18:17:09 +0100
-Subject: [PATCH 95/97] IPA: check ranges for collisions before saving them
-
-Fixes https://fedorahosted.org/sssd/ticket/2253
----
- src/providers/ipa/ipa_subdomains.c | 83 +++++++++++++++++++++++++++++---------
- 1 file changed, 63 insertions(+), 20 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 88b6ba52538be83417e98c9a5dd033bea87ebe4b..07ae03b6ab0325b011a26f36f4fdc9a5766b8445 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -351,14 +351,28 @@ const char *get_flat_name_from_subdomain_name(struct be_ctx *be_ctx,
- }
- 
- static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-+                                        char *domain_name,
-                                         size_t count,
-                                         struct sysdb_attrs **reply,
-                                         struct range_info ***_range_list)
- {
-     struct range_info **range_list = NULL;
-+    struct range_info *r;
-     const char *value;
-     size_t c;
-+    size_t d;
-     int ret;
-+    enum idmap_error_code err;
-+    char *name1;
-+    char *name2;
-+    char *sid1;
-+    char *sid2;
-+    uint32_t rid1;
-+    uint32_t rid2;
-+    struct sss_idmap_range range1;
-+    struct sss_idmap_range range2;
-+    bool mapping1;
-+    bool mapping2;
- 
-     range_list = talloc_array(mem_ctx, struct range_info *, count + 1);
-     if (range_list == NULL) {
-@@ -367,8 +381,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-     }
- 
-     for (c = 0; c < count; c++) {
--        range_list[c] = talloc_zero(range_list, struct range_info);
--        if (range_list[c] == NULL) {
-+        r = talloc_zero(range_list, struct range_info);
-+        if (r == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero failed.\n"));
-             ret = ENOMEM;
-             goto done;
-@@ -379,8 +393,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-             DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-             goto done;
-         }
--        range_list[c]->name = talloc_strdup(range_list[c], value);
--        if (range_list[c]->name == NULL) {
-+        r->name = talloc_strdup(r, value);
-+        if (r->name == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
-             ret = ENOMEM;
-             goto done;
-@@ -388,9 +402,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
- 
-         ret = sysdb_attrs_get_string(reply[c], IPA_TRUSTED_DOMAIN_SID, &value);
-         if (ret == EOK) {
--            range_list[c]->trusted_dom_sid = talloc_strdup(range_list[c],
--                                                           value);
--            if (range_list[c]->trusted_dom_sid == NULL) {
-+            r->trusted_dom_sid = talloc_strdup(r, value);
-+            if (r->trusted_dom_sid == NULL) {
-                 DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
-                 ret = ENOMEM;
-                 goto done;
-@@ -401,28 +414,28 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-         }
- 
-         ret = sysdb_attrs_get_uint32_t(reply[c], IPA_BASE_ID,
--                                       &range_list[c]->base_id);
-+                                       &r->base_id);
-         if (ret != EOK && ret != ENOENT) {
-             DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-             goto done;
-         }
- 
-         ret = sysdb_attrs_get_uint32_t(reply[c], IPA_ID_RANGE_SIZE,
--                                       &range_list[c]->id_range_size);
-+                                       &r->id_range_size);
-         if (ret != EOK && ret != ENOENT) {
-             DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-             goto done;
-         }
- 
-         ret = sysdb_attrs_get_uint32_t(reply[c], IPA_BASE_RID,
--                                       &range_list[c]->base_rid);
-+                                       &r->base_rid);
-         if (ret != EOK && ret != ENOENT) {
-             DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-             goto done;
-         }
- 
-         ret = sysdb_attrs_get_uint32_t(reply[c], IPA_SECONDARY_BASE_RID,
--                                       &range_list[c]->secondary_base_rid);
-+                                       &r->secondary_base_rid);
-         if (ret != EOK && ret != ENOENT) {
-             DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-             goto done;
-@@ -430,8 +443,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
- 
-         ret = sysdb_attrs_get_string(reply[c], IPA_RANGE_TYPE, &value);
-         if (ret == EOK) {
--            range_list[c]->range_type = talloc_strdup(range_list[c], value);
--            if (range_list[c]->range_type == NULL) {
-+            r->range_type = talloc_strdup(r, value);
-+            if (r->range_type == NULL) {
-                 DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
-                 ret = ENOMEM;
-                 goto done;
-@@ -439,23 +452,52 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-         } else if (ret == ENOENT) {
-             /* Older IPA servers might not have the range_type attribute, but
-              * only support local ranges and trusts with algorithmic mapping. */
--            if (range_list[c]->trusted_dom_sid == NULL) {
--                range_list[c]->range_type = talloc_strdup(range_list[c],
--                                                          IPA_RANGE_LOCAL);
-+            if (r->trusted_dom_sid == NULL) {
-+                r->range_type = talloc_strdup(r, IPA_RANGE_LOCAL);
-             } else {
--                range_list[c]->range_type = talloc_strdup(range_list[c],
--                                                          IPA_RANGE_AD_TRUST);
-+                r->range_type = talloc_strdup(r, IPA_RANGE_AD_TRUST);
-             }
-         } else {
-             DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-             goto done;
-         }
--        if (range_list[c]->range_type == NULL) {
-+        if (r->range_type == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
-             ret = ENOMEM;
-             goto done;
-         }
-+
-+        ret = get_idmap_data_from_range(r, domain_name, &name1, &sid1, &rid1,
-+                                        &range1, &mapping1);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("get_idmap_data_from_range failed.\n"));
-+            goto done;
-+        }
-+        for (d = 0; d < c; d++) {
-+            ret = get_idmap_data_from_range(range_list[d], domain_name, &name2,
-+                                            &sid2, &rid2, &range2, &mapping2);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      ("get_idmap_data_from_range failed.\n"));
-+                goto done;
-+            }
-+
-+            err = sss_idmap_check_collision_ex(name1, sid1, &range1, rid1,
-+                                               r->name, mapping1,
-+                                               name2, sid2, &range2, rid2,
-+                                               range_list[d]->name, mapping2);
-+            if (err != IDMAP_SUCCESS) {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      ("Collision of ranges [%s] and [%s] detected.\n",
-+                      r->name, range_list[d]->name));
-+                ret = EINVAL;
-+                goto done;
-+            }
-+        }
-+
-+        range_list[c] = r;
-     }
-+
-     range_list[c] = NULL;
- 
-     *_range_list = range_list;
-@@ -1013,7 +1055,8 @@ static void ipa_subdomains_handler_ranges_done(struct tevent_req *req)
-         goto done;
-     }
- 
--    ret = ipa_ranges_parse_results(ctx, reply_count, reply, &range_list);
-+    ret = ipa_ranges_parse_results(ctx, domain->name,
-+                                   reply_count, reply, &range_list);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("ipa_ranges_parse_results request failed.\n"));
--- 
-1.8.5.3
-
diff --git a/SOURCES/0095-sysdb-add-sysdb_search_object_by_uuid.patch b/SOURCES/0095-sysdb-add-sysdb_search_object_by_uuid.patch
new file mode 100644
index 0000000..01d0903
--- /dev/null
+++ b/SOURCES/0095-sysdb-add-sysdb_search_object_by_uuid.patch
@@ -0,0 +1,209 @@
+From 1f5796f2ab0a848712a7f5bc85c9f7c2f22a8a0f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 5 Nov 2014 21:01:08 +0100
+Subject: [PATCH 095/104] sysdb: add sysdb_search_object_by_uuid()
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb.h          |  7 +++++
+ src/db/sysdb_ops.c      | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/tests/sysdb-tests.c | 51 ++++++++++++++++++++++++++++++++
+ 3 files changed, 135 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index f582f6a516e43a453741acacbe3ca6957e23fc37..7a51117f439dc54ded3433c230d2d262a4d660dc 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -185,6 +185,7 @@
+ #define SYSDB_NETGR_TRIPLES_FILTER "(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_MEMBEROF"=%s))"
+ 
+ #define SYSDB_SID_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_SID_STR"=%s))"
++#define SYSDB_UUID_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_UUID"=%s))"
+ 
+ #define SYSDB_HAS_ENUMERATED "has_enumerated"
+ 
+@@ -1030,6 +1031,12 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
+                                    const char **attrs,
+                                    struct ldb_result **msg);
+ 
++errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
++                                    struct sss_domain_info *domain,
++                                    const char *uuid_str,
++                                    const char **attrs,
++                                    struct ldb_result **res);
++
+ /* === Functions related to GPOs === */
+ 
+ #define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom"
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index c88ff9b4bf39c649bc7993f3ed56729b7bfde310..998046a2ca1c746b2032f430e5f9c4a7151e1dbc 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -3499,12 +3499,79 @@ done:
+     return ret;
+ }
+ 
++static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx,
++                                   struct sss_domain_info *domain,
++                                   const char *filter_tmpl,
++                                   const char *str,
++                                   const char **attrs,
++                                   struct ldb_result **_res)
++{
++    TALLOC_CTX *tmp_ctx;
++    const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM,
++                                ORIGINALAD_PREFIX SYSDB_NAME,
++                                SYSDB_OBJECTCLASS, NULL };
++    struct ldb_dn *basedn;
++    int ret;
++    struct ldb_result *res = NULL;
++
++    tmp_ctx = talloc_new(NULL);
++    if (!tmp_ctx) {
++        return ENOMEM;
++    }
++
++    basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE,
++                            domain->name);
++    if (basedn == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
++                     basedn, LDB_SCOPE_SUBTREE, attrs?attrs:def_attrs,
++                     filter_tmpl, str);
++    if (ret != EOK) {
++        ret = sysdb_error_to_errno(ret);
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n");
++        goto done;
++    }
++
++    if (res->count > 1) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Search for [%s]  with filter [%s] " \
++                                   "returned more than one object.\n",
++                                   str, filter_tmpl);
++        ret = EINVAL;
++        goto done;
++    } else if (res->count == 0) {
++        ret = ENOENT;
++        goto done;
++    }
++
++    *_res = talloc_steal(mem_ctx, res);
++
++done:
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_FUNC, "No such entry.\n");
++    } else if (ret) {
++        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
++    }
++
++    talloc_zfree(tmp_ctx);
++    return ret;
++}
++
+ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *domain,
+                                    const char *sid_str,
+                                    const char **attrs,
+                                    struct ldb_result **msg)
+ {
++/* TODO: use
++    return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER,
++                                           sid_str, attrs, res);
++
++    when verified that all callers can handle ENOENT correctly. */
++
+     TALLOC_CTX *tmp_ctx;
+     const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM,
+                                 ORIGINALAD_PREFIX SYSDB_NAME,
+@@ -3553,3 +3620,13 @@ done:
+     talloc_zfree(tmp_ctx);
+     return ret;
+ }
++
++errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
++                                    struct sss_domain_info *domain,
++                                    const char *uuid_str,
++                                    const char **attrs,
++                                    struct ldb_result **res)
++{
++    return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_UUID_FILTER,
++                                           uuid_str, attrs, res);
++}
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index e01ddf4782c0a5a557f39d1adc2efd74b6234461..e9618727d4f8f4c544b28cce9d98b82000de3aad 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -5026,6 +5026,54 @@ START_TEST(test_sysdb_search_sid_str)
+ }
+ END_TEST
+ 
++START_TEST(test_sysdb_search_object_by_uuid)
++{
++    errno_t ret;
++    struct sysdb_test_ctx *test_ctx;
++    struct ldb_result *res;
++    struct sysdb_attrs *attrs = NULL;
++
++    /* Setup */
++    ret = setup_sysdb_tests(&test_ctx);
++    fail_if(ret != EOK, "Could not set up the test");
++
++    attrs = sysdb_new_attrs(test_ctx);
++    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_UUID,
++                                 "11111111-2222-3333-4444-555555555555");
++    fail_unless(ret == EOK, "sysdb_attrs_add_string failed with [%d][%s].",
++                ret, strerror(ret));
++
++    ret = sysdb_add_user(test_ctx->domain, "UUIDuser",
++                         123456, 0, "UUID user", "/home/uuiduser", "/bin/bash",
++                         NULL, attrs, 0, 0);
++    fail_unless(ret == EOK, "sysdb_add_user failed with [%d][%s].",
++                ret, strerror(ret));
++
++    ret = sysdb_search_object_by_uuid(test_ctx, test_ctx->domain,
++                                      "11111111-2222-3333-4444-555555555556",
++                                      NULL, &res);
++    fail_unless(ret == ENOENT,
++                "Unexpected return code from sysdb_search_object_by_uuid for "
++                "missing object, expected [%d], got [%d].", ENOENT, ret);
++
++    ret = sysdb_search_object_by_uuid(test_ctx, test_ctx->domain,
++                                      "11111111-2222-3333-4444-555555555555",
++                                      NULL, &res);
++    fail_unless(ret == EOK, "sysdb_search_object_by_uuid failed with [%d][%s].",
++                ret, strerror(ret));
++    fail_unless(res->count == 1, "Unexpected number of results, " \
++                                 "expected [%u], get [%u].", 1, res->count);
++    fail_unless(strcmp(ldb_msg_find_attr_as_string(res->msgs[0],
++                                                   SYSDB_NAME, ""),
++                      "UUIDuser") == 0, "Unexpected object found, " \
++                      "expected [%s], got [%s].", "UUIDuser",
++                      ldb_msg_find_attr_as_string(res->msgs[0],SYSDB_NAME, ""));
++
++    talloc_free(test_ctx);
++}
++END_TEST
+ 
+ START_TEST(test_sysdb_subdomain_create)
+ {
+@@ -6090,6 +6138,9 @@ Suite *create_sysdb_suite(void)
+     /* Test SID string searches */
+     tcase_add_test(tc_sysdb, test_sysdb_search_sid_str);
+ 
++    /* Test UUID string searches */
++    tcase_add_test(tc_sysdb, test_sysdb_search_object_by_uuid);
++
+     /* Test canonicalizing names */
+     tcase_add_test(tc_sysdb, test_sysdb_get_real_name);
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0096-OPTS-Allow-using-defaults-for-blobs.patch b/SOURCES/0096-OPTS-Allow-using-defaults-for-blobs.patch
deleted file mode 100644
index ac6b578..0000000
--- a/SOURCES/0096-OPTS-Allow-using-defaults-for-blobs.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 2f08218f0eb6e069c94401ac439d5d7f5b032564 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 24 Feb 2014 15:42:15 +0100
-Subject: [PATCH 96/97] OPTS: Allow using defaults for blobs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit ddd21d5dc3c89712d9286d1f66f4b2af73651cf2)
----
- src/providers/data_provider_opts.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/providers/data_provider_opts.c b/src/providers/data_provider_opts.c
-index 0edadecc12d2e354c590df9d3ed011cb4e44eee0..5a2e3b74da7d4af4326a56a9cd47b7826e4b78e3 100644
---- a/src/providers/data_provider_opts.c
-+++ b/src/providers/data_provider_opts.c
-@@ -78,6 +78,9 @@ int dp_get_options(TALLOC_CTX *memctx,
-             if (tmp) {
-                 opts[i].val.blob.data = (uint8_t *)tmp;
-                 opts[i].val.blob.length = strlen(tmp);
-+            } else if (opts[i].def_val.blob.data != NULL) {
-+                opts[i].val.blob.data = opts[i].def_val.blob.data;
-+                opts[i].val.blob.length = opts[i].def_val.blob.length;
-             } else {
-                 opts[i].val.blob.data = NULL;
-                 opts[i].val.blob.length = 0;
--- 
-1.8.5.3
-
diff --git a/SOURCES/0096-ipa-add-split_ipa_anchor.patch b/SOURCES/0096-ipa-add-split_ipa_anchor.patch
new file mode 100644
index 0000000..fd7df7e
--- /dev/null
+++ b/SOURCES/0096-ipa-add-split_ipa_anchor.patch
@@ -0,0 +1,179 @@
+From 7c8abc07058b37e743b1530c9e4a66e2d517e3c3 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 6 Nov 2014 13:13:27 +0100
+Subject: [PATCH 096/104] ipa: add split_ipa_anchor()
+
+This call extracts the domain and the UUID part from an IPA override
+anchor.
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                         |  2 ++
+ src/providers/ipa/ipa_id.h          |  2 ++
+ src/providers/ipa/ipa_utils.c       | 63 +++++++++++++++++++++++++++++++++++++
+ src/tests/cmocka/test_sysdb_views.c | 32 +++++++++++++++++++
+ 4 files changed, 99 insertions(+)
+ create mode 100644 src/providers/ipa/ipa_utils.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 156ef3c4eab1510126d2bfb47c06163885b8acfe..53ace65b9a9647ffdaff0776d5a55d3e7393a38c 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2064,6 +2064,7 @@ endif # BUILD_IFP
+ 
+ test_sysdb_views_SOURCES = \
+     src/tests/cmocka/test_sysdb_views.c \
++    src/providers/ipa/ipa_utils.c \
+     $(NULL)
+ test_sysdb_views_CFLAGS = \
+     $(AM_CFLAGS) \
+@@ -2387,6 +2388,7 @@ libsss_ipa_la_SOURCES = \
+     src/providers/ipa/ipa_subdomains_id.c \
+     src/providers/ipa/ipa_subdomains_ext_groups.c \
+     src/providers/ipa/ipa_views.c \
++    src/providers/ipa/ipa_utils.c \
+     src/providers/ipa/ipa_s2n_exop.c \
+     src/providers/ipa/ipa_hbac_hosts.c \
+     src/providers/ipa/ipa_hbac_private.h \
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index e13aded213ace8557dfccfc68e04d9ff69fae221..033ac40f1d7a7d8c4a968374ee190a5bcb17819c 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -103,4 +103,6 @@ struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
+ 
+ errno_t ipa_subdomain_account_recv(struct tevent_req *req, int *dp_error_out);
+ 
++errno_t split_ipa_anchor(TALLOC_CTX *mem_ctx, const char *anchor,
++                         char **_anchor_domain, char **_ipa_uuid);
+ #endif
+diff --git a/src/providers/ipa/ipa_utils.c b/src/providers/ipa/ipa_utils.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..86ba51c8adb49c4e0cabccf1ade522b582a8f4d7
+--- /dev/null
++++ b/src/providers/ipa/ipa_utils.c
+@@ -0,0 +1,63 @@
++/*
++    SSSD
++
++    IPA Module utility functions
++
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "util/util.h"
++
++#define OVERRIDE_ANCHOR_IPA_PREFIX ":IPA:"
++#define OVERRIDE_ANCHOR_IPA_PREFIX_LEN (sizeof(OVERRIDE_ANCHOR_IPA_PREFIX) -1 )
++
++errno_t split_ipa_anchor(TALLOC_CTX *mem_ctx, const char *anchor,
++                         char **_anchor_domain, char **_ipa_uuid)
++{
++    const char *sep;
++
++    if (anchor == NULL) {
++        return EINVAL;
++    }
++    if (strncmp(OVERRIDE_ANCHOR_IPA_PREFIX, anchor,
++                OVERRIDE_ANCHOR_IPA_PREFIX_LEN) != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "No IPA anchor [%s].\n", anchor);
++        return ENOMSG;
++    }
++
++    sep = strchr(anchor + OVERRIDE_ANCHOR_IPA_PREFIX_LEN, ':');
++    if (sep == NULL || sep[1] == '\0') {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Broken IPA anchor [%s].\n", anchor);
++        return EINVAL;
++    }
++
++    *_anchor_domain = talloc_strndup(mem_ctx,
++                                 anchor + OVERRIDE_ANCHOR_IPA_PREFIX_LEN,
++                                 sep - anchor - OVERRIDE_ANCHOR_IPA_PREFIX_LEN);
++    *_ipa_uuid = talloc_strdup(mem_ctx, sep + 1);
++
++    if (*_anchor_domain == NULL || *_ipa_uuid == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
++        talloc_free(*_anchor_domain);
++        talloc_free(*_ipa_uuid);
++        return ENOMEM;
++    }
++
++    return EOK;
++}
+diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
+index 9fb2d7201d06e84be83d6a516c5e3a0f15ec0639..0dc51443b406673f131cc69be4d781f7c49e538c 100644
+--- a/src/tests/cmocka/test_sysdb_views.c
++++ b/src/tests/cmocka/test_sysdb_views.c
+@@ -29,6 +29,7 @@
+ #include <popt.h>
+ 
+ #include "tests/cmocka/common_mock.h"
++#include "providers/ipa/ipa_id.h"
+ 
+ #define TESTS_PATH "tests_sysdb_views"
+ #define TEST_CONF_FILE "tests_conf.ldb"
+@@ -189,6 +190,35 @@ void test_sysdb_add_overrides_to_object(void **state)
+     assert_int_equal(ldb_val_string_cmp(&el->values[1], "OVERRIDEKEY2"), 0);
+ }
+ 
++void test_split_ipa_anchor(void **state)
++{
++    int ret;
++    char *dom;
++    char *uuid;
++    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                         struct sysdb_test_ctx);
++
++    ret = split_ipa_anchor(test_ctx, NULL, &dom, &uuid);
++    assert_int_equal(ret, EINVAL);
++
++    ret = split_ipa_anchor(test_ctx, "fwfkwjfkw", &dom, &uuid);
++    assert_int_equal(ret, ENOMSG);
++
++    ret = split_ipa_anchor(test_ctx, ":IPA:", &dom, &uuid);
++    assert_int_equal(ret, EINVAL);
++
++    ret = split_ipa_anchor(test_ctx, ":IPA:abc", &dom, &uuid);
++    assert_int_equal(ret, EINVAL);
++
++    ret = split_ipa_anchor(test_ctx, ":IPA:abc:", &dom, &uuid);
++    assert_int_equal(ret, EINVAL);
++
++    ret = split_ipa_anchor(test_ctx, ":IPA:abc:def", &dom, &uuid);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(dom, "abc");
++    assert_string_equal(uuid, "def");
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int rv;
+@@ -206,6 +236,8 @@ int main(int argc, const char *argv[])
+     const UnitTest tests[] = {
+         unit_test_setup_teardown(test_sysdb_add_overrides_to_object,
+                                  test_sysdb_setup, test_sysdb_teardown),
++        unit_test_setup_teardown(test_split_ipa_anchor,
++                                 test_sysdb_setup, test_sysdb_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+1.9.3
+
diff --git a/SOURCES/0097-DP-Provide-separate-dp_copy_defaults-function.patch b/SOURCES/0097-DP-Provide-separate-dp_copy_defaults-function.patch
deleted file mode 100644
index 4ef2599..0000000
--- a/SOURCES/0097-DP-Provide-separate-dp_copy_defaults-function.patch
+++ /dev/null
@@ -1,637 +0,0 @@
-From cb5090d6da0e0b378b095b151af70fa21cd62e9e Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 24 Feb 2014 15:42:51 +0100
-Subject: [PATCH 97/97] DP: Provide separate dp_copy_defaults function
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2257
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 90afedb00608547ae1f32aa7aafd552c4b306909)
----
- Makefile.am                        |  12 ++
- src/providers/ad/ad_common.c       |  16 +-
- src/providers/data_provider.h      |   5 +
- src/providers/data_provider_opts.c |  42 ++--
- src/tests/cmocka/test_dp_opts.c    | 421 +++++++++++++++++++++++++++++++++++++
- src/tests/ipa_ldap_opt-tests.c     |   2 +-
- 6 files changed, 476 insertions(+), 22 deletions(-)
- create mode 100644 src/tests/cmocka/test_dp_opts.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 2e1a1e6bacfb79e4ef7068a22a64c21d23858cb9..9025ec6a5bfa16408278506fdd573666b4b6dbe5 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -154,6 +154,7 @@ if HAVE_CMOCKA
-         test_utils \
-         ad_access_filter_tests \
-         ad_common_tests \
-+        dp_opt_tests \
-         test_search_bases
- endif
- 
-@@ -1459,6 +1460,17 @@ ad_common_tests_LDADD = \
-     libsss_krb5_common.la \
-     libsss_test_common.la
- 
-+dp_opt_tests_SOURCES = \
-+    src/providers/data_provider_opts.c \
-+    src/tests/cmocka/test_dp_opts.c
-+dp_opt_tests_CFLAGS = \
-+    $(AM_CFLAGS)
-+dp_opt_tests_LDADD = \
-+    $(CMOCKA_LIBS) \
-+    $(TALLOC_LIBS) \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    libsss_test_common.la
-+
- endif
- 
- noinst_PROGRAMS = pam_test_client
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index 99fa4c07af2a79bb3ca195214ddb0dbd60c61620..605de49f7f7ae910cbc78e38f888600ba78a0c4f 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -44,10 +44,10 @@ ad_create_default_sdap_options(TALLOC_CTX *mem_ctx)
-         return NULL;
-     }
- 
--    ret = dp_copy_options(id_opts,
--                          ad_def_ldap_opts,
--                          SDAP_OPTS_BASIC,
--                          &id_opts->basic);
-+    ret = dp_copy_defaults(id_opts,
-+                           ad_def_ldap_opts,
-+                           SDAP_OPTS_BASIC,
-+                           &id_opts->basic);
-     if (ret != EOK) {
-         goto fail;
-     }
-@@ -117,10 +117,10 @@ ad_create_default_options(TALLOC_CTX *mem_ctx,
-     ad_options = talloc_zero(mem_ctx, struct ad_options);
-     if (ad_options == NULL) return NULL;
- 
--    ret = dp_copy_options(ad_options,
--                          ad_basic_opts,
--                          AD_OPTS_BASIC,
--                          &ad_options->basic);
-+    ret = dp_copy_defaults(ad_options,
-+                           ad_basic_opts,
-+                           AD_OPTS_BASIC,
-+                           &ad_options->basic);
-     if (ret != EOK) {
-         talloc_free(ad_options);
-         return NULL;
-diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
-index d086d5d2f368578c6a44a2c3b33738c894feba95..d86ff58e65c7ae35f7269fdd10ed78f529ed8d8c 100644
---- a/src/providers/data_provider.h
-+++ b/src/providers/data_provider.h
-@@ -295,6 +295,11 @@ int dp_copy_options(TALLOC_CTX *memctx,
-                     int num_opts,
-                     struct dp_option **_opts);
- 
-+int dp_copy_defaults(TALLOC_CTX *memctx,
-+                     struct dp_option *src_opts,
-+                     int num_opts,
-+                     struct dp_option **_opts);
-+
- const char *_dp_opt_get_cstring(struct dp_option *opts,
-                                     int id, const char *location);
- char *_dp_opt_get_string(struct dp_option *opts,
-diff --git a/src/providers/data_provider_opts.c b/src/providers/data_provider_opts.c
-index 5a2e3b74da7d4af4326a56a9cd47b7826e4b78e3..0cc48e46e8bbba487aea15b4ad1044e8ddc0482a 100644
---- a/src/providers/data_provider_opts.c
-+++ b/src/providers/data_provider_opts.c
-@@ -131,11 +131,11 @@ done:
- }
- 
- /* =Basic-Option-Helpers================================================== */
--
--int dp_copy_options(TALLOC_CTX *memctx,
--                    struct dp_option *src_opts,
--                    int num_opts,
--                    struct dp_option **_opts)
-+static int dp_copy_options_ex(TALLOC_CTX *memctx,
-+                              bool copy_values,
-+                              struct dp_option *src_opts,
-+                              int num_opts,
-+                              struct dp_option **_opts)
- {
-     struct dp_option *opts;
-     int i, ret = EOK;
-@@ -151,9 +151,9 @@ int dp_copy_options(TALLOC_CTX *memctx,
- 
-         switch (src_opts[i].type) {
-         case DP_OPT_STRING:
--            if (src_opts[i].val.string) {
-+            if (copy_values) {
-                 ret = dp_opt_set_string(opts, i, src_opts[i].val.string);
--            } else if (src_opts[i].def_val.string) {
-+            } else {
-                 ret = dp_opt_set_string(opts, i, src_opts[i].def_val.string);
-             }
-             if (ret != EOK) {
-@@ -169,9 +169,9 @@ int dp_copy_options(TALLOC_CTX *memctx,
-             break;
- 
-         case DP_OPT_BLOB:
--            if (src_opts[i].val.blob.data) {
-+            if (copy_values) {
-                 ret = dp_opt_set_blob(opts, i, src_opts[i].val.blob);
--            } else if (src_opts[i].def_val.blob.data) {
-+            } else {
-                 ret = dp_opt_set_blob(opts, i, src_opts[i].def_val.blob);
-             }
-             if (ret != EOK) {
-@@ -185,9 +185,9 @@ int dp_copy_options(TALLOC_CTX *memctx,
-             break;
- 
-         case DP_OPT_NUMBER:
--            if (src_opts[i].val.number) {
-+            if (copy_values) {
-                 ret = dp_opt_set_int(opts, i, src_opts[i].val.number);
--            } else if (src_opts[i].def_val.number) {
-+            } else {
-                 ret = dp_opt_set_int(opts, i, src_opts[i].def_val.number);
-             }
-             if (ret != EOK) {
-@@ -201,9 +201,9 @@ int dp_copy_options(TALLOC_CTX *memctx,
-             break;
- 
-         case DP_OPT_BOOL:
--            if (src_opts[i].val.boolean) {
-+            if (copy_values) {
-                 ret = dp_opt_set_bool(opts, i, src_opts[i].val.boolean);
--            } else if (src_opts[i].def_val.boolean) {
-+            } else {
-                 ret = dp_opt_set_bool(opts, i, src_opts[i].def_val.boolean);
-             }
-             if (ret != EOK) {
-@@ -225,6 +225,22 @@ done:
-     return ret;
- }
- 
-+int dp_copy_options(TALLOC_CTX *memctx,
-+                    struct dp_option *src_opts,
-+                    int num_opts,
-+                    struct dp_option **_opts)
-+{
-+    return dp_copy_options_ex(memctx, true, src_opts, num_opts, _opts);
-+}
-+
-+int dp_copy_defaults(TALLOC_CTX *memctx,
-+                     struct dp_option *src_opts,
-+                     int num_opts,
-+                     struct dp_option **_opts)
-+{
-+    return dp_copy_options_ex(memctx, false, src_opts, num_opts, _opts);
-+}
-+
- static const char *dp_opt_type_to_string(enum dp_opt_type type)
- {
-     switch (type) {
-diff --git a/src/tests/cmocka/test_dp_opts.c b/src/tests/cmocka/test_dp_opts.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..07998b4034fb33195c99340e5544596925ecf145
---- /dev/null
-+++ b/src/tests/cmocka/test_dp_opts.c
-@@ -0,0 +1,421 @@
-+/*
-+    Authors:
-+        Jakub Hrozek <jhrozek@redhat.com>
-+
-+    Copyright (C) 2014 Red Hat
-+
-+    SSSD tests: Data Provider Option Tests
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include <popt.h>
-+
-+#include "providers/data_provider.h"
-+
-+#include "tests/cmocka/common_mock.h"
-+
-+#define STRING_DEFAULT  "stringval"
-+#define BLOB_DEFAULT    "blobval"
-+#define INT_DEFAULT     123
-+
-+#define TESTS_PATH "tests_opts"
-+#define TEST_CONF_DB "test_opt_conf.ldb"
-+#define TEST_SYSDB_FILE "cache_opt_test.ldb"
-+#define TEST_DOM_NAME "opt_test"
-+#define TEST_ID_PROVIDER "ldap"
-+
-+enum test_opts {
-+    OPT_STRING_NODEFAULT,
-+    OPT_STRING_DEFAULT,
-+    OPT_BLOB_NODEFAULT,
-+    OPT_BLOB_DEFAULT,
-+    OPT_INT_NODEFAULT,
-+    OPT_INT_DEFAULT,
-+    OPT_BOOL_TRUE,
-+    OPT_BOOL_FALSE,
-+
-+    OPT_NUM_OPTS
-+};
-+
-+struct dp_option test_def_opts[] = {
-+    { "string_nodefault", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-+    { "string_default", DP_OPT_STRING, { STRING_DEFAULT }, NULL_STRING},
-+    { "blob_nodefault", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
-+    { "blob_default", DP_OPT_BLOB,
-+                      { .blob = { discard_const(BLOB_DEFAULT),
-+                                  sizeof(BLOB_DEFAULT) - 1 } },
-+                      NULL_BLOB },
-+    { "int_nodefault", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
-+    { "int_default", DP_OPT_NUMBER, { .number = INT_DEFAULT }, NULL_NUMBER },
-+    { "bool_true", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
-+    { "bool_false", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
-+    DP_OPTION_TERMINATOR
-+};
-+
-+static void assert_defaults(struct dp_option *opts)
-+{
-+    char *s;
-+    struct dp_opt_blob b;
-+    int i;
-+    bool bo;
-+
-+    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
-+    assert_null(s);
-+
-+    s = dp_opt_get_string(opts, OPT_STRING_DEFAULT);
-+    assert_non_null(s);
-+    assert_string_equal(s, STRING_DEFAULT);
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
-+    assert_null(b.data);
-+    assert_int_equal(b.length, 0);
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT);
-+    assert_non_null(b.data);
-+    assert_int_equal(b.length, strlen(BLOB_DEFAULT));
-+    assert_memory_equal(b.data, BLOB_DEFAULT, strlen(BLOB_DEFAULT));
-+
-+    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
-+    assert_int_equal(i, 0);
-+
-+    i = dp_opt_get_int(opts, OPT_INT_DEFAULT);
-+    assert_int_equal(i, INT_DEFAULT);
-+
-+    bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
-+    assert_true(bo == true);
-+
-+    bo = dp_opt_get_bool(opts, OPT_BOOL_FALSE);
-+    assert_true(bo == false);
-+}
-+
-+void opt_test_copy_default(void **state)
-+{
-+    int ret;
-+    TALLOC_CTX *mem_ctx;
-+    struct dp_option *opts;
-+    struct dp_opt_blob b;
-+
-+    mem_ctx = talloc_new(global_talloc_context);
-+    assert_non_null(mem_ctx);
-+
-+    ret = dp_copy_defaults(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts);
-+    assert_int_equal(ret, EOK);
-+    assert_defaults(opts);
-+
-+    /* Test that copy_defaults would still copy defaults even if we
-+     * change the values
-+     */
-+    ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1");
-+    assert_int_equal(ret, EOK);
-+    ret = dp_opt_set_string(opts, OPT_STRING_DEFAULT, "str2");
-+    assert_int_equal(ret, EOK);
-+
-+    b.data = discard_const_p(uint8_t, "blob1");
-+    b.length = strlen("blob1");
-+    ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = dp_opt_set_blob(opts, OPT_BLOB_DEFAULT, b);
-+    b.data = discard_const_p(uint8_t, "blob2");
-+    b.length = strlen("blob2");
-+    assert_int_equal(ret, EOK);
-+
-+    ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456);
-+    assert_int_equal(ret, EOK);
-+    ret = dp_opt_set_int(opts, OPT_INT_DEFAULT, 789);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false);
-+    assert_int_equal(ret, EOK);
-+    ret = dp_opt_set_bool(opts, OPT_BOOL_FALSE, true);
-+    assert_int_equal(ret, EOK);
-+
-+    talloc_free(opts);
-+    ret = dp_copy_defaults(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts);
-+    assert_int_equal(ret, EOK);
-+    assert_defaults(opts);
-+}
-+
-+void opt_test_copy_options(void **state)
-+{
-+    int ret;
-+    TALLOC_CTX *mem_ctx;
-+    struct dp_option *opts;
-+    char *s;
-+    struct dp_opt_blob b;
-+    int i;
-+    bool bo;
-+
-+    mem_ctx = talloc_new(global_talloc_context);
-+    assert_non_null(mem_ctx);
-+
-+    ret = dp_copy_options(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1");
-+    assert_int_equal(ret, EOK);
-+
-+    b.data = discard_const_p(uint8_t, "blob1");
-+    b.length = strlen("blob1");
-+    ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Test that options set to an explicit value retain
-+     * the value and even options with default value
-+     * do not return the default unless explicitly set
-+     */
-+    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
-+    assert_string_equal(s, "str1");
-+    s = dp_opt_get_string(opts, OPT_STRING_DEFAULT);
-+    assert_null(s);
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
-+    assert_non_null(b.data);
-+    assert_int_equal(b.length, strlen("blob1"));
-+    assert_memory_equal(b.data, "blob1", strlen("blob1"));
-+    b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT);
-+    assert_null(b.data);
-+    assert_int_equal(b.length, 0);
-+
-+    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
-+    assert_int_equal(i, 456);
-+    i = dp_opt_get_int(opts, OPT_INT_DEFAULT);
-+    assert_int_equal(i, 0);
-+
-+    bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
-+    assert_false(bo == true);
-+}
-+
-+void opt_test_get(void **state)
-+{
-+    int ret;
-+    struct sss_test_ctx *tctx;
-+    struct dp_option *opts;
-+    char *dompath;
-+    struct sss_test_conf_param params[] = {
-+        { "string_nodefault", "stringval2" },
-+        { "blob_nodefault", "blobval2" },
-+        { "int_nodefault", "456" },
-+        { "bool_true", "false" },
-+        { NULL, NULL },             /* Sentinel */
-+    };
-+    char *s;
-+    struct dp_opt_blob b;
-+    int i;
-+    bool bo;
-+
-+    tctx = create_dom_test_ctx(global_talloc_context, TESTS_PATH, TEST_CONF_DB,
-+                               TEST_SYSDB_FILE, TEST_DOM_NAME,
-+                               TEST_ID_PROVIDER, params);
-+    assert_non_null(tctx);
-+
-+    dompath = talloc_asprintf(tctx, "config/domain/%s", TEST_DOM_NAME);
-+    assert_non_null(dompath);
-+
-+    ret = dp_get_options(global_talloc_context, tctx->confdb, dompath,
-+                         test_def_opts, OPT_NUM_OPTS, &opts);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Options that were not specified explicitly should only have the default
-+     * value, those that have been specified explicitly should carry that
-+     * value
-+     */
-+    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
-+    assert_non_null(s);
-+    assert_string_equal(s, "stringval2");
-+
-+    s = dp_opt_get_string(opts, OPT_STRING_DEFAULT);
-+    assert_non_null(s);
-+    assert_string_equal(s, STRING_DEFAULT);
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
-+    assert_non_null(b.data);
-+    assert_int_equal(b.length, strlen("blobval2"));
-+    assert_memory_equal(b.data, "blobval2", strlen("blobval2"));
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT);
-+    assert_non_null(b.data);
-+    assert_int_equal(b.length, strlen(BLOB_DEFAULT));
-+    assert_memory_equal(b.data, BLOB_DEFAULT, strlen(BLOB_DEFAULT));
-+
-+    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
-+    assert_int_equal(i, 456);
-+
-+    i = dp_opt_get_int(opts, OPT_INT_DEFAULT);
-+    assert_int_equal(i, INT_DEFAULT);
-+
-+    bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
-+    assert_true(bo == false);
-+
-+    bo = dp_opt_get_bool(opts, OPT_BOOL_FALSE);
-+    assert_true(bo == false);
-+}
-+
-+void opt_test_getset_setup(void **state)
-+{
-+    int ret;
-+    struct dp_option *opts;
-+
-+    ret = dp_copy_defaults(global_talloc_context,
-+                           test_def_opts, OPT_NUM_OPTS, &opts);
-+    assert_int_equal(ret, EOK);
-+    assert_defaults(opts);
-+
-+    *state = opts;
-+}
-+
-+void opt_test_getset_teardown(void **state)
-+{
-+    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
-+    talloc_free(opts);
-+}
-+
-+void opt_test_getset_string(void **state)
-+{
-+    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
-+    int ret;
-+    char *s;
-+
-+    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
-+    assert_null(s);
-+
-+    ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1");
-+    assert_int_equal(ret, EOK);
-+
-+    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
-+    assert_non_null(s);
-+    assert_string_equal(s, "str1");
-+}
-+
-+void opt_test_getset_blob(void **state)
-+{
-+    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
-+    int ret;
-+    struct dp_opt_blob b;
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
-+    assert_null(b.data);
-+    assert_int_equal(b.length, 0);
-+
-+    b.data = discard_const_p(uint8_t, "blob2");
-+    b.length = strlen("blob2");
-+    ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b);
-+    assert_int_equal(ret, EOK);
-+
-+    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
-+    assert_non_null(b.data);
-+    assert_int_equal(b.length, strlen("blob2"));
-+    assert_memory_equal(b.data, "blob2", strlen("blob2"));
-+}
-+
-+void opt_test_getset_int(void **state)
-+{
-+    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
-+    int ret;
-+    int i;
-+
-+    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
-+    assert_int_equal(i, 0);
-+
-+    ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456);
-+    assert_int_equal(ret, EOK);
-+
-+    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
-+    assert_int_equal(i, 456);
-+}
-+
-+void opt_test_getset_bool(void **state)
-+{
-+    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
-+    int ret;
-+    bool b;
-+
-+    b = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
-+    assert_true(b == true);
-+
-+    ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false);
-+    assert_int_equal(ret, EOK);
-+
-+    b = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
-+    assert_false(b == true);
-+}
-+
-+int main(int argc, const char *argv[])
-+{
-+    int no_cleanup = 0;
-+    poptContext pc;
-+    int opt;
-+    int ret;
-+    struct poptOption long_options[] = {
-+        POPT_AUTOHELP
-+        SSSD_DEBUG_OPTS
-+        {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
-+         _("Do not delete the test database after a test run"), NULL },
-+        POPT_TABLEEND
-+    };
-+    const UnitTest tests[] = {
-+        unit_test_setup_teardown(opt_test_getset_string,
-+                                 opt_test_getset_setup,
-+                                 opt_test_getset_teardown),
-+        unit_test_setup_teardown(opt_test_getset_int,
-+                                 opt_test_getset_setup,
-+                                 opt_test_getset_teardown),
-+        unit_test_setup_teardown(opt_test_getset_bool,
-+                                 opt_test_getset_setup,
-+                                 opt_test_getset_teardown),
-+        unit_test_setup_teardown(opt_test_getset_blob,
-+                                 opt_test_getset_setup,
-+                                 opt_test_getset_teardown),
-+        unit_test(opt_test_copy_default),
-+        unit_test(opt_test_copy_options),
-+        unit_test(opt_test_get)
-+    };
-+
-+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
-+    debug_level = SSSDBG_INVALID;
-+
-+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
-+    while((opt = poptGetNextOpt(pc)) != -1) {
-+        switch(opt) {
-+        default:
-+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
-+                    poptBadOption(pc, 0), poptStrerror(opt));
-+            poptPrintUsage(pc, stderr, 0);
-+            return 1;
-+        }
-+    }
-+    poptFreeContext(pc);
-+
-+    DEBUG_INIT(debug_level);
-+
-+    /* Even though normally the tests should clean up after themselves
-+     * they might not after a failed run. Remove the old db to be sure */
-+    tests_set_cwd();
-+    test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_SYSDB_FILE);
-+    test_dom_suite_setup(TESTS_PATH);
-+
-+    ret = run_tests(tests);
-+    if (ret == 0 && !no_cleanup) {
-+        test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_SYSDB_FILE);
-+    }
-+    return ret;
-+}
-diff --git a/src/tests/ipa_ldap_opt-tests.c b/src/tests/ipa_ldap_opt-tests.c
-index 40afa5cba87d89bc6fa7345302991fe766b43314..25a094082dc369092f10ad823d98909027dd9a7e 100644
---- a/src/tests/ipa_ldap_opt-tests.c
-+++ b/src/tests/ipa_ldap_opt-tests.c
-@@ -170,7 +170,7 @@ START_TEST(test_copy_opts)
-     tmp_ctx = talloc_new(NULL);
-     fail_unless(tmp_ctx != NULL, "talloc_new failed");
- 
--    ret = dp_copy_options(tmp_ctx, ad_def_ldap_opts, SDAP_OPTS_BASIC, &opts);
-+    ret = dp_copy_defaults(tmp_ctx, ad_def_ldap_opts, SDAP_OPTS_BASIC, &opts);
-     fail_unless(ret == EOK, "[%s]", strerror(ret));
- 
-     for (int i=0; i < SDAP_OPTS_BASIC; i++) {
--- 
-1.8.5.3
-
diff --git a/SOURCES/0097-LDAP-add-support-for-lookups-by-UUID.patch b/SOURCES/0097-LDAP-add-support-for-lookups-by-UUID.patch
new file mode 100644
index 0000000..f731fb0
--- /dev/null
+++ b/SOURCES/0097-LDAP-add-support-for-lookups-by-UUID.patch
@@ -0,0 +1,147 @@
+From 21bc70002db718c353724d3aea2121a2bac23218 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 7 Nov 2014 13:55:01 +0100
+Subject: [PATCH 097/104] LDAP: add support for lookups by UUID
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/data_provider.h |  2 ++
+ src/providers/ldap/ldap_id.c  | 58 +++++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 55 insertions(+), 5 deletions(-)
+
+diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
+index e1cb4befadba7e24a418790b10ff361b3092ec6a..5df493e9d1ae21ada6f5fd6198a6d9c36680d044 100644
+--- a/src/providers/data_provider.h
++++ b/src/providers/data_provider.h
+@@ -127,6 +127,7 @@
+ #define BE_FILTER_IDNUM 2
+ #define BE_FILTER_ENUM 3
+ #define BE_FILTER_SECID 4
++#define BE_FILTER_UUID 5
+ 
+ #define BE_REQ_USER          0x0001
+ #define BE_REQ_GROUP         0x0002
+@@ -139,6 +140,7 @@
+ #define BE_REQ_HOST          0x0010
+ #define BE_REQ_BY_SECID      0x0011
+ #define BE_REQ_USER_AND_GROUP 0x0012
++#define BE_REQ_BY_UUID      0x0013
+ #define BE_REQ_TYPE_MASK     0x00FF
+ #define BE_REQ_FAST          0x1000
+ 
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index e8b3a0e1e1dce6e0c8a9b21aa7c6299108dad24d..2e58f4e49eb33a85cbb8b4144c69004c6b5b312b 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -179,6 +179,20 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+             goto done;
+         }
+         break;
++    case BE_FILTER_UUID:
++        attr_name = ctx->opts->user_map[SDAP_AT_USER_UUID].name;
++        if (attr_name == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "UUID search not configured for this backend.\n");
++            ret = EINVAL;
++            goto done;
++        }
++
++        ret = sss_filter_sanitize(state, name, &clean_name);
++        if (ret != EOK) {
++            goto done;
++        }
++        break;
+     default:
+         ret = EINVAL;
+         goto done;
+@@ -458,8 +472,9 @@ static void users_get_done(struct tevent_req *subreq)
+             break;
+ 
+         case BE_FILTER_SECID:
+-            /* Since it is not clear if the SID belongs to a user or a group
+-             * we have nothing to do here. */
++        case BE_FILTER_UUID:
++            /* Since it is not clear if the SID/UUID belongs to a user or a
++             * group we have nothing to do here. */
+             break;
+ 
+         default:
+@@ -635,6 +650,20 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+             goto done;
+         }
+         break;
++    case BE_FILTER_UUID:
++        attr_name = ctx->opts->group_map[SDAP_AT_GROUP_UUID].name;
++        if (attr_name == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "UUID search not configured for this backend.\n");
++            ret = EINVAL;
++            goto done;
++        }
++
++        ret = sss_filter_sanitize(state, name, &clean_name);
++        if (ret != EOK) {
++            goto done;
++        }
++        break;
+     default:
+         ret = EINVAL;
+         goto done;
+@@ -884,8 +913,9 @@ static void groups_get_done(struct tevent_req *subreq)
+             break;
+ 
+         case BE_FILTER_SECID:
+-            /* Since it is not clear if the SID belongs to a user or a group
+-             * we have nothing to do here. */
++        case BE_FILTER_UUID:
++            /* Since it is not clear if the SID/UUID belongs to a user or a
++             * group we have nothing to do here. */
+             break;
+ 
+         default:
+@@ -1401,7 +1431,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+ 
+-        if (ar->filter_type == BE_FILTER_SECID) {
++        if (ar->filter_type == BE_FILTER_SECID
++                || ar->filter_type == BE_FILTER_UUID) {
+             ret = EINVAL;
+             state->err = "Invalid filter type";
+             goto done;
+@@ -1430,6 +1461,21 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
+                                          noexist_delete);
+         break;
+ 
++    case BE_REQ_BY_UUID:
++        if (ar->filter_type != BE_FILTER_UUID) {
++            ret = EINVAL;
++            state->err = "Invalid filter type";
++            goto done;
++        }
++
++        subreq = get_user_and_group_send(breq, be_ctx->ev, id_ctx,
++                                         sdom, conn,
++                                         ar->filter_value,
++                                         ar->filter_type,
++                                         ar->attr_type,
++                                         noexist_delete);
++        break;
++
+     case BE_REQ_USER_AND_GROUP:
+         if (!(ar->filter_type == BE_FILTER_NAME ||
+               ar->filter_type == BE_FILTER_IDNUM)) {
+@@ -1504,6 +1550,8 @@ sdap_handle_acct_req_done(struct tevent_req *subreq)
+         break;
+     case BE_REQ_BY_SECID:
+         /* Fallthrough */
++    case BE_REQ_BY_UUID:
++        /* Fallthrough */
+     case BE_REQ_USER_AND_GROUP:
+         err = "Lookup by SID failed";
+         ret = sdap_get_user_and_group_recv(subreq, &state->dp_error,
+-- 
+1.9.3
+
diff --git a/SOURCES/0098-LDAP-always-store-UUID-if-available.patch b/SOURCES/0098-LDAP-always-store-UUID-if-available.patch
new file mode 100644
index 0000000..21921b4
--- /dev/null
+++ b/SOURCES/0098-LDAP-always-store-UUID-if-available.patch
@@ -0,0 +1,200 @@
+From 8c68296b9e5d50951e19877bcad46444157d8fc5 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 7 Nov 2014 21:33:36 +0100
+Subject: [PATCH 098/104] LDAP: always store UUID if available
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ldap/sdap_async_groups.c | 42 +++++++++++++++++++++++++---------
+ src/providers/ldap/sdap_async_users.c  | 23 +++++++++++++++++--
+ 2 files changed, 52 insertions(+), 13 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
+index a82d2aa3418cf5d59181e4be5a1ed6aaeb0b05e9..8cf7f7ff1d414049f0694c7d2873556fc9dad741 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -511,6 +511,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     bool posix_group;
+     bool use_id_mapping;
+     char *sid_str;
++    const char *uuid;
+     struct sss_domain_info *subdomain;
+     int32_t ad_group_type;
+ 
+@@ -534,7 +535,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+         ret = sysdb_attrs_add_string(group_attrs, SYSDB_SID_STR, sid_str);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE, "Could not add SID string: [%s]\n",
+-                                         strerror(ret));
++                                         sss_strerror(ret));
+             goto done;
+         }
+     } else if (ret == ENOENT) {
+@@ -543,10 +544,29 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+         sid_str = NULL;
+     } else {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify objectSID: [%s]\n",
+-                                     strerror(ret));
++                                     sss_strerror(ret));
+         sid_str = NULL;
+     }
+ 
++    /* Always store UUID if available */
++    ret = sysdb_attrs_get_string(attrs,
++                                 opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
++                                 &uuid);
++    if (ret == EOK) {
++        ret = sysdb_attrs_add_string(group_attrs, SYSDB_UUID, uuid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not add UUID string: [%s]\n",
++                                         sss_strerror(ret));
++            goto done;
++        }
++    } else if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_ALL, "UUID not available for group [%s].\n",
++                                 group_name);
++    } else {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify UUID [%s]\n",
++                                     sss_strerror(ret));
++    }
++
+     /* If this object has a SID available, we will determine the correct
+      * domain by its SID. */
+     if (sid_str != NULL) {
+@@ -633,7 +653,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+             } else if (ret != EOK) {
+                 DEBUG(SSSDBG_MINOR_FAILURE,
+                       "Could not convert SID string: [%s]\n",
+-                       strerror(ret));
++                       sss_strerror(ret));
+                 goto done;
+             }
+ 
+@@ -652,7 +672,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+             } else if (ret != EOK) {
+                 DEBUG(SSSDBG_MINOR_FAILURE,
+                       "Error reading posix attribute: [%s]\n",
+-                       strerror(ret));
++                       sss_strerror(ret));
+                 goto done;
+             }
+ 
+@@ -662,7 +682,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_MINOR_FAILURE,
+                       "Error setting posix attribute: [%s]\n",
+-                       strerror(ret));
++                       sss_strerror(ret));
+                 goto done;
+             }
+ 
+@@ -695,7 +715,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     if (ret != EOK) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+               "Error setting original DN: [%s]\n",
+-               strerror(ret));
++               sss_strerror(ret));
+         goto done;
+     }
+ 
+@@ -706,7 +726,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     if (ret != EOK) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+               "Error setting mod timestamp: [%s]\n",
+-               strerror(ret));
++               sss_strerror(ret));
+         goto done;
+     }
+ 
+@@ -715,7 +735,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     if (ret) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+               "Error looking up group USN: [%s]\n",
+-               strerror(ret));
++               sss_strerror(ret));
+         goto done;
+     }
+     if (el->num_values == 0) {
+@@ -728,7 +748,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+         if (ret) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+                   "Error setting group USN: [%s]\n",
+-                   strerror(ret));
++                   sss_strerror(ret));
+             goto done;
+         }
+         usn_value = talloc_strdup(tmpctx, (const char*)el->values[0].data);
+@@ -759,7 +779,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     if (ret) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+               "Could not store group with GID: [%s]\n",
+-               strerror(ret));
++               sss_strerror(ret));
+         goto done;
+     }
+ 
+@@ -775,7 +795,7 @@ done:
+         DEBUG(SSSDBG_MINOR_FAILURE,
+               "Failed to save group [%s]: [%s]\n",
+                group_name ? group_name : "Unknown",
+-               strerror(ret));
++               sss_strerror(ret));
+     }
+     talloc_free(tmpctx);
+     return ret;
+diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
+index 2331ba9df90cdbf8fdb9ae85bd97485b0bcf8bb2..367e3d795ddd0db5c1c2f8e57d700419f371cd15 100644
+--- a/src/providers/ldap/sdap_async_users.c
++++ b/src/providers/ldap/sdap_async_users.c
+@@ -140,6 +140,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
+     TALLOC_CTX *tmpctx = NULL;
+     bool use_id_mapping;
+     char *sid_str;
++    const char *uuid;
+     char *dom_sid_str = NULL;
+     struct sss_domain_info *subdomain;
+ 
+@@ -165,7 +166,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
+         ret = sysdb_attrs_add_string(user_attrs, SYSDB_SID_STR, sid_str);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE, "Could not add SID string: [%s]\n",
+-                                         strerror(ret));
++                                         sss_strerror(ret));
+             goto done;
+         }
+     } else if (ret == ENOENT) {
+@@ -173,10 +174,28 @@ int sdap_save_user(TALLOC_CTX *memctx,
+         sid_str = NULL;
+     } else {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify objectSID: [%s]\n",
+-                                     strerror(ret));
++                                     sss_strerror(ret));
+         sid_str = NULL;
+     }
+ 
++    /* Always store UUID if available */
++    ret = sysdb_attrs_get_string(attrs,
++                                 opts->user_map[SDAP_AT_USER_UUID].sys_name,
++                                 &uuid);
++    if (ret == EOK) {
++        ret = sysdb_attrs_add_string(user_attrs, SYSDB_UUID, uuid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not add UUID string: [%s]\n",
++                                         sss_strerror(ret));
++            goto done;
++        }
++    } else if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_ALL, "UUID not available for user.\n");
++    } else {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify UUID [%s]\n",
++                                     sss_strerror(ret));
++    }
++
+     /* If this object has a SID available, we will determine the correct
+      * domain by its SID. */
+     if (sid_str != NULL) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0098-MAN-Clarify-the-ldap_access_filter-option-further.patch b/SOURCES/0098-MAN-Clarify-the-ldap_access_filter-option-further.patch
deleted file mode 100644
index d98e726..0000000
--- a/SOURCES/0098-MAN-Clarify-the-ldap_access_filter-option-further.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From af16267fc9d681fc4230fa82a9fe86de9491c8fd Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 24 Feb 2014 19:42:23 +0100
-Subject: [PATCH 98/99] MAN: Clarify the ldap_access_filter option further
-
-https://fedorahosted.org/sssd/ticket/2235
-
-The memberof example was misleading and was making aministrators think
-that the ldap_access_filter can resolve nested group memberships.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Stephen Gallagher <sgallagh@redhat.com>
-(cherry picked from commit 604d46e028ab62f83060fb88bdd3319a31aca2d1)
----
- src/man/sssd-ldap.5.xml | 9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
-index cc58544c38e8ffa779f0a1b22a69caaf3f193ce1..b271a2b7fa8b19ac3e4475bd8ca634b0414f5ea4 100644
---- a/src/man/sssd-ldap.5.xml
-+++ b/src/man/sssd-ldap.5.xml
-@@ -1775,19 +1775,20 @@
-                             and this option is not set, it will result in all
-                             users being denied access.
-                             Use access_provider = permit to change this default
--                            behavior.
-+                            behavior. Please note that this filter is applied on
-+                            the LDAP user entry only.
-                         </para>
-                         <para>
-                             Example:
-                         </para>
-                         <programlisting>
- access_provider = ldap
--ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com
-+ldap_access_filter = (employeeType=admin)
-                         </programlisting>
-                         <para>
-                             This example means that access to this host is
--                            restricted to members of the "allowedusers" group
--                            in ldap.
-+                            restricted to users whose employeeType
-+                            attribute is set to "admin".
-                         </para>
-                         <para>
-                             Offline caching for this feature is limited to
--- 
-1.8.5.3
-
diff --git a/SOURCES/0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch b/SOURCES/0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch
deleted file mode 100644
index d560ead..0000000
--- a/SOURCES/0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 59995f35b7dd6ec552be1081b0120f2344e3ded3 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 25 Feb 2014 17:09:00 +0100
-Subject: [PATCH 99/99] MAN: Clarify that changing ID mapping options might
- require purging the cache
-
-https://fedorahosted.org/sssd/ticket/2252
-
-Currently SSSD chokes when IDs of users change, we don't support ID
-changes yet. Because some users were confused about the failures, this
-patch adds additional clarification.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Stephen Gallagher <sgallagh@redhat.com>
-(cherry picked from commit 3dfa09a826e5f63b4948462c2452937fc329834d)
----
- src/man/include/ldap_id_mapping.xml | 42 +++++++++++++++++++++++++++++++++++++
- 1 file changed, 42 insertions(+)
-
-diff --git a/src/man/include/ldap_id_mapping.xml b/src/man/include/ldap_id_mapping.xml
-index 71ff248f1f24242b911f615fd6afeb0382dfa5a1..7f5dbd30be67745b26dbced341762705d6e09f14 100644
---- a/src/man/include/ldap_id_mapping.xml
-+++ b/src/man/include/ldap_id_mapping.xml
-@@ -12,6 +12,48 @@
-         need to use manually-assigned values, ALL values must be
-         manually-assigned.
-     </para>
-+    <para>
-+        Please note that changing the ID mapping related configuration
-+        options will cause user and group IDs to change. At the moment,
-+        SSSD does not support changing IDs, so the SSSD database must
-+        be removed. Because cached passwords are also stored in the
-+        database, removing the database should only be performed while
-+        the authentication servers are reachable, otherwise users might
-+        get locked out. In order to cache the password, an authentication
-+        must be performed. It is not sufficient to use
-+        <citerefentry>
-+            <refentrytitle>sss_cache</refentrytitle>
-+            <manvolnum>8</manvolnum>
-+        </citerefentry>
-+        to remove the database, rather the process
-+        consists of:
-+            <itemizedlist>
-+                <listitem>
-+                    <para>
-+                        Making sure the remote servers are reachable
-+                    </para>
-+                </listitem>
-+                <listitem>
-+                    <para>
-+                        Stopping the SSSD service
-+                    </para>
-+                </listitem>
-+                <listitem>
-+                    <para>
-+                        Removing the database
-+                    </para>
-+                </listitem>
-+                <listitem>
-+                    <para>
-+                        Starting the SSSD service
-+                    </para>
-+                </listitem>
-+            </itemizedlist>
-+        Moreover, as the change of IDs might necessitate the adjustment
-+        of other system properties such as file and directory ownership,
-+        it's advisable to plan ahead and test the ID mapping configuration
-+        thoroughly.
-+    </para>
- 
-     <refsect2 id='idmap_algorithm'>
-         <title>Mapping Algorithm</title>
--- 
-1.8.5.3
-
diff --git a/SOURCES/0099-ipa-add-get_be_acct_req_for_uuid.patch b/SOURCES/0099-ipa-add-get_be_acct_req_for_uuid.patch
new file mode 100644
index 0000000..503f95d
--- /dev/null
+++ b/SOURCES/0099-ipa-add-get_be_acct_req_for_uuid.patch
@@ -0,0 +1,102 @@
+From 0e1c39d4f66c80a510d13cf73273ee87ec998a0a Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 7 Nov 2014 15:05:41 +0100
+Subject: [PATCH 099/104] ipa: add get_be_acct_req_for_uuid()
+
+This new call creates the needs data for a lookup by UUID which is
+needed when trying to find the original object for an IPA override
+object.
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_id.h    |  4 ++++
+ src/providers/ipa/ipa_views.c | 42 ++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 40 insertions(+), 6 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index 033ac40f1d7a7d8c4a968374ee190a5bcb17819c..890d00d49097555acce62ecc5fa300c71c6c9981 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -83,6 +83,10 @@ errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+                                 const char *domain_name,
+                                 struct be_acct_req **_ar);
+ 
++errno_t get_be_acct_req_for_uuid(TALLOC_CTX *mem_ctx, const char *uuid,
++                                 const char *domain_name,
++                                 struct be_acct_req **_ar);
++
+ struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
+                                             struct tevent_context *ev,
+                                             struct sdap_id_ctx *sdap_id_ctx,
+diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
+index 2eb77216ab9759d8b1d66fbdf0b2e90cd07a4604..ee586894ec61b1b1330816c628bbc9617d58e31e 100644
+--- a/src/providers/ipa/ipa_views.c
++++ b/src/providers/ipa/ipa_views.c
+@@ -140,9 +140,10 @@ static errno_t be_acct_req_to_override_filter(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
+-errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+-                                const char *domain_name,
+-                                struct be_acct_req **_ar)
++static errno_t get_be_acct_req_for_xyz(TALLOC_CTX *mem_ctx, const char *val,
++                                       const char *domain_name,
++                                       int type,
++                                       struct be_acct_req **_ar)
+ {
+     struct be_acct_req *ar;
+ 
+@@ -152,9 +153,22 @@ errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+         return ENOMEM;
+     }
+ 
+-    ar->entry_type = BE_REQ_BY_SECID;
+-    ar->filter_type = BE_FILTER_SECID;
+-    ar->filter_value = talloc_strdup(ar, sid);
++    switch (type) {
++    case BE_REQ_BY_SECID:
++        ar->entry_type = BE_REQ_BY_SECID;
++        ar->filter_type = BE_FILTER_SECID;
++        break;
++    case BE_REQ_BY_UUID:
++        ar->entry_type = BE_REQ_BY_UUID;
++        ar->filter_type = BE_FILTER_UUID;
++        break;
++    default:
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported request type [%d].\n", type);
++        talloc_free(ar);
++        return EINVAL;
++    }
++
++    ar->filter_value = talloc_strdup(ar, val);
+     ar->domain = talloc_strdup(ar, domain_name);
+     if (ar->filter_value == NULL || ar->domain == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+@@ -168,6 +182,22 @@ errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+     return EOK;
+ }
+ 
++errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
++                                const char *domain_name,
++                                struct be_acct_req **_ar)
++{
++    return get_be_acct_req_for_xyz(mem_ctx, sid, domain_name, BE_REQ_BY_SECID,
++                                   _ar);
++}
++
++errno_t get_be_acct_req_for_uuid(TALLOC_CTX *mem_ctx, const char *uuid,
++                                 const char *domain_name,
++                                 struct be_acct_req **_ar)
++{
++    return get_be_acct_req_for_xyz(mem_ctx, uuid, domain_name, BE_REQ_BY_UUID,
++                                   _ar);
++}
++
+ struct ipa_get_ad_override_state {
+     struct tevent_context *ev;
+     struct sdap_id_ctx *sdap_id_ctx;
+-- 
+1.9.3
+
diff --git a/SOURCES/0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch b/SOURCES/0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch
deleted file mode 100644
index 5138aea..0000000
--- a/SOURCES/0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 02e3c4dad405464c2f0cec97203a98e5fb251273 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Thu, 13 Feb 2014 17:46:29 +0100
-Subject: [PATCH 100/101] DOC: Fix names of arguments in doxygen comments
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 3b35ff47651e4893ce537a273466766b962362da)
----
- src/lib/idmap/sss_idmap.h            | 2 +-
- src/sss_client/idmap/sss_nss_idmap.h | 6 +++---
- src/util/util.h                      | 2 +-
- 3 files changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
-index ccc63f7f760b877cdb17696325731f8e540b2736..0797083293f7e010962828ddcd72709b290859b9 100644
---- a/src/lib/idmap/sss_idmap.h
-+++ b/src/lib/idmap/sss_idmap.h
-@@ -608,7 +608,7 @@ enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx,
-  * @brief Free mapped binary SID.
-  *
-  * @param[in] ctx         Idmap context
-- * @param[in] smb_sid     Binary SID to be freed.
-+ * @param[in] bin_sid     Binary SID to be freed.
-  *
-  * @return
-  *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
-diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
-index be5c506e27f0e418022cff78b48ca3a37aacd5af..79dacfbdb1708569507742fbd8579cf7aaa06d9b 100644
---- a/src/sss_client/idmap/sss_nss_idmap.h
-+++ b/src/sss_client/idmap/sss_nss_idmap.h
-@@ -43,7 +43,7 @@ enum sss_id_type {
-  * @param[in] fq_name  Fully qualified name of a user or a group
-  * @param[out] sid     String representation of the SID of the requested user
-  *                     or group, must be freed by the caller
-- * @param[out] id_type Type of the object related to the given name
-+ * @param[out] type    Type of the object related to the given name
-  *
-  * @return
-  *  - 0 (EOK): success, sid contains the requested SID
-@@ -63,7 +63,7 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid,
-  * @param[in] id       POSIX UID or GID
-  * @param[out] sid     String representation of the SID of the requested user
-  *                     or group, must be freed by the caller
-- * @param[out] id_type Type of the object related to the given ID
-+ * @param[out] type    Type of the object related to the given ID
-  *
-  * @return
-  *  - see #sss_nss_getsidbyname
-@@ -76,7 +76,7 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type);
-  * @param[in] sid      String representation of the SID
-  * @param[out] fq_name Fully qualified name of a user or a group,
-  *                     must be freed by the caller
-- * @param[out] id_type Type of the object related to the SID
-+ * @param[out] type    Type of the object related to the SID
-  *
-  * @return
-  *  - see #sss_nss_getsidbyname
-diff --git a/src/util/util.h b/src/util/util.h
-index 7b185bcb4287a4afc5bf67b40164cf69b9beeb19..89684e84a5be6c26fe08e5d3ab3d20d3a0e199b1 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -513,7 +513,7 @@ bool string_in_list(const char *string, char **list, bool case_sensitive);
-  *        prevents the compiler from optimizing out
-  *
-  * @param data   The address of buffer to wipe
-- * @param s      Size of the buffer
-+ * @param size   Size of the buffer
-  */
- void safezero(void *data, size_t size);
- 
--- 
-1.8.5.3
-
diff --git a/SOURCES/0100-IPA-make-get_object_from_cache-public.patch b/SOURCES/0100-IPA-make-get_object_from_cache-public.patch
new file mode 100644
index 0000000..371eb07
--- /dev/null
+++ b/SOURCES/0100-IPA-make-get_object_from_cache-public.patch
@@ -0,0 +1,57 @@
+From 0f15a623392fa66832e8cbbc8e9293830e1fb0f8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 7 Nov 2014 21:34:55 +0100
+Subject: [PATCH 100/104] IPA: make get_object_from_cache() public
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_id.h            | 5 +++++
+ src/providers/ipa/ipa_subdomains_id.c | 9 +++++----
+ 2 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index 890d00d49097555acce62ecc5fa300c71c6c9981..9d219f281847df0ba4ac24061e598eb6915f9c38 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -109,4 +109,9 @@ errno_t ipa_subdomain_account_recv(struct tevent_req *req, int *dp_error_out);
+ 
+ errno_t split_ipa_anchor(TALLOC_CTX *mem_ctx, const char *anchor,
+                          char **_anchor_domain, char **_ipa_uuid);
++
++errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
++                              struct sss_domain_info *dom,
++                              struct be_acct_req *ar,
++                              struct ldb_message **_msg);
+ #endif
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 0a1c4c17eed37b2eb12a8c758e49fc17c3b642b5..891fc336483b507fd284b0c84b118534910ed9fc 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -848,10 +848,10 @@ done:
+     return ret;
+ }
+ 
+-static errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+-                                     struct sss_domain_info *dom,
+-                                     struct be_acct_req *ar,
+-                                     struct ldb_message **_msg)
++errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
++                              struct sss_domain_info *dom,
++                              struct be_acct_req *ar,
++                              struct ldb_message **_msg)
+ {
+     errno_t ret;
+     uint32_t id;
+@@ -861,6 +861,7 @@ static errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+                             SYSDB_UIDNUM,
+                             SYSDB_SID_STR,
+                             SYSDB_OBJECTCLASS,
++                            SYSDB_UUID,
+                             NULL };
+     char *name;
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0101-IPA-check-overrrides-for-IPA-users-as-well.patch b/SOURCES/0101-IPA-check-overrrides-for-IPA-users-as-well.patch
new file mode 100644
index 0000000..f1432a8
--- /dev/null
+++ b/SOURCES/0101-IPA-check-overrrides-for-IPA-users-as-well.patch
@@ -0,0 +1,517 @@
+From 2dfd383413d1c5bfc031f8396eccd1108c899e68 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 5 Nov 2014 15:58:04 +0100
+Subject: [PATCH 101/104] IPA: check overrrides for IPA users as well
+
+Currently overrides were only available for sub-domains, e.g. trusted AD
+domains. With this patch overrides can be used for IPA users as well.
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_id.c            | 405 +++++++++++++++++++++++++++++++++-
+ src/providers/ipa/ipa_subdomains_id.c |  16 +-
+ src/providers/ipa/ipa_views.c         |  15 ++
+ 3 files changed, 432 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index cd65f5b462c102ed502a014789a7232a93389b68..5665a1835e8b0ab18325bfc68a8d8b5650730943 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -56,6 +56,13 @@ static const char *ipa_account_info_error_text(int ret, int *dp_error,
+     return default_text;
+ }
+ 
++static struct tevent_req *
++ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
++                             struct ipa_id_ctx *ipa_ctx, struct be_req *be_req,
++                             struct be_acct_req *ar);
++
++static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error);
++
+ static struct tevent_req *ipa_id_get_netgroup_send(TALLOC_CTX *memctx,
+                                                    struct tevent_context *ev,
+                                                    struct ipa_id_ctx *ipa_ctx,
+@@ -100,7 +107,9 @@ void ipa_account_info_handler(struct be_req *breq)
+     } else {
+         /* any account request is handled by sdap,
+          * any invalid request is caught there. */
+-        return sdap_handle_account_info(breq, ctx, ctx->conn);
++
++        req = ipa_id_get_account_info_send(breq, be_ctx->ev, ipa_ctx, breq,
++                                           ar);
+     }
+ 
+     if (!req) {
+@@ -115,13 +124,18 @@ static void ipa_account_info_done(struct tevent_req *req)
+     struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+     struct be_acct_req *ar = talloc_get_type(be_req_get_data(breq),
+                                              struct be_acct_req);
++    struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
+     const char *error_text;
+     int ret, dp_error;
+ 
+     if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
+         ret = ipa_id_get_netgroup_recv(req, &dp_error);
+     } else {
+-        ret = ipa_subdomain_account_recv(req, &dp_error);
++        if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
++            ret = ipa_subdomain_account_recv(req, &dp_error);
++        } else {
++            ret = ipa_id_get_account_info_recv(req, &dp_error);
++        }
+     }
+     talloc_zfree(req);
+ 
+@@ -130,6 +144,393 @@ static void ipa_account_info_done(struct tevent_req *req)
+     sdap_handler_done(breq, dp_error, ret, error_text);
+ }
+ 
++struct ipa_id_get_account_info_state {
++    struct tevent_context *ev;
++    struct ipa_id_ctx *ipa_ctx;
++    struct sdap_id_ctx *ctx;
++    struct sdap_id_op *op;
++    struct sysdb_ctx *sysdb;
++    struct sss_domain_info *domain;
++    struct be_req *be_req;
++    struct be_acct_req *ar;
++    const char *realm;
++
++    struct sysdb_attrs *override_attrs;
++    struct ldb_message *obj_msg;
++    int dp_error;
++};
++
++static void ipa_id_get_account_info_connected(struct tevent_req *subreq);
++static void ipa_id_get_account_info_got_override(struct tevent_req *subreq);
++static errno_t ipa_id_get_account_info_get_original_step(struct tevent_req *req,
++                                                        struct be_acct_req *ar);
++static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq);
++static void ipa_id_get_account_info_done(struct tevent_req *subreq);
++
++static struct tevent_req *
++ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
++                             struct ipa_id_ctx *ipa_ctx, struct be_req *be_req,
++                             struct be_acct_req *ar)
++{
++    int ret;
++    struct tevent_req *req;
++    struct tevent_req *subreq;
++    struct ipa_id_get_account_info_state *state;
++
++    req = tevent_req_create(memctx, &state,
++                            struct ipa_id_get_account_info_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
++        return NULL;
++    }
++
++    state->ev = ev;
++    state->ipa_ctx = ipa_ctx;
++    state->ctx = ipa_ctx->sdap_id_ctx;
++    state->dp_error = DP_ERR_FATAL;
++
++    state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
++    if (state->op == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
++        ret = ENOMEM;
++        goto fail;
++    }
++
++    state->domain = find_domain_by_name(state->ctx->be->domain,
++                                        ar->domain, true);
++    if (state->domain == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
++        ret = ENOMEM;
++        goto fail;
++    }
++    state->sysdb = state->domain->sysdb;
++    state->be_req = be_req;
++    state->ar = ar;
++    state->realm = dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
++                                     IPA_KRB5_REALM);
++    if (state->realm == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm for IPA?\n");
++        ret = EINVAL;
++        goto fail;
++    }
++
++    /* We can skip the override lookup and go directly to the original object
++     * if
++     * - the lookup is by SID
++     * - there is no view set of it is the default view
++     * - if the EXTRA_INPUT_MAYBE_WITH_VIEW flag is not set
++     */
++    if (state->ipa_ctx->view_name == NULL
++            || state->ar->filter_type == BE_FILTER_SECID
++            || strcmp(state->ipa_ctx->view_name,
++                      SYSDB_DEFAULT_VIEW_NAME) == 0
++            || state->ar->extra_value == NULL
++            || strcmp(state->ar->extra_value,
++                      EXTRA_INPUT_MAYBE_WITH_VIEW) != 0 ) {
++        ret = ipa_id_get_account_info_get_original_step(req, ar);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "ipa_subdomain_account_get_original_step failed.\n");
++            goto fail;
++        }
++    } else {
++        subreq = sdap_id_op_connect_send(state->op, state, &ret);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed.\n");
++            goto fail;
++        }
++        tevent_req_set_callback(subreq, ipa_id_get_account_info_connected, req);
++    }
++
++    return req;
++
++fail:
++    tevent_req_error(req, ret);
++    tevent_req_post(req, ev);
++    return req;
++}
++
++static void ipa_id_get_account_info_connected(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    int dp_error = DP_ERR_FATAL;
++    int ret;
++
++    ret = sdap_id_op_connect_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect request failed.\n");
++        goto fail;
++    }
++
++    subreq = ipa_get_ad_override_send(state, state->ev, state->ctx,
++                                      state->ipa_ctx->ipa_options, state->realm,
++                                      state->ipa_ctx->view_name, state->ar);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
++        ret = ENOMEM;
++        goto fail;
++    }
++
++    tevent_req_set_callback(subreq, ipa_id_get_account_info_got_override, req);
++
++    return;
++
++fail:
++    state->dp_error = dp_error;
++    tevent_req_error(req, ret);
++    return;
++}
++
++static void ipa_id_get_account_info_got_override(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    int dp_error = DP_ERR_FATAL;
++    int ret;
++    const char *anchor = NULL;
++    char *anchor_domain;
++    char *ipa_uuid;
++
++    ret = ipa_get_ad_override_recv(subreq, &dp_error, state,
++                                   &state->override_attrs);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
++        goto fail;
++    }
++
++    if (state->override_attrs != NULL) {
++        ret = sysdb_attrs_get_string(state->override_attrs,
++                                     SYSDB_OVERRIDE_ANCHOR_UUID,
++                                     &anchor);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
++            goto fail;
++        }
++
++        ret = split_ipa_anchor(state, anchor, &anchor_domain, &ipa_uuid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Unsupported override anchor [%s].\n", anchor);
++            ret = EINVAL;
++            goto fail;
++        }
++
++        if (strcmp(state->ar->domain, anchor_domain) == 0) {
++
++            ret = get_be_acct_req_for_uuid(state, ipa_uuid,
++                                           state->ar->domain,
++                                           &state->ar);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
++                goto fail;
++            }
++        } else {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Anchor from a different domain [%s], expected [%s]. " \
++                  "This is currently not supported, continue lookup in " \
++                  "local IPA domain.\n",
++                  anchor_domain, state->ar->domain);
++        }
++    }
++
++    ret = ipa_id_get_account_info_get_original_step(req, state->ar);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "ipa_subdomain_account_get_original_step failed.\n");
++        goto fail;
++    }
++
++    return;
++
++fail:
++    state->dp_error = dp_error;
++    tevent_req_error(req, ret);
++    return;
++}
++
++static errno_t ipa_id_get_account_info_get_original_step(struct tevent_req *req,
++                                                         struct be_acct_req *ar)
++{
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    struct tevent_req *subreq;
++
++    subreq = sdap_handle_acct_req_send(state, state->be_req, ar,
++                                       state->ipa_ctx->sdap_id_ctx,
++                                       state->ipa_ctx->sdap_id_ctx->opts->sdom,
++                                       state->ipa_ctx->sdap_id_ctx->conn, true);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct_req_send failed.\n");
++        return ENOMEM;
++    }
++    tevent_req_set_callback(subreq, ipa_id_get_account_info_orig_done, req);
++
++    return EOK;
++}
++
++static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    int dp_error = DP_ERR_FATAL;
++    int ret;
++    const char *uuid;
++    const char *class;
++    enum sysdb_member_type type;
++
++    ret = sdap_handle_acct_req_recv(subreq, &dp_error, NULL, NULL);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct request failed: %d\n", ret);
++        goto fail;
++    }
++
++    ret = get_object_from_cache(state, state->domain, state->ar,
++                                &state->obj_msg);
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Object not found, ending request\n");
++        tevent_req_done(req);
++        return;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n");
++        goto fail;
++    }
++
++    if (state->override_attrs == NULL) {
++        uuid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_UUID, NULL);
++        if (uuid == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find a UUID.\n");
++            ret = EINVAL;
++            goto fail;
++        }
++
++        ret = get_be_acct_req_for_uuid(state, uuid, state->domain->name,
++                                       &state->ar);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
++            goto fail;
++        }
++
++        subreq = ipa_get_ad_override_send(state, state->ev,
++                                          state->ipa_ctx->sdap_id_ctx,
++                                          state->ipa_ctx->ipa_options,
++                                          state->realm,
++                                          state->ipa_ctx->view_name,
++                                          state->ar);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
++            ret = ENOMEM;
++            goto fail;
++        }
++        tevent_req_set_callback(subreq, ipa_id_get_account_info_done, req);
++        return;
++    } else {
++        class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCLASS,
++                                            NULL);
++        if (class == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find an objectclass.\n");
++            ret = EINVAL;
++            goto fail;
++        }
++
++        if (strcmp(class, SYSDB_USER_CLASS) == 0) {
++            type = SYSDB_MEMBER_USER;
++        } else {
++            type = SYSDB_MEMBER_GROUP;
++        }
++
++        ret = sysdb_store_override(state->domain, state->ipa_ctx->view_name,
++                                   type,
++                                   state->override_attrs, state->obj_msg->dn);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_override failed.\n");
++            goto fail;
++        }
++    }
++
++    state->dp_error = DP_ERR_OK;
++    tevent_req_done(req);
++    return;
++
++fail:
++    state->dp_error = dp_error;
++    tevent_req_error(req, ret);
++    return;
++}
++
++static void ipa_id_get_account_info_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    int dp_error = DP_ERR_FATAL;
++    int ret;
++    const char *class;
++    enum sysdb_member_type type;
++
++    ret = ipa_get_ad_override_recv(subreq, &dp_error, state,
++                                   &state->override_attrs);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
++        goto fail;
++    }
++
++    class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCLASS,
++                                        NULL);
++    if (class == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find an objectclass.\n");
++        ret = EINVAL;
++        goto fail;
++    }
++
++    if (strcmp(class, SYSDB_USER_CLASS) == 0) {
++        type = SYSDB_MEMBER_USER;
++    } else {
++        type = SYSDB_MEMBER_GROUP;
++    }
++
++    ret = sysdb_store_override(state->domain, state->ipa_ctx->view_name,
++                               type,
++                               state->override_attrs, state->obj_msg->dn);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_override failed.\n");
++        goto fail;
++    }
++
++    state->dp_error = DP_ERR_OK;
++    tevent_req_done(req);
++    return;
++
++fail:
++    state->dp_error = dp_error;
++    tevent_req_error(req, ret);
++    return;
++}
++
++static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error)
++{
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++
++    if (dp_error) {
++        *dp_error = state->dp_error;
++    }
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    return EOK;
++}
+ 
+ /* Request for netgroups
+  * - first start here and then go to ipa_netgroups.c
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 891fc336483b507fd284b0c84b118534910ed9fc..ce5a6d1a1048eda4d8b7017bd92bc7ee76e66ef9 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -879,9 +879,21 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+ 
+         ret = EOK;
+         goto done;
+-    }
++    } else if (ar->filter_type == BE_FILTER_UUID) {
++        ret = sysdb_search_object_by_uuid(mem_ctx, dom, ar->filter_value, attrs,
++                                          &res);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "Failed to make request to our cache: [%d]: [%s]\n",
++                   ret, sss_strerror(ret));
++            goto done;
++        }
+ 
+-    if (ar->filter_type == BE_FILTER_IDNUM) {
++        *_msg = res->msgs[0];
++
++        ret = EOK;
++        goto done;
++    } else if (ar->filter_type == BE_FILTER_IDNUM) {
+         errno = 0;
+         id = strtouint32(ar->filter_value, NULL, 10);
+         if (errno != 0) {
+diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
+index ee586894ec61b1b1330816c628bbc9617d58e31e..c768186d7cf5e5a997e2ca27a167b62c8dc99b3f 100644
+--- a/src/providers/ipa/ipa_views.c
++++ b/src/providers/ipa/ipa_views.c
+@@ -125,6 +125,21 @@ static errno_t be_acct_req_to_override_filter(TALLOC_CTX *mem_ctx,
+         }
+         break;
+ 
++    case BE_FILTER_UUID:
++        if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_UUID) {
++            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=:IPA:%s:%s))",
++                       ipa_opts->override_map[IPA_OC_OVERRIDE].name,
++                       ipa_opts->override_map[IPA_AT_OVERRIDE_ANCHOR_UUID].name,
++                       dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN),
++                       ar->filter_value);
++        } else {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Unexpected entry type [%d] for UUID filter.\n",
++                  ar->entry_type);
++            return EINVAL;
++        }
++        break;
++
+     default:
+         DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
+         return EINVAL;
+-- 
+1.9.3
+
diff --git a/SOURCES/0101-libsss_idmap-bump-version-info.patch b/SOURCES/0101-libsss_idmap-bump-version-info.patch
deleted file mode 100644
index d40eb17..0000000
--- a/SOURCES/0101-libsss_idmap-bump-version-info.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From e5792a6be9c3c75c7ec47af873309668f1943ae2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 26 Feb 2014 20:50:19 +0100
-Subject: [PATCH 101/101] libsss_idmap: bump version-info
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit 034ffb3c69cd04f03b36b89766c47a7c9bd9b831)
----
- Makefile.am | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index 9025ec6a5bfa16408278506fdd573666b4b6dbe5..879054c2fb96f937fbd58ca0757d703cdea218d8 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -614,7 +614,7 @@ libsss_idmap_la_SOURCES = \
-     src/lib/idmap/sss_idmap_conv.c \
-     src/util/murmurhash3.c
- libsss_idmap_la_LDFLAGS = \
--    -version-info 3:0:3
-+    -version-info 4:0:4
- 
- dist_pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc
- libsss_nss_idmap_la_SOURCES = \
--- 
-1.8.5.3
-
diff --git a/SOURCES/0102-Enable-views-for-all-domains.patch b/SOURCES/0102-Enable-views-for-all-domains.patch
new file mode 100644
index 0000000..877c138
--- /dev/null
+++ b/SOURCES/0102-Enable-views-for-all-domains.patch
@@ -0,0 +1,32 @@
+From 0271a86e2c1efd248b3c8df14178d0d401f92d08 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 7 Nov 2014 21:36:12 +0100
+Subject: [PATCH 102/104] Enable views for all domains
+
+Currently views and overrides were only available for sub-domains, this
+patch enables the lookup for the configured domains as well.
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/util/util.h | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/src/util/util.h b/src/util/util.h
+index ffc8a87eafa4c4b8271d195c7d27fd10f5aa3568..7c335b9a2ac2599304731082845fd382dc62465f 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -574,8 +574,7 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
+ 
+ #define IS_SUBDOMAIN(dom) ((dom)->parent != NULL)
+ 
+-/* Currently views are only supported for subdomains */
+-#define DOM_HAS_VIEWS(dom) ((dom)->has_views && IS_SUBDOMAIN(dom))
++#define DOM_HAS_VIEWS(dom) ((dom)->has_views)
+ 
+ errno_t sss_write_domain_mappings(struct sss_domain_info *domain);
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0102-config-API-add-missing-subdomain-target-to-AD-provid.patch b/SOURCES/0102-config-API-add-missing-subdomain-target-to-AD-provid.patch
deleted file mode 100644
index 3c91933..0000000
--- a/SOURCES/0102-config-API-add-missing-subdomain-target-to-AD-provid.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 565ae8c3bec0dd3f1cb618b3766a907b820625ca Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 28 Feb 2014 10:04:08 +0100
-Subject: [PATCH 102/104] config API: add missing subdomain target to AD
- provider test
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit b564424a77c7c3b361c944e0623023d0cfea2c9f)
----
- src/config/SSSDConfigTest.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
-index b6c1d74aa42917fde1222f90f99cb343c80d921a..e6cf663ec86396a3d50dcbc14d4cf4d1157b0d5d 100755
---- a/src/config/SSSDConfigTest.py
-+++ b/src/config/SSSDConfigTest.py
-@@ -730,7 +730,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
-         control_provider_dict = {
-             'ipa': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs',
-                     'session', 'hostid', 'subdomains'],
--            'ad': ['id', 'auth', 'access', 'chpass'],
-+            'ad': ['id', 'auth', 'access', 'chpass', 'subdomains'],
-             'local': ['id', 'auth', 'chpass'],
-             'ldap': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs'],
-             'krb5': ['auth', 'access', 'chpass'],
--- 
-1.8.5.3
-
diff --git a/SOURCES/0103-MAN-Update-case_sensitive-Preserving-in-man-pages.patch b/SOURCES/0103-MAN-Update-case_sensitive-Preserving-in-man-pages.patch
new file mode 100644
index 0000000..e91c003
--- /dev/null
+++ b/SOURCES/0103-MAN-Update-case_sensitive-Preserving-in-man-pages.patch
@@ -0,0 +1,31 @@
+From 834ab87e8f5a3f9937e0997cb5427e205959d344 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Wed, 12 Nov 2014 15:47:11 +0100
+Subject: [PATCH 103/104] MAN: Update case_sensitive=Preserving in man pages.
+
+https://fedorahosted.org/sssd/ticket/2462
+---
+ src/man/sssd.conf.5.xml | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index fbaca66724f7023dfa6068c225d6f61af0e662bb..5f801f25690f4f7c15b8e030968c6d052daa3812 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2013,8 +2013,11 @@ fallback_homedir = /home/%u
+                                 <listitem>
+                                     <para>
+                                         Same as False (case insensitive), but
+-                                        does not lowercase names in the output
+-                                        of getpwnam and getgrnam.
++                                        does not lowercase names in the result
++                                        of NSS operations. Note that name
++                                        aliases (and in case of services also
++                                        protocol names) are still lowercased in
++                                        the output.
+                                     </para>
+                                 </listitem>
+                             </varlistentry>
+-- 
+1.9.3
+
diff --git a/SOURCES/0103-SUDO-AD-provider.patch b/SOURCES/0103-SUDO-AD-provider.patch
deleted file mode 100644
index a456185..0000000
--- a/SOURCES/0103-SUDO-AD-provider.patch
+++ /dev/null
@@ -1,244 +0,0 @@
-From a15ab6146ebba795e3b58d5f32cf7a1d8653c082 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 28 Feb 2014 10:05:34 +0100
-Subject: [PATCH 103/104] SUDO: AD provider
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch adds the sudo target to the AD provider. The main reason is
-to cover different default settings in the LDAP and AD provider. E.g.
-the default for ldap_id_mapping is True in the AD provider and False
-in the LDAP provider. If ldap_id_mapping was not set explicitly in the
-config file both components worked with different setting.
-
-Fixes https://fedorahosted.org/sssd/ticket/2256
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 61804568ce5ede3b1a699cda17c033dd6c23f0e3)
----
- Makefile.am                            |  5 ++++
- src/config/SSSDConfigTest.py           |  2 +-
- src/config/etc/sssd.api.d/sssd-ad.conf | 21 ++++++++++++++
- src/man/sssd-ad.5.xml                  |  6 ++--
- src/man/sssd.conf.5.xml                | 15 ++++++++--
- src/providers/ad/ad_common.h           |  4 +++
- src/providers/ad/ad_init.c             | 25 +++++++++++++++++
- src/providers/ad/ad_sudo.c             | 51 ++++++++++++++++++++++++++++++++++
- 8 files changed, 122 insertions(+), 7 deletions(-)
- create mode 100644 src/providers/ad/ad_sudo.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 879054c2fb96f937fbd58ca0757d703cdea218d8..b37c04067d34569ad357327b7d463cc5b052f065 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1803,6 +1803,11 @@ libsss_ad_la_SOURCES = \
-     src/util/sss_krb5.c \
-     src/util/sss_ldap.c
- 
-+if BUILD_SUDO
-+libsss_ad_la_SOURCES += \
-+    src/providers/ad/ad_sudo.c
-+endif
-+
- libsss_ad_la_CFLAGS = \
-     $(AM_CFLAGS) \
-     $(LDAP_CFLAGS) \
-diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
-index e6cf663ec86396a3d50dcbc14d4cf4d1157b0d5d..98b2fee63d519201047b0c576295863d59b0a37a 100755
---- a/src/config/SSSDConfigTest.py
-+++ b/src/config/SSSDConfigTest.py
-@@ -730,7 +730,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
-         control_provider_dict = {
-             'ipa': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs',
-                     'session', 'hostid', 'subdomains'],
--            'ad': ['id', 'auth', 'access', 'chpass', 'subdomains'],
-+            'ad': ['id', 'auth', 'access', 'chpass', 'sudo', 'subdomains'],
-             'local': ['id', 'auth', 'chpass'],
-             'ldap': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs'],
-             'krb5': ['auth', 'access', 'chpass'],
-diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
-index 6b136f2ec88614092cf1ceb4e2cea79db064d468..aa20ca0bb5b70818525d61a1480a6b56bd8c4e48 100644
---- a/src/config/etc/sssd.api.d/sssd-ad.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
-@@ -132,3 +132,24 @@ krb5_kpasswd = str, None, false
- krb5_backup_kpasswd = str, None, false
- 
- [provider/ad/subdomains]
-+
-+[provider/ad/sudo]
-+ldap_sudo_search_base = str, None, false
-+ldap_sudo_full_refresh_interval = int, None, false
-+ldap_sudo_smart_refresh_interval = int, None, false
-+ldap_sudo_use_host_filter = bool, None, false
-+ldap_sudo_hostnames = str, None, false
-+ldap_sudo_ip = str, None, false
-+ldap_sudo_include_netgroups = bool, None, false
-+ldap_sudo_include_regexp = bool, None, false
-+ldap_sudorule_object_class = str, None, false
-+ldap_sudorule_name = str, None, false
-+ldap_sudorule_command = str, None, false
-+ldap_sudorule_host = str, None, false
-+ldap_sudorule_user = str, None, false
-+ldap_sudorule_option = str, None, false
-+ldap_sudorule_runasuser = str, None, false
-+ldap_sudorule_runasgroup = str, None, false
-+ldap_sudorule_notbefore = str, None, false
-+ldap_sudorule_notafter = str, None, false
-+ldap_sudorule_order = str, None, false
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 38cc31278cf87c98ca9e53cf91fda7b141bff78d..8cd94d4aeaf553ecb54e0e4c866be5fb7a44fa8e 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -60,9 +60,9 @@
-         </para>
-         <para>
-             However, it is neither necessary nor recommended to set these
--            options. The AD provider can also be used as an access and chpass
--            provider. No configuration of the access provider is required on
--            the client side.
-+            options. The AD provider can also be used as an access, chpass and
-+            sudo provider. No configuration of the access provider is required
-+            on the client side.
-         </para>
-         <para>
-             By default, the AD provider will map UID and GID values from the
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 5d861c73cfeb41920619d95e5c1e5c1975dcc45b..29b08d53d2568f2fce47b37ea0b88c9dc233c12e 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -1450,14 +1450,23 @@ fallback_homedir = /home/%u
-                             <citerefentry>
-                                 <refentrytitle>sssd-ldap</refentrytitle>
-                                 <manvolnum>5</manvolnum>
--                            </citerefentry> for more information on configuring LDAP.
-+                            </citerefentry> for more information on configuring
-+                            LDAP.
-+                        </para>
-+                        <para>
-+                            <quote>ipa</quote> the same as <quote>ldap</quote>
-+                            but with IPA default settings.
-+                        </para>
-+                        <para>
-+                            <quote>ad</quote> the same as <quote>ldap</quote>
-+                            but with AD default settings.
-                         </para>
-                         <para>
-                             <quote>none</quote> disables SUDO explicitly.
-                         </para>
-                         <para>
--                            Default: The value of <quote>id_provider</quote> is used if it
--                            is set.
-+                            Default: The value of <quote>id_provider</quote> is
-+                            used if it is set.
-                         </para>
-                     </listitem>
-                 </varlistentry>
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index d370cef69124c127f41d7c4cbaa25713363e7752..bc11e54b0c4903c876f23bfea3ef573f06ba8c69 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -128,4 +128,8 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
-                        struct ad_options *ctx);
- void ad_dyndns_timer(void *pvt);
- 
-+int ad_sudo_init(struct be_ctx *be_ctx,
-+                 struct ad_id_ctx *id_ctx,
-+                 struct bet_ops **ops,
-+                 void **pvt_data);
- #endif /* AD_COMMON_H_ */
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index eff6d990d131e3aba124d252d001dd39e78b45cf..500d807e9c44e92089d31c81f3b22c9606c476e5 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -467,3 +467,28 @@ int sssm_ad_subdomains_init(struct be_ctx *bectx,
- 
-     return EOK;
- }
-+
-+
-+int sssm_ad_sudo_init(struct be_ctx *bectx,
-+                      struct bet_ops **ops,
-+                      void **pvt_data)
-+{
-+#ifdef BUILD_SUDO
-+    struct ad_id_ctx *id_ctx;
-+    int ret;
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL, ("Initializing AD sudo handler\n"));
-+
-+    ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("sssm_ad_id_init failed.\n"));
-+        return ret;
-+    }
-+
-+    return ad_sudo_init(bectx, id_ctx, ops, pvt_data);
-+#else
-+    DEBUG(SSSDBG_MINOR_FAILURE, ("Sudo init handler called but SSSD is "
-+                                 "built without sudo support, ignoring\n"));
-+    return EOK;
-+#endif
-+}
-diff --git a/src/providers/ad/ad_sudo.c b/src/providers/ad/ad_sudo.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..b85c95c5c2f44e116a75bc24e073c067806621dd
---- /dev/null
-+++ b/src/providers/ad/ad_sudo.c
-@@ -0,0 +1,51 @@
-+/*
-+    SSSD
-+
-+    AD SUDO Provider Initialization functions
-+
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2014 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include "providers/ad/ad_common.h"
-+#include "providers/ldap/sdap_sudo.h"
-+
-+int ad_sudo_init(struct be_ctx *be_ctx,
-+                 struct ad_id_ctx *id_ctx,
-+                 struct bet_ops **ops,
-+                 void **pvt_data)
-+{
-+    int ret;
-+    struct ad_options *ad_options;
-+    struct sdap_options *ldap_options;
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL, ("Initializing sudo AD back end\n"));
-+
-+    ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize LDAP SUDO [%d]: %s\n",
-+                                 ret, strerror(ret)));
-+        return ret;
-+    }
-+
-+    ad_options = id_ctx->ad_options;
-+    ldap_options = id_ctx->sdap_id_ctx->opts;
-+
-+    ad_options->id->sudorule_map = ldap_options->sudorule_map;
-+    return EOK;
-+}
--- 
-1.8.5.3
-
diff --git a/SOURCES/0104-Man-debug_timestamps-and-debug_microseconds.patch b/SOURCES/0104-Man-debug_timestamps-and-debug_microseconds.patch
new file mode 100644
index 0000000..f8d95aa
--- /dev/null
+++ b/SOURCES/0104-Man-debug_timestamps-and-debug_microseconds.patch
@@ -0,0 +1,44 @@
+From 4eca230459561aa3b9bac96eebcbdd03b65777b2 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Thu, 13 Nov 2014 17:41:56 +0100
+Subject: [PATCH 104/104] Man: debug_timestamps and debug_microseconds
+
+Add note that these two options are ignored if
+journald is used.
+
+https://fedorahosted.org/sssd/ticket/2498
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/man/sssd.conf.5.xml | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 5f801f25690f4f7c15b8e030968c6d052daa3812..3525d78caff28fd05cc18061d023fec3c50d1a47 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -73,7 +73,9 @@
+                     <term>debug_timestamps (bool)</term>
+                     <listitem>
+                         <para>
+-                            Add a timestamp to the debug messages
++                            Add a timestamp to the debug messages.
++                            If journald is enabled for SSSD debug logging this
++                            option is ignored.
+                         </para>
+                         <para>
+                             Default: true
+@@ -84,7 +86,9 @@
+                     <term>debug_microseconds (bool)</term>
+                     <listitem>
+                         <para>
+-                            Add microseconds to the timestamp in debug messages
++                            Add microseconds to the timestamp in debug messages.
++                            If journald is enabled for SSSD debug logging this
++                            option is ignored.
+                         </para>
+                         <para>
+                             Default: false
+-- 
+1.9.3
+
diff --git a/SOURCES/0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch b/SOURCES/0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch
deleted file mode 100644
index 4071e9b..0000000
--- a/SOURCES/0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From 3b8640e8ef5cbcf934cdd6f42e9f6d956ca47395 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 3 Mar 2014 12:40:43 +0100
-Subject: [PATCH 104/104] ipa-server-mode: use lower-case user name for home
- dir
-
-In older IPA server versions where the AD users where looked up by
-winbind the user name component of the home directory path was always
-lower case.  This still holds for IPA clients as well. To avoid
-regression this patch makes the user name component lower case as well.
-
-Fixes https://fedorahosted.org/sssd/ticket/2263
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 48b1db73639135dd4a15ee153f958c912836c621)
----
- src/providers/ipa/ipa_subdomains_id.c | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 637dd61f9f272eb4ac4ecb8368d2210801bb0373..00993c496c1d100b37a780828c81492c2fac6157 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -358,6 +358,7 @@ get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
- {
-     errno_t ret;
-     char *name;
-+    char *lc_name;
-     const char *homedir;
-     TALLOC_CTX *tmp_ctx;
- 
-@@ -372,7 +373,15 @@ get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-         goto done;
-     }
- 
--    homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir, name,
-+    /* To be compatible with the old winbind based user lookups and IPA
-+     * clients the user name in the home directory path will be lower-case. */
-+    lc_name = sss_tc_utf8_str_tolower(tmp_ctx, name);
-+    if (lc_name == NULL) {
-+        ret =ENOMEM;
-+        goto done;
-+    }
-+
-+    homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir, lc_name,
-                                       uid, NULL, dom->name, dom->flat_name);
- 
-     if (homedir == NULL) {
--- 
-1.8.5.3
-
diff --git a/SOURCES/0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch b/SOURCES/0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch
deleted file mode 100644
index ba7de59..0000000
--- a/SOURCES/0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From 4fc9c7b11aa64a151d19b908ca07d8b16b6657ff Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 4 Mar 2014 13:48:36 +0100
-Subject: [PATCH 105/105] IPA: Do not save intermediate data to sysdb
-
-https://fedorahosted.org/sssd/ticket/2264
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/providers/ipa/ipa_selinux.c | 68 ++++++++++++++++++++---------------------
- 1 file changed, 34 insertions(+), 34 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
-index c227db937a84228c0f3945dbe11ba904c7ad9744..2209ca188654d8c79ee402ba71beeadab2904093 100644
---- a/src/providers/ipa/ipa_selinux.c
-+++ b/src/providers/ipa/ipa_selinux.c
-@@ -251,6 +251,40 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
-         goto fail;
-     }
- 
-+    ret = sysdb_transaction_start(sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
-+        goto fail;
-+    }
-+    in_transaction = true;
-+
-+    ret = sysdb_delete_usermaps(op_ctx->domain->sysdb, op_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              ("Cannot delete existing maps from sysdb\n"));
-+        goto fail;
-+    }
-+
-+    ret = sysdb_store_selinux_config(sysdb, op_ctx->domain,
-+                                     default_user, map_order);
-+    if (ret != EOK) {
-+        goto fail;
-+    }
-+
-+    if (map_count > 0 && maps != NULL) {
-+        ret = ipa_save_user_maps(sysdb, op_ctx->domain, map_count, maps);
-+        if (ret != EOK) {
-+            goto fail;
-+        }
-+    }
-+
-+    ret = sysdb_transaction_commit(sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n"));
-+        goto fail;
-+    }
-+    in_transaction = false;
-+
-     /* Process the maps and return list of best matches (maps with
-      * highest priority). The input maps are also parent memory
-      * context for the output list of best matches. The best match
-@@ -279,40 +313,6 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
-         goto fail;
-     }
- 
--    ret = sysdb_transaction_start(sysdb);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
--        goto fail;
--    }
--    in_transaction = true;
--
--    ret = sysdb_delete_usermaps(op_ctx->domain->sysdb, op_ctx->domain);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              ("Cannot delete existing maps from sysdb\n"));
--        goto fail;
--    }
--
--    ret = sysdb_store_selinux_config(sysdb, op_ctx->domain,
--                                     default_user, map_order);
--    if (ret != EOK) {
--        goto fail;
--    }
--
--    if (map_count > 0 && maps != NULL) {
--        ret = ipa_save_user_maps(sysdb, op_ctx->domain, map_count, maps);
--        if (ret != EOK) {
--            goto fail;
--        }
--    }
--
--    ret = sysdb_transaction_commit(sysdb);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n"));
--        goto fail;
--    }
--    in_transaction = false;
--
-     /* If we got here in online mode, set last_update to current time */
-     if (!be_is_offline(be_ctx)) {
-         op_ctx->selinux_ctx->last_update = time(NULL);
--- 
-1.8.5.3
-
diff --git a/SOURCES/0105-sss_client-Extract-destroying-of-mmap-cache-to-funct.patch b/SOURCES/0105-sss_client-Extract-destroying-of-mmap-cache-to-funct.patch
new file mode 100644
index 0000000..dd197e2
--- /dev/null
+++ b/SOURCES/0105-sss_client-Extract-destroying-of-mmap-cache-to-funct.patch
@@ -0,0 +1,72 @@
+From 82d37e1a84202d3609ceb70aaf0893199ec0e464 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 21 Nov 2014 14:00:23 +0100
+Subject: [PATCH 105/112] sss_client: Extract destroying of mmap cache to
+ function
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/sss_client/nss_mc_common.c | 30 ++++++++++++++----------------
+ 1 file changed, 14 insertions(+), 16 deletions(-)
+
+diff --git a/src/sss_client/nss_mc_common.c b/src/sss_client/nss_mc_common.c
+index 6c9b35de280c637bf957207993e539c889b16c23..9c6e1af1642275fc7738b51d7ca80d712d49b2ac 100644
+--- a/src/sss_client/nss_mc_common.c
++++ b/src/sss_client/nss_mc_common.c
+@@ -102,6 +102,18 @@ errno_t sss_nss_check_header(struct sss_cli_mc_ctx *ctx)
+     return 0;
+ }
+ 
++static void sss_nss_mc_destroy_ctx(struct sss_cli_mc_ctx *ctx)
++{
++    if ((ctx->mmap_base != NULL) && (ctx->mmap_size != 0)) {
++        munmap(ctx->mmap_base, ctx->mmap_size);
++    }
++    if (ctx->fd != -1) {
++        close(ctx->fd);
++    }
++    memset(ctx, 0, sizeof(struct sss_cli_mc_ctx));
++    ctx->fd = -1;
++}
++
+ static errno_t sss_nss_mc_init_ctx(const char *name,
+                                    struct sss_cli_mc_ctx *ctx)
+ {
+@@ -157,14 +169,7 @@ static errno_t sss_nss_mc_init_ctx(const char *name,
+ 
+ done:
+     if (ret) {
+-        if ((ctx->mmap_base != NULL) && (ctx->mmap_size != 0)) {
+-            munmap(ctx->mmap_base, ctx->mmap_size);
+-        }
+-        if (ctx->fd != -1) {
+-            close(ctx->fd);
+-        }
+-        memset(ctx, 0, sizeof(struct sss_cli_mc_ctx));
+-        ctx->fd = -1;
++        sss_nss_mc_destroy_ctx(ctx);
+     }
+     free(file);
+     sss_nss_unlock();
+@@ -191,14 +196,7 @@ errno_t sss_nss_mc_get_ctx(const char *name, struct sss_cli_mc_ctx *ctx)
+ 
+ done:
+     if (ret) {
+-        if ((ctx->mmap_base != NULL) && (ctx->mmap_size != 0)) {
+-            munmap(ctx->mmap_base, ctx->mmap_size);
+-        }
+-        if (ctx->fd != -1) {
+-            close(ctx->fd);
+-        }
+-        memset(ctx, 0, sizeof(struct sss_cli_mc_ctx));
+-        ctx->fd = -1;
++        sss_nss_mc_destroy_ctx(ctx);
+     }
+     return ret;
+ }
+-- 
+1.9.3
+
diff --git a/SOURCES/0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch b/SOURCES/0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch
deleted file mode 100644
index 5c7b4a8..0000000
--- a/SOURCES/0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-From bbe47ea8ebe6373d0b05181eb27bb65432a9cc97 Mon Sep 17 00:00:00 2001
-From: Nathaniel McCallum <npmccallum@redhat.com>
-Date: Fri, 7 Mar 2014 12:21:11 -0500
-Subject: [PATCH 106/107] Fix krb5 changepw when FAST-only preauth methods are
- used (like OTP)
-
-Before this patch, a different set of options was used when calling
-krb5_get_init_creds_password() for the changepw principal. Because
-this set of options did not contain the same FAST settings as the
-options for normal requests, all authentication would fail when the
-password of a FAST-only account would expire.
-
-The two sets approach was cargo-cult from kinit where multiple
-requests could be issued using the same options set. However, in the
-case of krb5_child, only one request (or occasionally a well-defined
-second request) will be issued. Two option sets are therefore not
-required.
-
-To fix this problem we removed the second option set used for changepw
-requests. All requests now use a single option set which is modified,
-if needed, for well-defined subsequent requests.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/providers/krb5/krb5_child.c | 40 ++++++----------------------------------
- 1 file changed, 6 insertions(+), 34 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index aa29de0cb4e14ea4804ba660b4b8e9b64e9e340e..461a27464f4fea09d4ca430b53aff072b29de141 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -65,27 +65,14 @@ struct krb5_req {
- static krb5_context krb5_error_ctx;
- #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
- 
--static krb5_error_code get_changepw_options(krb5_context ctx,
--                                            krb5_get_init_creds_opt **_options)
-+static void set_changepw_options(krb5_context ctx,
-+                                 krb5_get_init_creds_opt *options)
- {
--    krb5_get_init_creds_opt *options;
--    krb5_error_code kerr;
--
--    kerr = sss_krb5_get_init_creds_opt_alloc(ctx, &options);
--    if (kerr != 0) {
--        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
--        return kerr;
--    }
--
-     sss_krb5_get_init_creds_opt_set_canonicalize(options, 0);
-     krb5_get_init_creds_opt_set_forwardable(options, 0);
-     krb5_get_init_creds_opt_set_proxiable(options, 0);
-     krb5_get_init_creds_opt_set_renew_life(options, 0);
-     krb5_get_init_creds_opt_set_tkt_life(options, 5*60);
--
--    *_options = options;
--
--    return 0;
- }
- 
- static errno_t sss_send_pac(krb5_authdata **pac_authdata)
-@@ -1023,7 +1010,6 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
-     krb5_prompter_fct prompter = NULL;
-     const char *realm_name;
-     int realm_length;
--    krb5_get_init_creds_opt *chagepw_options;
-     size_t msg_len;
-     uint8_t *msg;
- 
-@@ -1041,12 +1027,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
-         prompter = sss_krb5_prompter;
-     }
- 
--    kerr = get_changepw_options(kr->ctx, &chagepw_options);
--    if (kerr != 0) {
--        DEBUG(SSSDBG_OP_FAILURE, ("get_changepw_options failed.\n"));
--        return kerr;
--    }
--
-+    set_changepw_options(kr->ctx, kr->options);
-     sss_krb5_princ_realm(kr->ctx, kr->princ, &realm_name, &realm_length);
- 
-     DEBUG(SSSDBG_TRACE_FUNC,
-@@ -1055,8 +1036,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
-                                         discard_const(password),
-                                         prompter, kr, 0,
-                                         SSSD_KRB5_CHANGEPW_PRINCIPAL,
--                                        chagepw_options);
--    sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options);
-+                                        kr->options);
-     if (kerr != 0) {
-         ret = pack_user_info_chpass_error(kr->pd, "Old password not accepted.",
-                                           &msg_len, &msg);
-@@ -1164,7 +1144,6 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
- 
- static errno_t tgt_req_child(struct krb5_req *kr)
- {
--    krb5_get_init_creds_opt *chagepw_options;
-     const char *password = NULL;
-     krb5_error_code kerr;
-     int ret;
-@@ -1210,19 +1189,12 @@ static errno_t tgt_req_child(struct krb5_req *kr)
-         DEBUG(1, ("Failed to unset expire callback, continue ...\n"));
-     }
- 
--    kerr = get_changepw_options(kr->ctx, &chagepw_options);
--    if (kerr != 0) {
--        DEBUG(SSSDBG_OP_FAILURE, ("get_changepw_options failed.\n"));
--        return kerr;
--    }
--
-+    set_changepw_options(kr->ctx, kr->options);
-     kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
-                                         discard_const(password),
-                                         sss_krb5_prompter, kr, 0,
-                                         SSSD_KRB5_CHANGEPW_PRINCIPAL,
--                                        chagepw_options);
--
--    sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options);
-+                                        kr->options);
- 
-     krb5_free_cred_contents(kr->ctx, kr->creds);
-     if (kerr == 0) {
--- 
-1.8.5.3
-
diff --git a/SOURCES/0106-sss_client-Fix-race-condition-in-memory-cache.patch b/SOURCES/0106-sss_client-Fix-race-condition-in-memory-cache.patch
new file mode 100644
index 0000000..40d08e9
--- /dev/null
+++ b/SOURCES/0106-sss_client-Fix-race-condition-in-memory-cache.patch
@@ -0,0 +1,243 @@
+From 15240b29d55cfd775221cc6482407c1172e2a5a1 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 21 Nov 2014 11:28:36 +0100
+Subject: [PATCH 106/112] sss_client: Fix race condition in memory cache
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Thread safe initialisation was fixed in ticket #2380, but there is
+still race condition in reinitialisation.
+
+If caches is invalidated with command sss_cache -U (-G or -E) then
+client code will need to reinitialize fast memory cache.
+Let say we have two threads. The 1st thread find out that memory cache
+should be reinitialized; therefore the fast memory cached is unmapped
+and context destroyed. In the same time, 2nd thread tried to check
+header of memory cache whether it is initialized and valid. As a result
+of previously unmapped memory the 2nd thread access
+out of bound memory (SEGFAULT).
+
+The destroying of fast memory cache cannot be done any time. We need
+to be sure that there isn't any other thread which uses mmaped memory.
+The new counter of active threads was added for this purpose. The state
+of fast memory cache was converted from boolean to three value state
+(UNINITIALIZED, INITIALIZED, RECYCLED)
+UNINITIALIZED
+    - the fast memory cache need to be initialized.
+    - if there is a problem with initialisation the state will not change
+    - after successful initialisation, the state will change to INITIALIZED
+INITIALIZED
+    - if the cahe was invalidated or there is any other problem was
+      detected in memory cache header the state will change to RECYCLED
+      and memory cache IS NOT destroyed.
+RECYCLED
+    - nothing will be done is there are any active threads which may use
+      the data from mmaped memory
+    - if there aren't active threads the fast memory cahe is destroyed and
+      state is changed to UNINITIALIZED.
+
+https://fedorahosted.org/sssd/ticket/2445
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/sss_client/nss_mc.h        | 10 ++++++++-
+ src/sss_client/nss_mc_common.c | 46 ++++++++++++++++++++++++++++++++++--------
+ src/sss_client/nss_mc_group.c  |  8 ++++++--
+ src/sss_client/nss_mc_passwd.c |  8 ++++++--
+ 4 files changed, 59 insertions(+), 13 deletions(-)
+
+diff --git a/src/sss_client/nss_mc.h b/src/sss_client/nss_mc.h
+index 685cc41c0530750d890050f0917dc88be14d96ea..050bd4100dec091cb096a7d97bfe6615b12654da 100644
+--- a/src/sss_client/nss_mc.h
++++ b/src/sss_client/nss_mc.h
+@@ -33,9 +33,15 @@
+ typedef int errno_t;
+ #endif
+ 
++enum sss_mc_state {
++    UNINITIALIZED = 0,
++    INITIALIZED,
++    RECYCLED,
++};
++
+ /* common stuff */
+ struct sss_cli_mc_ctx {
+-    bool initialized;
++    enum sss_mc_state initialized;
+     int fd;
+ 
+     uint32_t seed;          /* seed from the tables header */
+@@ -48,6 +54,8 @@ struct sss_cli_mc_ctx {
+ 
+     uint32_t *hash_table;   /* hash table address (in mmap) */
+     uint32_t ht_size;       /* size of hash table */
++
++    uint32_t active_threads; /* count of threads which use memory cache */
+ };
+ 
+ errno_t sss_nss_mc_get_ctx(const char *name, struct sss_cli_mc_ctx *ctx);
+diff --git a/src/sss_client/nss_mc_common.c b/src/sss_client/nss_mc_common.c
+index 9c6e1af1642275fc7738b51d7ca80d712d49b2ac..89ff6b46e2abee03039cfd632ef50231eab92eec 100644
+--- a/src/sss_client/nss_mc_common.c
++++ b/src/sss_client/nss_mc_common.c
+@@ -123,7 +123,7 @@ static errno_t sss_nss_mc_init_ctx(const char *name,
+ 
+     sss_nss_lock();
+     /* check if ctx is initialised by previous thread. */
+-    if (ctx->initialized) {
++    if (ctx->initialized != UNINITIALIZED) {
+         ret = sss_nss_check_header(ctx);
+         goto done;
+     }
+@@ -163,7 +163,7 @@ static errno_t sss_nss_mc_init_ctx(const char *name,
+         goto done;
+     }
+ 
+-    ctx->initialized = true;
++    ctx->initialized = INITIALIZED;
+ 
+     ret = 0;
+ 
+@@ -181,22 +181,52 @@ errno_t sss_nss_mc_get_ctx(const char *name, struct sss_cli_mc_ctx *ctx)
+ {
+     char *envval;
+     int ret;
++    bool need_decrement = false;
+ 
+     envval = getenv("SSS_NSS_USE_MEMCACHE");
+     if (envval && strcasecmp(envval, "NO") == 0) {
+         return EPERM;
+     }
+ 
+-    if (ctx->initialized) {
++    switch (ctx->initialized) {
++    case UNINITIALIZED:
++        __sync_add_and_fetch(&ctx->active_threads, 1);
++        ret = sss_nss_mc_init_ctx(name, ctx);
++        if (ret) {
++            need_decrement = true;
++        }
++        break;
++    case INITIALIZED:
++        __sync_add_and_fetch(&ctx->active_threads, 1);
+         ret = sss_nss_check_header(ctx);
+-        goto done;
++        if (ret) {
++            need_decrement = true;
++        }
++        break;
++    case RECYCLED:
++        /* we need to safely destroy memory cache */
++        ret = EAGAIN;
++        break;
++    default:
++        ret = EFAULT;
+     }
+ 
+-    ret = sss_nss_mc_init_ctx(name, ctx);
+-
+-done:
+     if (ret) {
+-        sss_nss_mc_destroy_ctx(ctx);
++        if (ctx->initialized == INITIALIZED) {
++            ctx->initialized = RECYCLED;
++        }
++        if (ctx->initialized == RECYCLED && ctx->active_threads == 0) {
++            /* just one thread should call munmap */
++            sss_nss_lock();
++            if (ctx->initialized == RECYCLED) {
++                sss_nss_mc_destroy_ctx(ctx);
++            }
++            sss_nss_unlock();
++        }
++        if (need_decrement) {
++            /* In case of error, we will not touch mmapped area => decrement */
++            __sync_sub_and_fetch(&ctx->active_threads, 1);
++        }
+     }
+     return ret;
+ }
+diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c
+index 268b40ef02f2a621c4f61755ce4dfe2c3786bfa6..e0fdb97f628ac19741409be29566e4af5a391f74 100644
+--- a/src/sss_client/nss_mc_group.c
++++ b/src/sss_client/nss_mc_group.c
+@@ -29,7 +29,8 @@
+ #include "nss_mc.h"
+ #include "util/util_safealign.h"
+ 
+-struct sss_cli_mc_ctx gr_mc_ctx = { false, -1, 0, NULL, 0, NULL, 0, NULL, 0 };
++struct sss_cli_mc_ctx gr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0,
++                                    NULL, 0, 0 };
+ 
+ static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
+                                        struct group *result,
+@@ -176,6 +177,7 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
+ 
+ done:
+     free(rec);
++    __sync_sub_and_fetch(&gr_mc_ctx.active_threads, 1);
+     return ret;
+ }
+ 
+@@ -198,7 +200,8 @@ errno_t sss_nss_mc_getgrgid(gid_t gid,
+ 
+     len = snprintf(gidstr, 11, "%ld", (long)gid);
+     if (len > 10) {
+-        return EINVAL;
++        ret = EINVAL;
++        goto done;
+     }
+ 
+     /* hashes are calculated including the NULL terminator */
+@@ -242,6 +245,7 @@ errno_t sss_nss_mc_getgrgid(gid_t gid,
+ 
+ done:
+     free(rec);
++    __sync_sub_and_fetch(&gr_mc_ctx.active_threads, 1);
+     return ret;
+ }
+ 
+diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c
+index fa19afc3c0e468430183ed3f13b80e086251ee01..10e43e2af43c5e7f1738e281b3ed260d89f3a004 100644
+--- a/src/sss_client/nss_mc_passwd.c
++++ b/src/sss_client/nss_mc_passwd.c
+@@ -28,7 +28,8 @@
+ #include <time.h>
+ #include "nss_mc.h"
+ 
+-struct sss_cli_mc_ctx pw_mc_ctx = { false, -1, 0, NULL, 0, NULL, 0, NULL, 0 };
++struct sss_cli_mc_ctx pw_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0,
++                                    NULL, 0, 0 };
+ 
+ static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
+                                        struct passwd *result,
+@@ -170,6 +171,7 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
+ 
+ done:
+     free(rec);
++    __sync_sub_and_fetch(&pw_mc_ctx.active_threads, 1);
+     return ret;
+ }
+ 
+@@ -192,7 +194,8 @@ errno_t sss_nss_mc_getpwuid(uid_t uid,
+ 
+     len = snprintf(uidstr, 11, "%ld", (long)uid);
+     if (len > 10) {
+-        return EINVAL;
++        ret = EINVAL;
++        goto done;
+     }
+ 
+     /* hashes are calculated including the NULL terminator */
+@@ -236,6 +239,7 @@ errno_t sss_nss_mc_getpwuid(uid_t uid,
+ 
+ done:
+     free(rec);
++    __sync_sub_and_fetch(&pw_mc_ctx.active_threads, 1);
+     return ret;
+ }
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0107-IPA-Handle-IPA-groups-returned-from-extop-plugin.patch b/SOURCES/0107-IPA-Handle-IPA-groups-returned-from-extop-plugin.patch
new file mode 100644
index 0000000..fc3b5c3
--- /dev/null
+++ b/SOURCES/0107-IPA-Handle-IPA-groups-returned-from-extop-plugin.patch
@@ -0,0 +1,37 @@
+From de740042c4a03f5683567939e73f6a8eb10f3ff1 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 23 Nov 2014 20:47:59 +0100
+Subject: [PATCH 107/112] IPA: Handle IPA groups returned from extop plugin
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 2c31120b196353df52c87ef5b924a80bda134a17..0eab1afc36e4d2c1d770c596c512a641fd276425 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -960,10 +960,15 @@ static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
+         return ret;
+     }
+ 
+-    state->obj_domain = find_domain_by_name(parent_domain, domain_name, true);
+-    if (state->obj_domain == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
+-        return ENOMEM;
++    if (domain_name) {
++        state->obj_domain = find_domain_by_name(parent_domain,
++                                                domain_name, true);
++        if (state->obj_domain == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
++            return ENOMEM;
++        }
++    } else {
++        state->obj_domain = parent_domain;
+     }
+ 
+     state->req_input.inp.name = group_name;
+-- 
+1.9.3
+
diff --git a/SOURCES/0107-IPA-Use-GC-for-AD-initgroup-requests.patch b/SOURCES/0107-IPA-Use-GC-for-AD-initgroup-requests.patch
deleted file mode 100644
index f795e50..0000000
--- a/SOURCES/0107-IPA-Use-GC-for-AD-initgroup-requests.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From d34211137c7e70563b073b83d773ae18688efbbc Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 6 Mar 2014 15:37:57 +0100
-Subject: [PATCH 107/107] IPA: Use GC for AD initgroup requests
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/ipa/ipa_subdomains_id.c | 21 +++++++++++++++------
- 1 file changed, 15 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 00993c496c1d100b37a780828c81492c2fac6157..978ccc261d7525662e835b867044b6a5238a29df 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -307,13 +307,22 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-     /* Currently only LDAP port for AD is used because POSIX
-      * attributes are not replicated to GC by default
-      */
--    clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2);
--    if (clist == NULL) {
--        ret = ENOMEM;
--        goto fail;
-+
-+    if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
-+        clist = ad_gc_conn_list(req, ad_id_ctx, state->user_dom);
-+        if (clist == NULL) {
-+            ret = ENOMEM;
-+            goto fail;
-+        }
-+    } else {
-+        clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2);
-+        if (clist == NULL) {
-+            ret = ENOMEM;
-+            goto fail;
-+        }
-+        clist[0] = ad_id_ctx->ldap_ctx;
-+        clist[1] = NULL;
-     }
--    clist[0] = ad_id_ctx->ldap_ctx;
--    clist[1] = NULL;
- 
-     /* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */
-     sdom = sdap_domain_get(sdap_id_ctx->opts, state->user_dom);
--- 
-1.8.5.3
-
diff --git a/SOURCES/0108-AD-Only-connect-to-GC-for-subdomain-users.patch b/SOURCES/0108-AD-Only-connect-to-GC-for-subdomain-users.patch
deleted file mode 100644
index 26f9aea..0000000
--- a/SOURCES/0108-AD-Only-connect-to-GC-for-subdomain-users.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From e62c422753537d8e2b98e979553626850b7b7600 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 5 Mar 2014 11:50:54 +0100
-Subject: [PATCH 108/110] AD: Only connect to GC for subdomain users
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2251
-
-By connecting to GC for users from both trusted domains and parent
-domain, we lose the ability to download the shell and homedir if these
-are used with ID mapping.
-
-This patch changes the user lookups only. Changing the logic for all
-lookups would break cross-domain group memberships, for example.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit bb8a08118db0916bf8252a9481c16271ec20acd3)
----
- src/providers/ad/ad_id.c | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 87af656b364344a8ef27a444e5dfcf8848939110..a35823b4b77d42fc583a61653a175f0ee4d22ac4 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -215,9 +215,26 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-               struct sss_domain_info *dom, struct be_acct_req *ar)
- {
-     struct sdap_id_conn_ctx **clist;
-+    int cindex = 0;
- 
-     switch (ar->entry_type & BE_REQ_TYPE_MASK) {
-     case BE_REQ_USER: /* user */
-+        clist = talloc_zero_array(ad_ctx, struct sdap_id_conn_ctx *, 3);
-+        if (clist == NULL) return NULL;
-+
-+        /* Try GC first for users from trusted domains */
-+        if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC)
-+                && IS_SUBDOMAIN(dom)) {
-+            clist[cindex] = ad_ctx->gc_ctx;
-+            clist[cindex]->ignore_mark_offline = true;
-+            cindex++;
-+        }
-+
-+        /* Users from primary domain can be just downloaded from LDAP.
-+         * The domain's LDAP connection also works as a fallback
-+         */
-+        clist[cindex] = ad_get_dom_ldap_conn(ad_ctx, dom);
-+        break;
-     case BE_REQ_BY_SECID:   /* by SID */
-     case BE_REQ_USER_AND_GROUP: /* get SID */
-     case BE_REQ_GROUP: /* group */
--- 
-1.8.5.3
-
diff --git a/SOURCES/0108-Fix-KRB5_CONF_PATH.patch b/SOURCES/0108-Fix-KRB5_CONF_PATH.patch
new file mode 100644
index 0000000..92e907b
--- /dev/null
+++ b/SOURCES/0108-Fix-KRB5_CONF_PATH.patch
@@ -0,0 +1,57 @@
+From 6b67b3bd49b826e572a1d136f8da48f947a79313 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 21 Nov 2014 15:22:24 +0100
+Subject: [PATCH 108/112] Fix KRB5_CONF_PATH
+
+Currently a shell/Makefile variable is used in the definition of
+KRB5_CONF_PATH for C code. This patch replaces it with a complier macro.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                 | 1 +
+ src/conf_macros.m4          | 2 +-
+ src/tests/cwrap/Makefile.am | 2 ++
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 53ace65b9a9647ffdaff0776d5a55d3e7393a38c..56a562c761d39ff5f54bc034ede563c40bf21ef8 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -386,6 +386,7 @@ AM_CPPFLAGS = \
+     $(JOURNALD_CFLAGS) \
+     -DLIBDIR=\"$(libdir)\" \
+     -DVARDIR=\"$(localstatedir)\" \
++    -DSYSCONFDIR=\"$(sysconfdir)\" \
+     -DSHLIBEXT=\"$(SHLIBEXT)\" \
+     -DSSSD_LIBEXEC_PATH=\"$(sssdlibexecdir)\" \
+     -DSSSD_CONF_DIR=\"$(sssdconfdir)\" \
+diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
+index fbee81f56e484b618379f7c987ecee50ae48917e..df9d1ddf89be38709e56ad4b214e5f7c6cbb0f97 100644
+--- a/src/conf_macros.m4
++++ b/src/conf_macros.m4
+@@ -353,7 +353,7 @@ AC_DEFUN([WITH_KRB5_CONF],
+                 ]
+                )
+ 
+-    KRB5_CONF_PATH="${sysconfdir}/krb5.conf"
++    KRB5_CONF_PATH="\"SYSCONFDIR\"/krb5.conf"
+     if test x"$with_krb5_conf" != x; then
+         KRB5_CONF_PATH=$with_krb5_conf
+     fi
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 02be67387110c0a440b647c35bba0c10e89e699d..46abab5ae32189b0561d1901407d2bb38a1ec4c0 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -4,7 +4,9 @@ AM_CPPFLAGS = \
+     -I$(top_srcdir)/src \
+     -I. \
+     -DLOCALEDIR=\"$(localedir)\" \
++    -DLIBDIR=\"$(libdir)\" \
+     -DVARDIR=\"$(localstatedir)\" \
++    -DSYSCONFDIR=\"$(sysconfdir)\" \
+     $(DBUS_CFLAGS) \
+     $(GLIB2_CFLAGS) \
+     $(NULL)
+-- 
+1.9.3
+
diff --git a/SOURCES/0109-AD-IPA-add-krb5_confd_path-configuration-option.patch b/SOURCES/0109-AD-IPA-add-krb5_confd_path-configuration-option.patch
new file mode 100644
index 0000000..e37de2c
--- /dev/null
+++ b/SOURCES/0109-AD-IPA-add-krb5_confd_path-configuration-option.patch
@@ -0,0 +1,464 @@
+From c230bce668a65649e9f2ca8b4424148ef9e19491 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 21 Nov 2014 18:07:10 +0100
+Subject: [PATCH 109/112] AD/IPA: add krb5_confd_path configuration option
+
+With this new parameter the directory where Kerberos configuration
+snippets are created can be specified.
+
+Fixes https://fedorahosted.org/sssd/ticket/2473
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/config/SSSDConfig/__init__.py.in    |   1 +
+ src/config/etc/sssd.api.d/sssd-ad.conf  |   1 +
+ src/config/etc/sssd.api.d/sssd-ipa.conf |   1 +
+ src/man/sssd-ad.5.xml                   |  18 ++++
+ src/man/sssd-ipa.5.xml                  |  18 ++++
+ src/providers/ad/ad_common.h            |   1 +
+ src/providers/ad/ad_opts.h              |   1 +
+ src/providers/ad/ad_subdomains.c        |   8 ++
+ src/providers/ipa/ipa_common.h          |   1 +
+ src/providers/ipa/ipa_opts.h            |   1 +
+ src/providers/ipa/ipa_subdomains.c      |   8 ++
+ src/tests/cmocka/test_utils.c           |  48 +++++++++++
+ src/util/domain_info_utils.c            | 146 +++++++++++++++++++++++++++++++-
+ src/util/util.h                         |   6 ++
+ 14 files changed, 256 insertions(+), 3 deletions(-)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 283ed2d37c894db95bac38c23d25c4ac8d1f4a40..500bd717fec7abcaafd5153ccca7847b91e208ad 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -195,6 +195,7 @@ option_strings = {
+     'krb5_realm' : _('Kerberos realm'),
+     'krb5_auth_timeout' : _('Authentication timeout'),
+     'krb5_use_kdcinfo' : _('Whether to create kdcinfo files'),
++    'krb5_confd_path' : _('Where to drop krb5 config snippets'),
+ 
+     # [provider/krb5/auth]
+     'krb5_ccachedir' : _('Directory to store credential caches'),
+diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
+index 3daa2560b14d74f7686ed47cf1b09e2005eb8917..3496fb4006697d380f7c9729ed9997272cbce2ea 100644
+--- a/src/config/etc/sssd.api.d/sssd-ad.conf
++++ b/src/config/etc/sssd.api.d/sssd-ad.conf
+@@ -54,6 +54,7 @@ ldap_page_size = int, None, false
+ ldap_deref_threshold = int, None, false
+ ldap_connection_expire_timeout = int, None, false
+ ldap_disable_paging = bool, None, false
++krb5_confd_path = str, None, false
+ 
+ [provider/ad/id]
+ ldap_search_timeout = int, None, false
+diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
+index 5df52581e67657e41e2f08820b885f100ccd7ca9..2a3b7ef1519e3476cb4b432336da0c359b1844ba 100644
+--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
+@@ -51,6 +51,7 @@ ldap_page_size = int, None, false
+ ldap_deref_threshold = int, None, false
+ ldap_connection_expire_timeout = int, None, false
+ ldap_disable_paging = bool, None, false
++krb5_confd_path = str, None, false
+ 
+ [provider/ipa/id]
+ ldap_search_timeout = int, None, false
+diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
+index f63a496d9c7294749fb046995985985e2cae4a57..4e29d4f75cae5bf17e4bb85fa46c921b25ee8047 100644
+--- a/src/man/sssd-ad.5.xml
++++ b/src/man/sssd-ad.5.xml
+@@ -778,6 +778,24 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com)
+                         </para>
+                     </listitem>
+                 </varlistentry>
++
++                <varlistentry>
++                    <term>krb5_confd_path (string)</term>
++                    <listitem>
++                        <para>
++                            Absolute path of a directory where SSSD should place
++                            Kerberos configuration snippets.
++                        </para>
++                        <para>
++                            To disable the creation of the configuration
++                            snippets set the parameter to 'none'.
++                        </para>
++                        <para>
++                            Default: not set (krb5.include.d subdirectory of
++                            SSSD's pubconf directory)
++                        </para>
++                    </listitem>
++                </varlistentry>
+             </variablelist>
+         </para>
+     </refsect1>
+diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
+index e8a716c4104b8038e354b8ae544a04d6773e708b..2d8654a3cde76ab205766f8fdcb836aa1002cd43 100644
+--- a/src/man/sssd-ipa.5.xml
++++ b/src/man/sssd-ipa.5.xml
+@@ -447,6 +447,24 @@
+                 </varlistentry>
+ 
+                 <varlistentry>
++                    <term>krb5_confd_path (string)</term>
++                    <listitem>
++                        <para>
++                            Absolute path of a directory where SSSD should place
++                            Kerberos configuration snippets.
++                        </para>
++                        <para>
++                            To disable the creation of the configuration
++                            snippets set the parameter to 'none'.
++                        </para>
++                        <para>
++                            Default: not set (krb5.include.d subdirectory of
++                            SSSD's pubconf directory)
++                        </para>
++                    </listitem>
++                </varlistentry>
++
++                <varlistentry>
+                     <term>ipa_hbac_refresh (integer)</term>
+                     <listitem>
+                         <para>
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index df8dcffea5f98030f6d5a6c98e95a7d887ace7fd..b39ade40cd00ad5fccdb5d4bf4df8790eb634a51 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -60,6 +60,7 @@ enum ad_basic_opt {
+     AD_GPO_MAP_PERMIT,
+     AD_GPO_MAP_DENY,
+     AD_GPO_DEFAULT_RIGHT,
++    AD_KRB5_CONFD_PATH,
+ 
+     AD_OPTS_BASIC /* opts counter */
+ };
+diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
+index ac6006c9200464956ccedb17ff53050fed5fc6ea..c3de3d94b1818665a86bba8a2432c699717b6a34 100644
+--- a/src/providers/ad/ad_opts.h
++++ b/src/providers/ad/ad_opts.h
+@@ -48,6 +48,7 @@ struct dp_option ad_basic_opts[] = {
+     { "ad_gpo_map_permit", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ad_gpo_map_deny", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ad_gpo_default_right", DP_OPT_STRING, NULL_STRING, NULL_STRING },
++    { "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index bc5bc8914ce84ecfbff69ff837250b5bf3a3515b..3c61d13522c7c773171ea8645dddb417e610745c 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -461,6 +461,14 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
+ {
+     errno_t ret;
+ 
++    ret = sss_write_krb5_conf_snippet(
++                            dp_opt_get_string(ctx->ad_id_ctx->ad_options->basic,
++                                              AD_KRB5_CONFD_PATH));
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
++        /* Just continue */
++    }
++
+     ret = sysdb_update_subdomains(ctx->be_ctx->domain);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
+diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
+index 495276548e57e91f9744dda6d8866971b627b4da..33085197c2a4807d4546289ead4c30d891d0d2c0 100644
+--- a/src/providers/ipa/ipa_common.h
++++ b/src/providers/ipa/ipa_common.h
+@@ -54,6 +54,7 @@ enum ipa_basic_opt {
+     IPA_ENABLE_DNS_SITES,
+     IPA_SERVER_MODE,
+     IPA_VIEWS_SEARCH_BASE,
++    IPA_KRB5_CONFD_PATH,
+ 
+     IPA_OPTS_BASIC /* opts counter */
+ };
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index 59282e8699091fbccf08ddfc6825034d4f81a87f..f77ff1d05b9540155db44d04d4fb3aac9d7b5988 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -51,6 +51,7 @@ struct dp_option ipa_basic_opts[] = {
+     { "ipa_enable_dns_sites", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "ipa_server_mode", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "ipa_views_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
++    { "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 9281aab1b028ebcaee8044b2768c6918efa4e514..883558c4d79d2da64ef6f010982ac89ccfae4e4f 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -312,6 +312,14 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
+ {
+     errno_t ret;
+ 
++    ret = sss_write_krb5_conf_snippet(
++                              dp_opt_get_string(ctx->id_ctx->ipa_options->basic,
++                                                IPA_KRB5_CONFD_PATH));
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
++        /* Just continue */
++    }
++
+     ret = sysdb_update_subdomains(ctx->be_ctx->domain);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index d9781377be70a0d58b0fd1fff2145483dbeb199c..5dc00c4cc9707776fabda50ad1eab8e582b16c0f 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -20,6 +20,8 @@
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+ 
++#define _GNU_SOURCE
++#include <stdio.h>
+ #include <popt.h>
+ 
+ #include "tests/cmocka/common_mock.h"
+@@ -983,6 +985,51 @@ void test_add_strings_lists(void **state)
+     talloc_free(res);
+ }
+ 
++void test_sss_write_krb5_conf_snippet(void **state)
++{
++    int ret;
++    char buf[PATH_MAX];
++    char *cwd;
++    char *path;
++    char *file;
++
++    ret = sss_write_krb5_conf_snippet(NULL);
++    assert_int_equal(ret, EINVAL);
++
++    ret = sss_write_krb5_conf_snippet("abc");
++    assert_int_equal(ret, EINVAL);
++
++    ret = sss_write_krb5_conf_snippet("");
++    assert_int_equal(ret, EOK);
++
++    ret = sss_write_krb5_conf_snippet("none");
++    assert_int_equal(ret, EOK);
++
++    cwd = getcwd(buf, PATH_MAX);
++    assert_non_null(cwd);
++
++    ret = asprintf(&path, "%s/%s", cwd, TESTS_PATH);
++    assert_true(ret > 0);
++
++    ret = asprintf(&file, "%s/%s/localauth_plugin", cwd, TESTS_PATH);
++    assert_true(ret > 0);
++
++    ret = sss_write_krb5_conf_snippet(path);
++    assert_int_equal(ret, EOK);
++
++    /* Check if writing a second time will work as well */
++    ret = sss_write_krb5_conf_snippet(path);
++    assert_int_equal(ret, EOK);
++
++#ifdef HAVE_KRB5_LOCALAUTH_PLUGIN
++    ret = unlink(file);
++    assert_int_equal(ret, EOK);
++#endif
++
++    free(file);
++    free(path);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -1030,6 +1077,7 @@ int main(int argc, const char *argv[])
+         unit_test_setup_teardown(test_add_strings_lists,
+                                  setup_add_strings_lists,
+                                  teardown_add_strings_lists),
++        unit_test(test_sss_write_krb5_conf_snippet),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 4e2c14c9432d38502422ddf2b0cb2b655a68d1cc..e04b905768078c503168f27327f974c0f19a6775 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -24,9 +24,6 @@
+ #include "db/sysdb.h"
+ #include "util/util.h"
+ 
+-/* the directory domain - realm mappings are written to */
+-#define KRB5_MAPPING_DIR PUBCONF_PATH"/krb5.include.d"
+-
+ struct sss_domain_info *get_domains_head(struct sss_domain_info *domain)
+ {
+     struct sss_domain_info *dom = NULL;
+@@ -637,3 +634,146 @@ done:
+     talloc_free(tmp_ctx);
+     return ret;
+ }
++
++#define LOCALAUTH_PLUGIN_CONFIG \
++"[plugins]\n" \
++" localauth = {\n" \
++"  module = sssd:"APP_MODULES_PATH"/sssd_krb5_localauth_plugin.so\n" \
++"  enable_only = sssd\n" \
++" }"
++
++static errno_t sss_write_krb5_localauth_snippet(const char *path)
++{
++#ifdef HAVE_KRB5_LOCALAUTH_PLUGIN
++    int ret;
++    errno_t err;
++    TALLOC_CTX *tmp_ctx = NULL;
++    char *tmp_file = NULL;
++    const char *file_name;
++    int fd = -1;
++    mode_t old_mode;
++    ssize_t written;
++    size_t size;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    file_name = talloc_asprintf(tmp_ctx, "%s/localauth_plugin", path);
++    if (file_name == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    DEBUG(SSSDBG_FUNC_DATA, "File for localauth plugin configuration is [%s]\n",
++                             file_name);
++
++    tmp_file = talloc_asprintf(tmp_ctx, "%sXXXXXX", file_name);
++    if (tmp_file == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    old_mode = umask(077);
++    fd = mkstemp(tmp_file);
++    umask(old_mode);
++    if (fd < 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "creating the temp file [%s] for domain-realm "
++                                  "mappings failed.", tmp_file);
++        ret = EIO;
++        talloc_zfree(tmp_ctx);
++        goto done;
++    }
++
++    size = sizeof(LOCALAUTH_PLUGIN_CONFIG) -1;
++    written = sss_atomic_write_s(fd, discard_const(LOCALAUTH_PLUGIN_CONFIG),
++                                 size);
++    close(fd);
++    if (written == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "write failed [%d][%s]\n", ret, sss_strerror(ret));
++        goto done;
++    }
++
++    if (written != size) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Wrote %zd bytes expected %zu\n", written, size);
++        ret = EIO;
++        goto done;
++    }
++
++    ret = rename(tmp_file, file_name);
++    if (ret == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "rename failed [%d][%s].\n", ret, sss_strerror(ret));
++        goto done;
++    }
++    tmp_file = NULL;
++
++    ret = chmod(file_name, 0644);
++    if (ret == -1) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "chmod failed [%d][%s].\n", ret, sss_strerror(ret));
++        goto done;
++    }
++
++done:
++    if (tmp_file != NULL) {
++        err = unlink(tmp_file);
++        if (err == -1) {
++            err = errno;
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Could not remove file [%s]: [%d]: %s",
++                   tmp_file, err, sss_strerror(err));
++        }
++    }
++
++    talloc_free(tmp_ctx);
++    return ret;
++#else
++    DEBUG(SSSDBG_TRACE_ALL, "Kerberos localauth plugin not available.\n");
++    return EOK;
++#endif
++}
++
++errno_t sss_write_krb5_conf_snippet(const char *path)
++{
++    errno_t ret;
++    errno_t err;
++
++    if (path != NULL && (*path == '\0' || strcasecmp(path, "none") == 0)) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Empty path, nothing to do.\n");
++        return EOK;
++    }
++
++    if (path == NULL || *path != '/') {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid or missing path [%s]-\n",
++                                    path == NULL ? "missing" : path);
++        return EINVAL;
++    }
++
++    ret = sss_write_krb5_localauth_snippet(path);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sss_write_krb5_localauth_snippet failed.\n");
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    err = sss_krb5_touch_config();
++    if (err != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to change last modification time "
++              "of krb5.conf. Created mappings may not be loaded.\n");
++        /* Ignore */
++    }
++
++    return ret;
++}
+diff --git a/src/util/util.h b/src/util/util.h
+index 7c335b9a2ac2599304731082845fd382dc62465f..45efd1aef94c2e058a435933e7c41adaecc676e2 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -576,8 +576,14 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
+ 
+ #define DOM_HAS_VIEWS(dom) ((dom)->has_views)
+ 
++/* the directory domain - realm mappings and other krb5 config snippers are
++ * written to */
++#define KRB5_MAPPING_DIR PUBCONF_PATH"/krb5.include.d"
++
+ errno_t sss_write_domain_mappings(struct sss_domain_info *domain);
+ 
++errno_t sss_write_krb5_conf_snippet(const char *path);
++
+ errno_t get_dom_names(TALLOC_CTX *mem_ctx,
+                       struct sss_domain_info *start_dom,
+                       char ***_dom_names,
+-- 
+1.9.3
+
diff --git a/SOURCES/0109-MAN-Clarify-the-GC-support-a-bit.patch b/SOURCES/0109-MAN-Clarify-the-GC-support-a-bit.patch
deleted file mode 100644
index 8269e74..0000000
--- a/SOURCES/0109-MAN-Clarify-the-GC-support-a-bit.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From b9336c0c96d409ecd7371a55fbfcf5691814efec Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 5 Mar 2014 12:13:48 +0100
-Subject: [PATCH 109/110] MAN: Clarify the GC support a bit
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-It should be noted that disabling GC does *not* disable lookups from
-trusted domains. Disabling GC might be a a good way for admins who wish
-to use POSIX attributes in trusted domains and the man page should hint
-this option.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit fdaaf2525e333af04ee9b48429b6766b5fd6cab6)
----
- src/man/sssd-ad.5.xml | 18 +++++++++++++-----
- 1 file changed, 13 insertions(+), 5 deletions(-)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 8cd94d4aeaf553ecb54e0e4c866be5fb7a44fa8e..0554317f533f2309d9fad60dfe5543f8546a6bbc 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -232,11 +232,19 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com)
-                     <listitem>
-                         <para>
-                             By default, the SSSD connects to the Global
--                            Catalog first to retrieve users and uses the
--                            LDAP port to retrieve group memberships or
--                            as a fallback. Disabling this option makes
--                            the SSSD only connect to the LDAP port of the
--                            current AD server.
-+                            Catalog first to retrieve users from trusted
-+                            domains and uses the LDAP port to retrieve
-+                            group memberships or as a fallback. Disabling
-+                            this option makes the SSSD only connect to
-+                            the LDAP port of the current AD server.
-+                        </para>
-+                        <para>
-+                            Please note that disabling Global Catalog support
-+                            does not disable retrieving users from trusted
-+                            domains. The SSSD would connect to the LDAP port
-+                            of trusted domains instead. However, Global
-+                            Catalog must be used in order to resolve
-+                            cross-domain group memberships.
-                         </para>
-                         <para>
-                             Default: true
--- 
-1.8.5.3
-
diff --git a/SOURCES/0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch b/SOURCES/0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch
deleted file mode 100644
index a5644b8..0000000
--- a/SOURCES/0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From 83eedf41e97e3fae59d92c0331cb3d1dc62a9010 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 5 Mar 2014 16:35:00 +0100
-Subject: [PATCH 110/110] IPA: Use the correct domain when processing SELinux
- rules
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-We blindly used the user's domain for everything. That wrong in case the
-user comes from a subdomain. We should use the IPA domain for accessing
-the SELinux rules and host data and the user domain only for the user.
-
-https://fedorahosted.org/sssd/ticket/2270
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 36f606d6743e77721bedeed0907f1be7a19fa4f4)
----
- src/providers/ipa/ipa_selinux.c | 26 ++++++++++++++++----------
- 1 file changed, 16 insertions(+), 10 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
-index 2209ca188654d8c79ee402ba71beeadab2904093..4ec5a64159de139f9ba5b30bf1f1a56baf32a52f 100644
---- a/src/providers/ipa/ipa_selinux.c
-+++ b/src/providers/ipa/ipa_selinux.c
-@@ -57,7 +57,8 @@ static errno_t ipa_get_selinux_recv(struct tevent_req *req,
- 
- static struct ipa_selinux_op_ctx *
- ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
--                          struct sss_domain_info *domain,
-+                          struct sss_domain_info *ipa_domain,
-+                          struct sss_domain_info *user_domain,
-                           struct be_req *be_req, const char *username,
-                           const char *hostname,
-                           struct ipa_selinux_ctx *selinux_ctx);
-@@ -80,7 +81,8 @@ static errno_t ipa_selinux_process_maps(TALLOC_CTX *mem_ctx,
- 
- struct ipa_selinux_op_ctx {
-     struct be_req *be_req;
--    struct sss_domain_info *domain;
-+    struct sss_domain_info *user_domain;
-+    struct sss_domain_info *ipa_domain;
-     struct ipa_selinux_ctx *selinux_ctx;
- 
-     struct sysdb_attrs *user;
-@@ -131,6 +133,7 @@ void ipa_selinux_handler(struct be_req *be_req)
-     }
- 
-     op_ctx = ipa_selinux_create_op_ctx(be_req, user_domain->sysdb,
-+                                       be_ctx->domain,
-                                        user_domain,
-                                        be_req, pd->user, hostname,
-                                        selinux_ctx);
-@@ -155,7 +158,8 @@ fail:
- 
- static struct ipa_selinux_op_ctx *
- ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
--                          struct sss_domain_info *domain,
-+                          struct sss_domain_info *ipa_domain,
-+                          struct sss_domain_info *user_domain,
-                           struct be_req *be_req, const char *username,
-                           const char *hostname,
-                           struct ipa_selinux_ctx *selinux_ctx)
-@@ -175,15 +179,16 @@ ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-         return NULL;
-     }
-     op_ctx->be_req = be_req;
--    op_ctx->domain = domain;
-+    op_ctx->ipa_domain = ipa_domain;
-+    op_ctx->user_domain = user_domain;
-     op_ctx->selinux_ctx = selinux_ctx;
- 
--    ret = sss_selinux_extract_user(op_ctx, sysdb, domain, username, &op_ctx->user);
-+    ret = sss_selinux_extract_user(op_ctx, sysdb, user_domain, username, &op_ctx->user);
-     if (ret != EOK) {
-         goto fail;
-     }
- 
--    host_dn = sysdb_custom_dn(sysdb, op_ctx, domain, hostname, HBAC_HOSTS_SUBDIR);
-+    host_dn = sysdb_custom_dn(sysdb, op_ctx, ipa_domain, hostname, HBAC_HOSTS_SUBDIR);
-     if (host_dn == NULL) {
-         goto fail;
-     }
-@@ -229,7 +234,7 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
-     struct ipa_selinux_op_ctx *op_ctx = tevent_req_callback_data(req, struct ipa_selinux_op_ctx);
-     struct be_req *breq = op_ctx->be_req;
-     struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
--    struct sysdb_ctx *sysdb = op_ctx->domain->sysdb;
-+    struct sysdb_ctx *sysdb = op_ctx->ipa_domain->sysdb;
-     errno_t ret, sret;
-     size_t map_count = 0;
-     struct sysdb_attrs **maps = NULL;
-@@ -258,21 +263,22 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
-     }
-     in_transaction = true;
- 
--    ret = sysdb_delete_usermaps(op_ctx->domain->sysdb, op_ctx->domain);
-+    ret = sysdb_delete_usermaps(op_ctx->ipa_domain->sysdb, op_ctx->ipa_domain);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               ("Cannot delete existing maps from sysdb\n"));
-         goto fail;
-     }
- 
--    ret = sysdb_store_selinux_config(sysdb, op_ctx->domain,
-+    ret = sysdb_store_selinux_config(op_ctx->ipa_domain->sysdb,
-+                                     op_ctx->ipa_domain,
-                                      default_user, map_order);
-     if (ret != EOK) {
-         goto fail;
-     }
- 
-     if (map_count > 0 && maps != NULL) {
--        ret = ipa_save_user_maps(sysdb, op_ctx->domain, map_count, maps);
-+        ret = ipa_save_user_maps(sysdb, op_ctx->ipa_domain, map_count, maps);
-         if (ret != EOK) {
-             goto fail;
-         }
--- 
-1.8.5.3
-
diff --git a/SOURCES/0110-test-Wrong-parameter-type-in-sss_parse_name_check.patch b/SOURCES/0110-test-Wrong-parameter-type-in-sss_parse_name_check.patch
new file mode 100644
index 0000000..5ac4004
--- /dev/null
+++ b/SOURCES/0110-test-Wrong-parameter-type-in-sss_parse_name_check.patch
@@ -0,0 +1,32 @@
+From 781f2feea5aa4d08a8c68aa33910b4f83a988e85 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Mon, 24 Nov 2014 19:10:01 +0100
+Subject: [PATCH 110/112] test: Wrong parameter type in sss_parse_name_check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This caused aritmetic overflow when SSSD specific error
+codes where used.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/cmocka/test_fqnames.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c
+index 71429c8773ef199c72163837d4b313660cf813c2..de208437d3d11429ebb4fd92ac6b1469564d9174 100644
+--- a/src/tests/cmocka/test_fqnames.c
++++ b/src/tests/cmocka/test_fqnames.c
+@@ -326,7 +326,7 @@ void parse_name_test_teardown(void **state)
+ 
+ void sss_parse_name_check(struct parse_name_test_ctx *test_ctx,
+                           const char *input_name,
+-                          const char exp_ret,
++                          const int exp_ret,
+                           const char *exp_name,
+                           const char *exp_domain)
+ {
+-- 
+1.9.3
+
diff --git a/SOURCES/0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch b/SOURCES/0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch
deleted file mode 100644
index edef6ea..0000000
--- a/SOURCES/0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From f8a49b3bff8d3969824fc7ba4e90d229f0c4edea Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 11 Mar 2014 13:16:14 +0100
-Subject: [PATCH 111/111] IPA/KRB5: handle KRB5_PROG_ETYPE_NOSUPP during IPA
- password migration
-
-Fixes https://fedorahosted.org/sssd/ticket/2279
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 63bf0b7697d5a51b5338070d0e2652d49a4728ce)
----
- src/providers/krb5/krb5_child.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index 461a27464f4fea09d4ca430b53aff072b29de141..af303e6c8c507c7cef108027c49cc4adb74162e7 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -986,6 +986,10 @@ static errno_t map_krb5_error(krb5_error_code kerr)
-     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
-         return ERR_AUTH_FAILED;
- 
-+    /* ERR_CREDS_INVALID is used to indicate to the IPA provider that trying
-+     * password migration would make sense. All Kerberos error codes which can
-+     * be seen while migrating LDAP users to IPA should be added here. */
-+    case KRB5_PROG_ETYPE_NOSUPP:
-     case KRB5_PREAUTH_FAILED:
-     case KRB5KDC_ERR_PREAUTH_FAILED:
-         return ERR_CREDS_INVALID;
--- 
-1.8.5.3
-
diff --git a/SOURCES/0111-util-Special-case-PCRE_ERROR_NOMATCH-in-sss_parse_na.patch b/SOURCES/0111-util-Special-case-PCRE_ERROR_NOMATCH-in-sss_parse_na.patch
new file mode 100644
index 0000000..0de6c3c
--- /dev/null
+++ b/SOURCES/0111-util-Special-case-PCRE_ERROR_NOMATCH-in-sss_parse_na.patch
@@ -0,0 +1,85 @@
+From eedf2fc4c1432f805b16ae52939cf5e67e8df550 Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Mon, 24 Nov 2014 19:50:14 +0100
+Subject: [PATCH 111/112] util: Special-case PCRE_ERROR_NOMATCH in
+ sss_parse_name
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add new SSSD specific error code for the case when
+pcre_exec returns PCRE_ERROR_NOMATCH.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/cmocka/test_fqnames.c | 14 +++++++-------
+ src/util/usertools.c            |  2 +-
+ src/util/util_errors.c          |  1 +
+ src/util/util_errors.h          |  1 +
+ 4 files changed, 10 insertions(+), 8 deletions(-)
+
+diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c
+index de208437d3d11429ebb4fd92ac6b1469564d9174..b9b6230b9e2c86dafae159630d5202e46992f5f3 100644
+--- a/src/tests/cmocka/test_fqnames.c
++++ b/src/tests/cmocka/test_fqnames.c
+@@ -471,13 +471,13 @@ void sss_parse_name_fail(void **state)
+     struct parse_name_test_ctx *test_ctx = talloc_get_type(*state,
+                                                            struct parse_name_test_ctx);
+ 
+-    sss_parse_name_check(test_ctx, "", EINVAL, NULL, NULL);
+-    sss_parse_name_check(test_ctx, "@", EINVAL, NULL, NULL);
+-    sss_parse_name_check(test_ctx, "\\", EINVAL, NULL, NULL);
+-    sss_parse_name_check(test_ctx, "\\"NAME, EINVAL, NULL, NULL);
+-    sss_parse_name_check(test_ctx, "@"NAME, EINVAL, NULL, NULL);
+-    sss_parse_name_check(test_ctx, NAME"@", EINVAL, NULL, NULL);
+-    sss_parse_name_check(test_ctx, NAME"\\", EINVAL, NULL, NULL);
++    sss_parse_name_check(test_ctx, "", ERR_REGEX_NOMATCH, NULL, NULL);
++    sss_parse_name_check(test_ctx, "@", ERR_REGEX_NOMATCH, NULL, NULL);
++    sss_parse_name_check(test_ctx, "\\", ERR_REGEX_NOMATCH, NULL, NULL);
++    sss_parse_name_check(test_ctx, "\\"NAME, ERR_REGEX_NOMATCH, NULL, NULL);
++    sss_parse_name_check(test_ctx, "@"NAME, ERR_REGEX_NOMATCH, NULL, NULL);
++    sss_parse_name_check(test_ctx, NAME"@", ERR_REGEX_NOMATCH, NULL, NULL);
++    sss_parse_name_check(test_ctx, NAME"\\", ERR_REGEX_NOMATCH, NULL, NULL);
+ }
+ 
+ void test_sss_get_domain_name(void **state)
+diff --git a/src/util/usertools.c b/src/util/usertools.c
+index a0b914e2fe8f65a71015944e63cb2d2813345d84..09cfd6b35505b8496413258fd05808ac0d2c095b 100644
+--- a/src/util/usertools.c
++++ b/src/util/usertools.c
+@@ -309,7 +309,7 @@ int sss_parse_name(TALLOC_CTX *memctx,
+ 
+     ret = pcre_exec(re, NULL, orig, origlen, 0, PCRE_NOTEMPTY, ovec, 30);
+     if (ret == PCRE_ERROR_NOMATCH) {
+-        return EINVAL;
++        return ERR_REGEX_NOMATCH;
+     } else if (ret < 0) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "PCRE Matching error, %d\n", ret);
+         return EINVAL;
+diff --git a/src/util/util_errors.c b/src/util/util_errors.c
+index c1ed0fb634c447904b63335d1cd161b7e7914a08..16d16fc777fc3344db8a3bdfeb3633bd5db48530 100644
+--- a/src/util/util_errors.c
++++ b/src/util/util_errors.c
+@@ -64,6 +64,7 @@ struct err_string error_to_str[] = {
+     { "Cannot connect to system bus" }, /* ERR_NO_SYSBUS */
+     { "LDAP search returned a referral" }, /* ERR_REFERRAL */
+     { "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */
++    { "Username format not allowed by re_expression" }, /* ERR_REGEX_NOMATCH */
+ };
+ 
+ 
+diff --git a/src/util/util_errors.h b/src/util/util_errors.h
+index f71ede8d0fa000627a1bd994ec8bd94a632b35b2..39455dc8adfe8784bd3f06382d701b7f9e97f004 100644
+--- a/src/util/util_errors.h
++++ b/src/util/util_errors.h
+@@ -86,6 +86,7 @@ enum sssd_errors {
+     ERR_NO_SYSBUS,
+     ERR_REFERRAL,
+     ERR_SELINUX_CONTEXT,
++    ERR_REGEX_NOMATCH,
+     ERR_LAST            /* ALWAYS LAST */
+ };
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch b/SOURCES/0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch
deleted file mode 100644
index 25f4e5c..0000000
--- a/SOURCES/0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 2ac5fed1ea4e9f56a18d0cc3b445855cdc6757c2 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 12 Mar 2014 17:38:22 +0100
-Subject: [PATCH 112/113] AD: Continue if sssd failes to check extra members
-
-Reported by scan-build
-
-    for (mi = 0; group_only[mi]; mi++) {
-                 ^~~~~~~~~~
-warning: Array access (from variable 'group_only') results in a null pointer
-dereference
-
-It can happend if function ad_group_extra_members fails (ret != EOK)
-
-Reviewed-by: Simo Sorce <simo@redhat.com>
-(cherry picked from commit bad65473c4c28ecbf2b6bd374a7ae2d634d57d8d)
----
- src/providers/ad/ad_id.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index a35823b4b77d42fc583a61653a175f0ee4d22ac4..01d18d7ae4bee82d8b75c7103c0f07635c6e08cc 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -772,6 +772,7 @@ ad_enum_cross_dom_members(struct sdap_options *opts,
-         ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n"));
-+            continue;
-         } else if (group_only == NULL) {
-             DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n"));
-             continue;
--- 
-1.8.5.3
-
diff --git a/SOURCES/0112-util-sss_get_domain_name-regex-mismatch-not-fatal.patch b/SOURCES/0112-util-sss_get_domain_name-regex-mismatch-not-fatal.patch
new file mode 100644
index 0000000..e4a8d6a
--- /dev/null
+++ b/SOURCES/0112-util-sss_get_domain_name-regex-mismatch-not-fatal.patch
@@ -0,0 +1,41 @@
+From 751447267c61d70016fd9f2231096188ede8eabe Mon Sep 17 00:00:00 2001
+From: Michal Zidek <mzidek@redhat.com>
+Date: Fri, 21 Nov 2014 20:06:32 +0100
+Subject: [PATCH 112/112] util: sss_get_domain_name regex mismatch not fatal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Assume name is not FQDN if sss_parse_name fails to
+match domain with regular expression.
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/2487
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/util/usertools.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/util/usertools.c b/src/util/usertools.c
+index 09cfd6b35505b8496413258fd05808ac0d2c095b..ebe139e6cd3c9eb270033629dab362fefb3e2682 100644
+--- a/src/util/usertools.c
++++ b/src/util/usertools.c
+@@ -646,7 +646,13 @@ sss_get_domain_name(TALLOC_CTX *mem_ctx,
+     /* check if the name already contains domain part */
+     if (dom->names != NULL) {
+         ret = sss_parse_name(mem_ctx, dom->names, orig_name, &domain, NULL);
+-        if (ret != EOK) {
++        if (ret == ERR_REGEX_NOMATCH) {
++            DEBUG(SSSDBG_TRACE_FUNC,
++                  "sss_parse_name could not parse domain from [%s]. "
++                  "Assuming it is not FQDN.\n", orig_name);
++        } else if (ret != EOK) {
++            DEBUG(SSSDBG_TRACE_FUNC,
++                  "sss_parse_name failed [%d]: %s\n", ret, sss_strerror(ret));
+             return NULL;
+         }
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0113-IPA-Write-SELinux-usernames-in-the-right-case.patch b/SOURCES/0113-IPA-Write-SELinux-usernames-in-the-right-case.patch
deleted file mode 100644
index c09551c..0000000
--- a/SOURCES/0113-IPA-Write-SELinux-usernames-in-the-right-case.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-From 12fa74c860993f154d1eb1585b4a735ca3684565 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 12 Mar 2014 15:19:02 +0100
-Subject: [PATCH 113/113] IPA: Write SELinux usernames in the right case
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2282
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/providers/ipa/ipa_selinux.c | 26 +++++++++++++++++++++-----
- 1 file changed, 21 insertions(+), 5 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
-index 4ec5a64159de139f9ba5b30bf1f1a56baf32a52f..7f59161918a04ff8c994a0ce0fe55924ff09eda7 100644
---- a/src/providers/ipa/ipa_selinux.c
-+++ b/src/providers/ipa/ipa_selinux.c
-@@ -225,6 +225,7 @@ static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order,
-                                   char ***_order_array, size_t *_order_count);
- static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
-                                   struct pam_data *pd,
-+                                  struct sss_domain_info *user_domain,
-                                   char **order_array, int order_count,
-                                   const char *default_user);
- 
-@@ -311,8 +312,8 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
-         goto fail;
-     }
- 
--    ret = choose_best_seuser(best_match_maps, pd, order_array, order_count,
--                             default_user);
-+    ret = choose_best_seuser(best_match_maps, pd, op_ctx->user_domain,
-+                             order_array, order_count, default_user);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               ("Failed to evaluate ordered SELinux users array.\n"));
-@@ -601,13 +602,16 @@ done:
-     return ret;
- }
- 
--static errno_t write_selinux_login_file(const char *username, char *string);
-+static errno_t write_selinux_login_file(const char *orig_name,
-+                                        struct sss_domain_info *dom,
-+                                        char *string);
- static errno_t remove_selinux_login_file(const char *username);
- 
- /* Choose best selinux user based on given order and write
-  * the user to selinux login file. */
- static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
-                                   struct pam_data *pd,
-+                                  struct sss_domain_info *user_domain,
-                                   char **order_array, int order_count,
-                                   const char *default_user)
- {
-@@ -662,7 +666,7 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps,
-         }
-     }
- 
--    ret = write_selinux_login_file(pd->user, file_content);
-+    ret = write_selinux_login_file(pd->user, user_domain, file_content);
- done:
-     if (!file_content) {
-         err = remove_selinux_login_file(pd->user);
-@@ -673,7 +677,9 @@ done:
-     return ret;
- }
- 
--static errno_t write_selinux_login_file(const char *username, char *string)
-+static errno_t write_selinux_login_file(const char *orig_name,
-+                                        struct sss_domain_info *dom,
-+                                        char *string)
- {
-     char *path = NULL;
-     char *tmp_path = NULL;
-@@ -685,6 +691,7 @@ static errno_t write_selinux_login_file(const char *username, char *string)
-     char *full_string = NULL;
-     int enforce;
-     errno_t ret = EOK;
-+    const char *username;
- 
-     len = strlen(string);
-     if (len == 0) {
-@@ -697,6 +704,15 @@ static errno_t write_selinux_login_file(const char *username, char *string)
-         return ENOMEM;
-     }
- 
-+    /* pam_selinux needs the username in the same format getpwnam() would
-+     * return it
-+     */
-+    username = sss_get_cased_name(tmp_ctx, orig_name, dom->case_sensitive);
-+    if (username == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     path = selogin_path(tmp_ctx, username);
-     if (path == NULL) {
-         ret = ENOMEM;
--- 
-1.8.5.3
-
diff --git a/SOURCES/0113-sysdb-add-sysdb_delete_view_tree.patch b/SOURCES/0113-sysdb-add-sysdb_delete_view_tree.patch
new file mode 100644
index 0000000..8173280
--- /dev/null
+++ b/SOURCES/0113-sysdb-add-sysdb_delete_view_tree.patch
@@ -0,0 +1,175 @@
+From 68f94d995142fc1aadf278be2f6816566208e189 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 12 Nov 2014 12:43:23 +0100
+Subject: [PATCH 113/115] sysdb: add sysdb_delete_view_tree()
+
+---
+ src/db/sysdb.h                      |  2 +
+ src/db/sysdb_views.c                | 34 +++++++++++++++++
+ src/tests/cmocka/test_sysdb_views.c | 74 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 110 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 7a51117f439dc54ded3433c230d2d262a4d660dc..a3ffa7b759e8aa16fc8a60cb01c6f0cb49278cc0 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -444,6 +444,8 @@ errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb, const char *view_name);
+ errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+                             char **view_name);
+ 
++errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name);
++
+ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+                                      struct sysdb_attrs *override_attrs,
+                                      struct ldb_dn *obj_dn);
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 27b58701fe0f9a4f545df5e4bfb884c04517d0d3..e17321455ad2ac4e4f17094f83c482d95bb00d8b 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -180,6 +180,40 @@ done:
+     return ret;
+ }
+ 
++errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name)
++{
++    struct ldb_dn *dn;
++    TALLOC_CTX *tmp_ctx;
++    int ret;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_VIEW_SEARCH_BASE,
++                        view_name);
++    if (dn == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
++        ret = EIO;
++        goto done;
++    }
++
++    ret = sysdb_delete_recursive(sysdb, dn, true);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n");
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
+ static errno_t
+ add_name_and_aliases_for_name_override(struct sss_domain_info *domain,
+                                        struct sysdb_attrs *attrs,
+diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
+index 0dc51443b406673f131cc69be4d781f7c49e538c..6be28e624d102060121f9afa91b282f7e8620676 100644
+--- a/src/tests/cmocka/test_sysdb_views.c
++++ b/src/tests/cmocka/test_sysdb_views.c
+@@ -30,10 +30,22 @@
+ 
+ #include "tests/cmocka/common_mock.h"
+ #include "providers/ipa/ipa_id.h"
++#include "db/sysdb_private.h" /* for sysdb->ldb member */
+ 
+ #define TESTS_PATH "tests_sysdb_views"
+ #define TEST_CONF_FILE "tests_conf.ldb"
+ 
++#define TEST_ANCHOR_PREFIX ":ANCHOR:"
++#define TEST_VIEW_NAME "test view"
++#define TEST_VIEW_CONTAINER "cn=" TEST_VIEW_NAME ",cn=views,cn=sysdb"
++#define TEST_USER_NAME "test_user"
++#define TEST_USER_UID 1234
++#define TEST_USER_GID 5678
++#define TEST_USER_GECOS "Gecos field"
++#define TEST_USER_HOMEDIR "/home/home"
++#define TEST_USER_SHELL "/bin/shell"
++#define TEST_USER_SID "S-1-2-3-4"
++
+ struct sysdb_test_ctx {
+     struct sysdb_ctx *sysdb;
+     struct confdb_ctx *confdb;
+@@ -219,6 +231,66 @@ void test_split_ipa_anchor(void **state)
+     assert_string_equal(uuid, "def");
+ }
+ 
++void test_sysdb_delete_view_tree(void **state)
++{
++    int ret;
++    struct ldb_message *msg;
++    struct ldb_message **msgs = NULL;
++    struct sysdb_attrs *attrs;
++    size_t count;
++    struct ldb_dn *views_dn;
++
++    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                         struct sysdb_test_ctx);
++
++    test_ctx->domain->mpg = false;
++
++    ret = sysdb_update_view_name(test_ctx->domain->sysdb, TEST_VIEW_NAME);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_store_user(test_ctx->domain, TEST_USER_NAME, NULL,
++                           TEST_USER_UID, TEST_USER_GID, TEST_USER_GECOS,
++                           TEST_USER_HOMEDIR, TEST_USER_SHELL, NULL, NULL, NULL,
++                           0,0);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_search_user_by_name(test_ctx, test_ctx->domain, TEST_USER_NAME,
++                                    NULL, &msg);
++    assert_int_equal(ret, EOK);
++    assert_non_null(msg);
++
++    attrs = sysdb_new_attrs(test_ctx);
++    assert_non_null(attrs);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID,
++                                 TEST_ANCHOR_PREFIX TEST_USER_SID);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_store_override(test_ctx->domain, TEST_VIEW_NAME,
++                               SYSDB_MEMBER_USER, attrs, msg->dn);
++    assert_int_equal(ret, EOK);
++
++    views_dn = ldb_dn_new(test_ctx, test_ctx->domain->sysdb->ldb,
++                          SYSDB_TMPL_VIEW_BASE);
++    assert_non_null(views_dn);
++
++    ret = sysdb_search_entry(test_ctx, test_ctx->domain->sysdb, views_dn,
++                             LDB_SCOPE_SUBTREE, NULL, NULL, &count, &msgs);
++    assert_int_equal(ret, EOK);
++    assert_true(count > 1);
++    assert_non_null(msgs);
++
++    ret = sysdb_delete_view_tree(test_ctx->domain->sysdb, TEST_VIEW_NAME);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_search_entry(test_ctx, test_ctx->domain->sysdb, views_dn,
++                             LDB_SCOPE_SUBTREE, NULL, NULL, &count, &msgs);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(count, 1);
++    assert_true(ldb_dn_compare(views_dn, msgs[0]->dn) == 0);
++
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int rv;
+@@ -238,6 +310,8 @@ int main(int argc, const char *argv[])
+                                  test_sysdb_setup, test_sysdb_teardown),
+         unit_test_setup_teardown(test_split_ipa_anchor,
+                                  test_sysdb_setup, test_sysdb_teardown),
++        unit_test_setup_teardown(test_sysdb_delete_view_tree,
++                                 test_sysdb_setup, test_sysdb_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+1.9.3
+
diff --git a/SOURCES/0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch b/SOURCES/0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch
deleted file mode 100644
index 4aeb7a6..0000000
--- a/SOURCES/0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 4069c662c32836f8ebba7f091c44f9db2a1ef62e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 20 Mar 2014 18:39:48 +0100
-Subject: [PATCH 114/117] krb5_child: remove unused option lifetime_str from
- k5c_setup_fast()
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_child.c | 9 +++------
- 1 file changed, 3 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index af303e6c8c507c7cef108027c49cc4adb74162e7..7f07efc161d0242e64bd67e13dec9a3faa9f2e30 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -1666,7 +1666,7 @@ static errno_t k5c_recv_data(struct krb5_req *kr, int fd, uint32_t *offline)
-     return ret;
- }
- 
--static int k5c_setup_fast(struct krb5_req *kr, char *lifetime_str, bool demand)
-+static int k5c_setup_fast(struct krb5_req *kr, bool demand)
- {
-     krb5_principal fast_princ_struct;
-     krb5_data *realm_data;
-@@ -1675,9 +1675,6 @@ static int k5c_setup_fast(struct krb5_req *kr, char *lifetime_str, bool demand)
-     krb5_error_code kerr;
-     char *tmp_str;
- 
--    DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
--                                 SSSD_KRB5_LIFETIME, lifetime_str));
--
-     tmp_str = getenv(SSSD_KRB5_FAST_PRINCIPAL);
-     if (tmp_str) {
-         DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
-@@ -1869,9 +1866,9 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
-         if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) {
-             DEBUG(SSSDBG_CONF_SETTINGS, ("Not using FAST.\n"));
-         } else if (strcasecmp(use_fast_str, "try") == 0) {
--            kerr = k5c_setup_fast(kr, lifetime_str, false);
-+            kerr = k5c_setup_fast(kr, false);
-         } else if (strcasecmp(use_fast_str, "demand") == 0) {
--            kerr = k5c_setup_fast(kr, lifetime_str, true);
-+            kerr = k5c_setup_fast(kr, true);
-         } else {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   ("Unsupported value [%s] for krb5_use_fast.\n",
--- 
-1.8.5.3
-
diff --git a/SOURCES/0114-sysdb-add-sysdb_invalidate_overrides.patch b/SOURCES/0114-sysdb-add-sysdb_invalidate_overrides.patch
new file mode 100644
index 0000000..8dadcc4
--- /dev/null
+++ b/SOURCES/0114-sysdb-add-sysdb_invalidate_overrides.patch
@@ -0,0 +1,248 @@
+From 26ae40bd74a00a9701f732a8957c06ff8fc857a4 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 12 Nov 2014 16:26:55 +0100
+Subject: [PATCH 114/115] sysdb: add sysdb_invalidate_overrides()
+
+---
+ src/db/sysdb.h                      |   2 +
+ src/db/sysdb_views.c                | 123 ++++++++++++++++++++++++++++++++++++
+ src/tests/cmocka/test_sysdb_views.c |  69 ++++++++++++++++++++
+ 3 files changed, 194 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index a3ffa7b759e8aa16fc8a60cb01c6f0cb49278cc0..5bd7f90acb685bbaff5c98f433c7dce8175c33ca 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -446,6 +446,8 @@ errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+ 
+ errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name);
+ 
++errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb);
++
+ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+                                      struct sysdb_attrs *override_attrs,
+                                      struct ldb_dn *obj_dn);
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index e17321455ad2ac4e4f17094f83c482d95bb00d8b..970d83e657d4fdfb73ac0e1fcc124ec690e29d4b 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -214,6 +214,129 @@ done:
+     return ret;
+ }
+ 
++errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb)
++{
++    int ret;
++    int sret;
++    TALLOC_CTX *tmp_ctx;
++    bool in_transaction = false;
++    struct ldb_result *res;
++    size_t c;
++    struct ldb_message *msg;
++    struct ldb_dn *base_dn;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    msg = ldb_msg_new(tmp_ctx);
++    if (msg == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    base_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_BASE);
++    if (base_dn == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE, LDB_FLAG_MOD_REPLACE,
++                            NULL);
++    if (ret != LDB_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++    ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1");
++    if (ret != LDB_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
++    ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, NULL);
++    if (ret != LDB_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
++    ret = sysdb_transaction_start(sysdb);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n");
++        goto done;
++    }
++    in_transaction = true;
++
++    ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, LDB_SCOPE_SUBTREE,
++                     NULL, "%s", SYSDB_UC);
++    if (ret != LDB_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n");
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
++    for (c = 0; c < res->count; c++) {
++        msg->dn = res->msgs[c]->dn;
++
++        ret = ldb_modify(sysdb->ldb, msg);
++        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
++            DEBUG(SSSDBG_OP_FAILURE, "ldb_modify failed.\n");
++            ret = sysdb_error_to_errno(ret);
++            goto done;
++        }
++    }
++
++    talloc_free(res);
++
++    ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, LDB_SCOPE_SUBTREE,
++                     NULL, "%s", SYSDB_GC);
++    if (ret != LDB_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n");
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
++    for (c = 0; c < res->count; c++) {
++        msg->dn = res->msgs[c]->dn;
++
++        ret = ldb_modify(sysdb->ldb, msg);
++        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
++            DEBUG(SSSDBG_OP_FAILURE, "ldb_modify failed.\n");
++            ret = sysdb_error_to_errno(ret);
++            goto done;
++        }
++    }
++
++    ret = EOK;
++done:
++    if (in_transaction) {
++        if (ret == EOK) {
++            sret = sysdb_transaction_commit(sysdb);
++            if (sret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_commit failed, " \
++                                         "nothing we can do about.\n");
++                ret = sret;
++            }
++        } else {
++            sret = sysdb_transaction_cancel(sysdb);
++            if (sret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_cancel failed, " \
++                                         "nothing we can do about.\n");
++            }
++        }
++    }
++
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
+ static errno_t
+ add_name_and_aliases_for_name_override(struct sss_domain_info *domain,
+                                        struct sysdb_attrs *attrs,
+diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
+index 6be28e624d102060121f9afa91b282f7e8620676..7238467c3c9bf91fd0d48204dd7217d4d273e965 100644
+--- a/src/tests/cmocka/test_sysdb_views.c
++++ b/src/tests/cmocka/test_sysdb_views.c
+@@ -291,6 +291,73 @@ void test_sysdb_delete_view_tree(void **state)
+ 
+ }
+ 
++void test_sysdb_invalidate_overrides(void **state)
++{
++    int ret;
++    struct ldb_message *msg;
++    struct sysdb_attrs *attrs;
++    struct ldb_dn *views_dn;
++    const char *user_attrs[] = { SYSDB_NAME,
++                                 SYSDB_CACHE_EXPIRE,
++                                 SYSDB_OVERRIDE_DN,
++                                 NULL};
++
++    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                         struct sysdb_test_ctx);
++
++    test_ctx->domain->mpg = false;
++
++    ret = sysdb_update_view_name(test_ctx->domain->sysdb, TEST_VIEW_NAME);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_store_user(test_ctx->domain, TEST_USER_NAME, NULL,
++                           TEST_USER_UID, TEST_USER_GID, TEST_USER_GECOS,
++                           TEST_USER_HOMEDIR, TEST_USER_SHELL, NULL, NULL, NULL,
++                           10,0);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_search_user_by_name(test_ctx, test_ctx->domain, TEST_USER_NAME,
++                                    NULL, &msg);
++    assert_int_equal(ret, EOK);
++    assert_non_null(msg);
++
++    attrs = sysdb_new_attrs(test_ctx);
++    assert_non_null(attrs);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID,
++                                 TEST_ANCHOR_PREFIX TEST_USER_SID);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_store_override(test_ctx->domain, TEST_VIEW_NAME,
++                               SYSDB_MEMBER_USER, attrs, msg->dn);
++    assert_int_equal(ret, EOK);
++
++    views_dn = ldb_dn_new(test_ctx, test_ctx->domain->sysdb->ldb,
++                          SYSDB_TMPL_VIEW_BASE);
++    assert_non_null(views_dn);
++
++    ret = sysdb_delete_view_tree(test_ctx->domain->sysdb, TEST_VIEW_NAME);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_search_user_by_name(test_ctx, test_ctx->domain, TEST_USER_NAME,
++                                    user_attrs, &msg);
++    assert_int_equal(ret, EOK);
++    assert_non_null(msg);
++    assert_true(ldb_msg_find_attr_as_uint64(msg, SYSDB_CACHE_EXPIRE, 0) > 1);
++    assert_non_null(ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, NULL));
++
++    ret = sysdb_invalidate_overrides(test_ctx->domain->sysdb);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_search_user_by_name(test_ctx, test_ctx->domain, TEST_USER_NAME,
++                                    user_attrs, &msg);
++    assert_int_equal(ret, EOK);
++    assert_non_null(msg);
++    assert_int_equal(ldb_msg_find_attr_as_uint64(msg, SYSDB_CACHE_EXPIRE, 0),
++                     1);
++    assert_null(ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, NULL));
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int rv;
+@@ -312,6 +379,8 @@ int main(int argc, const char *argv[])
+                                  test_sysdb_setup, test_sysdb_teardown),
+         unit_test_setup_teardown(test_sysdb_delete_view_tree,
+                                  test_sysdb_setup, test_sysdb_teardown),
++        unit_test_setup_teardown(test_sysdb_invalidate_overrides,
++                                 test_sysdb_setup, test_sysdb_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+1.9.3
+
diff --git a/SOURCES/0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch b/SOURCES/0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch
deleted file mode 100644
index c9502fa..0000000
--- a/SOURCES/0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From b86041a3760faa9273f1df879e8bfa38fbbb84aa Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 21 Mar 2014 12:14:11 +0100
-Subject: [PATCH 115/117] krb5-child: extract lifetime settings into
- set_lifetime_options()
-
-Additionally the lifetime option flags are unset if there are no
-explicit settings to make sure the defaults from krb5.conf are used even
-if other values were set manually in between.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_child.c | 89 +++++++++++++++++++++++++----------------
- 1 file changed, 55 insertions(+), 34 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index 7f07efc161d0242e64bd67e13dec9a3faa9f2e30..7ea111e108e189c6839feec0f1108175c0291605 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -65,6 +65,57 @@ struct krb5_req {
- static krb5_context krb5_error_ctx;
- #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
- 
-+static krb5_error_code set_lifetime_options(krb5_get_init_creds_opt *options)
-+{
-+    char *lifetime_str;
-+    krb5_error_code kerr;
-+    krb5_deltat lifetime;
-+
-+    lifetime_str = getenv(SSSD_KRB5_RENEWABLE_LIFETIME);
-+    if (lifetime_str == NULL) {
-+        DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n",
-+              SSSD_KRB5_RENEWABLE_LIFETIME));
-+
-+        /* Unset option flag to make sure defaults from krb5.conf are used. */
-+        options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE);
-+    } else {
-+        kerr = krb5_string_to_deltat(lifetime_str, &lifetime);
-+        if (kerr != 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  ("krb5_string_to_deltat failed for [%s].\n",
-+                      lifetime_str));
-+            KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
-+            return kerr;
-+        }
-+        DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
-+              SSSD_KRB5_RENEWABLE_LIFETIME, lifetime_str));
-+        krb5_get_init_creds_opt_set_renew_life(options, lifetime);
-+    }
-+
-+    lifetime_str = getenv(SSSD_KRB5_LIFETIME);
-+    if (lifetime_str == NULL) {
-+        DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n",
-+              SSSD_KRB5_LIFETIME));
-+
-+        /* Unset option flag to make sure defaults from krb5.conf are used. */
-+        options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_TKT_LIFE);
-+    } else {
-+        kerr = krb5_string_to_deltat(lifetime_str, &lifetime);
-+        if (kerr != 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  ("krb5_string_to_deltat failed for [%s].\n",
-+                      lifetime_str));
-+            KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
-+            return kerr;
-+        }
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              ("%s is set to [%s]\n", SSSD_KRB5_LIFETIME, lifetime_str));
-+        krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
-+    }
-+
-+    return 0;
-+}
-+
- static void set_changepw_options(krb5_context ctx,
-                                  krb5_get_init_creds_opt *options)
- {
-@@ -1744,9 +1795,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
- static int k5c_setup(struct krb5_req *kr, uint32_t offline)
- {
-     krb5_error_code kerr;
--    char *lifetime_str;
-     char *use_fast_str;
--    krb5_deltat lifetime;
-     int parse_flags;
- 
-     kr->realm = getenv(SSSD_KRB5_REALM);
-@@ -1825,38 +1874,10 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
-     krb5_get_init_creds_opt_set_change_password_prompt(kr->options, 0);
- #endif
- 
--    lifetime_str = getenv(SSSD_KRB5_RENEWABLE_LIFETIME);
--    if (lifetime_str == NULL) {
--        DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n",
--              SSSD_KRB5_RENEWABLE_LIFETIME));
--    } else {
--        kerr = krb5_string_to_deltat(lifetime_str, &lifetime);
--        if (kerr != 0) {
--            DEBUG(1, ("krb5_string_to_deltat failed for [%s].\n",
--                      lifetime_str));
--            KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
--            return kerr;
--        }
--        DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
--              SSSD_KRB5_RENEWABLE_LIFETIME, lifetime_str));
--        krb5_get_init_creds_opt_set_renew_life(kr->options, lifetime);
--    }
--
--    lifetime_str = getenv(SSSD_KRB5_LIFETIME);
--    if (lifetime_str == NULL) {
--        DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n",
--              SSSD_KRB5_LIFETIME));
--    } else {
--        kerr = krb5_string_to_deltat(lifetime_str, &lifetime);
--        if (kerr != 0) {
--            DEBUG(1, ("krb5_string_to_deltat failed for [%s].\n",
--                      lifetime_str));
--            KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
--            return kerr;
--        }
--        DEBUG(SSSDBG_CONF_SETTINGS,
--              ("%s is set to [%s]\n", SSSD_KRB5_LIFETIME, lifetime_str));
--        krb5_get_init_creds_opt_set_tkt_life(kr->options, lifetime);
-+    kerr = set_lifetime_options(kr->options);
-+    if (kerr != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("set_lifetime_options failed.\n"));
-+        return kerr;
-     }
- 
-     if (!offline) {
--- 
-1.8.5.3
-
diff --git a/SOURCES/0115-views-allow-view-name-change-at-startup.patch b/SOURCES/0115-views-allow-view-name-change-at-startup.patch
new file mode 100644
index 0000000..71678f0
--- /dev/null
+++ b/SOURCES/0115-views-allow-view-name-change-at-startup.patch
@@ -0,0 +1,231 @@
+From af22737f9e8b31a6a0671d3e6b58df7863646380 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 12 Nov 2014 16:30:57 +0100
+Subject: [PATCH 115/115] views: allow view name change at startup
+
+Currently some manual steps are needed on a FreeIPA to switch from one
+view to another. With this patch the IPA provider checks at startup if
+the view name changed and does the needed steps automatically. Besides
+saving the new view name this includes removing the old view data and
+marking the user and group entries as invalid.
+---
+ src/db/sysdb_views.c               | 12 ++---
+ src/providers/ipa/ipa_subdomains.c | 97 +++++++++++++++++++++++++++++++-------
+ 2 files changed, 85 insertions(+), 24 deletions(-)
+
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 970d83e657d4fdfb73ac0e1fcc124ec690e29d4b..3b3aac0dc1dea32cf3df5e29358f5dfefd8fde22 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -123,17 +123,13 @@ errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb,
+             goto done;
+         } else {
+             /* view name changed */
+-            /* not supported atm */
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "View name changed from [%s] to [%s]. NOT SUPPORTED.\n",
+-                  tmp_str, view_name);
+-            ret = ENOTSUP;
+-            goto done;
++            DEBUG(SSSDBG_CONF_SETTINGS,
++                  "View name changed from [%s] to [%s].\n", tmp_str, view_name);
+         }
++    } else {
++        add_view_name = true;
+     }
+ 
+-    add_view_name = true;
+-
+     msg = ldb_msg_new(tmp_ctx);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 883558c4d79d2da64ef6f010982ac89ccfae4e4f..6fdb0befa32f96d01c9b3666a3ef9c8331a83242 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -80,8 +80,17 @@ struct ipa_subdomains_ctx {
+     struct tevent_timer *timer_event;
+     bool configured_explicit;
+     time_t disabled_until;
++    bool view_read_at_init;
+ };
+ 
++static void ipa_subdomains_done(struct ipa_subdomains_ctx *sd_ctx,
++                                struct be_req *req, int dp_err,
++                                int error, const char *errstr)
++{
++    sd_ctx->view_read_at_init = true;
++    return be_req_terminate(req, dp_err, error, errstr);
++}
++
+ struct be_ctx *ipa_get_subdomains_be_ctx(struct be_ctx *be_ctx)
+ {
+     struct ipa_subdomains_ctx *subdom_ctx;
+@@ -903,7 +912,7 @@ done:
+     if (ret == EOK) {
+         dp_error = DP_ERR_OK;
+     }
+-    be_req_terminate(be_req, dp_error, ret, NULL);
++    ipa_subdomains_done(ctx, be_req, dp_error, ret, NULL);
+ }
+ 
+ static void ipa_subdomains_get_conn_done(struct tevent_req *req)
+@@ -938,7 +947,7 @@ static void ipa_subdomains_get_conn_done(struct tevent_req *req)
+     return;
+ 
+ fail:
+-    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
++    ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ }
+ 
+ static errno_t
+@@ -1030,6 +1039,7 @@ static errno_t ipa_get_view_name(struct ipa_subdomains_req_ctx *ctx)
+ static void ipa_get_view_name_done(struct tevent_req *req)
+ {
+     int ret;
++    int sret;
+     struct ipa_subdomains_req_ctx *ctx;
+     size_t reply_count;
+     struct sdap_deref_attrs **reply = NULL;
+@@ -1089,24 +1099,79 @@ static void ipa_get_view_name_done(struct tevent_req *req)
+         view_name = SYSDB_DEFAULT_VIEW_NAME;
+     }
+ 
++    DEBUG(SSSDBG_TRACE_ALL, "read_at_init [%s] current view  [%s].\n",
++                             ctx->sd_ctx->view_read_at_init ? "true" : "false",
++                             ctx->sd_ctx->id_ctx->view_name);
++
+     if (ctx->sd_ctx->id_ctx->view_name != NULL
+-            && strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0) {
++            && strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0
++            && ctx->sd_ctx->view_read_at_init) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+-              "View name changed, this is currently not supported!\n");
++              "View name changed, this is not supported at runtime. " \
++              "Please restart SSSD to get the new view applied.\n");
+     } else {
++        ctx->sd_ctx->view_read_at_init = true;
++        /* View name changed */
++        if (ctx->sd_ctx->id_ctx->view_name != NULL) {
++            ret = sysdb_transaction_start(ctx->sd_ctx->be_ctx->domain->sysdb);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n");
++                goto done;
++            }
++
++            if (strcmp(ctx->sd_ctx->id_ctx->view_name,
++                       SYSDB_DEFAULT_VIEW_NAME) != 0) {
++                /* Old view was not the default view, delete view tree */
++                ret = sysdb_delete_view_tree(ctx->sd_ctx->be_ctx->domain->sysdb,
++                                             ctx->sd_ctx->id_ctx->view_name);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sysdb_delete_view_tree failed.\n");
++                    sret = sysdb_transaction_cancel(
++                                            ctx->sd_ctx->be_ctx->domain->sysdb);
++                    if (sret != EOK) {
++                        DEBUG(SSSDBG_OP_FAILURE,
++                              "sysdb_transaction_cancel failed.\n");
++                        goto done;
++                    }
++                    goto done;
++                }
++            }
++
++            ret = sysdb_invalidate_overrides(
++                                            ctx->sd_ctx->be_ctx->domain->sysdb);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "sysdb_invalidate_overrides failed.\n");
++                sret = sysdb_transaction_cancel(
++                                            ctx->sd_ctx->be_ctx->domain->sysdb);
++                if (sret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_cancel failed.\n");
++                    goto done;
++                }
++                goto done;
++            }
++
++            ret = sysdb_transaction_commit(ctx->sd_ctx->be_ctx->domain->sysdb);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_commit failed.\n");
++                goto done;
++            }
++
++            /* TODO: start referesh task */
++        }
++
+         ret = sysdb_update_view_name(ctx->sd_ctx->be_ctx->domain->sysdb,
+                                      view_name);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "Cannot add/update view name to sysdb.\n");
+         } else {
++            talloc_free(ctx->sd_ctx->id_ctx->view_name);
++            ctx->sd_ctx->id_ctx->view_name = talloc_strdup(ctx->sd_ctx->id_ctx,
++                                                           view_name);
+             if (ctx->sd_ctx->id_ctx->view_name == NULL) {
+-                ctx->sd_ctx->id_ctx->view_name =
+-                                              talloc_strdup(ctx->sd_ctx->id_ctx,
+-                                                            view_name);
+-                if (ctx->sd_ctx->id_ctx->view_name == NULL) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
+-                }
++                DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
+             }
+         }
+     }
+@@ -1122,7 +1187,7 @@ done:
+     if (ret == EOK) {
+         dp_error = DP_ERR_OK;
+     }
+-    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
++    ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ }
+ 
+ static void ipa_subdomains_handler_done(struct tevent_req *req)
+@@ -1222,7 +1287,7 @@ done:
+     if (ret == EOK) {
+         dp_error = DP_ERR_OK;
+     }
+-    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
++    ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ }
+ 
+ static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx)
+@@ -1308,7 +1373,7 @@ done:
+     if (ret == EOK) {
+         dp_error = DP_ERR_OK;
+     }
+-    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
++    ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ }
+ 
+ static void ipa_subdomains_handler_master_done(struct tevent_req *req)
+@@ -1370,7 +1435,7 @@ done:
+     if (ret == EOK) {
+         dp_error = DP_ERR_OK;
+     }
+-    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
++    ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ }
+ 
+ static void ipa_subdom_online_cb(void *pvt);
+@@ -1505,12 +1570,12 @@ void ipa_subdomains_handler(struct be_req *be_req)
+ 
+     if (ctx->disabled_until > now) {
+         DEBUG(SSSDBG_TRACE_ALL, "Subdomain provider disabled.\n");
+-        be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
++        ipa_subdomains_done(ctx, be_req, DP_ERR_OK, EOK, NULL);
+         return;
+     }
+ 
+     if (ctx->last_refreshed > now - IPA_SUBDOMAIN_REFRESH_LIMIT) {
+-        be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
++        ipa_subdomains_done(ctx, be_req, DP_ERR_OK, EOK, NULL);
+         return;
+     }
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0116-PAM-Check-for-trusted-domain-before-sending-the-requ.patch b/SOURCES/0116-PAM-Check-for-trusted-domain-before-sending-the-requ.patch
new file mode 100644
index 0000000..18ccd03
--- /dev/null
+++ b/SOURCES/0116-PAM-Check-for-trusted-domain-before-sending-the-requ.patch
@@ -0,0 +1,146 @@
+From 663fb2625181ca8b80d26526a8298674ab6242a1 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 23 Nov 2014 19:43:04 +0100
+Subject: [PATCH 116/117] PAM: Check for trusted domain before sending the
+ request to BE
+
+https://fedorahosted.org/sssd/ticket/2501
+
+Moving the checks to one place has the advantage of not duplicating
+security decisions. Previously, the checks were scattered all over the
+responder code, making testing hard.
+
+The disadvantage is that we actually check for the presence of the user,
+which might trigger some back end lookups. But I think the benefits
+overweight the disadvantage.
+
+Also only check the requested domains from a trusted client. An untrusted
+client should simply have no say in what domains he wants to talk to, it
+should ignore the 'domains' option.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/responder/pam/pamsrv_cmd.c | 67 ++++++++++++++++--------------------------
+ 1 file changed, 26 insertions(+), 41 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index dd0e6e4cf54e6d98da807808ad6973dddc013413..b60ccba2d4ff669e7ed0252923a53755410851e3 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -898,17 +898,6 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+             goto done;
+         }
+ 
+-        /* Untrusted users can access only public domains. */
+-        if (!pctx->is_uid_trusted &&
+-            !is_domain_public(pd->domain, pctx->public_domains,
+-                              pctx->public_domains_count)) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Untrusted user %"PRIu32" cannot access unpublic domain %s.\n",
+-                  cctx->client_euid, pd->domain);
+-            ret = EPERM;
+-            goto done;
+-        }
+-
+         ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
+                                       preq->domain, pd->user);
+         if (ncret == EEXIST) {
+@@ -916,34 +905,12 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+             ret = ENOENT;
+             goto done;
+         }
+-
+-        /* skip this domain if not requested */
+-        if (!is_domain_requested(pd, pd->domain)) {
+-            ret = ENOENT;
+-            goto done;
+-        }
+     } else {
+         for (dom = preq->cctx->rctx->domains;
+              dom;
+              dom = get_next_domain(dom, false)) {
+             if (dom->fqnames) continue;
+ 
+-            /* Untrusted users can access only public domains. */
+-            if (!pctx->is_uid_trusted &&
+-                !is_domain_public(dom->name, pctx->public_domains,
+-                                  pctx->public_domains_count)) {
+-                DEBUG(SSSDBG_MINOR_FAILURE,
+-                      "Untrusted user %"PRIu32" cannot access unpublic domain %s."
+-                      " Trying next domain.\n",
+-                      cctx->client_euid, dom->name);
+-                continue;
+-            }
+-
+-            /* skip this domain if not requested */
+-            if (!is_domain_requested(pd, dom->name)) {
+-                continue;
+-            }
+-
+             ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
+                                           dom, pd->user);
+             if (ncret == ENOENT) {
+@@ -959,7 +926,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+                    "Trying next domain.\n", pd->user, dom->name);
+         }
+ 
+-        if (!dom || !is_domain_requested(pd, dom->name)) {
++        if (!dom) {
+             ret = ENOENT;
+             goto done;
+         }
+@@ -1055,14 +1022,9 @@ static int pam_check_user_search(struct pam_auth_req *preq)
+ 
+     while (dom) {
+        /* if it is a domainless search, skip domains that require fully
+-        * qualified names instead, also untrusted users can access only
+-        * public domains */
++        * qualified names instead */
+         while (dom && !preq->pd->domain && !preq->pd->name_is_upn
+-               && (dom->fqnames ||
+-                   (!pctx->is_uid_trusted &&
+-                    !is_domain_public(dom->name,
+-                                      pctx->public_domains,
+-                                      pctx->public_domains_count)))) {
++               && dom->fqnames) {
+             dom = get_next_domain(dom, false);
+         }
+ 
+@@ -1334,11 +1296,34 @@ done:
+ static void pam_dom_forwarder(struct pam_auth_req *preq)
+ {
+     int ret;
++    struct pam_ctx *pctx =
++            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
+ 
+     if (!preq->pd->domain) {
+         preq->pd->domain = preq->domain->name;
+     }
+ 
++    /* Untrusted users can access only public domains. */
++    if (!pctx->is_uid_trusted &&
++            !is_domain_public(preq->pd->domain, pctx->public_domains,
++                            pctx->public_domains_count)) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++                "Untrusted user %"PRIu32" cannot access non-public domain %s.\n",
++                preq->cctx->client_euid, preq->pd->domain);
++        preq->pd->pam_status = PAM_PERM_DENIED;
++        pam_reply(preq);
++        return;
++    }
++
++    /* skip this domain if not requested and the user is trusted
++     * as untrusted users can't request a domain */
++    if (pctx->is_uid_trusted &&
++            !is_domain_requested(preq->pd, preq->pd->domain)) {
++        preq->pd->pam_status = PAM_USER_UNKNOWN;
++        pam_reply(preq);
++        return;
++    }
++
+     if (!NEED_CHECK_PROVIDER(preq->domain->provider)) {
+         preq->callback = pam_reply;
+         ret = LOCAL_pam_handler(preq);
+-- 
+1.9.3
+
diff --git a/SOURCES/0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch b/SOURCES/0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch
deleted file mode 100644
index 96a23b3..0000000
--- a/SOURCES/0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-From 7dbdbb87a5660128b0bbac011c3684e13380f162 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 21 Mar 2014 16:15:39 +0100
-Subject: [PATCH 116/117] krb5_client: rename krb5_set_canonicalize() to
- set_canonicalize_option()
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_child.c | 32 ++++++++++++++++----------------
- 1 file changed, 16 insertions(+), 16 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index 7ea111e108e189c6839feec0f1108175c0291605..674dad7387c6874209ee5e491cefc18eba4a6da5 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -116,6 +116,20 @@ static krb5_error_code set_lifetime_options(krb5_get_init_creds_opt *options)
-     return 0;
- }
- 
-+static void set_canonicalize_option(krb5_get_init_creds_opt *opts)
-+{
-+    int canonicalize = 0;
-+    char *tmp_str;
-+
-+    tmp_str = getenv(SSSD_KRB5_CANONICALIZE);
-+    if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) {
-+        canonicalize = 1;
-+    }
-+    DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
-+          SSSD_KRB5_CANONICALIZE, tmp_str ? tmp_str : "not set"));
-+    sss_krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize);
-+}
-+
- static void set_changepw_options(krb5_context ctx,
-                                  krb5_get_init_creds_opt *options)
- {
-@@ -875,20 +889,6 @@ done:
- 
- }
- 
--static void krb5_set_canonicalize(krb5_get_init_creds_opt *opts)
--{
--    int canonicalize = 0;
--    char *tmp_str;
--
--    tmp_str = getenv(SSSD_KRB5_CANONICALIZE);
--    if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) {
--        canonicalize = 1;
--    }
--    DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
--          SSSD_KRB5_CANONICALIZE, tmp_str ? tmp_str : "not set"));
--    sss_krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize);
--}
--
- static krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx,
-                                                     krb5_principal princ,
-                                                     krb5_keytab keytab,
-@@ -904,7 +904,7 @@ static krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx,
-     krb5_get_init_creds_opt_set_address_list(&options, NULL);
-     krb5_get_init_creds_opt_set_forwardable(&options, 0);
-     krb5_get_init_creds_opt_set_proxiable(&options, 0);
--    krb5_set_canonicalize(&options);
-+    set_canonicalize_option(&options);
- 
-     kerr = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL,
-                                       &options);
-@@ -1881,7 +1881,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
-     }
- 
-     if (!offline) {
--        krb5_set_canonicalize(kr->options);
-+        set_canonicalize_option(kr->options);
- 
-         use_fast_str = getenv(SSSD_KRB5_USE_FAST);
-         if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) {
--- 
-1.8.5.3
-
diff --git a/SOURCES/0117-PAM-Move-is_uid_trusted-from-pam_ctx-to-preq.patch b/SOURCES/0117-PAM-Move-is_uid_trusted-from-pam_ctx-to-preq.patch
new file mode 100644
index 0000000..25b5f5b
--- /dev/null
+++ b/SOURCES/0117-PAM-Move-is_uid_trusted-from-pam_ctx-to-preq.patch
@@ -0,0 +1,91 @@
+From 377741700be52a7f496231ab808a673e3e8ff10e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 23 Nov 2014 21:07:58 +0100
+Subject: [PATCH 117/117] PAM: Move is_uid_trusted from pam_ctx to preq
+
+Keeping a per-request flag in a global structure is really dangerous.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/responder/pam/pamsrv.h     |  2 +-
+ src/responder/pam/pamsrv_cmd.c | 23 ++++++++++++-----------
+ 2 files changed, 13 insertions(+), 12 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
+index f92e7f7db0964777c26d69c7c08471a19de8ade3..066f35a428a9af81d665309b4ab5a80cf69561ba 100644
+--- a/src/responder/pam/pamsrv.h
++++ b/src/responder/pam/pamsrv.h
+@@ -39,7 +39,6 @@ struct pam_ctx {
+     hash_table_t *id_table;
+     size_t trusted_uids_count;
+     uid_t *trusted_uids;
+-    bool is_uid_trusted;
+ 
+     /* List of domains that are accessible even for untrusted users. */
+     char **public_domains;
+@@ -58,6 +57,7 @@ struct pam_auth_req {
+ 
+     pam_dp_callback_t *callback;
+ 
++    bool is_uid_trusted;
+     bool check_provider;
+     void *data;
+ 
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index b60ccba2d4ff669e7ed0252923a53755410851e3..02720018b91e1319346a023eca571913b544284a 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -849,15 +849,6 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+             talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx);
+     struct tevent_req *req;
+ 
+-    pctx->is_uid_trusted = is_uid_trusted(cctx->client_euid,
+-                                          pctx->trusted_uids_count,
+-                                          pctx->trusted_uids);
+-
+-    if (!pctx->is_uid_trusted) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "uid %"PRIu32" is not trusted.\n",
+-              cctx->client_euid);
+-    }
+-
+     preq = talloc_zero(cctx, struct pam_auth_req);
+     if (!preq) {
+         return ENOMEM;
+@@ -872,6 +863,16 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+     }
+     pd = preq->pd;
+ 
++    preq->is_uid_trusted = is_uid_trusted(cctx->client_euid,
++                                          pctx->trusted_uids_count,
++                                          pctx->trusted_uids);
++
++    if (!preq->is_uid_trusted) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "uid %"PRIu32" is not trusted.\n",
++              cctx->client_euid);
++    }
++
++
+     pd->cmd = pam_cmd;
+     pd->priv = cctx->priv;
+ 
+@@ -1304,7 +1305,7 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
+     }
+ 
+     /* Untrusted users can access only public domains. */
+-    if (!pctx->is_uid_trusted &&
++    if (!preq->is_uid_trusted &&
+             !is_domain_public(preq->pd->domain, pctx->public_domains,
+                             pctx->public_domains_count)) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+@@ -1317,7 +1318,7 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
+ 
+     /* skip this domain if not requested and the user is trusted
+      * as untrusted users can't request a domain */
+-    if (pctx->is_uid_trusted &&
++    if (preq->is_uid_trusted &&
+             !is_domain_requested(preq->pd, preq->pd->domain)) {
+         preq->pd->pam_status = PAM_USER_UNKNOWN;
+         pam_reply(preq);
+-- 
+1.9.3
+
diff --git a/SOURCES/0117-krb5-child-add-revert_changepw_options.patch b/SOURCES/0117-krb5-child-add-revert_changepw_options.patch
deleted file mode 100644
index 10478f3..0000000
--- a/SOURCES/0117-krb5-child-add-revert_changepw_options.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 62b3828dae4445e30d948cf858e0ecbe120eaf36 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 21 Mar 2014 16:16:23 +0100
-Subject: [PATCH 117/117] krb5-child: add revert_changepw_options()
-
-After changing the Kerberos password krb5-child will try to get a fresh
-TGT with the new password. This patch tries to make sure the right gic
-options are used.
-
-Resolves: https://fedorahosted.org/sssd/ticket/2289
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_child.c | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index 674dad7387c6874209ee5e491cefc18eba4a6da5..97c5a590ad78080613325b5a397ac965905932fd 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -140,6 +140,24 @@ static void set_changepw_options(krb5_context ctx,
-     krb5_get_init_creds_opt_set_tkt_life(options, 5*60);
- }
- 
-+static void revert_changepw_options(krb5_get_init_creds_opt *options)
-+{
-+    krb5_error_code kerr;
-+
-+    set_canonicalize_option(options);
-+
-+    /* Currently we do not set forwardable and proxiable explicitly, the flags
-+     * must be removed so that libkrb5 can take the defaults from krb5.conf */
-+    options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_FORWARDABLE);
-+    options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_PROXIABLE);
-+
-+    kerr = set_lifetime_options(options);
-+    if (kerr != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("set_lifetime_options failed.\n"));
-+    }
-+}
-+
-+
- static errno_t sss_send_pac(krb5_authdata **pac_authdata)
- {
-     struct sss_cli_req_data sss_data;
-@@ -1187,6 +1205,10 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
- 
-     krb5_free_cred_contents(kr->ctx, kr->creds);
- 
-+    /* We changed some of the gic options for the password change, now we have
-+     * to change them back to get a fresh TGT. */
-+    revert_changepw_options(kr->options);
-+
-     kerr = get_and_save_tgt(kr, newpassword);
- 
-     sss_authtok_set_empty(kr->pd->newauthtok);
--- 
-1.8.5.3
-
diff --git a/SOURCES/0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch b/SOURCES/0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch
deleted file mode 100644
index 700c581..0000000
--- a/SOURCES/0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch
+++ /dev/null
@@ -1,164 +0,0 @@
-From a9278ff6f7b387c529c3b57251974403c5990d44 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 18 Mar 2014 16:48:11 +0100
-Subject: [PATCH] KRB5: Do not attempt to get a TGT after a password change
- using OTP
-
-https://fedorahosted.org/sssd/ticket/2271
-
-The current krb5_child code attempts to get a TGT for the convenience of
-the user using the new password after a password change operation.
-However, an OTP should never be used twice, which means we can't perform
-the kinit operation after chpass is finished. Instead, we only print a
-PAM information instructing the user to log out and back in manually.
----
- src/providers/krb5/krb5_auth.c  | 21 ++++++++++++++++++---
- src/providers/krb5/krb5_child.c | 12 ++++++++++++
- src/sss_client/pam_sss.c        | 19 +++++++++++++++++++
- src/sss_client/sss_cli.h        |  3 +++
- 4 files changed, 52 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
-index ce461f5adefc6e42fdc69726ff71d23526375c0c..48c0746efc3d136a1f13e8982384d503d8d20723 100644
---- a/src/providers/krb5/krb5_auth.c
-+++ b/src/providers/krb5/krb5_auth.c
-@@ -815,6 +815,7 @@ static void krb5_auth_done(struct tevent_req *subreq)
-     char *renew_interval_str;
-     time_t renew_interval_time = 0;
-     bool use_enterprise_principal;
-+    uint32_t user_info_type;
- 
-     ret = handle_child_recv(subreq, pd, &buf, &len);
-     talloc_zfree(subreq);
-@@ -1062,9 +1063,23 @@ static void krb5_auth_done(struct tevent_req *subreq)
- 
-     ret = sss_krb5_check_ccache_princ(kr->uid, kr->gid, kr->ccname, kr->upn);
-     if (ret) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--                ("No ccache for %s in %s?\n", kr->upn, kr->ccname));
--        goto done;
-+        if (res->otp == true && pd->cmd == SSS_PAM_CHAUTHTOK) {
-+            DEBUG(SSSDBG_IMPORTANT_INFO,
-+                  ("Password change succeeded but currently "
-+                   "post-chpass kinit is not implemented\n"));
-+
-+            user_info_type = SSS_PAM_USER_INFO_OTP_CHPASS;
-+            ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
-+                                   (const uint8_t *) &user_info_type);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CRIT_FAILURE, ("pam_add_response failed.\n"));
-+                /* Not fatal */
-+            }
-+        } else {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  ("No ccache for %s in %s?\n", kr->upn, kr->ccname));
-+            goto done;
-+        }
-     }
- 
-     if (kr->old_ccname) {
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index d000d70167936b09bbaa39ec7a665089572d9aaa..3ee49e4678078d15dab98eeddf56d36f87955dcf 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -45,6 +45,7 @@ struct krb5_req {
-     krb5_principal princ;
-     char* name;
-     krb5_creds *creds;
-+    bool otp;
-     krb5_get_init_creds_opt *options;
- 
-     struct pam_data *pd;
-@@ -370,6 +371,8 @@ static krb5_error_code answer_otp(krb5_context ctx,
-         goto done;
-     }
- 
-+    kr->otp = true;
-+
-     /* Validate our assumptions about the contents of authtok. */
-     ret = sss_authtok_get_password(kr->pd->authtok, &pwd, &len);
-     if (ret != EOK)
-@@ -694,6 +697,8 @@ static errno_t k5c_send_data(struct krb5_req *kr, int fd, errno_t error)
-     size_t len;
-     int ret;
- 
-+    DEBUG(SSSDBG_FUNC_DATA, ("Received error code %d\n", error));
-+
-     ret = pack_response_packet(kr, error, kr->pd->resp_list, &buf, &len);
-     if (ret != EOK) {
-         DEBUG(1, ("pack_response_packet failed.\n"));
-@@ -1110,6 +1115,8 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
-                                         prompter, kr, 0,
-                                         SSSD_KRB5_CHANGEPW_PRINCIPAL,
-                                         kr->options);
-+    DEBUG(SSSDBG_TRACE_INTERNAL,
-+          ("chpass is%s using OTP\n", kr->otp ? "" : " not"));
-     if (kerr != 0) {
-         ret = pack_user_info_chpass_error(kr->pd, "Old password not accepted.",
-                                           &msg_len, &msg);
-@@ -1205,6 +1212,11 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim)
- 
-     krb5_free_cred_contents(kr->ctx, kr->creds);
- 
-+    if (kr->otp == true) {
-+        sss_authtok_set_empty(kr->pd->newauthtok);
-+        return map_krb5_error(kerr);
-+    }
-+
-     /* We changed some of the gic options for the password change, now we have
-      * to change them back to get a fresh TGT. */
-     revert_changepw_options(kr->options);
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index 4ff38f299bec75a49c8aace06eecab5735ca9443..e629fc19bd705ac35c2fa1ea4946f40c5eb49079 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -771,6 +771,22 @@ static int user_info_offline_chpass(pam_handle_t *pamh)
-     return PAM_SUCCESS;
- }
- 
-+static int user_info_otp_chpass(pam_handle_t *pamh)
-+{
-+    int ret;
-+
-+    ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
-+                              _("After changing the OTP password, you need to "
-+                                "log out and back in order to acquire a ticket"),
-+                              NULL, NULL);
-+    if (ret != PAM_SUCCESS) {
-+        D(("do_pam_conversation failed."));
-+        return PAM_SYSTEM_ERR;
-+    }
-+
-+    return PAM_SUCCESS;
-+}
-+
- static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen,
-                                   uint8_t *buf)
- {
-@@ -856,6 +872,9 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen,
-         case SSS_PAM_USER_INFO_OFFLINE_CHPASS:
-             ret = user_info_offline_chpass(pamh);
-             break;
-+        case SSS_PAM_USER_INFO_OTP_CHPASS:
-+            ret = user_info_otp_chpass(pamh);
-+            break;
-         case SSS_PAM_USER_INFO_CHPASS_ERROR:
-             ret = user_info_chpass_error(pamh, buflen, buf);
-             break;
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index 285a2979addb0c0677527b76b3b6755f2f173815..16a08e1869bb81ede2c1db87f1fb6d0a51087847 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -451,6 +451,9 @@ enum user_info_type {
-                                        * possible to change the password while
-                                        * the system is offline. This message
-                                        * is generated by the PAM responder. */
-+    SSS_PAM_USER_INFO_OTP_CHPASS,   /**< Tell the user that he needs to kinit
-+                                      * or login and logout to get a TGT after
-+                                      * an OTP password change */
-     SSS_PAM_USER_INFO_CHPASS_ERROR, /**< Tell the user that a password change
-                                      * failed and optionally give a reason.
-                                      * @param Size of the message as unsigned
--- 
-1.8.5.3
-
diff --git a/SOURCES/0118-krb5-make-krb5-provider-view-aware.patch b/SOURCES/0118-krb5-make-krb5-provider-view-aware.patch
new file mode 100644
index 0000000..df110b6
--- /dev/null
+++ b/SOURCES/0118-krb5-make-krb5-provider-view-aware.patch
@@ -0,0 +1,88 @@
+From f2a61159a9d8a73405d5dbc6f74bb176b3ee34c9 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 27 Nov 2014 10:01:40 +0100
+Subject: [PATCH 118/128] krb5: make krb5 provider view aware
+
+https://fedorahosted.org/sssd/ticket/2510
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c | 13 +++++++++++++
+ src/providers/krb5/krb5_auth.c     | 18 ++++++++++++------
+ 2 files changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 6fdb0befa32f96d01c9b3666a3ef9c8331a83242..d053d46ac4208bd52fcbf524a11243896b849612 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -1174,6 +1174,19 @@ static void ipa_get_view_name_done(struct tevent_req *req)
+                 DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
+             }
+         }
++
++        /* TODO: only needed if view changed */
++        ret = sysdb_master_domain_update(ctx->sd_ctx->be_ctx->domain);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_master_domain_update failed.\n");
++            goto done;
++        }
++
++        ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
++            goto done;
++        }
+     }
+ 
+     ret = ipa_check_master(ctx);
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index e791aee1c2d83f84ba617db1d5d93948c0e4e2a1..e43b3652786678b79499e30ed546712ef080fe2c 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -462,8 +462,8 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+     }
+     kr = state->kr;
+ 
+-    ret = sysdb_get_user_attr(state, state->domain, state->pd->user, attrs,
+-                              &res);
++    ret = sysdb_get_user_attr_with_views(state, state->domain, state->pd->user,
++                                         attrs, &res);
+     if (ret) {
+         DEBUG(SSSDBG_FUNC_DATA,
+               "sysdb search for upn of user [%s] failed.\n", pd->user);
+@@ -503,14 +503,18 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+ 
+-        kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR,
+-                                                  NULL);
++        kr->homedir = sss_view_ldb_msg_find_attr_as_string(state->domain,
++                                                           res->msgs[0],
++                                                           SYSDB_HOMEDIR,
++                                                           NULL);
+         if (kr->homedir == NULL) {
+             DEBUG(SSSDBG_CONF_SETTINGS,
+                   "Home directory for user [%s] not known.\n", pd->user);
+         }
+ 
+-        kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
++        kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
++                                                       res->msgs[0],
++                                                       SYSDB_UIDNUM, 0);
+         if (kr->uid == 0) {
+             DEBUG(SSSDBG_CONF_SETTINGS,
+                   "UID for user [%s] not known.\n", pd->user);
+@@ -518,7 +522,9 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+ 
+-        kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);
++        kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
++                                                       res->msgs[0],
++                                                       SYSDB_GIDNUM, 0);
+         if (kr->gid == 0) {
+             DEBUG(SSSDBG_CONF_SETTINGS,
+                   "GID for user [%s] not known.\n", pd->user);
+-- 
+1.9.3
+
diff --git a/SOURCES/0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch b/SOURCES/0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch
deleted file mode 100644
index 2aa64b7..0000000
--- a/SOURCES/0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From a9385ea99d15976c5e7585059945f6964f85339c Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 25 Mar 2014 17:57:32 +0100
-Subject: [PATCH] IPA: Use function sysdb_attrs_get_el in safe way
-
-Function sysdb_attrs_get_el can enlarge array of ldb_message_element in "struct
-sysdb_attrs" if attribute is not among available attributes. Array will be
-enlarged with function talloc_realloc but realloc can move array to another
-place in memory therefore ldb_message_element should not be used after next
-call of function sysdb_attrs_get_el
-
-    sysdb_attrs_get_el(netgroup, SYSDB_ORIG_MEMBER_USER, &user_found);
-    sysdb_attrs_get_el(netgroup, SYSDB_ORIG_MEMBER_HOST, &host_found);
-With netgroups, it is common to omit user or host from netgroup triple.
-There is very high probability that realloc will be called. it is possible
-pointer user_found can refer to the old area after the second call of function
-sysdb_attrs_get_el.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2284
----
- src/providers/ipa/ipa_netgroups.c | 17 +++++++----------
- 1 file changed, 7 insertions(+), 10 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_netgroups.c b/src/providers/ipa/ipa_netgroups.c
-index 49a4ba9ab60a05b31241916cf0a7669c785764d4..9cc374bc17eb53accaf607736a19555e17ebf4e1 100644
---- a/src/providers/ipa/ipa_netgroups.c
-+++ b/src/providers/ipa/ipa_netgroups.c
-@@ -297,9 +297,7 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq)
-     struct ipa_get_netgroups_state *state = tevent_req_data(req,
-                                                struct ipa_get_netgroups_state);
-     int i, ret;
--    struct ldb_message_element *ng_found;
--    struct ldb_message_element *host_found;
--    struct ldb_message_element *user_found;
-+    struct ldb_message_element *el;
-     struct sdap_search_base **netgr_bases;
-     struct sysdb_attrs **netgroups;
-     size_t netgroups_count;
-@@ -345,16 +343,19 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq)
- 
-     for (i = 0; i < netgroups_count; i++) {
-         ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_NETGROUP_MEMBER,
--                                 &ng_found);
-+                                 &el);
-         if (ret != EOK) goto done;
-+        if (el->num_values) state->entities_found |= ENTITY_NG;
- 
-         ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_MEMBER_USER,
--                                 &user_found);
-+                                 &el);
-         if (ret != EOK) goto done;
-+        if (el->num_values) state->entities_found |= ENTITY_USER;
- 
-         ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_MEMBER_HOST,
--                                 &host_found);
-+                                 &el);
-         if (ret != EOK) goto done;
-+        if (el->num_values) state->entities_found |= ENTITY_HOST;
- 
-         ret = sysdb_attrs_get_string(netgroups[i], SYSDB_ORIG_DN, &orig_dn);
-         if (ret != EOK) {
-@@ -371,10 +372,6 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq)
-             goto done;
-         }
- 
--        if (ng_found->num_values) state->entities_found |= ENTITY_NG;
--        if (user_found->num_values) state->entities_found |= ENTITY_USER;
--        if (host_found->num_values) state->entities_found |= ENTITY_HOST;
--
-         if (state->entities_found == 0) {
-             continue;
-         }
--- 
-1.8.5.3
-
diff --git a/SOURCES/0119-IPA-only-update-view-data-if-it-really-changed.patch b/SOURCES/0119-IPA-only-update-view-data-if-it-really-changed.patch
new file mode 100644
index 0000000..00e13b8
--- /dev/null
+++ b/SOURCES/0119-IPA-only-update-view-data-if-it-really-changed.patch
@@ -0,0 +1,167 @@
+From 50d00230cbbc4fd960ffd2ebfced826c2e671bc2 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 27 Nov 2014 13:41:37 +0100
+Subject: [PATCH 119/128] IPA: only update view data if it really changed
+
+https://fedorahosted.org/sssd/ticket/2510
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c | 116 +++++++++++++++++++++----------------
+ 1 file changed, 66 insertions(+), 50 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index d053d46ac4208bd52fcbf524a11243896b849612..3148389f71135b6c64e62d1cf7f4064dd183f595 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -1110,23 +1110,44 @@ static void ipa_get_view_name_done(struct tevent_req *req)
+               "View name changed, this is not supported at runtime. " \
+               "Please restart SSSD to get the new view applied.\n");
+     } else {
+-        ctx->sd_ctx->view_read_at_init = true;
+-        /* View name changed */
+-        if (ctx->sd_ctx->id_ctx->view_name != NULL) {
+-            ret = sysdb_transaction_start(ctx->sd_ctx->be_ctx->domain->sysdb);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n");
+-                goto done;
+-            }
++        if (ctx->sd_ctx->id_ctx->view_name == NULL
++            || strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0) {
++            /* View name changed */
+ 
+-            if (strcmp(ctx->sd_ctx->id_ctx->view_name,
+-                       SYSDB_DEFAULT_VIEW_NAME) != 0) {
+-                /* Old view was not the default view, delete view tree */
+-                ret = sysdb_delete_view_tree(ctx->sd_ctx->be_ctx->domain->sysdb,
++            if (ctx->sd_ctx->id_ctx->view_name != NULL) {
++                ret = sysdb_transaction_start(
++                                            ctx->sd_ctx->be_ctx->domain->sysdb);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sysdb_transaction_start failed.\n");
++                    goto done;
++                }
++
++                if (strcmp(ctx->sd_ctx->id_ctx->view_name,
++                           SYSDB_DEFAULT_VIEW_NAME) != 0) {
++                    /* Old view was not the default view, delete view tree */
++                    ret = sysdb_delete_view_tree(
++                                             ctx->sd_ctx->be_ctx->domain->sysdb,
+                                              ctx->sd_ctx->id_ctx->view_name);
++                    if (ret != EOK) {
++                        DEBUG(SSSDBG_OP_FAILURE,
++                              "sysdb_delete_view_tree failed.\n");
++                        sret = sysdb_transaction_cancel(
++                                            ctx->sd_ctx->be_ctx->domain->sysdb);
++                        if (sret != EOK) {
++                            DEBUG(SSSDBG_OP_FAILURE,
++                                  "sysdb_transaction_cancel failed.\n");
++                            goto done;
++                        }
++                        goto done;
++                    }
++                }
++
++                ret = sysdb_invalidate_overrides(
++                                            ctx->sd_ctx->be_ctx->domain->sysdb);
+                 if (ret != EOK) {
+                     DEBUG(SSSDBG_OP_FAILURE,
+-                          "sysdb_delete_view_tree failed.\n");
++                          "sysdb_invalidate_overrides failed.\n");
+                     sret = sysdb_transaction_cancel(
+                                             ctx->sd_ctx->be_ctx->domain->sysdb);
+                     if (sret != EOK) {
+@@ -1136,57 +1157,52 @@ static void ipa_get_view_name_done(struct tevent_req *req)
+                     }
+                     goto done;
+                 }
+-            }
+ 
+-            ret = sysdb_invalidate_overrides(
++                ret = sysdb_transaction_commit(
+                                             ctx->sd_ctx->be_ctx->domain->sysdb);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE,
+-                      "sysdb_invalidate_overrides failed.\n");
+-                sret = sysdb_transaction_cancel(
+-                                            ctx->sd_ctx->be_ctx->domain->sysdb);
+-                if (sret != EOK) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_cancel failed.\n");
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                                          "sysdb_transaction_commit failed.\n");
+                     goto done;
+                 }
+-                goto done;
++
++                /* TODO: start referesh task */
+             }
+ 
+-            ret = sysdb_transaction_commit(ctx->sd_ctx->be_ctx->domain->sysdb);
++            ret = sysdb_update_view_name(ctx->sd_ctx->be_ctx->domain->sysdb,
++                                         view_name);
+             if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_commit failed.\n");
+-                goto done;
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Cannot add/update view name to sysdb.\n");
++            } else {
++                talloc_free(ctx->sd_ctx->id_ctx->view_name);
++                ctx->sd_ctx->id_ctx->view_name = talloc_strdup(
++                                                            ctx->sd_ctx->id_ctx,
++                                                            view_name);
++                if (ctx->sd_ctx->id_ctx->view_name == NULL) {
++                    DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
++                }
+             }
+-
+-            /* TODO: start referesh task */
+         }
+ 
+-        ret = sysdb_update_view_name(ctx->sd_ctx->be_ctx->domain->sysdb,
+-                                     view_name);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Cannot add/update view name to sysdb.\n");
+-        } else {
+-            talloc_free(ctx->sd_ctx->id_ctx->view_name);
+-            ctx->sd_ctx->id_ctx->view_name = talloc_strdup(ctx->sd_ctx->id_ctx,
+-                                                           view_name);
+-            if (ctx->sd_ctx->id_ctx->view_name == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
++        if (!ctx->sd_ctx->view_read_at_init) {
++            /* refresh view data of all domains at startup */
++            ret = sysdb_master_domain_update(ctx->sd_ctx->be_ctx->domain);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "sysdb_master_domain_update failed.\n");
++                goto done;
++            }
++
++            ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
++                goto done;
+             }
+         }
+ 
+-        /* TODO: only needed if view changed */
+-        ret = sysdb_master_domain_update(ctx->sd_ctx->be_ctx->domain);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE, "sysdb_master_domain_update failed.\n");
+-            goto done;
+-        }
++        ctx->sd_ctx->view_read_at_init = true;
+ 
+-        ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
+-            goto done;
+-        }
+     }
+ 
+     ret = ipa_check_master(ctx);
+-- 
+1.9.3
+
diff --git a/SOURCES/0120-AD-connect-to-forest-root-when-downloading-the-list-.patch b/SOURCES/0120-AD-connect-to-forest-root-when-downloading-the-list-.patch
deleted file mode 100644
index de10d29..0000000
--- a/SOURCES/0120-AD-connect-to-forest-root-when-downloading-the-list-.patch
+++ /dev/null
@@ -1,478 +0,0 @@
-From d97ff9abd276e9216e5868be37c3762d208b36c0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 1 Apr 2014 13:51:49 -0400
-Subject: [PATCH 120/120] AD: connect to forest root when downloading the list
- of subdomains
-
-https://fedorahosted.org/sssd/ticket/2285
-
-Only the forest root has the knowledge about all the domains in the forest,
-the forest leaves only see themselves and the forest root.
-
-This patch switches to connecting to the forest root for downloading the
-trusted domains instead of the server we are connected to.
----
- src/providers/ad/ad_subdomains.c | 372 ++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 363 insertions(+), 9 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 0d9652b5c615add47958cfdc61eba862a332ae4d..3c841788d5d88069d79a9438b72f57c8c2e0ffda 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -54,7 +54,9 @@
-  * the same forest. See http://msdn.microsoft.com/en-us/library/cc223786.aspx
-  * for more information.
-  */
--#define SLAVE_DOMAIN_FILTER "(&(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*)))"
-+#define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))"
-+#define SLAVE_DOMAIN_FILTER      "(&"SLAVE_DOMAIN_FILTER_BASE")"
-+#define FOREST_ROOT_FILTER_FMT   "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))"
- 
- /* do not refresh more often than every 5 seconds for now */
- #define AD_SUBDOMAIN_REFRESH_LIMIT 5
-@@ -80,6 +82,11 @@ struct ad_subdomains_req_ctx {
-     char *current_filter;
-     size_t base_iter;
- 
-+    struct ad_id_ctx *root_id_ctx;
-+    struct sdap_id_op *root_op;
-+    size_t root_base_iter;
-+    struct sysdb_attrs *root_domain;
-+
-     size_t reply_count;
-     struct sysdb_attrs **reply;
- 
-@@ -461,6 +468,7 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
- 
- static void ad_subdomains_get_conn_done(struct tevent_req *req);
- static void ad_subdomains_master_dom_done(struct tevent_req *req);
-+static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx);
- static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx);
- 
- static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
-@@ -481,6 +489,10 @@ static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
-     req_ctx->sd_ctx = ctx;
-     req_ctx->current_filter = NULL;
-     req_ctx->base_iter = 0;
-+    req_ctx->root_base_iter = 0;
-+    req_ctx->root_id_ctx = NULL;
-+    req_ctx->root_op = NULL;
-+    req_ctx->root_domain = NULL;
-     req_ctx->reply_count = 0;
-     req_ctx->reply = NULL;
- 
-@@ -575,7 +587,20 @@ static void ad_subdomains_master_dom_done(struct tevent_req *req)
-         goto done;
-     }
- 
--    ret = ad_subdomains_get_slave(ctx);
-+    if (strcasecmp(ctx->sd_ctx->be_ctx->domain->name, ctx->forest) != 0) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              ("SSSD needs to look up the forest root domain\n"));
-+        ret = ad_subdomains_get_root(ctx);
-+    } else {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              ("Connected to forest root, looking up child domains..\n"));
-+
-+        ctx->root_op = ctx->sdap_op;
-+        ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
-+
-+        ret = ad_subdomains_get_slave(ctx);
-+    }
-+
-     if (ret == EAGAIN) {
-         return;
-     } else if (ret != EOK) {
-@@ -586,6 +611,244 @@ done:
-     be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
- }
- 
-+static void ad_subdomains_get_root_domain_done(struct tevent_req *req);
-+
-+static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx)
-+{
-+    struct tevent_req *req;
-+    struct sdap_search_base *base;
-+    struct sdap_id_ctx *sdap_id_ctx;
-+    char *filter;
-+    const char *forest_root_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
-+                                        AD_AT_SID, AD_AT_TRUST_TYPE,
-+                                        AD_AT_TRUST_ATTRS, NULL };
-+
-+    sdap_id_ctx = ctx->sd_ctx->sdap_id_ctx;
-+    base = sdap_id_ctx->opts->sdom->search_bases[ctx->root_base_iter];
-+    if (base == NULL) {
-+        return EOK;
-+    }
-+
-+    filter = talloc_asprintf(ctx, FOREST_ROOT_FILTER_FMT, ctx->forest);
-+    if (filter == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
-+                                sdap_id_ctx->opts,
-+                                sdap_id_op_handle(ctx->sdap_op),
-+                                base->basedn, LDAP_SCOPE_SUBTREE,
-+                                filter, forest_root_attrs,
-+                                NULL, 0,
-+                                dp_opt_get_int(sdap_id_ctx->opts->basic,
-+                                                SDAP_SEARCH_TIMEOUT),
-+                                false);
-+
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send failed.\n"));
-+        return ENOMEM;
-+    }
-+
-+    tevent_req_set_callback(req, ad_subdomains_get_root_domain_done, ctx);
-+    return EAGAIN;
-+}
-+
-+static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx);
-+static void ad_subdomains_root_conn_done(struct tevent_req *req);
-+
-+static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
-+{
-+    int ret;
-+    size_t reply_count;
-+    struct sysdb_attrs **reply = NULL;
-+    struct ad_subdomains_req_ctx *ctx;
-+    int dp_error = DP_ERR_FATAL;
-+    bool has_changes;
-+
-+    ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
-+
-+    ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
-+    talloc_zfree(req);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send request failed.\n"));
-+        goto fail;
-+    }
-+
-+    if (reply_count == 0) {
-+        /* If no root domain was found in the default search base, try the
-+         * next one, if available
-+         */
-+        ctx->root_base_iter++;
-+        ret = ad_subdomains_get_root(ctx);
-+        if (ret == EAGAIN) {
-+            return;
-+        }
-+
-+        goto fail;
-+    } else if (reply_count > 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              ("Multiple results for root domain search, "
-+               "domain list might be incomplete!\n"));
-+
-+        ctx->root_op = ctx->sdap_op;
-+        ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
-+
-+        ret = ad_subdomains_get_slave(ctx);
-+        if (ret == EAGAIN) {
-+            return;
-+        }
-+
-+        goto fail;
-+    }
-+    /* Exactly one result, good. */
-+
-+    /* We won't use the operation to the local LDAP anymore, but
-+     * read from the forest root
-+     */
-+    ret = sdap_id_op_done(ctx->sdap_op, ret, &dp_error);
-+    if (ret != EOK) {
-+        if (dp_error == DP_ERR_OFFLINE) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  ("No AD server is available, cannot get the "
-+                   "subdomain list while offline\n"));
-+        } else {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  ("Failed to search the AD server: [%d](%s)\n",
-+                  ret, strerror(ret)));
-+        }
-+        goto fail;
-+    }
-+
-+    ret = ad_subdomains_refresh(ctx->sd_ctx, 1, reply, &has_changes);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("ad_subdomains_refresh failed.\n"));
-+        goto fail;
-+    }
-+
-+    if (has_changes) {
-+        ret = ad_subdom_reinit(ctx->sd_ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n"));
-+            goto fail;
-+        }
-+    }
-+
-+    ctx->root_domain = reply[0];
-+    ctx->root_id_ctx = ads_get_root_id_ctx(ctx);
-+    if (ctx->root_id_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Cannot create id ctx for the root domain\n"));
-+        ret = EFAULT;
-+        goto fail;
-+    }
-+
-+    ctx->root_op = sdap_id_op_create(ctx,
-+                                     ctx->root_id_ctx->ldap_ctx->conn_cache);
-+    if (ctx->root_op == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n"));
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+
-+    req = sdap_id_op_connect_send(ctx->root_op, ctx, &ret);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_connect_send failed: %d(%s).\n",
-+                                   ret, strerror(ret)));
-+        goto fail;
-+    }
-+
-+    tevent_req_set_callback(req, ad_subdomains_root_conn_done, ctx);
-+    return;
-+
-+fail:
-+    if (ret == EOK) {
-+        ctx->sd_ctx->last_refreshed = time(NULL);
-+        dp_error = DP_ERR_OK;
-+    }
-+    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
-+}
-+
-+static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
-+{
-+    errno_t ret;
-+    const char *name;
-+    struct sss_domain_info *root;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *root_id_ctx;
-+
-+    ret = sysdb_attrs_get_string(ctx->root_domain, AD_AT_TRUST_PARTNER, &name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-+        return NULL;
-+    }
-+
-+    /* With a subsequent run, the root should already be known */
-+    root = find_subdomain_by_name(ctx->sd_ctx->be_ctx->domain,
-+                                  name, false);
-+    if (root == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Could not find the root domain\n"));
-+        return NULL;
-+    }
-+
-+    sdom = sdap_domain_get(ctx->sd_ctx->ad_id_ctx->sdap_id_ctx->opts, root);
-+    if (sdom == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              ("Cannot get the sdom for %s!\n", root->name));
-+        return NULL;
-+    }
-+
-+    if (sdom->pvt == NULL) {
-+        ret = ad_subdom_ad_ctx_new(ctx->sd_ctx->be_ctx,
-+                                   ctx->sd_ctx->ad_id_ctx,
-+                                   root,
-+                                   &root_id_ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("ad_subdom_ad_ctx_new failed.\n"));
-+            return NULL;
-+        }
-+        sdom->pvt = root_id_ctx;
-+    } else {
-+        root_id_ctx = sdom->pvt;
-+    }
-+
-+    return root_id_ctx;
-+}
-+
-+static void ad_subdomains_root_conn_done(struct tevent_req *req)
-+{
-+    int ret;
-+    int dp_error = DP_ERR_FATAL;
-+    struct ad_subdomains_req_ctx *ctx;
-+
-+    ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
-+
-+    ret = sdap_id_op_connect_recv(req, &dp_error);
-+    talloc_zfree(req);
-+    if (ret) {
-+        if (dp_error == DP_ERR_OFFLINE) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  ("No AD server is available, cannot get the "
-+                   "subdomain list while offline\n"));
-+        } else {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  ("Failed to connect to AD server: [%d](%s)\n",
-+                  ret, strerror(ret)));
-+        }
-+
-+        goto fail;
-+    }
-+
-+    ret = ad_subdomains_get_slave(ctx);
-+    if (ret == EAGAIN) {
-+        return;
-+    } else if (ret != EOK) {
-+        goto fail;
-+    }
-+
-+fail:
-+    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
-+}
-+
- static void ad_subdomains_get_slave_domain_done(struct tevent_req *req);
- 
- static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx)
-@@ -596,18 +859,18 @@ static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx)
-                                       AD_AT_SID, AD_AT_TRUST_TYPE,
-                                       AD_AT_TRUST_ATTRS, NULL };
- 
--    base = ctx->sd_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter];
-+    base = ctx->root_id_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter];
-     if (base == NULL) {
-         return EOK;
-     }
- 
-     req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
--                           ctx->sd_ctx->sdap_id_ctx->opts,
--                           sdap_id_op_handle(ctx->sdap_op),
-+                           ctx->root_id_ctx->sdap_id_ctx->opts,
-+                           sdap_id_op_handle(ctx->root_op),
-                            base->basedn, LDAP_SCOPE_SUBTREE,
-                            SLAVE_DOMAIN_FILTER, slave_dom_attrs,
-                            NULL, 0,
--                           dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
-+                           dp_opt_get_int(ctx->root_id_ctx->sdap_id_ctx->opts->basic,
-                                           SDAP_SEARCH_TIMEOUT),
-                            false);
- 
-@@ -620,6 +883,68 @@ static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx)
-     return EAGAIN;
- }
- 
-+static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
-+                                     struct sss_domain_info *domain,
-+                                     size_t nsd, struct sysdb_attrs **sd,
-+                                     struct sysdb_attrs *root,
-+                                     size_t *_nsd_out,
-+                                     struct sysdb_attrs ***_sd_out)
-+{
-+    size_t i, sdi;
-+    struct sysdb_attrs **sd_out;
-+    const char *sd_name;
-+    errno_t ret;
-+
-+    if (root == NULL) {
-+        /* We are connected directly to the root domain. The 'sd'
-+         * list is complete and we can just use it
-+         */
-+        *_nsd_out = nsd;
-+        *_sd_out = sd;
-+        return EOK;
-+    }
-+
-+    /* If we searched for root separately, we must:
-+     *  a) treat the root domain as a subdomain
-+     *  b) filter the subdomain we are connected to from the subdomain
-+     *     list, from our point of view, it's the master domain
-+     */
-+    sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
-+    if (sd_out == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    sdi = 0;
-+    for (i = 0; i < nsd; i++) {
-+        ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-+            goto fail;
-+        }
-+
-+        if (strcasecmp(sd_name, domain->name) == 0) {
-+            DEBUG(SSSDBG_TRACE_INTERNAL,
-+                  ("Not including primary domain %s in the subdomain list\n",
-+                  domain->name));
-+            continue;
-+        }
-+
-+        sd_out[sdi] = talloc_steal(sd_out, sd[i]);
-+        sdi++;
-+    }
-+
-+    /* Now include the root */
-+    sd_out[sdi] = talloc_steal(sd_out, root);
-+
-+    *_nsd_out = sdi+1;
-+    *_sd_out = sd_out;
-+    return EOK;
-+
-+fail:
-+    talloc_free(sd_out);
-+    return ret;
-+}
-+
- static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
- {
-     int ret;
-@@ -628,6 +953,8 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
-     struct ad_subdomains_req_ctx *ctx;
-     int dp_error = DP_ERR_FATAL;
-     bool refresh_has_changes = false;
-+    size_t nsubdoms;
-+    struct sysdb_attrs **subdoms;
- 
-     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
- 
-@@ -653,13 +980,40 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
-     ctx->base_iter++;
-     ret = ad_subdomains_get_slave(ctx);
-     if (ret == EAGAIN) {
-+        /* Search in progress */
-+        return;
-+    }
-+
-+    ret = sdap_id_op_done(ctx->root_op, ret, &dp_error);
-+    if (ret != EOK) {
-+        if (dp_error == DP_ERR_OFFLINE) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  ("No AD server is available, cannot get the "
-+                   "subdomain list while offline\n"));
-+        } else {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  ("Failed to search the AD server: [%d](%s)\n",
-+                  ret, strerror(ret)));
-+        }
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    /* Based on whether we are connected to the forest root or not, we might
-+     * need to exclude the subdomain we are connected to from the list of
-+     * subdomains
-+     */
-+    ret = ad_subdomains_process(ctx, ctx->sd_ctx->be_ctx->domain,
-+                                ctx->reply_count, ctx->reply,
-+                                ctx->root_domain, &nsubdoms, &subdoms);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot process subdomain list\n"));
-+        tevent_req_error(req, ret);
-         return;
--    } else if (ret != EOK) {
--        goto done;
-     }
- 
-     /* Got all the subdomains, let's process them */
--    ret = ad_subdomains_refresh(ctx->sd_ctx, ctx->reply_count, ctx->reply,
-+    ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, subdoms,
-                                 &refresh_has_changes);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Failed to refresh subdomains.\n"));
--- 
-1.9.0
-
diff --git a/SOURCES/0120-krb5-do-not-fail-if-checking-the-old-ccache-failed.patch b/SOURCES/0120-krb5-do-not-fail-if-checking-the-old-ccache-failed.patch
new file mode 100644
index 0000000..8e91746
--- /dev/null
+++ b/SOURCES/0120-krb5-do-not-fail-if-checking-the-old-ccache-failed.patch
@@ -0,0 +1,53 @@
+From 8aa6f3460bc0b1a5cf29b6958f508735b5e82999 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 27 Nov 2014 13:42:19 +0100
+Subject: [PATCH 120/128] krb5: do not fail if checking the old ccache failed
+
+https://fedorahosted.org/sssd/ticket/2510
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                     | 1 +
+ src/providers/krb5/krb5_child.c | 7 +++++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 56a562c761d39ff5f54bc034ede563c40bf21ef8..130c647e51d3554b2b0f69e83f17b38f1366eb3b 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2505,6 +2505,7 @@ krb5_child_SOURCES = \
+     src/util/signal.c \
+     src/util/strtonum.c \
+     src/util/become_user.c \
++    src/util/util_errors.c \
+     src/sss_client/common.c \
+     $(NULL)
+ krb5_child_CFLAGS = \
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 94cd34e433cf6a197860d233fbf9ca30cd3eb535..d828dd550251d70851edcdc6b1eda6f5c051baf2 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -34,6 +34,7 @@
+ #include "util/user_info_msg.h"
+ #include "util/child_common.h"
+ #include "util/find_uid.h"
++#include "src/util/util_errors.h"
+ #include "providers/dp_backend.h"
+ #include "providers/krb5/krb5_auth.h"
+ #include "providers/krb5/krb5_utils.h"
+@@ -2039,8 +2040,10 @@ static int k5c_ccache_setup(struct krb5_req *kr, uint32_t offline)
+ 
+     ret = k5c_check_old_ccache(kr);
+     if (ret != 0) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Cannot check old ccache\n");
+-        return ret;
++        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot check old ccache [%s]: [%d][%s]. " \
++                                   "Assuming old cache is invalid " \
++                                   "and not used.\n",
++                                   kr->old_ccname, ret, sss_strerror(ret));
+     }
+ 
+     /* Pre-creating the ccache must be done as root, otherwise we can't mkdir
+-- 
+1.9.3
+
diff --git a/SOURCES/0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch b/SOURCES/0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch
deleted file mode 100644
index e48bd0e..0000000
--- a/SOURCES/0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 1a088724c4d70edfbecab4252c1644100374f0f0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Apr 2014 22:11:59 +0200
-Subject: [PATCH 121/121] IPA: Fix SELinux mapping order memory hierarchy
-
-https://fedorahosted.org/sssd/ticket/2300
-
-The list of SELinux mapping orders was allocated on tmp_ctx and parsed
-into an array. The array itself was correctly allocated on mem_ctx but
-its contents remained on tmp_ctx, leading to a use-after-free error.
-This patch fixes the memory hierarchy so that both the array and its
-contents are allocated on mem_ctx.
-
-(cherry picked from commit 355b8a655cfcc4e783077d12f76b55da1d23fb87)
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/providers/ipa/ipa_selinux.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
-index 7f59161918a04ff8c994a0ce0fe55924ff09eda7..b7cbe445f1ecbfffaa84bb049aaf45ba4ecb1a35 100644
---- a/src/providers/ipa/ipa_selinux.c
-+++ b/src/providers/ipa/ipa_selinux.c
-@@ -557,21 +557,15 @@ static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order,
-         goto done;
-     }
- 
--    order = talloc_strdup(tmp_ctx, map_order);
--    if (order == NULL) {
--        ret = ENOMEM;
--        goto done;
--    }
--    len = strlen(order);
--
-     /* The "order" string contains one or more SELinux user records
-      * separated by $. Now we need to create an array of string from
-      * this one string. First find out how many elements in the array
-      * will be. This way only one alloc will be necessary for the array
-      */
-     order_count = 1;
-+    len = strlen(map_order);
-     for (i = 0; i < len; i++) {
--        if (order[i] == '$') order_count++;
-+        if (map_order[i] == '$') order_count++;
-     }
- 
-     order_array = talloc_array(tmp_ctx, char *, order_count);
-@@ -580,6 +574,12 @@ static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order,
-         goto done;
-     }
- 
-+    order = talloc_strdup(order_array, map_order);
-+    if (order == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     /* Now fill the array with pointers to the original string. Also
-      * use binary zeros to make multiple string out of the one.
-      */
--- 
-1.9.0
-
diff --git a/SOURCES/0121-test-avoid-leaks-in-leak-tests.patch b/SOURCES/0121-test-avoid-leaks-in-leak-tests.patch
new file mode 100644
index 0000000..c7d226b
--- /dev/null
+++ b/SOURCES/0121-test-avoid-leaks-in-leak-tests.patch
@@ -0,0 +1,57 @@
+From 664843123793879049459326127c2686f6361106 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 28 Nov 2014 18:16:33 +0100
+Subject: [PATCH 121/128] test: avoid leaks in leak tests
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/tests/cmocka/test_ifp.c | 5 ++++-
+ src/tests/leak_check.c      | 6 +++++-
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c
+index d6e41706d5f55414c0376bd04d299ec6ad73c11e..5793f91911c1e15c2c241aaa51ffcd4196daea63 100644
+--- a/src/tests/cmocka/test_ifp.c
++++ b/src/tests/cmocka/test_ifp.c
+@@ -209,6 +209,8 @@ void test_el_to_dict(void **state)
+     dbus_message_iter_get_basic(&iter_dict, &attr_val);
+     assert_string_equal(attr_val, "two");
+     assert_false(dbus_message_iter_next(&iter_dict));
++
++    talloc_free(sr);
+ }
+ 
+ static void assert_string_list_equal(const char **s1,
+@@ -500,7 +502,8 @@ int main(int argc, const char *argv[])
+         unit_test(ifp_test_req_create),
+         unit_test(ifp_test_req_wrong_uid),
+         unit_test(test_path_prefix),
+-        unit_test(test_el_to_dict),
++        unit_test_setup_teardown(test_el_to_dict,
++                                 ifp_test_req_setup, ifp_test_req_teardown),
+         unit_test(test_attr_acl),
+         unit_test(test_attr_acl_ex),
+         unit_test(test_attr_allowed),
+diff --git a/src/tests/leak_check.c b/src/tests/leak_check.c
+index bb5698cd80d5b360433d95a6297b740bb5cded87..1eaa2cd097bda54094098a2947bb3834a9bf04f4 100644
+--- a/src/tests/leak_check.c
++++ b/src/tests/leak_check.c
+@@ -130,10 +130,14 @@ leak_check_setup(void)
+ bool
+ leak_check_teardown(void)
+ {
++    bool res;
+     check_leaks_pop(global_talloc_context);
+     if (snapshot_stack != NULL) {
+         _set_leak_err_msg("Exiting with a non-empty stack");
+         return false;
+     }
+-    return check_leaks(global_talloc_context, 0);
++    res = check_leaks(global_talloc_context, 0);
++    talloc_disable_null_tracking();
++    talloc_free(global_talloc_context);
++    return res;
+ }
+-- 
+1.9.3
+
diff --git a/SOURCES/0122-AD-Do-not-remove-non-root-domains-when-looking-up-ro.patch b/SOURCES/0122-AD-Do-not-remove-non-root-domains-when-looking-up-ro.patch
deleted file mode 100644
index 9247fdd..0000000
--- a/SOURCES/0122-AD-Do-not-remove-non-root-domains-when-looking-up-ro.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From a3877f8eb322be17f7d08d74ad3cf655b96219b5 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 13 May 2014 15:18:07 +0200
-Subject: [PATCH 122/124] AD: Do not remove non-root domains when looking up
- root domain
-
-https://fedorahosted.org/sssd/ticket/2322
-
-When the AD subdomains code looked up the root domain subsequently
-(after the domain list was already populated), the non-root domains
-might have been removed along with their respective tasks, because the
-root domain lookup only ever matched a single root domain.
-
-This could cause havoc especially during login when different lookups
-for different domains might be going on during user group refresh.
----
- src/providers/ad/ad_subdomains.c | 25 ++++++++++++++++++++++---
- 1 file changed, 22 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 3c841788d5d88069d79a9438b72f57c8c2e0ffda..ee04cbbe048e55666db22c48cf22c4c0241a0e3c 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -325,13 +325,15 @@ done:
- }
- 
- static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
--                                     int count, struct sysdb_attrs **reply,
-+                                     int count, bool root_domain,
-+                                     struct sysdb_attrs **reply,
-                                      bool *changes)
- {
-     struct sdap_domain *sdom;
-     struct sss_domain_info *domain, *dom;
-     bool handled[count];
-     const char *value;
-+    const char *root_name = NULL;
-     int c, h;
-     int ret;
-     bool enumerate;
-@@ -340,10 +342,27 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
-     memset(handled, 0, sizeof(bool) * count);
-     h = 0;
- 
-+    if (root_domain) {
-+        ret = sysdb_attrs_get_string(reply[0], AD_AT_TRUST_PARTNER,
-+                                     &root_name);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-+            goto done;
-+        }
-+    }
-+
-     /* check existing subdomains */
-     for (dom = get_next_domain(domain, true);
-          dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
-          dom = get_next_domain(dom, false)) {
-+
-+        /* If we are handling root domain, skip all the other domains. We don't
-+         * want to accidentally remove non-root domains
-+         */
-+        if (root_name && strcmp(root_name, dom->name) != 0) {
-+            continue;
-+        }
-+
-         for (c = 0; c < count; c++) {
-             if (handled[c]) {
-                 continue;
-@@ -719,7 +738,7 @@ static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
-         goto fail;
-     }
- 
--    ret = ad_subdomains_refresh(ctx->sd_ctx, 1, reply, &has_changes);
-+    ret = ad_subdomains_refresh(ctx->sd_ctx, 1, true, reply, &has_changes);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("ad_subdomains_refresh failed.\n"));
-         goto fail;
-@@ -1013,7 +1032,7 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
-     }
- 
-     /* Got all the subdomains, let's process them */
--    ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, subdoms,
-+    ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, false, subdoms,
-                                 &refresh_has_changes);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Failed to refresh subdomains.\n"));
--- 
-1.9.0
-
diff --git a/SOURCES/0122-krb5-add-copy_ccache_into_memory.patch b/SOURCES/0122-krb5-add-copy_ccache_into_memory.patch
new file mode 100644
index 0000000..256b98b
--- /dev/null
+++ b/SOURCES/0122-krb5-add-copy_ccache_into_memory.patch
@@ -0,0 +1,441 @@
+From 3e53a8cd98b9410cd378ad68d8528e2a8d6d4f6a Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 17 Nov 2014 17:39:38 +0100
+Subject: [PATCH 122/128] krb5: add copy_ccache_into_memory()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                         |  18 +++
+ src/providers/krb5/krb5_ccache.c    | 110 +++++++++++++++++
+ src/providers/krb5/krb5_ccache.h    |  17 +++
+ src/tests/cmocka/test_copy_ccache.c | 238 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 383 insertions(+)
+ create mode 100644 src/tests/cmocka/test_copy_ccache.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 130c647e51d3554b2b0f69e83f17b38f1366eb3b..62d900dec654baff59762c934885aef9ae5510b9 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -214,6 +214,7 @@ if HAVE_CMOCKA
+         test_search_bases \
+         sdap-tests \
+         test_sysdb_views \
++        test_copy_ccache \
+         $(NULL)
+ 
+ if BUILD_IFP
+@@ -2079,6 +2080,23 @@ test_sysdb_views_LDADD = \
+     libsss_test_common.la \
+     $(NULL)
+ 
++test_copy_ccache_SOURCES = \
++    src/tests/cmocka/test_copy_ccache.c \
++    src/providers/krb5/krb5_ccache.c \
++    src/util/sss_krb5.c \
++    $(NULL)
++test_copy_ccache_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
++test_copy_ccache_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(POPT_LIBS) \
++    $(TALLOC_LIBS) \
++    $(KRB5_LIBS) \
++    $(SSSD_INTERNAL_LTLIBS) \
++    libsss_test_common.la \
++    $(NULL)
++
+ endif # HAVE_CMOCKA
+ 
+ noinst_PROGRAMS = pam_test_client
+diff --git a/src/providers/krb5/krb5_ccache.c b/src/providers/krb5/krb5_ccache.c
+index 7aa36b744ddcf7e46edcc26405a5101645b8b546..de6e694a9ba7099e3b05fa8ab3aa9245c280dba5 100644
+--- a/src/providers/krb5/krb5_ccache.c
++++ b/src/providers/krb5/krb5_ccache.c
+@@ -667,3 +667,113 @@ errno_t safe_remove_old_ccache_file(const char *old_ccache,
+ 
+     return sss_krb5_cc_destroy(old_ccache, uid, gid);
+ }
++
++krb5_error_code copy_ccache_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
++                                        const char *ccache_file,
++                                        char **_mem_name)
++{
++    krb5_error_code kerr;
++    krb5_ccache ccache;
++    krb5_ccache mem_ccache = NULL;
++    char *ccache_name = NULL;
++    krb5_principal princ = NULL;
++    char *mem_name = NULL;
++    char *sep;
++
++    kerr = krb5_cc_resolve(kctx, ccache_file, &ccache);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error resolving ccache [%s].\n",
++                                    ccache_file);
++        return kerr;
++    }
++
++    kerr = krb5_cc_get_full_name(kctx, ccache, &ccache_name);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read name for ccache [%s].\n",
++                                    ccache_file);
++        goto done;
++    }
++
++    sep = strchr(ccache_name, ':');
++    if (sep == NULL || sep[1] == '\0') {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Ccache name [%s] does not have delimiter[:] .\n", ccache_name);
++        kerr = KRB5KRB_ERR_GENERIC;
++        goto done;
++    }
++
++    if (strncmp(ccache_name, "MEMORY:", sizeof("MEMORY:") -1) == 0) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Ccache [%s] is already memory ccache.\n",
++                                 ccache_name);
++        *_mem_name = talloc_strdup(mem_ctx, ccache_name);
++        if(*_mem_name == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++            kerr = KRB5KRB_ERR_GENERIC;
++            goto done;
++        }
++        kerr = 0;
++        goto done;
++    }
++    if (strncmp(ccache_name, "FILE:", sizeof("FILE:") -1) == 0) {
++        mem_name = talloc_asprintf(mem_ctx, "MEMORY:%s", sep + 1);
++        if (mem_name == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++            kerr = KRB5KRB_ERR_GENERIC;
++            goto done;
++        }
++    } else {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Unexpected ccache type for ccache [%s], " \
++                                    "currently only FILE is supported.\n",
++                                    ccache_name);
++        kerr = KRB5KRB_ERR_GENERIC;
++        goto done;
++    }
++
++    kerr = krb5_cc_resolve(kctx, mem_name, &mem_ccache);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error resolving ccache [%s].\n", mem_name);
++        goto done;
++    }
++
++    kerr = krb5_cc_get_principal(kctx, ccache, &princ);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "error reading principal from ccache [%s].\n", ccache_name);
++        goto done;
++    }
++
++    kerr = krb5_cc_initialize(kctx, mem_ccache, princ);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to initialize ccache [%s].\n", mem_name);
++        goto done;
++    }
++
++    kerr = krb5_cc_copy_creds(kctx, ccache, mem_ccache);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to copy ccache [%s] to [%s].\n", ccache_name, mem_name);
++        goto done;
++    }
++
++    *_mem_name = mem_name;
++    kerr = 0;
++
++done:
++    if (kerr != 0) {
++        talloc_free(mem_name);
++    }
++
++    free(ccache_name);
++    krb5_free_principal(kctx, princ);
++
++    if (krb5_cc_close(kctx, ccache) != 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_close failed.\n");
++    }
++
++    if (krb5_cc_close(kctx, mem_ccache) != 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_close failed.\n");
++    }
++
++    return  kerr;
++}
+diff --git a/src/providers/krb5/krb5_ccache.h b/src/providers/krb5/krb5_ccache.h
+index e47df3665e3f325cc56d34767b416662577cc048..f3928e644d704ed263cbe28bab327bf75b2f5cce 100644
+--- a/src/providers/krb5/krb5_ccache.h
++++ b/src/providers/krb5/krb5_ccache.h
+@@ -53,4 +53,21 @@ errno_t safe_remove_old_ccache_file(const char *old_ccache,
+                                     const char *new_ccache,
+                                     uid_t uid, gid_t gid);
+ 
++/**
++ * @brief Copy given ccache into a MEMORY ccache
++ *
++ * @param[in] mem_ctx Talloc memory context the new ccache name should be
++ *                    allocated on
++ * @param[in] kctx Kerberos context
++ * @param[in] ccache_file Name of existing ccache
++ * @param[out] _mem_name Name of the new MEMORY ccache
++ *
++ * In contrast to MEMORY keytabs MEMORY ccaches can and must be removed
++ * explicitly with krb5_cc_destroy() from the memory. Just calling
++ * krb5_cc_close() will keep the MEMORY ccache in memory even if there are no
++ * open handles for the given MEMORY ccache.
++ */
++krb5_error_code copy_ccache_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
++                                        const char *ccache_file,
++                                        char **_mem_name);
+ #endif /* __KRB5_CCACHE_H__ */
+diff --git a/src/tests/cmocka/test_copy_ccache.c b/src/tests/cmocka/test_copy_ccache.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..c7a5573b83b8faeb5c7447b48fa40ec8957e1aaf
+--- /dev/null
++++ b/src/tests/cmocka/test_copy_ccache.c
+@@ -0,0 +1,238 @@
++/*
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    SSSD tests: Tests ccache utilities
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <stdio.h>
++#include <popt.h>
++
++#include "util/sss_krb5.h"
++#include "providers/krb5/krb5_common.h"
++#include "providers/krb5/krb5_ccache.h"
++#include "tests/cmocka/common_mock.h"
++
++#define CCACHE_TEST_CLIENT_PRINC "test/client@TEST.CCACHE"
++#define CCACHE_TEST_SERVER_PRINC "test/server@TEST.CCACHE"
++#define CCACHE_PATH TEST_DIR "/ccache_test.ccache"
++
++struct ccache_test_ctx {
++    krb5_context kctx;
++    const char *ccache_file_name;
++    krb5_principal client_principal;
++    krb5_principal server_principal;
++};
++
++void setup_ccache(void **state)
++{
++    struct ccache_test_ctx *test_ctx;
++    krb5_error_code kerr;
++    krb5_ccache ccache;
++    krb5_creds test_creds;
++    static krb5_address addr;
++    int add=0x12345;
++    krb5_authdata *a;
++
++    static krb5_address *addrs[] = {
++        &addr,
++        NULL,
++    };
++
++    assert_true(leak_check_setup());
++
++
++    test_ctx = talloc_zero(global_talloc_context, struct ccache_test_ctx);
++    assert_non_null(test_ctx);
++
++    kerr = krb5_init_context(&test_ctx->kctx);
++    assert_int_equal(kerr, 0);
++
++    addr.magic = KV5M_ADDRESS;
++    addr.addrtype = ADDRTYPE_INET;
++    addr.length = 4;
++    addr.contents = (krb5_octet *) &add;
++
++    memset(&test_creds, 0, sizeof(test_creds));
++    test_creds.magic = KV5M_CREDS;
++    kerr = krb5_parse_name(test_ctx->kctx, CCACHE_TEST_CLIENT_PRINC,
++                           &test_ctx->client_principal);
++    assert_int_equal(kerr, 0);
++    test_creds.client = test_ctx->client_principal;
++    kerr = krb5_parse_name(test_ctx->kctx, CCACHE_TEST_SERVER_PRINC,
++                           &test_ctx->server_principal);
++    assert_int_equal(kerr, 0);
++    test_creds.server = test_ctx->server_principal;
++
++    test_creds.keyblock.magic = KV5M_KEYBLOCK;
++    test_creds.keyblock.contents = 0;
++    test_creds.keyblock.enctype = 1;
++    test_creds.keyblock.length = 1;
++    test_creds.keyblock.contents = (unsigned char *) discard_const("1");
++    test_creds.times.authtime = 1111;
++    test_creds.times.starttime = 2222;
++    test_creds.times.endtime = 3333;
++    test_creds.times.renew_till = 4444;
++    test_creds.is_skey = 1;
++    test_creds.ticket_flags = 5555;
++    test_creds.addresses = addrs;
++
++    test_creds.ticket.magic = KV5M_DATA;
++    test_creds.ticket.length = sizeof("Ticket");
++    test_creds.ticket.data = discard_const("Ticket");
++
++    test_creds.authdata = malloc (2 * sizeof(krb5_authdata *));
++    assert_non_null(test_creds.authdata);
++
++    a = (krb5_authdata *) malloc(sizeof(krb5_authdata));
++    assert_non_null(a);
++
++    a->magic = KV5M_AUTHDATA;
++    a->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
++    a->contents = (krb5_octet * ) malloc(1);
++    assert_non_null(a->contents);
++    a->contents[0]=5;
++    a->length = 1;
++    test_creds.authdata[0] = a;
++    test_creds.authdata[1] = NULL;
++
++
++    test_ctx->ccache_file_name = "FILE:" CCACHE_PATH;
++
++    kerr = krb5_cc_resolve(test_ctx->kctx, test_ctx->ccache_file_name,
++                               &ccache);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_cc_initialize(test_ctx->kctx, ccache, test_creds.client);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_cc_store_cred(test_ctx->kctx, ccache, &test_creds);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_cc_close(test_ctx->kctx, ccache);
++    assert_int_equal(kerr, 0);
++
++    check_leaks_push(test_ctx);
++    *state = test_ctx;
++
++    krb5_free_authdata(test_ctx->kctx, test_creds.authdata);
++}
++
++void teardown_ccache(void **state)
++{
++    int ret;
++    struct ccache_test_ctx *test_ctx = talloc_get_type(*state,
++                                                        struct ccache_test_ctx);
++    assert_non_null(test_ctx);
++
++    krb5_free_principal(test_ctx->kctx, test_ctx->client_principal);
++    krb5_free_principal(test_ctx->kctx, test_ctx->server_principal);
++    krb5_free_context(test_ctx->kctx);
++
++    ret = unlink(CCACHE_PATH);
++    assert_int_equal(ret, 0);
++
++    assert_true(check_leaks_pop(test_ctx) == true);
++    talloc_free(test_ctx);
++    assert_true(leak_check_teardown());
++}
++
++void test_copy_ccache(void **state)
++{
++    krb5_error_code kerr;
++    char *mem_ccache_name;
++    krb5_ccache ccache;
++    krb5_creds mcreds;
++    krb5_creds creds;
++    krb5_principal mem_principal;
++    struct ccache_test_ctx *test_ctx = talloc_get_type(*state,
++                                                        struct ccache_test_ctx);
++    assert_non_null(test_ctx);
++
++    kerr = copy_ccache_into_memory(test_ctx, test_ctx->kctx,
++                                   test_ctx->ccache_file_name,
++                                   &mem_ccache_name);
++    assert_int_equal(kerr, 0);
++    assert_non_null(mem_ccache_name);
++
++    kerr = krb5_cc_resolve(test_ctx->kctx, mem_ccache_name, &ccache);
++    assert_int_equal(kerr, 0);
++
++    talloc_free(mem_ccache_name);
++
++    kerr = krb5_cc_get_principal(test_ctx->kctx, ccache, &mem_principal);
++    assert_int_equal(kerr, 0);
++    assert_non_null(mem_principal);
++
++    assert_true(krb5_principal_compare(test_ctx->kctx, mem_principal,
++                                       test_ctx->client_principal));
++    krb5_free_principal(test_ctx->kctx, mem_principal);
++
++    memset(&mcreds, 0, sizeof(mcreds));
++    memset(&creds, 0, sizeof(mcreds));
++    mcreds.client = test_ctx->client_principal;
++    mcreds.server = test_ctx->server_principal;
++    kerr = krb5_cc_retrieve_cred(test_ctx->kctx, ccache, 0, &mcreds, &creds);
++    assert_int_equal(kerr, 0);
++    krb5_free_cred_contents(test_ctx->kctx, &creds);
++
++    kerr = krb5_cc_destroy(test_ctx->kctx, ccache);
++    assert_int_equal(kerr, 0);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    int rv;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test_setup_teardown(test_copy_ccache,
++                                 setup_ccache, teardown_ccache),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    /* Even though normally the tests should clean up after themselves
++     * they might not after a failed run. Remove the old db to be sure */
++    tests_set_cwd();
++
++    rv = run_tests(tests);
++
++    return rv;
++}
+-- 
+1.9.3
+
diff --git a/SOURCES/0123-AD-Provider-bug-fix-uninitialized-variable.patch b/SOURCES/0123-AD-Provider-bug-fix-uninitialized-variable.patch
deleted file mode 100644
index 0649862..0000000
--- a/SOURCES/0123-AD-Provider-bug-fix-uninitialized-variable.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 400c06ebd99bfa447d0f88228320224291c862e0 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Fri, 25 Apr 2014 13:26:19 +0100
-Subject: [PATCH 123/124] AD Provider: bug-fix uninitialized variable
-
-ad_subdomains_refresh() always set value to output parameter 'changes' if EOK is returned.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit cef2384a3a6fc1a1637c6a55e2bced93d28e8fca)
----
- src/providers/ad/ad_subdomains.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index ee04cbbe048e55666db22c48cf22c4c0241a0e3c..ef3bb50e83fc8e39b91922d6fc9646dfe6da58a3 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -423,6 +423,7 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
-     if (count == h) {
-         /* all domains were already accounted for and have been updated */
-         ret = EOK;
-+        *changes = false;
-         goto done;
-     }
- 
-@@ -682,7 +683,7 @@ static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
-     struct sysdb_attrs **reply = NULL;
-     struct ad_subdomains_req_ctx *ctx;
-     int dp_error = DP_ERR_FATAL;
--    bool has_changes;
-+    bool has_changes = false;
- 
-     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
- 
--- 
-1.9.0
-
diff --git a/SOURCES/0123-krb5-add-copy_keytab_into_memory.patch b/SOURCES/0123-krb5-add-copy_keytab_into_memory.patch
new file mode 100644
index 0000000..6a9f46f
--- /dev/null
+++ b/SOURCES/0123-krb5-add-copy_keytab_into_memory.patch
@@ -0,0 +1,484 @@
+From c3dd5cd9ba4020d0db0dd4ae1d9003ba852780c8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 17 Nov 2014 17:40:26 +0100
+Subject: [PATCH 123/128] krb5: add copy_keytab_into_memory()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                         |  18 +++
+ src/providers/krb5/krb5_common.h    |  31 ++++++
+ src/providers/krb5/krb5_keytab.c    | 165 ++++++++++++++++++++++++++++
+ src/tests/cmocka/test_copy_keytab.c | 213 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 427 insertions(+)
+ create mode 100644 src/providers/krb5/krb5_keytab.c
+ create mode 100644 src/tests/cmocka/test_copy_keytab.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 62d900dec654baff59762c934885aef9ae5510b9..065992b84ce491b8b6ce1826cb5e88d7e0295176 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -215,6 +215,7 @@ if HAVE_CMOCKA
+         sdap-tests \
+         test_sysdb_views \
+         test_copy_ccache \
++        test_copy_keytab \
+         $(NULL)
+ 
+ if BUILD_IFP
+@@ -2097,6 +2098,23 @@ test_copy_ccache_LDADD = \
+     libsss_test_common.la \
+     $(NULL)
+ 
++test_copy_keytab_SOURCES = \
++    src/tests/cmocka/test_copy_keytab.c \
++    src/providers/krb5/krb5_keytab.c \
++    src/util/sss_krb5.c \
++    $(NULL)
++test_copy_keytab_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
++test_copy_keytab_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(POPT_LIBS) \
++    $(TALLOC_LIBS) \
++    $(KRB5_LIBS) \
++    $(SSSD_INTERNAL_LTLIBS) \
++    libsss_test_common.la \
++    $(NULL)
++
+ endif # HAVE_CMOCKA
+ 
+ noinst_PROGRAMS = pam_test_client
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index a5cee6497e4930b16b1102a525d9fa3452845a58..81e64688a6d93a4b3ecf41d75d1bf6166b4619ce 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -189,4 +189,35 @@ int sssm_krb5_auth_init(struct be_ctx *bectx,
+                         struct bet_ops **ops,
+                         void **pvt_auth_data);
+ 
++/* from krb5_keytab.c */
++
++/**
++ * @brief Copy given keytab into a MEMORY keytab
++ *
++ * @param[in] mem_ctx Talloc memory context the new keytab name should be
++ *                    allocated on
++ * @param[in] kctx Kerberos context
++ * @param[in] inp_keytab_file Existing keytab, if set to NULL the default
++ *                            keytab will be used
++ * @param[out] _mem_name Name of the new MEMORY keytab
++ * @param[out] _mem_keytab Krb5 keytab handle for the new MEMORY keytab, NULL
++ *                         may be passed here if the caller has no use for the
++ *                         handle
++ *
++ * The memory for the MEMORY keytab is handled by libkrb5 internally and
++ * a reference counter is used. If the reference counter of the specific
++ * MEMORY keytab reaches 0, i.e. no open ones are left, the memory is free.
++ * This means we cannot call krb5_kt_close() for the new MEMORY keytab  in
++ * copy_keytab_into_memory() because this would destroy it immediately. Hence
++ * we have to return the handle so that the caller can safely remove the
++ * MEMORY keytab if the is not needed anymore. Since libkrb5 frees the
++ * internal memory when the library is unloaded short running processes can
++ * safely pass NULL as the 5th argument because on exit all memory is freed.
++ * Long running processes which need more control over the memory consumption
++ * should close the handle for free the memory at runtime.
++ */
++krb5_error_code copy_keytab_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
++                                        const char *inp_keytab_file,
++                                        char **_mem_name,
++                                        krb5_keytab *_mem_keytab);
+ #endif /* __KRB5_COMMON_H__ */
+diff --git a/src/providers/krb5/krb5_keytab.c b/src/providers/krb5/krb5_keytab.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..855f69419611b863a7aea79e2788272f819b0736
+--- /dev/null
++++ b/src/providers/krb5/krb5_keytab.c
+@@ -0,0 +1,165 @@
++/*
++    SSSD
++
++    Kerberos 5 Backend Module -- keytab related utilities
++
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "util/util.h"
++#include "util/sss_krb5.h"
++
++krb5_error_code copy_keytab_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
++                                        char *inp_keytab_file,
++                                        char **_mem_name,
++                                        krb5_keytab *_mem_keytab)
++{
++    krb5_error_code kerr;
++    krb5_error_code kt_err;
++    krb5_keytab keytab = NULL;
++    krb5_keytab mem_keytab = NULL;
++    krb5_kt_cursor cursor;
++    krb5_keytab_entry entry;
++    char keytab_name[MAX_KEYTAB_NAME_LEN];
++    char *sep;
++    char *mem_name = NULL;
++    char *keytab_file;
++    char default_keytab_name[MAX_KEYTAB_NAME_LEN];
++
++    keytab_file = inp_keytab_file;
++    if (keytab_file == NULL) {
++        kerr = krb5_kt_default_name(kctx, default_keytab_name,
++                                    sizeof(default_keytab_name));
++        if (kerr != 0) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "krb5_kt_default_name failed.\n");
++            return kerr;
++        }
++
++        keytab_file = default_keytab_name;
++    }
++
++    kerr = krb5_kt_resolve(kctx, keytab_file, &keytab);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error resolving keytab [%s].\n",
++                                    keytab_file);
++        return kerr;
++    }
++
++    kerr = krb5_kt_have_content(kctx, keytab);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "keytab [%s] has not entries.\n",
++                                    keytab_file);
++        goto done;
++    }
++
++    kerr = krb5_kt_get_name(kctx, keytab, keytab_name, sizeof(keytab_name));
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read name for keytab [%s].\n",
++                                    keytab_file);
++        goto done;
++    }
++
++    sep = strchr(keytab_name, ':');
++    if (sep == NULL || sep[1] == '\0') {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Keytab name [%s] does not have delimiter[:] .\n", keytab_name);
++        kerr = KRB5KRB_ERR_GENERIC;
++        goto done;
++    }
++
++    if (strncmp(keytab_name, "MEMORY:", sizeof("MEMORY:") -1) == 0) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Keytab [%s] is already memory keytab.\n",
++                                 keytab_name);
++        *_mem_name = talloc_strdup(mem_ctx, keytab_name);
++        if(*_mem_name == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++            kerr = KRB5KRB_ERR_GENERIC;
++            goto done;
++        }
++        kerr = 0;
++        goto done;
++    }
++
++    mem_name = talloc_asprintf(mem_ctx, "MEMORY:%s", sep + 1);
++    if (mem_name == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++        kerr = KRB5KRB_ERR_GENERIC;
++        goto done;
++    }
++
++    kerr = krb5_kt_resolve(kctx, mem_name, &mem_keytab);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error resolving keytab [%s].\n",
++                                    mem_name);
++        goto done;
++    }
++
++    memset(&cursor, 0, sizeof(cursor));
++    kerr = krb5_kt_start_seq_get(kctx, keytab, &cursor);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error reading keytab [%s].\n", keytab_file);
++        goto done;
++    }
++
++    memset(&entry, 0, sizeof(entry));
++    while ((kt_err = krb5_kt_next_entry(kctx, keytab, &entry, &cursor)) == 0) {
++        kerr = krb5_kt_add_entry(kctx, mem_keytab, &entry);
++        if (kerr != 0) {
++            DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_add_entry failed.\n");
++            goto done;
++        }
++
++        kerr = sss_krb5_free_keytab_entry_contents(kctx, &entry);
++        if (kerr != 0) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Failed to free keytab entry.\n");
++        }
++        memset(&entry, 0, sizeof(entry));
++    }
++
++    kerr = krb5_kt_end_seq_get(kctx, keytab, &cursor);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_kt_end_seq_get failed.\n");
++        goto done;
++    }
++
++    /* check if we got any errors from krb5_kt_next_entry */
++    if (kt_err != 0 && kt_err != KRB5_KT_END) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error reading keytab [%s].\n", keytab_file);
++        kerr = KRB5KRB_ERR_GENERIC;
++        goto done;
++    }
++
++    *_mem_name = mem_name;
++    if (_mem_keytab != NULL) {
++        *_mem_keytab = mem_keytab;
++    }
++
++    kerr = 0;
++done:
++
++    if (kerr != 0) {
++        talloc_free(mem_name);
++    }
++
++    if (keytab != NULL && krb5_kt_close(kctx, keytab) != 0) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "krb5_kt_close failed");
++    }
++
++    return kerr;
++}
+diff --git a/src/tests/cmocka/test_copy_keytab.c b/src/tests/cmocka/test_copy_keytab.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..9d2b801564f738b4a75445045bd7602b2fd01625
+--- /dev/null
++++ b/src/tests/cmocka/test_copy_keytab.c
+@@ -0,0 +1,213 @@
++/*
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    SSSD tests: Tests keytab utilities
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <stdio.h>
++#include <popt.h>
++
++#include "util/sss_krb5.h"
++#include "providers/krb5/krb5_common.h"
++#include "tests/cmocka/common_mock.h"
++
++#define KEYTAB_TEST_PRINC "test/keytab@TEST.KEYTAB"
++#define KEYTAB_PATH TEST_DIR "/keytab_test.keytab"
++
++struct keytab_test_ctx {
++    krb5_context kctx;
++    const char *keytab_file_name;
++    krb5_principal principal;
++};
++
++void setup_keytab(void **state)
++{
++    struct keytab_test_ctx *test_ctx;
++    krb5_error_code kerr;
++    krb5_keytab keytab;
++    krb5_keytab_entry kent;
++
++    assert_true(leak_check_setup());
++
++    test_ctx = talloc_zero(global_talloc_context, struct keytab_test_ctx);
++    assert_non_null(test_ctx);
++
++    kerr = krb5_init_context(&test_ctx->kctx);
++    assert_int_equal(kerr, 0);
++
++    test_ctx->keytab_file_name = "FILE:" KEYTAB_PATH;
++
++    kerr = krb5_kt_resolve(test_ctx->kctx, test_ctx->keytab_file_name, &keytab);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_parse_name(test_ctx->kctx, KEYTAB_TEST_PRINC,
++                           &test_ctx->principal);
++    assert_int_equal(kerr, 0);
++
++    memset(&kent, 0, sizeof(kent));
++    kent.magic = KV5M_KEYTAB_ENTRY;
++    kent.principal = test_ctx->principal;
++    kent.timestamp = 12345;
++    kent.vno = 1;
++    kent.key.magic = KV5M_KEYBLOCK;
++    kent.key.enctype = 1;
++    kent.key.length = 2;
++    kent.key.contents = (krb5_octet *) discard_const("11");
++
++    kerr = krb5_kt_add_entry(test_ctx->kctx, keytab, &kent);
++    assert_int_equal(kerr, 0);
++
++    kent.key.enctype = 2;
++    kent.key.contents = (krb5_octet *) discard_const("12");
++
++    kerr = krb5_kt_add_entry(test_ctx->kctx, keytab, &kent);
++    assert_int_equal(kerr, 0);
++
++    kent.vno = 2;
++    kent.key.enctype = 1;
++    kent.key.contents = (krb5_octet *) discard_const("21");
++
++    kerr = krb5_kt_add_entry(test_ctx->kctx, keytab, &kent);
++    assert_int_equal(kerr, 0);
++
++    kent.key.enctype = 2;
++    kent.key.contents = (krb5_octet *) discard_const("22");
++
++    kerr = krb5_kt_add_entry(test_ctx->kctx, keytab, &kent);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_kt_close(test_ctx->kctx, keytab);
++    assert_int_equal(kerr, 0);
++
++    check_leaks_push(test_ctx);
++    *state = test_ctx;
++}
++
++void teardown_keytab(void **state)
++{
++    int ret;
++    struct keytab_test_ctx *test_ctx = talloc_get_type(*state,
++                                                        struct keytab_test_ctx);
++    assert_non_null(test_ctx);
++
++    krb5_free_principal(test_ctx->kctx, test_ctx->principal);
++    krb5_free_context(test_ctx->kctx);
++
++    ret = unlink(KEYTAB_PATH);
++    assert_int_equal(ret, 0);
++
++    assert_true(check_leaks_pop(test_ctx) == true);
++    talloc_free(test_ctx);
++    assert_true(leak_check_teardown());
++}
++
++void test_copy_keytab(void **state)
++{
++    krb5_error_code kerr;
++    char *mem_keytab_name;
++    krb5_keytab mem_keytab;
++    krb5_keytab keytab;
++    krb5_keytab_entry kent;
++    struct keytab_test_ctx *test_ctx = talloc_get_type(*state,
++                                                        struct keytab_test_ctx);
++    assert_non_null(test_ctx);
++
++    kerr = copy_keytab_into_memory(test_ctx, test_ctx->kctx,
++                                   test_ctx->keytab_file_name,
++                                   &mem_keytab_name, &mem_keytab);
++    assert_int_equal(kerr, 0);
++    assert_non_null(mem_keytab_name);
++
++    kerr = krb5_kt_resolve(test_ctx->kctx, mem_keytab_name, &keytab);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_kt_get_entry(test_ctx->kctx, keytab, test_ctx->principal, 9, 9,
++                             &kent);
++    assert_int_not_equal(kerr, 0);
++
++    kerr = krb5_kt_get_entry(test_ctx->kctx, keytab, test_ctx->principal, 1, 1,
++                             &kent);
++    assert_int_equal(kerr, 0);
++    krb5_free_keytab_entry_contents(test_ctx->kctx, &kent);
++
++    kerr = krb5_kt_get_entry(test_ctx->kctx, keytab, test_ctx->principal, 1, 2,
++                             &kent);
++    assert_int_equal(kerr, 0);
++    krb5_free_keytab_entry_contents(test_ctx->kctx, &kent);
++
++    kerr = krb5_kt_get_entry(test_ctx->kctx, keytab, test_ctx->principal, 2, 1,
++                             &kent);
++    assert_int_equal(kerr, 0);
++    krb5_free_keytab_entry_contents(test_ctx->kctx, &kent);
++
++    kerr = krb5_kt_get_entry(test_ctx->kctx, keytab, test_ctx->principal, 2, 2,
++                             &kent);
++    assert_int_equal(kerr, 0);
++    krb5_free_keytab_entry_contents(test_ctx->kctx, &kent);
++
++    talloc_free(mem_keytab_name);
++
++    kerr = krb5_kt_close(test_ctx->kctx, keytab);
++    assert_int_equal(kerr, 0);
++
++    kerr = krb5_kt_close(test_ctx->kctx, mem_keytab);
++    assert_int_equal(kerr, 0);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    int rv;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test_setup_teardown(test_copy_keytab,
++                                 setup_keytab, teardown_keytab),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    /* Even though normally the tests should clean up after themselves
++     * they might not after a failed run. Remove the old db to be sure */
++    tests_set_cwd();
++
++    rv = run_tests(tests);
++
++    return rv;
++}
+-- 
+1.9.3
+
diff --git a/SOURCES/0124-AD-Provider-bugfix-use-after-free.patch b/SOURCES/0124-AD-Provider-bugfix-use-after-free.patch
deleted file mode 100644
index e10c4b9..0000000
--- a/SOURCES/0124-AD-Provider-bugfix-use-after-free.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 25193cfe110b328b428cde9641400f7dc999416e Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Fri, 25 Apr 2014 14:42:39 +0100
-Subject: [PATCH 124/124] AD Provider: bugfix use-after-free
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2322
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit ed61bfc5184d9c7a46d17681a22a1abb64423708)
----
- src/providers/data_provider_be.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
-index 37b687f25810447c08c6e0c6e8da4f64c99a5f5f..f85c63065252b24d4eeec0d2671ab0a1a16d4b9a 100644
---- a/src/providers/data_provider_be.c
-+++ b/src/providers/data_provider_be.c
-@@ -210,7 +210,8 @@ void be_req_terminate(struct be_req *be_req,
- void be_terminate_domain_requests(struct be_ctx *be_ctx,
-                                   const char *domain)
- {
--    struct be_req *be_req = NULL;
-+    struct be_req *be_req;
-+    struct be_req *next_be_req;
- 
-     DEBUG(SSSDBG_TRACE_FUNC, ("Terminating requests for domain [%s]\n",
-                               domain));
-@@ -220,11 +221,15 @@ void be_terminate_domain_requests(struct be_ctx *be_ctx,
-         return;
-     }
- 
--    DLIST_FOR_EACH(be_req, be_ctx->active_requests) {
-+    be_req = be_ctx->active_requests;
-+    while (be_req) {
-+        /* save pointer to next request in case be_req will be freed */
-+        next_be_req = be_req->next;
-         if (strcmp(domain, be_req->domain->name) == 0) {
-             be_req_terminate(be_req, DP_ERR_FATAL, ERR_DOMAIN_NOT_FOUND,
-                              sss_strerror(ERR_DOMAIN_NOT_FOUND));
-         }
-+        be_req = next_be_req;
-     }
- }
- 
--- 
-1.9.0
-
diff --git a/SOURCES/0124-ldap_child-copy-keytab-into-memory-to-drop-privilege.patch b/SOURCES/0124-ldap_child-copy-keytab-into-memory-to-drop-privilege.patch
new file mode 100644
index 0000000..27ea1c3
--- /dev/null
+++ b/SOURCES/0124-ldap_child-copy-keytab-into-memory-to-drop-privilege.patch
@@ -0,0 +1,159 @@
+From ebda717383bf29731c3b4d7e809be7c7fae76284 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 1 Dec 2014 17:24:31 +0100
+Subject: [PATCH 124/128] ldap_child: copy keytab into memory to drop
+ privileges earlier
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                     |  1 +
+ src/providers/ldap/ldap_child.c | 64 +++++++++++++++++++++++++++++------------
+ 2 files changed, 46 insertions(+), 19 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 065992b84ce491b8b6ce1826cb5e88d7e0295176..3d16428856d6cb2e9e190b0df8895ab3f45db39c 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2564,6 +2564,7 @@ krb5_child_LDADD = \
+ 
+ ldap_child_SOURCES = \
+     src/providers/ldap/ldap_child.c \
++    src/providers/krb5/krb5_keytab.c \
+     src/util/sss_krb5.c \
+     src/util/atomic_io.c \
+     src/util/authtok.c \
+diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
+index a922b181715c5e89301e9f50bdb81723d1ff2a6a..f7f8d1d2eab3f66fe4f7d09e50458b495739c1d2 100644
+--- a/src/providers/ldap/ldap_child.c
++++ b/src/providers/ldap/ldap_child.c
+@@ -33,6 +33,7 @@
+ #include "util/sss_krb5.h"
+ #include "util/child_common.h"
+ #include "providers/dp_backend.h"
++#include "providers/krb5/krb5_common.h"
+ 
+ static krb5_context krb5_error_ctx;
+ #define LDAP_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
+@@ -47,8 +48,9 @@ static const char *__ldap_child_krb5_error_msg;
+ struct input_buffer {
+     const char *realm_str;
+     const char *princ_str;
+-    const char *keytab_name;
++    char *keytab_name;
+     krb5_deltat lifetime;
++    krb5_context context;
+     uid_t uid;
+     gid_t gid;
+ };
+@@ -246,12 +248,11 @@ static int lc_verify_keytab_ex(const char *principal,
+ }
+ 
+ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
++                                               krb5_context context,
+                                                const char *realm_str,
+                                                const char *princ_str,
+                                                const char *keytab_name,
+                                                const krb5_deltat lifetime,
+-                                               uid_t uid,
+-                                               gid_t gid,
+                                                const char **ccname_out,
+                                                time_t *expire_time_out)
+ {
+@@ -262,7 +263,6 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+     char *full_princ = NULL;
+     char *default_realm = NULL;
+     char *tmp_str = NULL;
+-    krb5_context context = NULL;
+     krb5_keytab keytab = NULL;
+     krb5_ccache ccache = NULL;
+     krb5_principal kprinc;
+@@ -278,13 +278,6 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+     char *ccname_file;
+     mode_t old_umask;
+ 
+-    krberr = krb5_init_context(&context);
+-    if (krberr) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Failed to init kerberos context\n");
+-        return krberr;
+-    }
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
+-
+     tmp_ctx = talloc_new(memctx);
+     if (tmp_ctx == NULL) {
+         krberr = KRB5KRB_ERR_GENERIC;
+@@ -440,12 +433,6 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
+     }
+     DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n");
+ 
+-    krberr = become_user(uid, gid);
+-    if (krberr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
+-        goto done;
+-    }
+-
+     ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy);
+     ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file);
+     if (ccname_dummy == NULL || ccname == NULL) {
+@@ -558,6 +545,30 @@ static int prepare_response(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++static krb5_error_code privileged_krb5_setup(struct input_buffer *ibuf)
++{
++    krb5_error_code kerr;
++    char *keytab_name;
++
++    kerr = krb5_init_context(&ibuf->context);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to init kerberos context\n");
++        return kerr;
++    }
++    DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
++
++    kerr = copy_keytab_into_memory(ibuf, ibuf->context, ibuf->keytab_name,
++                                   &keytab_name, NULL);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "copy_keytab_into_memory failed.\n");
++        return kerr;
++    }
++    talloc_free(ibuf->keytab_name);
++    ibuf->keytab_name = keytab_name;
++
++    return 0;
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int ret;
+@@ -662,11 +673,26 @@ int main(int argc, const char *argv[])
+         goto fail;
+     }
+ 
++    kerr = privileged_krb5_setup(ibuf);
++    if (kerr != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Privileged Krb5 setup failed.\n");
++        goto fail;
++    }
++    DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
++
++    kerr = become_user(ibuf->uid, ibuf->gid);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
++        goto fail;
++    }
++
++    DEBUG(SSSDBG_TRACE_INTERNAL,
++          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
++
+     DEBUG(SSSDBG_TRACE_INTERNAL, "getting TGT sync\n");
+-    kerr = ldap_child_get_tgt_sync(main_ctx,
++    kerr = ldap_child_get_tgt_sync(main_ctx, ibuf->context,
+                                    ibuf->realm_str, ibuf->princ_str,
+                                    ibuf->keytab_name, ibuf->lifetime,
+-                                   ibuf->uid, ibuf->gid,
+                                    &ccname, &expire_time);
+     if (kerr != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child_get_tgt_sync failed.\n");
+-- 
+1.9.3
+
diff --git a/SOURCES/0125-ipa-subdomains-provider-make-sure-search-by-SID-work.patch b/SOURCES/0125-ipa-subdomains-provider-make-sure-search-by-SID-work.patch
deleted file mode 100644
index 80cd52c..0000000
--- a/SOURCES/0125-ipa-subdomains-provider-make-sure-search-by-SID-work.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-From 503e1ebb9c36ecb978a28a5cefd94d24945ee39b Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Tue, 13 May 2014 11:22:29 +0300
-Subject: [PATCH 125/126] ipa subdomains provider: make sure search by SID
- works for homedir
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/ipa/ipa_subdomains_id.c | 20 +++++++++++++++-----
- 1 file changed, 15 insertions(+), 5 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 978ccc261d7525662e835b867044b6a5238a29df..d8922a461fc1cbbec4bb65b8cd6e6cf25f2dc605 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -484,7 +484,11 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-     uint32_t uid;
-     const char *fqname;
-     const char *homedir = NULL;
--    struct ldb_result *res;
-+    struct ldb_result *res = NULL;
-+    struct ldb_message *msg = NULL;
-+    const char *attrs[] = { SYSDB_NAME,
-+                            SYSDB_UIDNUM,
-+                            NULL };
- 
-     if (filter_type == BE_FILTER_NAME) {
-         ret = sysdb_getpwnam(mem_ctx, dom->sysdb, dom, filter_value, &res);
-@@ -496,6 +500,9 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-             goto done;
-         }
-         ret = sysdb_getpwuid(mem_ctx, dom->sysdb, dom, uid, &res);
-+    } else if (filter_type == BE_FILTER_SECID) {
-+        ret = sysdb_search_user_by_sid_str(mem_ctx, dom->sysdb, dom,
-+                                           filter_value, attrs, &msg);
-     } else {
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("Unsupported filter type: [%d].\n", filter_type));
-@@ -503,24 +510,27 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-         goto done;
-     }
- 
--    if (ret != EOK) {
-+    if (ret != EOK && ret != ENOENT) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               ("Failed to make request to our cache: [%d]: [%s]\n",
-                ret, sss_strerror(ret)));
-         goto done;
-     }
- 
--    if (res->count == 0) {
-+    if ((res && res->count == 0) || (msg && msg->num_elements == 0)) {
-         ret = ENOENT;
-         goto done;
-     }
- 
-+    if (res != NULL) {
-+        msg = res->msgs[0];
-+    }
-     /*
-      * Homedir is always overriden by subdomain_homedir even if it was
-      * explicitly set by user.
-      */
--    fqname = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
--    uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
-+    fqname = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+    uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
-     if (uid == 0) {
-         DEBUG(SSSDBG_OP_FAILURE, ("UID for user [%s] is not known.\n",
-                                   filter_value));
--- 
-1.9.0
-
diff --git a/SOURCES/0125-krb5_child-become-user-earlier.patch b/SOURCES/0125-krb5_child-become-user-earlier.patch
new file mode 100644
index 0000000..6a5fd92
--- /dev/null
+++ b/SOURCES/0125-krb5_child-become-user-earlier.patch
@@ -0,0 +1,249 @@
+From 0c7f33bb6b16ef7dd27816489d9ec0b5c758c64f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 1 Dec 2014 17:36:56 +0100
+Subject: [PATCH 125/128] krb5_child: become user earlier
+
+The host keytab and the FAST credential cache are copied into memory
+early at startup to allow to drop privileges earlier.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                     |   1 +
+ src/providers/krb5/krb5_child.c | 131 ++++++++++++++++++++++++++++------------
+ 2 files changed, 94 insertions(+), 38 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 3d16428856d6cb2e9e190b0df8895ab3f45db39c..6f6db56f5d6229b530cc6f18f66c42f22140bdeb 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2531,6 +2531,7 @@ libsss_ad_la_LDFLAGS = \
+ krb5_child_SOURCES = \
+     src/providers/krb5/krb5_child.c \
+     src/providers/krb5/krb5_ccache.c \
++    src/providers/krb5/krb5_keytab.c \
+     src/providers/dp_pam_data_util.c \
+     src/util/user_info_msg.c \
+     src/util/sss_krb5.c \
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index d828dd550251d70851edcdc6b1eda6f5c051baf2..ce8a9235e1d64bccc91d367bc744cca2b32a40da 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -42,6 +42,12 @@
+ 
+ #define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
+ 
++enum k5c_fast_opt {
++    K5C_FAST_NEVER,
++    K5C_FAST_TRY,
++    K5C_FAST_DEMAND,
++};
++
+ struct krb5_req {
+     krb5_context ctx;
+     krb5_principal princ;
+@@ -67,6 +73,7 @@ struct krb5_req {
+     char *old_ccname;
+     bool old_cc_valid;
+     bool old_cc_active;
++    enum k5c_fast_opt fast_val;
+ };
+ 
+ static krb5_context krb5_error_ctx;
+@@ -1839,6 +1846,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
+     char *fast_principal;
+     krb5_error_code kerr;
+     char *tmp_str;
++    char *new_ccname;
+ 
+     tmp_str = getenv(SSSD_KRB5_FAST_PRINCIPAL);
+     if (tmp_str) {
+@@ -1881,6 +1889,15 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
+         return kerr;
+     }
+ 
++    kerr = copy_ccache_into_memory(kr, kr->ctx, kr->fast_ccname, &new_ccname);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "copy_ccache_into_memory failed.\n");
++        return kerr;
++    }
++
++    talloc_free(kr->fast_ccname);
++    kr->fast_ccname = new_ccname;
++
+     kerr = sss_krb5_get_init_creds_opt_set_fast_ccache_name(kr->ctx,
+                                                             kr->options,
+                                                             kr->fast_ccname);
+@@ -1908,12 +1925,6 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
+     return EOK;
+ }
+ 
+-enum k5c_fast_opt {
+-    K5C_FAST_NEVER,
+-    K5C_FAST_TRY,
+-    K5C_FAST_DEMAND,
+-};
+-
+ static errno_t check_use_fast(enum k5c_fast_opt *_fast_val)
+ {
+     char *use_fast_str;
+@@ -2064,19 +2075,8 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+ {
+     krb5_error_code kerr;
+     int parse_flags;
+-    enum k5c_fast_opt fast_val;
+ 
+-    kerr = check_use_fast(&fast_val);
+-    if (kerr != EOK) {
+-        return kerr;
+-    }
+-
+-    kerr = k5c_ccache_setup(kr, offline);
+-    if (kerr != EOK) {
+-        return kerr;
+-    }
+-
+-    if (offline || (fast_val == K5C_FAST_NEVER && kr->validate == false)) {
++    if (offline || (kr->fast_val == K5C_FAST_NEVER && kr->validate == false)) {
+         /* If krb5_child was started as setuid, but we don't need to
+          * perform either validation or FAST, just drop privileges to
+          * the user who is logging in. The same applies to the offline case
+@@ -2097,12 +2097,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+               "Cannot read [%s] from environment.\n", SSSD_KRB5_REALM);
+     }
+ 
+-    kerr = krb5_init_context(&kr->ctx);
+-    if (kerr != 0) {
+-        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+-        return kerr;
+-    }
+-
+     /* Set the global error context */
+     krb5_error_ctx = kr->ctx;
+ 
+@@ -2145,12 +2139,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+         return ENOMEM;
+     }
+ 
+-    kerr = sss_krb5_get_init_creds_opt_alloc(kr->ctx, &kr->options);
+-    if (kerr != 0) {
+-        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+-        return kerr;
+-    }
+-
+ #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_RESPONDER
+     kerr = krb5_get_init_creds_opt_set_responder(kr->ctx, kr->options,
+                                                  sss_krb5_responder, kr);
+@@ -2175,14 +2163,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+ 
+     if (!offline) {
+         set_canonicalize_option(kr->options);
+-
+-        if (fast_val != K5C_FAST_NEVER) {
+-            kerr = k5c_setup_fast(kr, fast_val == K5C_FAST_DEMAND);
+-            if (kerr != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "Cannot set up FAST\n");
+-                return kerr;
+-            }
+-        }
+     }
+ 
+ /* TODO: set options, e.g.
+@@ -2199,6 +2179,63 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+     return kerr;
+ }
+ 
++static krb5_error_code privileged_krb5_setup(struct krb5_req *kr,
++                                             uint32_t offline)
++{
++    krb5_error_code kerr;
++    int ret;
++    char *mem_keytab;
++
++    kerr = krb5_init_context(&kr->ctx);
++    if (kerr != 0) {
++        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
++        return kerr;
++    }
++
++    kerr = sss_krb5_get_init_creds_opt_alloc(kr->ctx, &kr->options);
++    if (kerr != 0) {
++        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
++        return kerr;
++    }
++
++    ret = check_use_fast(&kr->fast_val);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "check_use_fast failed.\n");
++        return ret;;
++    }
++
++    /* For ccache types FILE: and DIR: we might need to create some directory
++     * components as root */
++    ret = k5c_ccache_setup(kr, offline);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "k5c_ccache_setup failed.\n");
++        return ret;
++    }
++
++    if (!(offline ||
++            (kr->fast_val == K5C_FAST_NEVER && kr->validate == false))) {
++        kerr = copy_keytab_into_memory(kr, kr->ctx, kr->keytab, &mem_keytab,
++                                       NULL);
++        if (kerr != 0) {
++            DEBUG(SSSDBG_OP_FAILURE, "copy_keytab_into_memory failed.\n");
++            return kerr;
++        }
++
++        talloc_free(kr->keytab);
++        kr->keytab = mem_keytab;
++
++        if (kr->fast_val != K5C_FAST_NEVER) {
++            kerr = k5c_setup_fast(kr, kr->fast_val == K5C_FAST_DEMAND);
++            if (kerr != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "Cannot set up FAST\n");
++                return kerr;
++            }
++        }
++    }
++
++    return 0;
++}
++
+ int main(int argc, const char *argv[])
+ {
+     struct krb5_req *kr = NULL;
+@@ -2207,6 +2244,7 @@ int main(int argc, const char *argv[])
+     poptContext pc;
+     int debug_fd = -1;
+     errno_t ret;
++    krb5_error_code kerr;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+@@ -2274,6 +2312,23 @@ int main(int argc, const char *argv[])
+ 
+     close(STDIN_FILENO);
+ 
++    kerr = privileged_krb5_setup(kr, offline);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "privileged_krb5_setup failed.\n");
++        ret = EFAULT;
++        goto done;
++    }
++
++    kerr = become_user(kr->uid, kr->gid);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
++        ret = EFAULT;
++        goto done;
++    }
++
++    DEBUG(SSSDBG_TRACE_INTERNAL,
++          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
++
+     ret = k5c_setup(kr, offline);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_child_setup failed.\n");
+-- 
+1.9.3
+
diff --git a/SOURCES/0126-TESTS-Basic-child-tests.patch b/SOURCES/0126-TESTS-Basic-child-tests.patch
new file mode 100644
index 0000000..3abf8a0
--- /dev/null
+++ b/SOURCES/0126-TESTS-Basic-child-tests.patch
@@ -0,0 +1,314 @@
+From 9d501b05b47a63e29c586c6dd3d40ac615a98886 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 1 Dec 2014 12:04:25 +0100
+Subject: [PATCH 126/128] TESTS: Basic child tests
+
+The child_common.c module had no unit tests, yet we need to amend it.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ Makefile.am                          |  25 ++++++
+ src/tests/cmocka/test_child.c        |  83 +++++++++++++++++++
+ src/tests/cmocka/test_child_common.c | 150 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 258 insertions(+)
+ create mode 100644 src/tests/cmocka/test_child.c
+ create mode 100644 src/tests/cmocka/test_child_common.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 6f6db56f5d6229b530cc6f18f66c42f22140bdeb..b719c646721835096931819b10be6f1a766ef22e 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -216,6 +216,7 @@ if HAVE_CMOCKA
+         test_sysdb_views \
+         test_copy_ccache \
+         test_copy_keytab \
++        test_child_common \
+         $(NULL)
+ 
+ if BUILD_IFP
+@@ -233,6 +234,7 @@ endif   # HAVE_CMOCKA
+ check_PROGRAMS = \
+     stress-tests \
+     krb5-child-test \
++    test-child \
+     $(non_interactive_cmocka_based_tests) \
+     $(non_interactive_check_based_tests)
+ 
+@@ -2115,6 +2117,29 @@ test_copy_keytab_LDADD = \
+     libsss_test_common.la \
+     $(NULL)
+ 
++test_child_SOURCES = \
++    src/tests/cmocka/test_child.c \
++    $(NULL)
++test_child_LDADD = \
++    $(POPT_LIBS) \
++    $(SSSD_INTERNAL_LTLIBS) \
++    $(NULL)
++
++test_child_common_SOURCES = \
++    src/tests/cmocka/test_child_common.c \
++    $(NULL)
++test_child_common_CFLAGS = \
++    $(AM_CFLAGS) \
++    -DCHILD_DIR=\"$(builddir)\" \
++    $(NULL)
++test_child_common_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(POPT_LIBS) \
++    $(TALLOC_LIBS) \
++    $(SSSD_INTERNAL_LTLIBS) \
++    libsss_test_common.la \
++    $(NULL)
++
+ endif # HAVE_CMOCKA
+ 
+ noinst_PROGRAMS = pam_test_client
+diff --git a/src/tests/cmocka/test_child.c b/src/tests/cmocka/test_child.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..a857afce1fe7c4f3949fe77fe4e0a24e15961a4f
+--- /dev/null
++++ b/src/tests/cmocka/test_child.c
+@@ -0,0 +1,83 @@
++/*
++    SSSD
++
++    Tests -- a simple test process that echoes input back
++
++    Authors:
++        Jakub Hrozek <jhrozek@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <sys/types.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <popt.h>
++
++#include "util/util.h"
++#include "util/child_common.h"
++
++int main(int argc, const char *argv[])
++{
++    int opt;
++    int debug_fd = -1;
++    poptContext pc;
++    const char *action;
++    ssize_t len = 0;
++    ssize_t written;
++    errno_t ret;
++    uint8_t *buf[IN_BUF_SIZE];
++    uid_t uid;
++    gid_t gid;
++
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
++         _("Debug level"), NULL},
++        {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
++         _("Add debug timestamps"), NULL},
++        {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
++         _("Show timestamps with microseconds"), NULL},
++        {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
++         _("An open file descriptor for the debug logs"), NULL},
++        {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
++         _("Send the debug output to stderr directly."), NULL }, \
++        SSSD_SERVER_OPTS(uid, gid)
++        POPT_TABLEEND
++    };
++
++    /* Set debug level to invalid value so we can decide if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++        fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                  poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            _exit(1);
++        }
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "test_child completed successfully\n");
++    _exit(0);
++
++fail:
++    DEBUG(SSSDBG_TRACE_FUNC, "test_child completed successfully\n");
++    close(STDOUT_FILENO);
++    _exit(-1);
++}
+diff --git a/src/tests/cmocka/test_child_common.c b/src/tests/cmocka/test_child_common.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..f2cd8c0081c2e85432db1c9696102780dc990e75
+--- /dev/null
++++ b/src/tests/cmocka/test_child_common.c
+@@ -0,0 +1,150 @@
++/*
++    Authors:
++        Jakub Hrozek <jhrozek@redhat.com>
++
++    Copyright (C) 2014 Red Hat
++
++    SSSD tests: Child handlers
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++#include <tevent.h>
++#include <errno.h>
++#include <popt.h>
++
++#include "util/child_common.h"
++#include "tests/cmocka/common_mock.h"
++
++#define TEST_BIN    "test-child"
++#define ECHO_STR    "Hello child"
++
++struct child_test_ctx {
++    int pipefd_to_child[2];
++    int pipefd_from_child[2];
++
++    struct sss_test_ctx *test_ctx;
++};
++
++void child_test_setup(void **state)
++{
++    struct child_test_ctx *child_tctx;
++    errno_t ret;
++
++    check_leaks_push(global_talloc_context);
++    child_tctx = talloc(global_talloc_context, struct child_test_ctx);
++    assert_non_null(child_tctx);
++
++    child_tctx->test_ctx = create_ev_test_ctx(child_tctx);
++    assert_non_null(child_tctx->test_ctx);
++
++    ret = pipe(child_tctx->pipefd_from_child);
++    assert_int_not_equal(ret, -1);
++    DEBUG(SSSDBG_TRACE_LIBS, "from_child: %d:%d\n",
++                             child_tctx->pipefd_from_child[0],
++                             child_tctx->pipefd_from_child[1]);
++
++    ret = pipe(child_tctx->pipefd_to_child);
++    assert_int_not_equal(ret, -1);
++    DEBUG(SSSDBG_TRACE_LIBS, "to_child: %d:%d\n",
++                             child_tctx->pipefd_to_child[0],
++                             child_tctx->pipefd_to_child[1]);
++
++    *state = child_tctx;
++}
++
++void child_test_teardown(void **state)
++{
++    struct child_test_ctx *child_tctx = talloc_get_type(*state,
++                                                        struct child_test_ctx);
++
++    talloc_free(child_tctx);
++    check_leaks_pop(global_talloc_context);
++}
++
++/* Just make sure the exec works. The child does nothing but exits */
++void test_exec_child(void **state)
++{
++    errno_t ret;
++    pid_t child_pid;
++    int status;
++    struct child_test_ctx *child_tctx = talloc_get_type(*state,
++                                                        struct child_test_ctx);
++
++    child_pid = fork();
++    assert_int_not_equal(child_pid, -1);
++    if (child_pid == 0) {
++        ret = exec_child(child_tctx,
++                         child_tctx->pipefd_to_child,
++                         child_tctx->pipefd_from_child,
++                         CHILD_DIR"/"TEST_BIN, 2);
++        assert_int_equal(ret, EOK);
++    } else {
++            do {
++                errno = 0;
++                ret = waitpid(child_pid, &status, 0);
++            } while (ret == -1 && errno == EINTR);
++
++            if (ret > 0) {
++                ret = EIO;
++                if (WIFEXITED(status)) {
++                    ret = WEXITSTATUS(status);
++                    assert_int_equal(ret, 0);
++                }
++            } else {
++                DEBUG(SSSDBG_FUNC_DATA,
++                    "Failed to wait for children %d\n", child_pid);
++                ret = EIO;
++            }
++    }
++}
++
++int main(int argc, const char *argv[])
++{
++    int rv;
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test_setup_teardown(test_exec_child,
++                                 child_test_setup,
++                                 child_test_teardown),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    rv = run_tests(tests);
++    return rv;
++}
+-- 
+1.9.3
+
diff --git a/SOURCES/0126-tests-Remove-tests-that-check-creating-public-direct.patch b/SOURCES/0126-tests-Remove-tests-that-check-creating-public-direct.patch
deleted file mode 100644
index e75778e..0000000
--- a/SOURCES/0126-tests-Remove-tests-that-check-creating-public-direct.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From 43dc5617a037f60e4560cb33c050815e03ccdff0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 7 Jan 2014 10:43:55 +0100
-Subject: [PATCH 126/126] tests: Remove tests that check creating public
- directories
-
-The functionality was removed, but we forgot to remove the corresponding
-tests, mostly because these tests were only ever ran as root.
----
- src/tests/krb5_utils-tests.c | 121 -------------------------------------------
- 1 file changed, 121 deletions(-)
-
-diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
-index 3e0c607a58b9ff0840a93867c1ad61cc5a2ae665..11fe1d749dccb5d367e3840ebc0a396b992bce2a 100644
---- a/src/tests/krb5_utils-tests.c
-+++ b/src/tests/krb5_utils-tests.c
-@@ -91,124 +91,6 @@ static void check_dir(const char *dirname, uid_t uid, gid_t gid, mode_t mode)
-                                             mode, (stat_buf.st_mode & ~S_IFMT));
- }
- 
--START_TEST(test_pub_ccache_dir)
--{
--    int ret;
--    char *cwd;
--    char *testpath;
--    char *dirname;
--    char *subdirname;
--    char *filename;
--
--    fail_unless(getuid() == 0, "This test must be run as root.");
--
--    cwd = getcwd(NULL, 0);
--    fail_unless(cwd != NULL, "getcwd failed.");
--
--    testpath = talloc_asprintf(tmp_ctx, "%s/%s", cwd, TESTS_PATH);
--    free(cwd);
--    fail_unless(testpath != NULL, "talloc_asprintf failed.");
--    dirname = talloc_asprintf(tmp_ctx, "%s/pub_ccdir", testpath);
--    fail_unless(dirname != NULL, "talloc_asprintf failed.");
--    subdirname = talloc_asprintf(tmp_ctx, "%s/subdir", dirname);
--    fail_unless(subdirname != NULL, "talloc_asprintf failed.");
--    filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname);
--    fail_unless(filename != NULL, "talloc_asprintf failed.");
--
--    ret = chmod(testpath, 0754);
--    fail_unless(ret == EOK, "chmod failed.");
--    ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345);
--    fail_unless(ret == EINVAL, "sss_krb5_precreate_ccache does not return EINVAL "
--                               "while x-bit is missing.");
--
--    ret = chmod(testpath, 0755);
--    fail_unless(ret == EOK, "chmod failed.");
--    ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345);
--    fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed.");
--
--    check_dir(subdirname, 0, 0, 01777);
--    RMDIR(subdirname);
--    check_dir(dirname, 0, 0, 0755);
--    RMDIR(dirname);
--}
--END_TEST
--
--START_TEST(test_pub_ccache_dir_in_user_dir)
--{
--    int ret;
--    char *cwd;
--    char *dirname;
--    char *subdirname;
--    char *filename;
--
--    fail_unless(getuid() == 0, "This test must be run as root.");
--
--    cwd = getcwd(NULL, 0);
--    fail_unless(cwd != NULL, "getcwd failed.");
--
--    dirname = talloc_asprintf(tmp_ctx, "%s/%s/pub_ccdir", cwd, TESTS_PATH);
--    free(cwd);
--    fail_unless(dirname != NULL, "talloc_asprintf failed.");
--    ret = mkdir(dirname, 0700);
--    fail_unless(ret == EOK, "mkdir failed.\n");
--    ret = chown(dirname, 12345, 12345);
--    fail_unless(ret == EOK, "chown failed.\n");
--    subdirname = talloc_asprintf(tmp_ctx, "%s/subdir", dirname);
--    fail_unless(subdirname != NULL, "talloc_asprintf failed.");
--    filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname);
--    fail_unless(filename != NULL, "talloc_asprintf failed.");
--
--    ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345);
--    fail_unless(ret == EINVAL, "Creating public ccache dir in user dir "
--                               "does not failed with EINVAL.");
--
--    RMDIR(dirname);
--}
--END_TEST
--
--START_TEST(test_priv_ccache_dir)
--{
--    int ret;
--    char *cwd;
--    char *testpath;
--    char *dirname;
--    char *subdir;
--    char *filename;
--    uid_t uid = 12345;
--    gid_t gid = 12345;
--
--    fail_unless(getuid() == 0, "This test must be run as root.");
--
--    cwd = getcwd(NULL, 0);
--    fail_unless(cwd != NULL, "getcwd failed.");
--
--    testpath = talloc_asprintf(tmp_ctx, "%s/%s", cwd, TESTS_PATH);
--    free(cwd);
--    fail_unless(testpath != NULL, "talloc_asprintf failed.");
--    dirname = talloc_asprintf(tmp_ctx, "%s/base", testpath);
--    subdir = talloc_asprintf(tmp_ctx, "%s/priv_ccdir", dirname);
--    fail_unless(subdir != NULL, "talloc_asprintf failed.");
--    filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdir);
--    fail_unless(filename != NULL, "talloc_asprintf failed.");
--
--    ret = chmod(testpath, 0754);
--    fail_unless(ret == EOK, "chmod failed.");
--    ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid);
--    fail_unless(ret == EINVAL, "sss_krb5_precreate_ccache does not return EINVAL "
--                               "while x-bit is missing.");
--
--    ret = chmod(testpath, 0755);
--    fail_unless(ret == EOK, "chmod failed.");
--    ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid);
--    fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed.");
--
--    check_dir(subdir, uid, gid, 0700);
--    RMDIR(subdir);
--    check_dir(dirname, 0, 0, 0755);
--    RMDIR(dirname);
--}
--END_TEST
--
- START_TEST(test_private_ccache_dir_in_user_dir)
- {
-     int ret;
-@@ -736,10 +618,7 @@ Suite *krb5_utils_suite (void)
-     tcase_add_test (tc_create_dir, test_illegal_patterns);
-     tcase_add_test (tc_create_dir, test_cc_dir_create);
-     if (getuid() == 0) {
--        tcase_add_test (tc_create_dir, test_priv_ccache_dir);
-         tcase_add_test (tc_create_dir, test_private_ccache_dir_in_user_dir);
--        tcase_add_test (tc_create_dir, test_pub_ccache_dir);
--        tcase_add_test (tc_create_dir, test_pub_ccache_dir_in_user_dir);
-         tcase_add_test (tc_create_dir, test_private_ccache_dir_in_wrong_user_dir);
-     } else {
-         printf("Run as root to enable more tests.\n");
--- 
-1.9.0
-
diff --git a/SOURCES/0127-Add-extra_args-to-exec_child.patch b/SOURCES/0127-Add-extra_args-to-exec_child.patch
new file mode 100644
index 0000000..7ab2f55
--- /dev/null
+++ b/SOURCES/0127-Add-extra_args-to-exec_child.patch
@@ -0,0 +1,287 @@
+From 6468d9f2bb30147967a724075c504afb3481d465 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 1 Dec 2014 12:25:24 +0100
+Subject: [PATCH 127/128] Add extra_args to exec_child()
+
+Related:
+    https://fedorahosted.org/sssd/ticket/2503
+
+Currently all child processes use the same arguments, the construction
+of argv[] is even hardcoded in exec_child(). Add an extra_args[] array
+that extends the common set of argvs so that we can have child-specific
+arguments. Also adds a unit test.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_gpo.c               |  2 +-
+ src/providers/ipa/ipa_selinux.c         |  3 ++-
+ src/providers/krb5/krb5_child_handler.c |  3 ++-
+ src/providers/ldap/sdap_child_helpers.c |  3 ++-
+ src/tests/cmocka/test_child.c           | 31 ++++++++++++----------
+ src/tests/cmocka/test_child_common.c    | 47 ++++++++++++++++++++++++++++++++-
+ src/util/child_common.c                 | 23 ++++++++++++++--
+ src/util/child_common.h                 |  3 ++-
+ 8 files changed, 93 insertions(+), 22 deletions(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 83edbe4fb5a7e617cab95c0330ceae31392b18b2..62715861c91484fa2a57e7cc13ba403c9096d9a7 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3960,7 +3960,7 @@ gpo_fork_child(struct tevent_req *req)
+     if (pid == 0) { /* child */
+         err = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+-                         GPO_CHILD, gpo_child_debug_fd);
++                         GPO_CHILD, gpo_child_debug_fd, NULL);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec gpo_child: [%d][%s].\n",
+               err, strerror(err));
+         return err;
+diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
+index 30ad6f0a7c4622ca5eb9a75ae4f57183543515c6..531258dac5c033b5896598e44e28a373d6cf5e3b 100644
+--- a/src/providers/ipa/ipa_selinux.c
++++ b/src/providers/ipa/ipa_selinux.c
+@@ -1036,7 +1036,8 @@ static errno_t selinux_fork_child(struct selinux_child_state *state)
+     if (pid == 0) { /* child */
+         ret = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+-                         SELINUX_CHILD, selinux_child_debug_fd);
++                         SELINUX_CHILD, selinux_child_debug_fd,
++                         NULL);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec selinux_child: [%d][%s].\n",
+               ret, sss_strerror(ret));
+         return ret;
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 93961172c7a3a5d8f2a4fb320370037f188b5909..9bb61f65437694d8aa2109513b5f061dfc9ee21c 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -299,7 +299,8 @@ static errno_t fork_child(struct tevent_req *req)
+     if (pid == 0) { /* child */
+         err = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+-                         KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd);
++                         KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
++                         NULL);
+         if (err != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec KRB5 child: [%d][%s].\n",
+                       err, strerror(err));
+diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c
+index 40010989021eb7cf77b96876b2d1c4119ed39163..b60891d2b41f9a359856eb22174128d7f07559fb 100644
+--- a/src/providers/ldap/sdap_child_helpers.c
++++ b/src/providers/ldap/sdap_child_helpers.c
+@@ -108,7 +108,8 @@ static errno_t sdap_fork_child(struct tevent_context *ev,
+     if (pid == 0) { /* child */
+         err = exec_child(child,
+                          pipefd_to_child, pipefd_from_child,
+-                         LDAP_CHILD, ldap_child_debug_fd);
++                         LDAP_CHILD, ldap_child_debug_fd,
++                         NULL);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec LDAP child: [%d][%s].\n",
+                                     err, strerror(err));
+         return err;
+diff --git a/src/tests/cmocka/test_child.c b/src/tests/cmocka/test_child.c
+index a857afce1fe7c4f3949fe77fe4e0a24e15961a4f..0bb50a4e005a26b1fbd332b17558d1284de77ea1 100644
+--- a/src/tests/cmocka/test_child.c
++++ b/src/tests/cmocka/test_child.c
+@@ -35,13 +35,9 @@ int main(int argc, const char *argv[])
+     int opt;
+     int debug_fd = -1;
+     poptContext pc;
+-    const char *action;
+-    ssize_t len = 0;
+-    ssize_t written;
+-    errno_t ret;
+-    uint8_t *buf[IN_BUF_SIZE];
+-    uid_t uid;
+-    gid_t gid;
++    const char *action = NULL;
++    const char *guitar;
++    const char *drums;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+@@ -54,8 +50,9 @@ int main(int argc, const char *argv[])
+         {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
+          _("An open file descriptor for the debug logs"), NULL},
+         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
+-         _("Send the debug output to stderr directly."), NULL }, \
+-        SSSD_SERVER_OPTS(uid, gid)
++         _("Send the debug output to stderr directly."), NULL },
++        {"guitar", 0, POPT_ARG_STRING, &guitar, 0, _("Who plays guitar"), NULL },
++        {"drums", 0, POPT_ARG_STRING, &drums, 0, _("Who plays drums"), NULL },
+         POPT_TABLEEND
+     };
+ 
+@@ -73,11 +70,17 @@ int main(int argc, const char *argv[])
+         }
+     }
+ 
++    action = getenv("TEST_CHILD_ACTION");
++    if (action) {
++        if (strcasecmp(action, "check_extra_args") == 0) {
++            if (!(strcmp(guitar, "george") == 0 \
++                        && strcmp(drums, "ringo") == 0)) {
++                DEBUG(SSSDBG_CRIT_FAILURE, "This band sounds weird\n");
++                _exit(1);
++            }
++        }
++    }
++
+     DEBUG(SSSDBG_TRACE_FUNC, "test_child completed successfully\n");
+     _exit(0);
+-
+-fail:
+-    DEBUG(SSSDBG_TRACE_FUNC, "test_child completed successfully\n");
+-    close(STDOUT_FILENO);
+-    _exit(-1);
+ }
+diff --git a/src/tests/cmocka/test_child_common.c b/src/tests/cmocka/test_child_common.c
+index f2cd8c0081c2e85432db1c9696102780dc990e75..112ed0ad97294bc45eac7c2124155e6b1908ad92 100644
+--- a/src/tests/cmocka/test_child_common.c
++++ b/src/tests/cmocka/test_child_common.c
+@@ -89,7 +89,49 @@ void test_exec_child(void **state)
+         ret = exec_child(child_tctx,
+                          child_tctx->pipefd_to_child,
+                          child_tctx->pipefd_from_child,
+-                         CHILD_DIR"/"TEST_BIN, 2);
++                         CHILD_DIR"/"TEST_BIN, 2, NULL);
++        assert_int_equal(ret, EOK);
++    } else {
++            do {
++                errno = 0;
++                ret = waitpid(child_pid, &status, 0);
++            } while (ret == -1 && errno == EINTR);
++
++            if (ret > 0) {
++                ret = EIO;
++                if (WIFEXITED(status)) {
++                    ret = WEXITSTATUS(status);
++                    assert_int_equal(ret, 0);
++                }
++            } else {
++                DEBUG(SSSDBG_FUNC_DATA,
++                    "Failed to wait for children %d\n", child_pid);
++                ret = EIO;
++            }
++    }
++}
++
++/* Just make sure the exec works. The child does nothing but exits */
++void test_exec_child_extra_args(void **state)
++{
++    errno_t ret;
++    pid_t child_pid;
++    int status;
++    struct child_test_ctx *child_tctx = talloc_get_type(*state,
++                                                        struct child_test_ctx);
++    const char *extra_args[] = { "--guitar=george",
++                                 "--drums=ringo",
++                                 NULL };
++
++    setenv("TEST_CHILD_ACTION", "check_extra_args", 1);
++
++    child_pid = fork();
++    assert_int_not_equal(child_pid, -1);
++    if (child_pid == 0) {
++        ret = exec_child(child_tctx,
++                         child_tctx->pipefd_to_child,
++                         child_tctx->pipefd_from_child,
++                         CHILD_DIR"/"TEST_BIN, 2, extra_args);
+         assert_int_equal(ret, EOK);
+     } else {
+             do {
+@@ -126,6 +168,9 @@ int main(int argc, const char *argv[])
+         unit_test_setup_teardown(test_exec_child,
+                                  child_test_setup,
+                                  child_test_teardown),
++        unit_test_setup_teardown(test_exec_child_extra_args,
++                                 child_test_setup,
++                                 child_test_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+diff --git a/src/util/child_common.c b/src/util/child_common.c
+index cc6a8fa758bfa6efa511c28cd9121e759b590342..9710630f9773ae02258e4f0dd609a3d74978c8f4 100644
+--- a/src/util/child_common.c
++++ b/src/util/child_common.c
+@@ -623,6 +623,7 @@ static void child_invoke_callback(struct tevent_context *ev,
+ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
+                                   int child_debug_fd,
+                                   const char *binary,
++                                  const char *extra_argv[],
+                                   char ***_argv)
+ {
+     /*
+@@ -632,6 +633,7 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
+     uint_t argc = 5;
+     char ** argv;
+     errno_t ret = EINVAL;
++    size_t i;
+ 
+     /* Save the current state in case an interrupt changes it */
+     bool child_debug_to_file = debug_to_file;
+@@ -642,6 +644,10 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
+     if (child_debug_to_file) argc++;
+     if (child_debug_stderr) argc++;
+ 
++    if (extra_argv) {
++        for (i = 0; extra_argv[i]; i++) argc++;
++    }
++
+     /*
+      * program name, debug_level, debug_to_file, debug_timestamps,
+      * debug_microseconds and NULL
+@@ -654,6 +660,17 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
+ 
+     argv[--argc] = NULL;
+ 
++    /* Add extra_attrs first */
++    if (extra_argv) {
++        for (i = 0; extra_argv[i]; i++) {
++            argv[--argc] = talloc_strdup(argv, extra_argv[i]);
++            if (argv[argc] == NULL) {
++                ret = ENOMEM;
++                goto fail;
++            }
++        }
++    }
++
+     argv[--argc] = talloc_asprintf(argv, "--debug-level=%#.4x",
+                               debug_level);
+     if (argv[argc] == NULL) {
+@@ -714,7 +731,8 @@ fail:
+ 
+ errno_t exec_child(TALLOC_CTX *mem_ctx,
+                    int *pipefd_to_child, int *pipefd_from_child,
+-                   const char *binary, int debug_fd)
++                   const char *binary, int debug_fd,
++                   const char *extra_argv[])
+ {
+     int ret;
+     errno_t err;
+@@ -739,7 +757,8 @@ errno_t exec_child(TALLOC_CTX *mem_ctx,
+     }
+ 
+     ret = prepare_child_argv(mem_ctx, debug_fd,
+-                             binary, &argv);
++                             binary, extra_argv,
++                             &argv);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "prepare_child_argv.\n");
+         return ret;
+diff --git a/src/util/child_common.h b/src/util/child_common.h
+index e159719a2fca70a4ea044d79530a0d21cb3577e8..e659388ece3677b7746c159d7de3e86171bb4146 100644
+--- a/src/util/child_common.h
++++ b/src/util/child_common.h
+@@ -114,7 +114,8 @@ void child_sig_handler(struct tevent_context *ev,
+ /* Never returns EOK, ether returns an error, or doesn't return on success */
+ errno_t exec_child(TALLOC_CTX *mem_ctx,
+                    int *pipefd_to_child, int *pipefd_from_child,
+-                   const char *binary, int debug_fd);
++                   const char *binary, int debug_fd,
++                   const char *extra_argv[]);
+ 
+ void child_cleanup(int readfd, int writefd);
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0127-IPA-handle-searches-by-SID-in-apply_subdomain_homedi.patch b/SOURCES/0127-IPA-handle-searches-by-SID-in-apply_subdomain_homedi.patch
deleted file mode 100644
index de65245..0000000
--- a/SOURCES/0127-IPA-handle-searches-by-SID-in-apply_subdomain_homedi.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 5ecab6dc08ac35a400e067af09b49e7fcb0f17c0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 12 Aug 2014 10:32:33 +0200
-Subject: [PATCH 127/130] IPA: handle searches by SID in
- apply_subdomain_homedir
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2391
-
-apply_subdomain_homedir() didn't handle the situation where an entity
-that doesn't match was requested from the cache. For user and group
-lookups this wasn't a problem because the negative match was caught
-sooner.
-
-But SID lookups can match either user or group. When a group SID was
-requested, the preceding LDAP request matched the SID and stored the
-group in the cache. Then apply_subdomain_homedir() only tried to search
-user by SID, didn't find the entry and accessed a NULL pointer.
-
-A simple reproducer is:
-$ python
->>> import pysss_nss_idmap
->>> pysss_nss_idmap.getnamebysid(group_sid)
-
-The group_sid can be anything, including Domain Users (XXX-513)
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit 82347f452febe3cbffc36b0a3308ffb462515442)
----
- src/providers/ipa/ipa_subdomains_id.c | 13 +++++++++----
- 1 file changed, 9 insertions(+), 4 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index d8922a461fc1cbbec4bb65b8cd6e6cf25f2dc605..5517602a6e9c7d56406e42aa3afbd2527e2df7ea 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -492,6 +492,9 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
- 
-     if (filter_type == BE_FILTER_NAME) {
-         ret = sysdb_getpwnam(mem_ctx, dom->sysdb, dom, filter_value, &res);
-+        if (res && res->count == 0) {
-+            ret = ENOENT;
-+        }
-     } else if (filter_type == BE_FILTER_IDNUM) {
-         errno = 0;
-         uid = strtouint32(filter_value, NULL, 10);
-@@ -500,6 +503,9 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-             goto done;
-         }
-         ret = sysdb_getpwuid(mem_ctx, dom->sysdb, dom, uid, &res);
-+        if (res && res->count == 0) {
-+            ret = ENOENT;
-+        }
-     } else if (filter_type == BE_FILTER_SECID) {
-         ret = sysdb_search_user_by_sid_str(mem_ctx, dom->sysdb, dom,
-                                            filter_value, attrs, &msg);
-@@ -515,10 +521,9 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-               ("Failed to make request to our cache: [%d]: [%s]\n",
-                ret, sss_strerror(ret)));
-         goto done;
--    }
--
--    if ((res && res->count == 0) || (msg && msg->num_elements == 0)) {
--        ret = ENOENT;
-+    } else if (ret == ENOENT) {
-+        DEBUG(SSSDBG_TRACE_FUNC, ("Cannot find [%s] with search type [%d]\n",
-+              filter_value, filter_type));
-         goto done;
-     }
- 
--- 
-1.9.3
-
diff --git a/SOURCES/0128-KRB5-Create-the-fast-ccache-in-a-child-process.patch b/SOURCES/0128-KRB5-Create-the-fast-ccache-in-a-child-process.patch
new file mode 100644
index 0000000..674badb
--- /dev/null
+++ b/SOURCES/0128-KRB5-Create-the-fast-ccache-in-a-child-process.patch
@@ -0,0 +1,240 @@
+From c32ceaed108c86305d5862430225be636fd7532b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 28 Nov 2014 13:04:42 +0100
+Subject: [PATCH 128/128] KRB5: Create the fast ccache in a child process
+
+Related:
+    https://fedorahosted.org/sssd/ticket/2503
+
+In order to avoid calling Kerberos library calls as root, the krb5_child
+forks itself and recreates the FAST ccache as the SSSD user.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/krb5/krb5_child.c         | 118 ++++++++++++++++++++++++--------
+ src/providers/krb5/krb5_child_handler.c |  10 ++-
+ 2 files changed, 100 insertions(+), 28 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index ce8a9235e1d64bccc91d367bc744cca2b32a40da..1ce1220751a338cb2a2e5f204107b376000a4e3e 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -74,6 +74,9 @@ struct krb5_req {
+     bool old_cc_valid;
+     bool old_cc_active;
+     enum k5c_fast_opt fast_val;
++
++    uid_t fast_uid;
++    gid_t fast_gid;
+ };
+ 
+ static krb5_context krb5_error_ctx;
+@@ -1005,17 +1008,6 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
+         DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n");
+     }
+ 
+-    if (kr->validate || kr->fast_ccname != NULL) {
+-        /* We drop root privileges which were needed to read the keytab file
+-         * for the validation of the credentials or for FAST here to run the
+-         * ccache I/O operations with user privileges. */
+-        kerr = become_user(kr->uid, kr->gid);
+-        if (kerr != 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
+-            return kerr;
+-        }
+-    }
+-
+     /* If kr->ccname is cache collection (DIR:/...), we want to work
+      * directly with file ccache (DIR::/...), but cache collection
+      * should be returned back to back end.
+@@ -1432,17 +1424,6 @@ static errno_t renew_tgt_child(struct krb5_req *kr)
+         DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n");
+     }
+ 
+-    if (kr->validate || kr->fast_ccname != NULL) {
+-        /* We drop root privileges which were needed to read the keytab file
+-         * for the validation of the credentials or for FAST here to run the
+-         * ccache I/O operations with user privileges. */
+-        kerr = become_user(kr->uid, kr->gid);
+-        if (kerr != 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
+-            goto done;
+-        }
+-    }
+-
+     kerr = krb5_cc_initialize(kr->ctx, ccache, kr->princ);
+     if (kerr != 0) {
+         KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+@@ -1716,6 +1697,8 @@ done:
+ 
+ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
+                                          krb5_context ctx,
++                                         uid_t fast_uid,
++                                         gid_t fast_gid,
+                                          const char *primary,
+                                          const char *realm,
+                                          const char *keytab_name,
+@@ -1729,6 +1712,8 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
+     krb5_keytab keytab = NULL;
+     krb5_principal client_princ = NULL;
+     krb5_principal server_princ = NULL;
++    pid_t fchild_pid;
++    int status;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -1786,10 +1771,79 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
+-    kerr = get_and_save_tgt_with_keytab(ctx, client_princ, keytab, ccname);
+-    if (kerr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "get_and_save_tgt_with_keytab failed.\n");
+-        goto done;
++    /* Need to recreate the FAST ccache */
++    fchild_pid = fork();
++    switch (fchild_pid) {
++        case -1:
++            DEBUG(SSSDBG_CRIT_FAILURE, "fork failed\n");
++            kerr = EIO;
++            goto done;
++        case 0:
++            /* Child */
++            debug_prg_name = talloc_asprintf(NULL, "[sssd[krb5_child[%d]]]", getpid());
++            if (debug_prg_name == NULL) {
++                debug_prg_name = "[sssd[krb5_child]]";
++                DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
++                /* Try to carry on */
++            }
++
++            kerr = become_user(fast_uid, fast_gid);
++            if (kerr != 0) {
++                DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr);
++                exit(1);
++            }
++            DEBUG(SSSDBG_TRACE_INTERNAL,
++                  "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
++
++            kerr = get_and_save_tgt_with_keytab(ctx, client_princ,
++                                                keytab, ccname);
++            if (kerr != 0) {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "get_and_save_tgt_with_keytab failed: %d\n", kerr);
++                exit(2);
++            }
++            exit(0);
++        default:
++            /* Parent */
++            do {
++                errno = 0;
++                kerr = waitpid(fchild_pid, &status, 0);
++            } while (kerr == -1 && errno == EINTR);
++
++            if (kerr > 0) {
++                kerr = EIO;
++                if (WIFEXITED(status)) {
++                    kerr = WEXITSTATUS(status);
++                    /* Don't blindly fail if the child fails, but check
++                     * the ccache again */
++                    if (kerr != 0) {
++                        DEBUG(SSSDBG_MINOR_FAILURE,
++                              "Creating FAST ccache failed, krb5_child will "
++                              "likely fail!\n");
++                    }
++                } else {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "krb5_child subprocess %d terminated unexpectedly\n",
++                          fchild_pid);
++                }
++            } else {
++                DEBUG(SSSDBG_FUNC_DATA,
++                    "Failed to wait for children %d\n", fchild_pid);
++                kerr = EIO;
++            }
++    }
++
++    /* Check the ccache times again. Should be updated ... */
++    memset(&tgtt, 0, sizeof(tgtt));
++    kerr = get_tgt_times(ctx, ccname, server_princ, client_princ, &tgtt);
++    if (kerr == 0) {
++        if (tgtt.endtime > time(NULL)) {
++            DEBUG(SSSDBG_FUNC_DATA, "FAST TGT was successfully recreated!\n");
++            goto done;
++        } else {
++            kerr = ERR_CREDS_EXPIRED;
++            goto done;
++        }
+     }
+ 
+     kerr = 0;
+@@ -1881,7 +1935,8 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
+         fast_principal = NULL;
+     }
+ 
+-    kerr = check_fast_ccache(kr, kr->ctx, fast_principal, fast_principal_realm,
++    kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid,
++                             fast_principal, fast_principal_realm,
+                              kr->keytab, &kr->fast_ccname);
+     if (kerr != 0) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "check_fast_ccache failed.\n");
+@@ -2245,6 +2300,8 @@ int main(int argc, const char *argv[])
+     int debug_fd = -1;
+     errno_t ret;
+     krb5_error_code kerr;
++    uid_t fast_uid;
++    gid_t fast_gid;
+ 
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+@@ -2259,6 +2316,10 @@ int main(int argc, const char *argv[])
+         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
+          &debug_to_stderr, 0,
+          _("Send the debug output to stderr directly."), NULL },
++        {"fast-ccache-uid", 0, POPT_ARG_INT, &fast_uid, 0,
++          _("The user to create FAST ccache as"), NULL},
++        {"fast-ccache-gid", 0, POPT_ARG_INT, &fast_gid, 0,
++          _("The group to create FAST ccache as"), NULL},
+         POPT_TABLEEND
+     };
+ 
+@@ -2305,6 +2366,9 @@ int main(int argc, const char *argv[])
+     }
+     talloc_steal(kr, debug_prg_name);
+ 
++    kr->fast_uid = fast_uid;
++    kr->fast_gid = fast_gid;
++
+     ret = k5c_recv_data(kr, STDIN_FILENO, &offline);
+     if (ret != EOK) {
+         goto done;
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 9bb61f65437694d8aa2109513b5f061dfc9ee21c..1454d220fb294abc339df6e862154012a03fdca0 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -278,6 +278,14 @@ static errno_t fork_child(struct tevent_req *req)
+     errno_t err;
+     struct handle_child_state *state = tevent_req_data(req,
+                                                      struct handle_child_state);
++    const char *k5c_extra_args[3];
++
++    k5c_extra_args[0] = talloc_asprintf(state, "--fast-ccache-uid=%"SPRIuid, getuid());
++    k5c_extra_args[1] = talloc_asprintf(state, "--fast-ccache-gid=%"SPRIgid, getgid());
++    k5c_extra_args[2] = NULL;
++    if (k5c_extra_args[0] == NULL || k5c_extra_args[1] == NULL) {
++        return ENOMEM;
++    }
+ 
+     ret = pipe(pipefd_from_child);
+     if (ret == -1) {
+@@ -300,7 +308,7 @@ static errno_t fork_child(struct tevent_req *req)
+         err = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+                          KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
+-                         NULL);
++                         k5c_extra_args);
+         if (err != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec KRB5 child: [%d][%s].\n",
+                       err, strerror(err));
+-- 
+1.9.3
+
diff --git a/SOURCES/0128-LDAP-Ignore-returned-referrals-if-referral-support-i.patch b/SOURCES/0128-LDAP-Ignore-returned-referrals-if-referral-support-i.patch
deleted file mode 100644
index 3069a3b..0000000
--- a/SOURCES/0128-LDAP-Ignore-returned-referrals-if-referral-support-i.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From b224c49b8f0a9cdf343a443fdf2190dc6f047508 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 20 Aug 2014 14:00:38 +0200
-Subject: [PATCH 128/130] LDAP: Ignore returned referrals if referral support
- is disabled
-
-Reviewed-by: Pavel Reichl <preichl@redhat.com>
-(cherry picked from commit a2ea3f5d9ef9f17efbb61e942c2bc6cff7d1ebf2)
----
- src/providers/ldap/sdap_async.c | 18 +++++++++++++++---
- src/util/util_errors.c          |  1 +
- src/util/util_errors.h          |  2 ++
- 3 files changed, 18 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index 1022a093f06ec7e9a50b13160fc9a4660a255e92..7db01d979ee81a3707126a4c3eb1f36006e8b392 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -1404,6 +1404,10 @@ static void sdap_get_generic_ext_done(struct sdap_op *op,
-             ldap_memfree(errmsg);
-             tevent_req_error(req, ENOTSUP);
-             return;
-+        } else if (result == LDAP_REFERRAL) {
-+            ldap_memfree(errmsg);
-+            tevent_req_error(req, ERR_REFERRAL);
-+            return;
-         } else if (result != LDAP_SUCCESS && result != LDAP_NO_SUCH_OBJECT) {
-             DEBUG(SSSDBG_OP_FAILURE,
-                   ("Unexpected result from ldap: %s(%d), %s\n",
-@@ -1565,13 +1569,21 @@ static void sdap_get_generic_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
-+    struct sdap_get_generic_state *state =
-+                tevent_req_data(req, struct sdap_get_generic_state);
-     int ret;
- 
-     ret = sdap_get_generic_ext_recv(subreq);
-     talloc_zfree(subreq);
--    if (ret) {
--        DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
--                  ret, sss_strerror(ret)));
-+    if (ret == ERR_REFERRAL) {
-+        if (dp_opt_get_bool(state->opts->basic, SDAP_REFERRALS)) {
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+    } else if (ret) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              ("sdap_get_generic_ext_recv failed [%d]: %s\n",
-+                ret, sss_strerror(ret)));
-         tevent_req_error(req, ret);
-         return;
-     }
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index c9b507557da07555c719bb0dd18145e6799a53eb..eb7b1aec7b388e2509471cce8322cf38f9388151 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -53,6 +53,7 @@ struct err_string error_to_str[] = {
-     { "Missing configuration file" }, /* ERR_MISSING_CONF */
-     { "Malformed search filter" }, /* ERR_INVALID_FILTER, */
-     { "No POSIX attributes detected" }, /* ERR_NO_POSIX */
-+    { "LDAP search returned a referral" }, /* ERR_REFERRAL */
- };
- 
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index 3dd94af1f304d65e22515c859c6f69a021fa7e92..2858311dec90ae0ea57dbcd7b6de4beb9fb19c50 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -75,6 +75,8 @@ enum sssd_errors {
-     ERR_MISSING_CONF,
-     ERR_INVALID_FILTER,
-     ERR_NO_POSIX,
-+    ERR_NO_SYSBUS,
-+    ERR_REFERRAL,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-1.9.3
-
diff --git a/SOURCES/0129-Ignore-referrals-in-deref-and-ASQ-too.patch b/SOURCES/0129-Ignore-referrals-in-deref-and-ASQ-too.patch
deleted file mode 100644
index c2da9d5..0000000
--- a/SOURCES/0129-Ignore-referrals-in-deref-and-ASQ-too.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 5b5cb000d63c3edad40ebb420776df2a18950fcb Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 10 Sep 2014 11:55:24 +0200
-Subject: [PATCH 129/130] Ignore referrals in deref and ASQ, too
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/providers/ldap/sdap_async.c | 20 ++++++++++++++++++--
- 1 file changed, 18 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index 7db01d979ee81a3707126a4c3eb1f36006e8b392..b06d94bfd9d1a60f587de5c807389c74f908af5e 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -1622,6 +1622,7 @@ static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
- struct sdap_x_deref_search_state {
-     struct sdap_handle *sh;
-     struct sdap_op *op;
-+    struct sdap_options *opts;
-     struct sdap_attr_map_info *maps;
-     LDAPControl **ctrls;
- 
-@@ -1647,6 +1648,7 @@ sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-     state->sh = sh;
-     state->maps = maps;
-     state->op = NULL;
-+    state->opts = opts;
-     state->num_maps = num_maps;
-     state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
-     if (state->ctrls == NULL) {
-@@ -1797,11 +1799,18 @@ static void sdap_x_deref_search_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
-+    struct sdap_x_deref_search_state *state = tevent_req_data(req,
-+                                            struct sdap_x_deref_search_state);
-     int ret;
- 
-     ret = sdap_get_generic_ext_recv(subreq);
-     talloc_zfree(subreq);
--    if (ret) {
-+    if (ret == ERR_REFERRAL) {
-+        if (dp_opt_get_bool(state->opts->basic, SDAP_REFERRALS)) {
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+    } else if (ret) {
-         DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
-                   ret, sss_strerror(ret)));
-         tevent_req_error(req, ret);
-@@ -2056,11 +2065,18 @@ static void sdap_asq_search_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
-+    struct sdap_asq_search_state *state =
-+                tevent_req_data(req, struct sdap_asq_search_state);
-     int ret;
- 
-     ret = sdap_get_generic_ext_recv(subreq);
-     talloc_zfree(subreq);
--    if (ret) {
-+    if (ret == ERR_REFERRAL) {
-+        if (dp_opt_get_bool(state->opts->basic, SDAP_REFERRALS)) {
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+    } else if (ret) {
-         DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
-                   ret, sss_strerror(ret)));
-         tevent_req_error(req, ret);
--- 
-1.9.3
-
diff --git a/SOURCES/0129-KRB5-Relax-DEBUG-message.patch b/SOURCES/0129-KRB5-Relax-DEBUG-message.patch
new file mode 100644
index 0000000..27115e4
--- /dev/null
+++ b/SOURCES/0129-KRB5-Relax-DEBUG-message.patch
@@ -0,0 +1,31 @@
+From cf944e48215fa55bbc268e291aff11adb2bba4aa Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 28 Nov 2014 19:56:27 +0100
+Subject: [PATCH 129/130] KRB5: Relax DEBUG message
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/krb5/krb5_child.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 1ce1220751a338cb2a2e5f204107b376000a4e3e..8f23346a67d4d2467a4d1869fd298ec4d6f68e92 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -1672,8 +1672,11 @@ static krb5_error_code get_tgt_times(krb5_context ctx, const char *ccname,
+     mcred.client = client_principal;
+ 
+     krberr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred);
+-    if (krberr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed.\n");
++    if (krberr == KRB5_FCC_NOFILE) {
++        DEBUG(SSSDBG_TRACE_LIBS, "FAST ccache must be recreated\n");
++    } else if (krberr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed\n");
++        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, krberr);
+         krberr = 0;
+         goto done;
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0130-IPA-Do-not-append-domain-name-to-fq-name.patch b/SOURCES/0130-IPA-Do-not-append-domain-name-to-fq-name.patch
new file mode 100644
index 0000000..3ceebcd
--- /dev/null
+++ b/SOURCES/0130-IPA-Do-not-append-domain-name-to-fq-name.patch
@@ -0,0 +1,61 @@
+From edcaf7122748fb2cd5dcfe055b904127c99f3234 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 1 Dec 2014 17:29:49 +0100
+Subject: [PATCH 130/130] IPA: Do not append domain name to fq name
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Usernames from AD subdomains are already in fqdn we should not append
+domain name in this case.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2512
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/providers/ipa/ipa_selinux.c | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
+index 531258dac5c033b5896598e44e28a373d6cf5e3b..c4e70cfcb0748988d91fc1db57cf5a30d5365be4 100644
+--- a/src/providers/ipa/ipa_selinux.c
++++ b/src/providers/ipa/ipa_selinux.c
+@@ -812,6 +812,7 @@ selinux_child_setup(TALLOC_CTX *mem_ctx,
+     char *ptr;
+     char *username;
+     char *username_final;
++    char *domain_name = NULL;
+     TALLOC_CTX *tmp_ctx;
+     struct selinux_child_input *sci;
+ 
+@@ -849,10 +850,22 @@ selinux_child_setup(TALLOC_CTX *mem_ctx,
+     }
+ 
+     if (dom->fqnames) {
+-        username_final = talloc_asprintf(tmp_ctx, dom->names->fq_fmt,
+-                                         username, dom->name);
+-        if (username_final == NULL) {
+-            ret = ENOMEM;
++        ret = sss_parse_name(tmp_ctx, dom->names, username, &domain_name,
++                             NULL);
++        if (ret == EOK && domain_name != NULL) {
++            /* username is already a fully qualified name */
++            username_final = username;
++        } else if ((ret == EOK && domain_name == NULL)
++                   || ret == ERR_REGEX_NOMATCH) {
++            username_final = talloc_asprintf(tmp_ctx, dom->names->fq_fmt,
++                                             username, dom->name);
++            if (username_final == NULL) {
++                ret = ENOMEM;
++                goto done;
++            }
++        } else {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "sss_parse_name failed: [%d] %s", ret, sss_strerror(ret));
+             goto done;
+         }
+     } else {
+-- 
+1.9.3
+
diff --git a/SOURCES/0130-IPA-Use-GC-for-group-lookups-in-server-mode.patch b/SOURCES/0130-IPA-Use-GC-for-group-lookups-in-server-mode.patch
deleted file mode 100644
index b42b8e4..0000000
--- a/SOURCES/0130-IPA-Use-GC-for-group-lookups-in-server-mode.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From 756a944b898e55a83c212999b31ba6550af4b1ce Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 9 Sep 2014 22:13:52 +0200
-Subject: [PATCH 130/130] IPA: Use GC for group lookups in server mode
-
-https://fedorahosted.org/sssd/ticket/2412
-
-Even though AD trusts often work with POSIX attributes which are
-normally not replicated to GC, our group lookups are smart since commit
-008e1ee835602023891ac45408483d87f41e4d5c and look up the group itself using
-the LDAP connection and only use the GC connection to look up the members.
-
-Reviewed-by: Pavel Reichl <preichl@redhat.com>
-(cherry picked from commit a20ce8cd43d72c89e2ea1d65aefe24ba270f040f)
----
- src/providers/ipa/ipa_subdomains_id.c | 14 +++++++++-----
- 1 file changed, 9 insertions(+), 5 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 5517602a6e9c7d56406e42aa3afbd2527e2df7ea..9a90bc2d68561ce518bd31d74ec010c697036352 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -304,17 +304,21 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-     }
-     sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
- 
--    /* Currently only LDAP port for AD is used because POSIX
--     * attributes are not replicated to GC by default
-+    /* We read users and groups from GC. From groups, we may switch to
-+     * using LDAP connection in the group request itself, but in order
-+     * to resolve Universal group memberships, we also need the GC
-+     * connection
-      */
--
--    if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
-+    switch (state->ar->entry_type & BE_REQ_TYPE_MASK) {
-+    case BE_REQ_INITGROUPS:
-+    case BE_REQ_GROUP:
-         clist = ad_gc_conn_list(req, ad_id_ctx, state->user_dom);
-         if (clist == NULL) {
-             ret = ENOMEM;
-             goto fail;
-         }
--    } else {
-+        break;
-+    default:
-         clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2);
-         if (clist == NULL) {
-             ret = ENOMEM;
--- 
-1.9.3
-
diff --git a/SOURCES/0131-TESTS-Build-test_child-even-without-cmocka.patch b/SOURCES/0131-TESTS-Build-test_child-even-without-cmocka.patch
new file mode 100644
index 0000000..8611b93
--- /dev/null
+++ b/SOURCES/0131-TESTS-Build-test_child-even-without-cmocka.patch
@@ -0,0 +1,35 @@
+From ebf091115b9aaca6a8a78e83b7b4ca7fde95e990 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 3 Dec 2014 17:00:25 +0100
+Subject: [PATCH 131/131] TESTS: Build test_child even without cmocka
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index b719c646721835096931819b10be6f1a766ef22e..8202659e0933529ca7911952bbf1476dbb4a76fc 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -234,10 +234,13 @@ endif   # HAVE_CMOCKA
+ check_PROGRAMS = \
+     stress-tests \
+     krb5-child-test \
+-    test-child \
+     $(non_interactive_cmocka_based_tests) \
+     $(non_interactive_check_based_tests)
+ 
++if HAVE_CMOCKA
++check_PROGRAMS += test-child
++endif # HAVE_CMOCKA
++
+ PYTHON_TESTS =
+ 
+ if BUILD_PYTHON_BINDINGS
+-- 
+1.9.3
+
diff --git a/SOURCES/0132-sss_client-Work-around-glibc-bug.patch b/SOURCES/0132-sss_client-Work-around-glibc-bug.patch
new file mode 100644
index 0000000..7281024
--- /dev/null
+++ b/SOURCES/0132-sss_client-Work-around-glibc-bug.patch
@@ -0,0 +1,82 @@
+From 2e84796d8e23ee6e406c0625288655e056b0d90d Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 18 Nov 2014 12:02:10 +0100
+Subject: [PATCH 132/132] sss_client: Work around glibc bug
+
+glibc is inconsistent with how it treats and returns NSS_STATUS_UNAVAIL.
+
+The sss nss plugin is present in nsswitch by default on some platforms
+due to glibc caching and problem with long living applications (e.g. GNOME).
+But sssd needn't be configuread and it cause problems in some programs.
+In this situation, the SSSD nss plugin should behave as if it was functioning
+but had no data even thought sssd is not running. The errors have to be passed
+from nss plugin up to the user with minimal moidiffication.
+
+Thanks to Stephen Gallagher for initial patch.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2439
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/conf_macros.m4      | 13 +++++++++++++
+ src/sss_client/common.c | 10 ++++++++++
+ 2 files changed, 23 insertions(+)
+
+diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
+index df9d1ddf89be38709e56ad4b214e5f7c6cbb0f97..027490e524f321b9d444395e788aa7476dd916e9 100644
+--- a/src/conf_macros.m4
++++ b/src/conf_macros.m4
+@@ -708,6 +708,19 @@ AC_ARG_ENABLE([dbus-tests],
+               [build_dbus_tests=yes])
+ AM_CONDITIONAL([BUILD_DBUS_TESTS], [test x$build_dbus_tests = xyes])
+ 
++AC_ARG_ENABLE([sss-default-nss-plugin],
++              [AS_HELP_STRING([--enable-sss-default-nss-plugin],
++                              [This option change standard behaviour of sss nss
++                               plugin. If this option is enabled the sss nss
++                               plugin will behave as it was not in
++                               nsswitch.conf when sssd is not running.
++                               [default=no]])],
++              [enable_sss_default_nss_plugin=$enableval],
++              [enable_sss_default_nss_plugin=no])
++AS_IF([test x$enable_sss_default_nss_plugin = xyes],
++      AC_DEFINE_UNQUOTED([NONSTANDARD_SSS_NSS_BEHAVIOUR], [1],
++          [whether to build sssd nss plugin with nonstandard glibc behaviour]))
++
+ AC_DEFUN([WITH_NFS],
+   [ AC_ARG_WITH([nfsv4-idmapd-plugin],
+                 [AC_HELP_STRING([--with-nfsv4-idmapd-plugin],
+diff --git a/src/sss_client/common.c b/src/sss_client/common.c
+index ebe783aba9cfa3dc11a529e7875966f139eea1af..7c4bb7ab8769a72f943158366f358b108bfc3bdc 100644
+--- a/src/sss_client/common.c
++++ b/src/sss_client/common.c
+@@ -724,7 +724,12 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
+ 
+     ret = sss_cli_check_socket(errnop, SSS_NSS_SOCKET_NAME);
+     if (ret != SSS_STATUS_SUCCESS) {
++#ifdef NONSTANDARD_SSS_NSS_BEHAVIOUR
++        errno = 0;
++        return NSS_STATUS_NOTFOUND;
++#else
+         return NSS_STATUS_UNAVAIL;
++#endif
+     }
+ 
+     ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
+@@ -735,7 +740,12 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
+         return NSS_STATUS_SUCCESS;
+     case SSS_STATUS_UNAVAIL:
+     default:
++#ifdef NONSTANDARD_SSS_NSS_BEHAVIOUR
++        errno = 0;
++        return NSS_STATUS_NOTFOUND;
++#else
+         return NSS_STATUS_UNAVAIL;
++#endif
+     }
+ }
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0133-Skip-CHAUTHTOK_PRELIM-when-using-OTPs.patch b/SOURCES/0133-Skip-CHAUTHTOK_PRELIM-when-using-OTPs.patch
new file mode 100644
index 0000000..6a4159d
--- /dev/null
+++ b/SOURCES/0133-Skip-CHAUTHTOK_PRELIM-when-using-OTPs.patch
@@ -0,0 +1,186 @@
+From fc4862295d512e464feff60cbc5df8c50bf83644 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 27 Nov 2014 20:29:03 +0100
+Subject: [PATCH 133/138] Skip CHAUTHTOK_PRELIM when using OTPs
+
+https://fedorahosted.org/sssd/ticket/2484
+
+When OTPs are used, we can only used each authtoken at most once. When
+it comes to Kerberos password changes, this was only working previously
+by accident, because the old authtoken was first used to verify the old
+password is valid and not expired and then also to acquire a chpass
+principal.
+
+This patch looks at the user object in LDAP to check if the user has any
+OTPs enabled. If he does, the CHAUTHTOK_PRELIM step is skipped
+completely so that the OTP can be used to acquire the chpass ticket
+later.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/db/sysdb.h                 |  2 ++
+ src/providers/ad/ad_opts.h     |  1 +
+ src/providers/ipa/ipa_opts.h   |  1 +
+ src/providers/krb5/krb5_auth.c | 38 +++++++++++++++++++++++++++++++++++---
+ src/providers/ldap/ldap_opts.h |  3 +++
+ src/providers/ldap/sdap.h      |  1 +
+ 6 files changed, 43 insertions(+), 3 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 5bd7f90acb685bbaff5c98f433c7dce8175c33ca..4fbbb16718a2fc3d444e4c6dba5fca4c1bb3096a 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -127,6 +127,8 @@
+ 
+ #define SYSDB_SSH_PUBKEY "sshPublicKey"
+ 
++#define SYSDB_AUTH_TYPE "authType"
++
+ #define SYSDB_SUBDOMAIN_REALM "realmName"
+ #define SYSDB_SUBDOMAIN_FLAT "flatName"
+ #define SYSDB_SUBDOMAIN_ID "domainID"
+diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
+index c3de3d94b1818665a86bba8a2432c699717b6a34..d9405e5020ca724a0f7caa752ac10fb07d8aa397 100644
+--- a/src/providers/ad/ad_opts.h
++++ b/src/providers/ad/ad_opts.h
+@@ -212,6 +212,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
+     { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
+     { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
+     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
++    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index f77ff1d05b9540155db44d04d4fb3aac9d7b5988..66af648583e552d7edd932f6bb5a2c3bef107e51 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -203,6 +203,7 @@ struct sdap_attr_map ipa_user_map[] = {
+     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
+     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
+     { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
++    { "ldap_user_auth_type", "ipaUserAuthType", SYSDB_AUTH_TYPE, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index e43b3652786678b79499e30ed546712ef080fe2c..25caf7b788a3f373f47e9d8aad38a2ea6fc12621 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -311,6 +311,25 @@ static void krb5_auth_store_creds(struct sss_domain_info *domain,
+     }
+ }
+ 
++static bool is_otp_enabled(struct ldb_message *user_msg)
++{
++    struct ldb_message_element *el;
++    size_t i;
++
++    el = ldb_msg_find_element(user_msg, SYSDB_AUTH_TYPE);
++    if (el == NULL) {
++        return false;
++    }
++
++    for (i = 0; i < el->num_values; i++) {
++        if (strcmp((const char * )el->values[i].data, "otp") == 0) {
++            return true;
++        }
++    }
++
++    return false;
++}
++
+ /* krb5_auth request */
+ 
+ struct krb5_auth_state {
+@@ -344,8 +363,9 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+     const char *realm;
+     struct tevent_req *req;
+     struct tevent_req *subreq;
+-    int authtok_type;
++    enum sss_authtok_type authtok_type;
+     int ret;
++    bool otp;
+ 
+     req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
+     if (req == NULL) {
+@@ -441,7 +461,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    attrs = talloc_array(state, const char *, 7);
++    attrs = talloc_array(state, const char *, 8);
+     if (attrs == NULL) {
+         ret = ENOMEM;
+         goto done;
+@@ -453,7 +473,8 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+     attrs[3] = SYSDB_UIDNUM;
+     attrs[4] = SYSDB_GIDNUM;
+     attrs[5] = SYSDB_CANONICAL_UPN;
+-    attrs[6] = NULL;
++    attrs[6] = SYSDB_AUTH_TYPE;
++    attrs[7] = NULL;
+ 
+     ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
+     if (ret != EOK) {
+@@ -547,6 +568,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+         break;
+     }
+ 
++    otp = is_otp_enabled(res->msgs[0]);
++    if (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && otp == true) {
++        /* To avoid consuming the OTP */
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "Skipping password checks for OTP-enabled user\n");
++        state->pam_status = PAM_SUCCESS;
++        state->dp_err = DP_ERR_OK;
++        ret = EOK;
++        goto done;
++    }
++
+     kr->srv = NULL;
+     kr->kpasswd_srv = NULL;
+ 
+diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
+index f46381e9fac7b93730ce0767154989f2e3b7ebbf..7c9ed3e01f726f2ba6ecb2a7268867abd3baa37d 100644
+--- a/src/providers/ldap/ldap_opts.h
++++ b/src/providers/ldap/ldap_opts.h
+@@ -179,6 +179,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
+     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
+     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
+     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
++    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+@@ -233,6 +234,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
+     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
+     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
+     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
++    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+@@ -287,6 +289,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = {
+     { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
+     { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
+     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
++    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index aa10623a58d7d667205b09e744dc2b924ca821ed..921051b41a911a2d1117672a8e9c2697b679f24e 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -280,6 +280,7 @@ enum sdap_user_attrs {
+     SDAP_AT_NDS_LOGIN_EXPIRATION_TIME,
+     SDAP_AT_NDS_LOGIN_ALLOWED_TIME_MAP,
+     SDAP_AT_USER_SSH_PUBLIC_KEY,
++    SDAP_AT_USER_AUTH_TYPE,
+ 
+     SDAP_OPTS_USER /* attrs counter */
+ };
+-- 
+1.9.3
+
diff --git a/SOURCES/0134-PAM-Domain-names-are-case-insensitive.patch b/SOURCES/0134-PAM-Domain-names-are-case-insensitive.patch
new file mode 100644
index 0000000..bda512e
--- /dev/null
+++ b/SOURCES/0134-PAM-Domain-names-are-case-insensitive.patch
@@ -0,0 +1,39 @@
+From f5ecf965b20acf977ad7e8e2ff97b57dd9c94000 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 10 Dec 2014 11:35:18 +0100
+Subject: [PATCH 134/138] PAM: Domain names are case-insensitive
+
+The pam_public_domains option and matching the domain requested by a
+trusted process was done in a case-sensitive manner which is different
+from how we match domain names in SSSD normally.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/responder/pam/pamsrv_cmd.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 02720018b91e1319346a023eca571913b544284a..29a9810e6f2d86210d9e1303f55a411d81704ddf 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -56,7 +56,7 @@ static bool is_domain_requested(struct pam_data *pd, const char *domain_name)
+     }
+ 
+     for (i = 0; pd->requested_domains[i]; i++) {
+-        if (strcmp(domain_name, pd->requested_domains[i])) {
++        if (strcasecmp(domain_name, pd->requested_domains[i])) {
+             continue;
+         }
+ 
+@@ -831,7 +831,7 @@ static bool is_domain_public(char *name,
+     size_t i;
+ 
+     for(i=0; i < public_dom_names_count; i++) {
+-        if (strcmp(name, public_dom_names[i]) == 0) {
++        if (strcasecmp(name, public_dom_names[i]) == 0) {
+             return true;
+         }
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0135-PAM-Missing-argument-to-domains-should-fail-auth.patch b/SOURCES/0135-PAM-Missing-argument-to-domains-should-fail-auth.patch
new file mode 100644
index 0000000..1217bed
--- /dev/null
+++ b/SOURCES/0135-PAM-Missing-argument-to-domains-should-fail-auth.patch
@@ -0,0 +1,36 @@
+From 0620f73a3c4b494112b75eeedfed4933e231382f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 10 Dec 2014 12:02:47 +0100
+Subject: [PATCH 135/138] PAM: Missing argument to domains= should fail auth
+
+When the administrator sets the domains= list, he usually wants to
+restrict the set of domains. An empty list is an undefined configuration
+and it's safer to fail then.
+
+https://fedorahosted.org/sssd/ticket/2516
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/sss_client/pam_sss.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
+index d64e826daeb80be8998ef3b410047e3a44051b07..fdf6c9e6da75c9f7eaa7c00d9a5792fbdd97eabc 100644
+--- a/src/sss_client/pam_sss.c
++++ b/src/sss_client/pam_sss.c
+@@ -1487,6 +1487,12 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
+ 
+     eval_argv(pamh, argc, argv, &flags, &retries, &quiet_mode, &domains);
+ 
++    /* Fail all authentication on misconfigured domains= parameter. The admin
++     * probably wanted to restrict authentication, so it's safer to fail */
++    if (domains && strcmp(domains, "") == 0) {
++        return PAM_SYSTEM_ERR;
++    }
++
+     pi.requested_domains = domains;
+ 
+     ret = get_pam_items(pamh, &pi);
+-- 
+1.9.3
+
diff --git a/SOURCES/0136-MAN-Misspelled-username-in-pam_trusted_users-is-not-.patch b/SOURCES/0136-MAN-Misspelled-username-in-pam_trusted_users-is-not-.patch
new file mode 100644
index 0000000..2b12fba
--- /dev/null
+++ b/SOURCES/0136-MAN-Misspelled-username-in-pam_trusted_users-is-not-.patch
@@ -0,0 +1,37 @@
+From e786e081edecabb8e8506dd3c5e668094827bc52 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 11 Dec 2014 11:19:58 +0100
+Subject: [PATCH 136/138] MAN: Misspelled username in pam_trusted_users is not
+ fatal
+
+The man page claimed that failing to resolve an user name results in
+failure to start SSSD, but it's not the case and shouldn't be, because
+marking a user as trusted only elevates privileges, so it's safe to
+ignore that failure.
+
+https://fedorahosted.org/sssd/ticket/2530
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/man/sssd.conf.5.xml | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 3525d78caff28fd05cc18061d023fec3c50d1a47..2002ccc7caf7013ead5b97c463fba46b734090ae 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -907,11 +907,6 @@ fallback_homedir = /home/%u
+                             the PAM responder even in case it is not in the
+                             pam_trusted_users list.
+                         </para>
+-                        <para>
+-                            Also please note that if there is a user name in
+-                            pam_trusted_users list which fails to be resolved
+-                            it will cause that SSSD will not be started.
+-                        </para>
+                     </listitem>
+                 </varlistentry>
+                 <varlistentry>
+-- 
+1.9.3
+
diff --git a/SOURCES/0137-RESPONDER-Log-failures-to-resolve-user-names-in-csv_.patch b/SOURCES/0137-RESPONDER-Log-failures-to-resolve-user-names-in-csv_.patch
new file mode 100644
index 0000000..807e319
--- /dev/null
+++ b/SOURCES/0137-RESPONDER-Log-failures-to-resolve-user-names-in-csv_.patch
@@ -0,0 +1,33 @@
+From 12e075db7ef0e72fba64ca2cd0eb55a6414388c0 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 11 Dec 2014 11:28:57 +0100
+Subject: [PATCH 137/138] RESPONDER: Log failures to resolve user names in
+ csv_string_to_uid_array
+
+This patch makes it more discoverable for the admin to find typos in the
+various user lists. Typically, the user lists are used to add access to
+some feature and printing a syslog message would make sure the admin
+sees the mistake.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/responder/common/responder_common.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index 6646fa2587a8299de40eaef35830351136b8149a..a5a44478759e0d515e8437c3bb9bcd78dbb1e4f5 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -215,6 +215,9 @@ errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
+                 DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is neither a valid "
+                                          "UID nor a user name which could be "
+                                          "resolved by getpwnam().\n", list[c]);
++                sss_log(SSS_LOG_WARNING, "List item [%s] is neither a valid "
++                                         "UID nor a user name which could be "
++                                         "resolved by getpwnam().\n", list[c]);
+                 goto done;
+             }
+         }
+-- 
+1.9.3
+
diff --git a/SOURCES/0138-KRB5-Check-FAST-kinit-errors-using-get_tgt_times.patch b/SOURCES/0138-KRB5-Check-FAST-kinit-errors-using-get_tgt_times.patch
new file mode 100644
index 0000000..d1cbfc6
--- /dev/null
+++ b/SOURCES/0138-KRB5-Check-FAST-kinit-errors-using-get_tgt_times.patch
@@ -0,0 +1,77 @@
+From 03afa4cbef2c2ba3c70fbad4f3e1e36c05fafe82 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 8 Dec 2014 13:29:23 +0100
+Subject: [PATCH 138/138] KRB5: Check FAST kinit errors using get_tgt_times()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/krb5/krb5_child.c | 28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 8f23346a67d4d2467a4d1869fd298ec4d6f68e92..3318e0647c0e7d7f0e7305cc4204d9c2db020162 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -1662,6 +1662,7 @@ static krb5_error_code get_tgt_times(krb5_context ctx, const char *ccname,
+     krberr = krb5_cc_resolve(ctx, ccname, &ccache);
+     if (krberr != 0) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
++        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, krberr);
+         goto done;
+     }
+ 
+@@ -1814,7 +1815,6 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
+             } while (kerr == -1 && errno == EINTR);
+ 
+             if (kerr > 0) {
+-                kerr = EIO;
+                 if (WIFEXITED(status)) {
+                     kerr = WEXITSTATUS(status);
+                     /* Don't blindly fail if the child fails, but check
+@@ -1830,26 +1830,28 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
+                           fchild_pid);
+                 }
+             } else {
+-                DEBUG(SSSDBG_FUNC_DATA,
+-                    "Failed to wait for children %d\n", fchild_pid);
+-                kerr = EIO;
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Failed to wait for child %d\n", fchild_pid);
++                /* Let the code re-check the TGT times and fail if we
++                 * can't find the updated principal */
+             }
+     }
+ 
+     /* Check the ccache times again. Should be updated ... */
+     memset(&tgtt, 0, sizeof(tgtt));
+     kerr = get_tgt_times(ctx, ccname, server_princ, client_princ, &tgtt);
+-    if (kerr == 0) {
+-        if (tgtt.endtime > time(NULL)) {
+-            DEBUG(SSSDBG_FUNC_DATA, "FAST TGT was successfully recreated!\n");
+-            goto done;
+-        } else {
+-            kerr = ERR_CREDS_EXPIRED;
+-            goto done;
+-        }
++    if (kerr != 0) {
++        DEBUG(SSSDBG_OP_FAILURE, "get_tgt_times() failed\n");
++        goto done;
+     }
+ 
+-    kerr = 0;
++    if (tgtt.endtime < time(NULL)) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Valid FAST TGT not found after attempting to renew it\n");
++        kerr = ERR_CREDS_EXPIRED;
++        goto done;
++    }
++    DEBUG(SSSDBG_FUNC_DATA, "FAST TGT was successfully recreated!\n");
+ 
+ done:
+     if (client_princ != NULL) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0139-MAN-Clarify-ad_gpo_map-options.patch b/SOURCES/0139-MAN-Clarify-ad_gpo_map-options.patch
new file mode 100644
index 0000000..cba3d15
--- /dev/null
+++ b/SOURCES/0139-MAN-Clarify-ad_gpo_map-options.patch
@@ -0,0 +1,43 @@
+From 01fa6711add8c52aa1a8474cf34af67d1e555c91 Mon Sep 17 00:00:00 2001
+From: Dan Lavu <side_control@runlevelone.net>
+Date: Mon, 15 Dec 2014 03:20:40 +0100
+Subject: [PATCH 1/2] MAN: Clarify ad_gpo_map* options
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2515
+---
+ src/man/sssd-ad.5.xml | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
+index 4e29d4f75cae5bf17e4bb85fa46c921b25ee8047..b721fb73b20837c9dc3abac25d3300649115c607 100644
+--- a/src/man/sssd-ad.5.xml
++++ b/src/man/sssd-ad.5.xml
+@@ -342,6 +342,11 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com)
+                             DenyInteractiveLogonRight policy settings.
+                         </para>
+                         <para>
++                            Note: Using the Group Policy Management Editor this
++                            value InteractiveLogonRight  is called "Allow log on
++                            locally" and "Deny log on locally".
++                        </para>
++                        <para>
+                             It is possible to add another PAM service name
+                             to the default set by using <quote>+service_name</quote>
+                             or to explicitly remove a PAM service name from
+@@ -407,6 +412,12 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com)
+                             DenyRemoteInteractiveLogonRight policy settings.
+                         </para>
+                         <para>
++                            Note: Using the Group Policy Management Editor this
++                            value is called "Allow log on through Remote Desktop
++                            Services" and "Deny log on through Remote Desktop
++                            Services".
++                        </para>
++                        <para>
+                             It is possible to add another PAM service name
+                             to the default set by using <quote>+service_name</quote>
+                             or to explicitly remove a PAM service name from
+-- 
+1.9.3
+
diff --git a/SOURCES/0140-krb5_child-Initialize-REALM-earlier.patch b/SOURCES/0140-krb5_child-Initialize-REALM-earlier.patch
new file mode 100644
index 0000000..c4e5f68
--- /dev/null
+++ b/SOURCES/0140-krb5_child-Initialize-REALM-earlier.patch
@@ -0,0 +1,67 @@
+From a183e279f754afdd571d8b084c7a36b71d5c1701 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Wed, 17 Dec 2014 09:10:33 +0100
+Subject: [PATCH 2/2] krb5_child: Initialize REALM earlier
+
+Environment variable SSSD_KRB5_REALM was used to late for initialisation
+realm. and therefore default value NULL was used.
+The SSSD_KRB5_REALM (kr->realm) was used as fast_principal_realm for checking
+fast cache: privileged_krb5_setup -> k5c_setup_fast -> check_fast_ccache
+And therefore wrong principal was used when the option krb5_fast_principal is
+empty.
+
+[find_principal_in_keytab] (0x4000): Trying to find principal (null)@(null) in keytab.
+[match_principal] (0x1000): Principal matched to the sample ((null)@(null)).
+[get_tgt_times] (0x1000): FAST ccache must be recreated
+[get_tgt_times] (0x0020): krb5_cc_retrieve_cred failed
+[get_tgt_times] (0x0020): 1688: [-1765328243][Matching credential not found]
+[check_fast_ccache] (0x0040): Valid FAST TGT not found after attempting to renew it
+[k5c_setup_fast] (0x0020): check_fast_ccache failed.
+[k5c_setup_fast] (0x0020): 1956: [1432158213][Unknown code UUz 5]
+[privileged_krb5_setup] (0x0040): Cannot set up FAST
+[main] (0x0020): privileged_krb5_setup failed.
+[main] (0x0020): krb5_child failed!
+
+As a result of this user was not able to authenticate.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2526
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/krb5/krb5_child.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 76a0757f6176d4ad9d049bc8825a64328b19a818..64fe6f0cb19e831ed4b49f627cb3b3a124272943 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -2159,12 +2159,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
+     DEBUG(SSSDBG_TRACE_INTERNAL,
+           "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
+ 
+-    kr->realm = getenv(SSSD_KRB5_REALM);
+-    if (kr->realm == NULL) {
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Cannot read [%s] from environment.\n", SSSD_KRB5_REALM);
+-    }
+-
+     /* Set the global error context */
+     krb5_error_ctx = kr->ctx;
+ 
+@@ -2254,6 +2248,12 @@ static krb5_error_code privileged_krb5_setup(struct krb5_req *kr,
+     int ret;
+     char *mem_keytab;
+ 
++    kr->realm = getenv(SSSD_KRB5_REALM);
++    if (kr->realm == NULL) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot read [%s] from environment.\n", SSSD_KRB5_REALM);
++    }
++
+     kerr = krb5_init_context(&kr->ctx);
+     if (kerr != 0) {
+         KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+-- 
+1.9.3
+
diff --git a/SOURCES/0141-TESTS-sysdb_delete_by_sid-test-return-value.patch b/SOURCES/0141-TESTS-sysdb_delete_by_sid-test-return-value.patch
new file mode 100644
index 0000000..07a6408
--- /dev/null
+++ b/SOURCES/0141-TESTS-sysdb_delete_by_sid-test-return-value.patch
@@ -0,0 +1,63 @@
+From 13c0cf829eca7891ad9d0087e91c72650f990149 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Tue, 9 Dec 2014 09:47:11 +0000
+Subject: [PATCH 2/7] TESTS: sysdb_delete_by_sid() test return value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Check that return value of sysdb_delete_by_sid() is not changed as
+called SYSDB functions have changed the return value.
+
+Part of patches for:
+https://fedorahosted.org/sssd/ticket/1991
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/sysdb-tests.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index b55901a30feb94cd8199eab096785a02dfc89b9a..d303982647547eefdce7c37ac5b70e1ffbe869ce 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -5127,7 +5127,28 @@ START_TEST(test_sysdb_search_object_by_uuid)
+                       "UUIDuser") == 0, "Unexpected object found, " \
+                       "expected [%s], got [%s].", "UUIDuser",
+                       ldb_msg_find_attr_as_string(res->msgs[0],SYSDB_NAME, ""));
++    talloc_free(test_ctx);
++}
++END_TEST
+ 
++START_TEST(test_sysdb_delete_by_sid)
++{
++    errno_t ret;
++    struct sysdb_test_ctx *test_ctx;
++
++    /* Setup */
++    ret = setup_sysdb_tests(&test_ctx);
++    fail_if(ret != EOK, "Could not set up the test");
++
++    check_leaks_push(test_ctx);
++
++    /* Delete the group by SID */
++    ret = sysdb_delete_by_sid(test_ctx->sysdb, test_ctx->domain,
++                              "S-1-2-3-4-NON_EXISTING_SID");
++    fail_unless(ret == EOK, "sysdb_delete_by_sid failed with [%d][%s].",
++                ret, strerror(ret));
++
++    fail_unless(check_leaks_pop(test_ctx) == true, "Memory leak");
+     talloc_free(test_ctx);
+ }
+ END_TEST
+@@ -6175,6 +6196,7 @@ Suite *create_sysdb_suite(void)
+     tcase_add_test(tc_sysdb, test_sysdb_search_custom_update);
+     tcase_add_test(tc_sysdb, test_sysdb_search_custom);
+     tcase_add_test(tc_sysdb, test_sysdb_delete_custom);
++    tcase_add_test(tc_sysdb, test_sysdb_delete_by_sid);
+ 
+     /* test recursive delete */
+     tcase_add_test(tc_sysdb, test_sysdb_delete_recursive);
+-- 
+1.9.3
+
diff --git a/SOURCES/0142-NSS-nss_cmd_getbysid_search-return-ENOENT.patch b/SOURCES/0142-NSS-nss_cmd_getbysid_search-return-ENOENT.patch
new file mode 100644
index 0000000..9267d53
--- /dev/null
+++ b/SOURCES/0142-NSS-nss_cmd_getbysid_search-return-ENOENT.patch
@@ -0,0 +1,45 @@
+From d7b90921c1a404f0d9fb8384a8fd55fd15b86916 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Wed, 17 Dec 2014 14:10:45 +0000
+Subject: [PATCH 3/7] NSS: nss_cmd_getbysid_search return ENOENT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/responder/nss/nsssrv_cmd.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index ea58920bc3611c84958e8d0aca0e122d90c68e5c..80ac221e288665741d8b1e2bd020ecca568106c1 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4502,16 +4502,16 @@ static errno_t nss_cmd_getbysid_search(struct nss_dom_ctx *dctx)
+         return ENOENT;
+     }
+ 
+-    if (dctx->res->count == 0 && !dctx->check_provider) {
++    if (dctx->res->count == 0) {
+         DEBUG(SSSDBG_OP_FAILURE, "No results for getbysid call.\n");
+-
+-        /* set negative cache only if not result of cache check */
+-        ret = sss_ncache_set_sid(nctx->ncache, false, cmdctx->secid);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Cannot set negative cache for %s\n", cmdctx->secid);
++        if (!dctx->check_provider) {
++            /* set negative cache only if not result of cache check */
++            ret = sss_ncache_set_sid(nctx->ncache, false, cmdctx->secid);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_MINOR_FAILURE,
++                      "Cannot set negative cache for %s\n", cmdctx->secid);
++            }
+         }
+-
+         return ENOENT;
+     }
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0143-SYSDB-sysdb_search_object_by_sid-returns-ENOENT.patch b/SOURCES/0143-SYSDB-sysdb_search_object_by_sid-returns-ENOENT.patch
new file mode 100644
index 0000000..6cd2d4f
--- /dev/null
+++ b/SOURCES/0143-SYSDB-sysdb_search_object_by_sid-returns-ENOENT.patch
@@ -0,0 +1,249 @@
+From 4bbcc2d6d3f16b015796818746a45134861c93a4 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Tue, 9 Dec 2014 11:01:13 +0000
+Subject: [PATCH 4/7] SYSDB: sysdb_search_object_by_sid returns ENOENT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sysdb_search_object_by_sid returns ENOENT if no results are found.
+
+Part od solution for:
+https://fedorahosted.org/sssd/ticket/1991
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/2520
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/db/sysdb.h                 |  2 +-
+ src/db/sysdb_ops.c             | 68 ++++++------------------------------------
+ src/responder/nss/nsssrv_cmd.c | 25 ++++++++--------
+ src/responder/pac/pacsrv_cmd.c | 29 ++++++++++--------
+ src/tests/sysdb-tests.c        |  5 +---
+ 5 files changed, 39 insertions(+), 90 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 01900425ac5e8733eb57877bbadef0e8da00475f..b1e057107cc6e3d4ce7b7bb8e821a2414c3424a7 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1035,7 +1035,7 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *domain,
+                                    const char *sid_str,
+                                    const char **attrs,
+-                                   struct ldb_result **msg);
++                                   struct ldb_result **res);
+ 
+ errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
+                                     struct sss_domain_info *domain,
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 768f9455329b136b3de9794ad127dd349f1eaa43..b12540b68d1c81c419455416294f3449dd84914e 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -2994,7 +2994,14 @@ int sysdb_delete_by_sid(struct sysdb_ctx *sysdb,
+     }
+ 
+     ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res);
+-    if (ret != EOK) {
++
++    if (ret == ENOENT) {
++        /* No existing entry. Just quit. */
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "search by sid did not return any results.\n");
++        ret = EOK;
++        goto done;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "search by sid failed: %d (%s)\n",
+               ret, strerror(ret));
+         goto done;
+@@ -3007,12 +3014,6 @@ int sysdb_delete_by_sid(struct sysdb_ctx *sysdb,
+         goto done;
+     }
+ 
+-    if (res->count == 0) {
+-        /* No existing entry. Just quit. */
+-        ret = EOK;
+-        goto done;
+-    }
+-
+     ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, false);
+     if (ret != EOK) {
+         goto done;
+@@ -3564,61 +3565,10 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *domain,
+                                    const char *sid_str,
+                                    const char **attrs,
+-                                   struct ldb_result **msg)
++                                   struct ldb_result **res)
+ {
+-/* TODO: use
+     return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER,
+                                            sid_str, attrs, res);
+-
+-    when verified that all callers can handle ENOENT correctly. */
+-
+-    TALLOC_CTX *tmp_ctx;
+-    const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM,
+-                                ORIGINALAD_PREFIX SYSDB_NAME,
+-                                SYSDB_OBJECTCLASS, NULL };
+-    struct ldb_dn *basedn;
+-    int ret;
+-    struct ldb_result *res = NULL;
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (!tmp_ctx) {
+-        return ENOMEM;
+-    }
+-
+-    basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE, domain->name);
+-    if (basedn == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
+-                     basedn, LDB_SCOPE_SUBTREE, attrs?attrs:def_attrs,
+-                     SYSDB_SID_FILTER, sid_str);
+-    if (ret != EOK) {
+-        ret = sysdb_error_to_errno(ret);
+-        DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n");
+-        goto done;
+-    }
+-
+-    if (res->count > 1) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Search for SID [%s] returned more than " \
+-                                    "one object.\n", sid_str);
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    *msg = talloc_steal(mem_ctx, res);
+-
+-done:
+-    if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "No such entry.\n");
+-    } else if (ret) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
+-    }
+-
+-    talloc_zfree(tmp_ctx);
+-    return ret;
+ }
+ 
+ errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 80ac221e288665741d8b1e2bd020ecca568106c1..3c5d450714fb3f7655cd32aeef900b4f5e9782c7 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4491,20 +4491,10 @@ static errno_t nss_cmd_getbysid_search(struct nss_dom_ctx *dctx)
+ 
+     ret = sysdb_search_object_by_sid(cmdctx, dom, cmdctx->secid, NULL,
+                                      &dctx->res);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache!\n");
+-        return EIO;
+-    }
+-
+-    if (dctx->res->count > 1) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \
+-                                     "result !?!\n");
+-        return ENOENT;
+-    }
+-
+-    if (dctx->res->count == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE, "No results for getbysid call.\n");
++    if (ret == ENOENT) {
+         if (!dctx->check_provider) {
++            DEBUG(SSSDBG_OP_FAILURE, "No results for getbysid call.\n");
++
+             /* set negative cache only if not result of cache check */
+             ret = sss_ncache_set_sid(nctx->ncache, false, cmdctx->secid);
+             if (ret != EOK) {
+@@ -4513,6 +4503,15 @@ static errno_t nss_cmd_getbysid_search(struct nss_dom_ctx *dctx)
+             }
+         }
+         return ENOENT;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache!\n");
++        return EIO;
++    }
++
++    if (dctx->res->count > 1) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \
++                                     "result !?!\n");
++        return ENOENT;
+     }
+ 
+     /* if this is a caching provider (or if we haven't checked the cache
+diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
+index cc92592893899b1fa269188facc1a8154f80991d..07d2f0cf79b70429dc7cf2784a8e31d651e5095f 100644
+--- a/src/responder/pac/pacsrv_cmd.c
++++ b/src/responder/pac/pacsrv_cmd.c
+@@ -297,17 +297,17 @@ static void pac_lookup_sids_done(struct tevent_req *req)
+             msg = NULL;
+             ret = sysdb_search_object_by_sid(pr_ctx, dom, entries[c].key.str,
+                                              NULL, &msg);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_object_by_sid " \
+-                                          "failed.\n");
+-                continue;
+-            }
+-
+-            if (msg->count == 0) {
++            if (ret == ENOENT) {
+                 DEBUG(SSSDBG_OP_FAILURE, "No entry found for SID [%s].\n",
+-                                          entries[c].key.str);
++                      entries[c].key.str);
+                 continue;
+-            } else if (msg->count > 1) {
++            } else if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "sysdb_search_object_by_sid failed.\n");
++                continue;
++            }
++
++            if (msg->count > 1) {
+                 DEBUG(SSSDBG_CRIT_FAILURE, "More then one result returned " \
+                                             "for SID [%s].\n",
+                                             entries[c].key.str);
+@@ -911,10 +911,13 @@ pac_store_membership(struct pac_req_ctx *pr_ctx,
+ 
+     ret = sysdb_search_object_by_sid(tmp_ctx, grp_dom, grp_sid_str,
+                                      group_attrs, &group);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_TRACE_INTERNAL, "sysdb_search_object_by_sid " \
+-                                      "for SID [%s] failed [%d][%s].\n",
+-                                      grp_sid_str, ret, strerror(ret));
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_OP_FAILURE, "Unexpected number of groups returned.\n");
++        goto done;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_TRACE_INTERNAL,
++              "sysdb_search_object_by_sid for SID [%s] failed [%d][%s].\n",
++              grp_sid_str, ret, strerror(ret));
+         goto done;
+     }
+ 
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index d303982647547eefdce7c37ac5b70e1ffbe869ce..92b41e90d08c2d50775289ba8c922f39350ce625 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -4861,13 +4861,10 @@ START_TEST (test_sysdb_search_return_ENOENT)
+     talloc_zfree(res);
+ 
+     /* Search object */
+-    /* TODO: Should return ENOENT */
+     ret = sysdb_search_object_by_sid(test_ctx, test_ctx->domain,
+                                      "S-5-4-3-2-1", NULL, &res);
+-    fail_unless(ret == EOK, "sysdb_search_object_by_sid_str failed with "
++    fail_unless(ret == ENOENT, "sysdb_search_object_by_sid_str failed with "
+                              "[%d][%s].", ret, strerror(ret));
+-    fail_unless(res->count == 0, "sysdb_search_object_by_sid_str should not "
+-                                 "return anything.");
+     talloc_zfree(res);
+ 
+     /* Search can return more results */
+-- 
+1.9.3
+
diff --git a/SOURCES/0144-handle-KRB5KRB_ERR_GENERIC-as-unspecific-error.patch b/SOURCES/0144-handle-KRB5KRB_ERR_GENERIC-as-unspecific-error.patch
new file mode 100644
index 0000000..6301175
--- /dev/null
+++ b/SOURCES/0144-handle-KRB5KRB_ERR_GENERIC-as-unspecific-error.patch
@@ -0,0 +1,54 @@
+From 956dbefd49ce3cbf27539d8846a6d71462a3a927 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 17 Dec 2014 09:42:57 +0100
+Subject: [PATCH 5/7] krb5: handle KRB5KRB_ERR_GENERIC as unspecific error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+KRB5KRB_ERR_GENERIC is a generic error and we cannot make any
+assumptions about the cause. If there are cases where
+KRB5KRB_ERR_GENERIC is returned and SSSD should behave differently this
+must be solved by other means.
+
+Resolves https://fedorahosted.org/sssd/ticket/2535
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/krb5/krb5_child.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 64fe6f0cb19e831ed4b49f627cb3b3a124272943..e5ce50be4bb088df3c45e5f642e8b3f3608c4662 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -1076,7 +1076,6 @@ static errno_t map_krb5_error(krb5_error_code kerr)
+     case KRB5_LIBOS_CANTREADPWD:
+         return ERR_NO_CREDS;
+ 
+-    case KRB5KRB_ERR_GENERIC:
+     case KRB5KRB_AP_ERR_SKEW:
+     case KRB5_KDC_UNREACH:
+     case KRB5_REALM_CANT_RESOLVE:
+@@ -1099,6 +1098,18 @@ static errno_t map_krb5_error(krb5_error_code kerr)
+     case KRB5KDC_ERR_PREAUTH_FAILED:
+         return ERR_CREDS_INVALID;
+ 
++    /* Please do not remove KRB5KRB_ERR_GENERIC here, it is a _generic_ error
++     * code and we cannot make any assumptions about the reason for the error.
++     * As a consequence we cannot return a different error code than a generic
++     * one which unfortunately might result in a unspecific system error
++     * message to the user.
++     *
++     * If there are cases where libkrb5 calls return KRB5KRB_ERR_GENERIC where
++     * SSSD should behave differently this has to be detected by different
++     * means, e.g. by evaluation error messages, and then the error code
++     * should be changed to a more suitable KRB5* error code or immediately to
++     * a SSSD ERR_* error code to avoid the default handling here. */
++    case KRB5KRB_ERR_GENERIC:
+     default:
+         return ERR_INTERNAL;
+     }
+-- 
+1.9.3
+
diff --git a/SOURCES/0145-IPA-verify-group-memberships-of-trusted-domain-users.patch b/SOURCES/0145-IPA-verify-group-memberships-of-trusted-domain-users.patch
new file mode 100644
index 0000000..37f9d78
--- /dev/null
+++ b/SOURCES/0145-IPA-verify-group-memberships-of-trusted-domain-users.patch
@@ -0,0 +1,215 @@
+From ad463501d3bdea4c24c17d792efc1c3e65c08c19 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 11 Dec 2014 10:49:39 +0100
+Subject: [PATCH 6/7] IPA: verify group memberships of trusted domain users
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Depending on the state of the cache group object a freshly created or
+updates user entry for a trusted domain user might already be a member
+of the group or not. This cache makes sure the requested user is a
+member of all groups returned from the extdom request. Special care has
+to be taken to cover cross-domain group-memberships properly.
+
+Resolves https://fedorahosted.org/sssd/ticket/2529
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 145 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 144 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 0eab1afc36e4d2c1d770c596c512a641fd276425..677d1625860186ad02d4d8c7290d45b782bc4c38 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -568,7 +568,7 @@ static errno_t add_v1_user_data(BerElement *ber, struct resp_attrs *attrs)
+          attrs->ngroups++);
+ 
+     if (attrs->ngroups > 0) {
+-        attrs->groups = talloc_array(attrs, char *, attrs->ngroups);
++        attrs->groups = talloc_zero_array(attrs, char *, attrs->ngroups + 1);
+         if (attrs->groups == NULL) {
+             DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+             ret = ENOMEM;
+@@ -1528,6 +1528,81 @@ done:
+     return;
+ }
+ 
++static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
++                              char **name_list, char ***_dn_list)
++{
++    int ret;
++    TALLOC_CTX *tmp_ctx;
++    int c;
++    struct sss_domain_info *root_domain;
++    char **dn_list;
++
++    if (name_list == NULL) {
++        *_dn_list = NULL;
++        return EOK;
++    }
++
++    /* To handle cross-domain memberships we have to check the domain for
++     * each group the member should be added or deleted. Since sub-domains
++     * use fully-qualified names by default any short name can only belong
++     * to the root/head domain. find_domain_by_object_name() will return
++     * the domain given in the first argument if the second argument is a
++     * a short name hence we always use root_domain as first argument. */
++    root_domain = get_domains_head(dom);
++    if (root_domain->fqnames) {
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "Root domain uses fully-qualified names, " \
++              "objects might not be correctly added to groups with " \
++              "short names.\n");
++    }
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    for (c = 0; name_list[c] != NULL; c++);
++
++    dn_list = talloc_zero_array(tmp_ctx, char *, c + 1);
++    if (dn_list == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    for (c = 0; name_list[c] != NULL; c++) {
++        dom = find_domain_by_object_name(root_domain, name_list[c]);
++        if (dom == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Cannot find domain for [%s].\n", name_list[c]);
++            ret = ENOENT;
++            goto done;
++        }
++
++        /* This might fail if some unexpected cases are used. But current
++         * sysdb code which handles group membership constructs DNs this way
++         * as well, IPA names are lowercased and AD names by default will be
++         * lowercased as well. If there are really use-cases which cause an
++         * issue here, sysdb_group_strdn() has to be replaced by a proper
++         * search. */
++        dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]);
++        if (dn_list[c] == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_group_strdn failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    *_dn_list = talloc_steal(mem_ctx, dn_list);
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
+ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                                     struct req_input *req_input,
+                                     struct resp_attrs *attrs,
+@@ -1548,6 +1623,13 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     const char *tmp_str;
+     struct ldb_result *res;
+     enum sysdb_member_type type;
++    char **sysdb_grouplist;
++    char **add_groups;
++    char **add_groups_dns;
++    char **del_groups;
++    char **del_groups_dns;
++    bool in_transaction = false;
++    int tret;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -1716,6 +1798,13 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 gid = attrs->a.user.pw_gid;
+             }
+ 
++            ret = sysdb_transaction_start(dom->sysdb);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
++                goto done;
++            }
++            in_transaction = true;
++
+             ret = sysdb_store_user(dom, name, NULL,
+                                    attrs->a.user.pw_uid,
+                                    gid, attrs->a.user.pw_gecos,
+@@ -1726,6 +1815,53 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_user failed.\n");
+                 goto done;
+             }
++
++            if (attrs->response_type == RESP_USER_GROUPLIST) {
++                ret = get_sysdb_grouplist(tmp_ctx, dom->sysdb, dom, name,
++                                          &sysdb_grouplist);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "get_sysdb_grouplist failed.\n");
++                    goto done;
++                }
++
++                ret = diff_string_lists(tmp_ctx, attrs->groups, sysdb_grouplist,
++                                        &add_groups, &del_groups, NULL);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n");
++                    goto done;
++                }
++
++                ret = get_groups_dns(tmp_ctx, dom, add_groups, &add_groups_dns);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
++                    goto done;
++                }
++
++                ret = get_groups_dns(tmp_ctx, dom, del_groups, &del_groups_dns);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
++                    goto done;
++                }
++
++                DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n",
++                                             name);
++                ret = sysdb_update_members_dn(dom, name, SYSDB_MEMBER_USER,
++                                          (const char *const *) add_groups_dns,
++                                          (const char *const *) del_groups_dns);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_CRIT_FAILURE, "Membership update failed [%d]: %s\n",
++                                               ret, sss_strerror(ret));
++                    goto done;
++                }
++            }
++
++            ret = sysdb_transaction_commit(dom->sysdb);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
++                goto done;
++            }
++            in_transaction = false;
++
+             break;
+         case RESP_GROUP:
+         case RESP_GROUP_MEMBERS:
+@@ -1818,6 +1954,13 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     }
+ 
+ done:
++    if (in_transaction) {
++        tret = sysdb_transaction_cancel(dom->sysdb);
++        if (tret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
++        }
++    }
++
+     talloc_free(tmp_ctx);
+ 
+     return ret;
+-- 
+1.9.3
+
diff --git a/SOURCES/0146-IPA-properly-handle-groups-from-different-domains.patch b/SOURCES/0146-IPA-properly-handle-groups-from-different-domains.patch
new file mode 100644
index 0000000..bfc5abf
--- /dev/null
+++ b/SOURCES/0146-IPA-properly-handle-groups-from-different-domains.patch
@@ -0,0 +1,51 @@
+From 8f9d7684a47cd4715dce22c8254ddde205db9afe Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 12 Dec 2014 13:07:55 -0500
+Subject: [PATCH 7/7] IPA: properly handle groups from different domains
+
+When groups are resolved on IPA clients as part of a user lookup not all
+groups have to be from the same domain as the used. This has to be
+checked to store the group object properly in the cache.
+
+Related to https://fedorahosted.org/sssd/ticket/2529
+       and https://fedorahosted.org/sssd/ticket/2524
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 677d1625860186ad02d4d8c7290d45b782bc4c38..6d5b45edf20f720f5b97f0ed5c8ec591c580de0d 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1867,10 +1867,24 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+         case RESP_GROUP_MEMBERS:
+             type = SYSDB_MEMBER_GROUP;
+ 
++            if (0 != strcmp(dom->name, attrs->domain_name)) {
++                dom = find_domain_by_name(get_domains_head(dom),
++                                          attrs->domain_name, true);
++                if (dom == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "Cannot find domain: [%s]\n", attrs->domain_name);
++                    ret = EINVAL;
++                    goto done;
++                }
++            }
++
+             if (name == NULL) {
++                name = attrs->a.group.gr_name;
++            }
++
++            if (IS_SUBDOMAIN(dom)) {
+                 /* we always use the fully qualified name for subdomain users */
+-                name = sss_tc_fqname(tmp_ctx, dom->names, dom,
+-                                     attrs->a.group.gr_name);
++                name = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
+                 if (!name) {
+                     DEBUG(SSSDBG_OP_FAILURE, "failed to format user name,\n");
+                     ret = ENOMEM;
+-- 
+1.9.3
+
diff --git a/SOURCES/0147-LDAP-retain-external-members.patch b/SOURCES/0147-LDAP-retain-external-members.patch
new file mode 100644
index 0000000..ddb3499
--- /dev/null
+++ b/SOURCES/0147-LDAP-retain-external-members.patch
@@ -0,0 +1,261 @@
+From 6fac5e5f0c54a0f92872ce1450606cfcb577a920 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Thu, 20 Nov 2014 18:27:04 +0000
+Subject: [PATCH] LDAP: retain external members
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When processing group membership check sysdb for group members from
+extern domain and include them in newly processed group membership as
+extern members are curently found only when initgroups() is called.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2492
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/db/sysdb.h                         |   6 ++
+ src/db/sysdb_ops.c                     |  83 ++++++++++++++++++++++++++
+ src/providers/ldap/sdap_async_groups.c | 104 +++++++++++++++++++++++++++++++++
+ 3 files changed, 193 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 5bd7f90acb685bbaff5c98f433c7dce8175c33ca..cdcdfd51d6146bee5b212e6acfe98c831b635d33 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1103,4 +1103,10 @@ errno_t sysdb_gpo_get_gpo_result_setting(TALLOC_CTX *mem_ctx,
+                                          const char *policy_setting_key,
+                                          const char **policy_setting_value);
+ 
++errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
++                                  struct sss_domain_info *dom,
++                                  const char *group_name,
++                                  const char ***_sids,
++                                  const char ***_dns,
++                                  size_t *_n);
+ #endif /* __SYS_DB_H__ */
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 998046a2ca1c746b2032f430e5f9c4a7151e1dbc..768f9455329b136b3de9794ad127dd349f1eaa43 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -3630,3 +3630,86 @@ errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
+     return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_UUID_FILTER,
+                                            uuid_str, attrs, res);
+ }
++
++errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
++                                  struct sss_domain_info *dom,
++                                  const char *group_name,
++                                  const char ***_sids,
++                                  const char ***_dns,
++                                  size_t *_n)
++{
++    errno_t ret;
++    size_t i, m_count;
++    TALLOC_CTX *tmp_ctx;
++    struct ldb_message *msg;
++    struct ldb_message **members;
++    const char *attrs[] = { SYSDB_SID_STR, NULL };
++    const char **sids = NULL, **dns = NULL;
++    size_t n = 0;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    ret = sysdb_search_group_by_name(tmp_ctx, dom, group_name, NULL, &msg);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    /* Get sid_str attribute of all elemets pointed to by group members */
++    ret = sysdb_asq_search(tmp_ctx, dom, msg->dn, NULL, SYSDB_MEMBER, attrs,
++                           &m_count, &members);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    sids = talloc_array(tmp_ctx, const char*, m_count);
++    if (sids == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    dns = talloc_array(tmp_ctx, const char*, m_count);
++    if (dns == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    for (i=0; i < m_count; i++) {
++        const char *sidstr;
++
++        sidstr = ldb_msg_find_attr_as_string(members[i], SYSDB_SID_STR, NULL);
++
++        if (sidstr != NULL) {
++            sids[n] = talloc_steal(sids, sidstr);
++
++            dns[n] = talloc_steal(dns, ldb_dn_get_linearized(members[i]->dn));
++            if (dns[n] == NULL) {
++                ret = ENOMEM;
++                goto done;
++            }
++            n++;
++        }
++    }
++
++    if (n == 0) {
++        ret = ENOENT;
++        goto done;
++    }
++
++    *_n = n;
++    *_sids = talloc_steal(mem_ctx, sids);
++    *_dns = talloc_steal(mem_ctx, dns);
++
++    ret = EOK;
++
++done:
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
++    } else if (ret) {
++        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
++    }
++    talloc_free(tmp_ctx);
++    return ret;
++}
+diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
+index 8cf7f7ff1d414049f0694c7d2873556fc9dad741..c86b5c6b59a4de7e945b95cafae9149f681e2e18 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -801,6 +801,87 @@ done:
+     return ret;
+ }
+ 
++static errno_t
++are_sids_from_same_dom(const char *sid1, const char *sid2, bool *_result)
++{
++    size_t len_prefix_sid1;
++    size_t len_prefix_sid2;
++    char *rid1, *rid2;
++    bool result;
++
++    rid1 = strrchr(sid1, '-');
++    if (rid1 == NULL) {
++        return EINVAL;
++    }
++
++    rid2 = strrchr(sid2, '-');
++    if (rid2 == NULL) {
++        return EINVAL;
++    }
++
++    len_prefix_sid1 = rid1 - sid1;
++    len_prefix_sid2 = rid2 - sid2;
++
++    result = (len_prefix_sid1 == len_prefix_sid2) &&
++        (strncmp(sid1, sid2, len_prefix_sid1) == 0);
++
++    *_result = result;
++
++    return EOK;
++}
++
++static errno_t
++retain_extern_members(TALLOC_CTX *mem_ctx,
++                      struct sss_domain_info *dom,
++                      const char *group_name,
++                      const char *group_sid,
++                      char ***_userdns,
++                      size_t *_nuserdns)
++{
++    TALLOC_CTX *tmp_ctx;
++    const char **sids, **dns;
++    bool same_domain;
++    errno_t ret;
++    size_t i, n;
++    size_t nuserdns = 0;
++    const char **userdns = NULL;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    ret = sysdb_get_sids_of_members(tmp_ctx, dom, group_name, &sids, &dns, &n);
++    if (ret != EOK) {
++        if (ret != ENOENT) {
++            DEBUG(SSSDBG_TRACE_ALL,
++                  "get_sids_of_members failed: %d [%s]\n",
++                  ret, sss_strerror(ret));
++        }
++        goto done;
++    }
++
++    for (i=0; i < n; i++) {
++        ret = are_sids_from_same_dom(group_sid, sids[i], &same_domain);
++        if (ret == EOK && !same_domain) {
++            DEBUG(SSSDBG_TRACE_ALL, "extern member: %s\n", dns[i]);
++            nuserdns++;
++            userdns = talloc_realloc(tmp_ctx, userdns, const char*, nuserdns);
++            if (userdns == NULL) {
++                ret = ENOMEM;
++                goto done;
++            }
++            userdns[nuserdns-1] = talloc_steal(userdns, dns[i]);
++        }
++    }
++    *_nuserdns = nuserdns;
++    *_userdns = discard_const(talloc_steal(mem_ctx, userdns));
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
+ 
+ /* ==Save-Group-Memebrs=================================================== */
+ 
+@@ -817,6 +898,7 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx,
+ {
+     struct ldb_message_element *el;
+     struct sysdb_attrs *group_attrs = NULL;
++    const char *group_sid;
+     const char *group_name;
+     char **userdns = NULL;
+     size_t nuserdns = 0;
+@@ -843,6 +925,28 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx,
+         }
+     }
+ 
++    /* This is a temporal solution until the IPA provider is able to
++     * resolve external group membership.
++     * https://fedorahosted.org/sssd/ticket/2522
++     */
++    if (opts->schema_type == SDAP_SCHEMA_IPA_V1) {
++        ret = sysdb_attrs_get_string(attrs, SYSDB_SID_STR, &group_sid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_TRACE_FUNC, "Failed to get group sid\n");
++            group_sid = NULL;
++        }
++
++        if (group_sid != NULL) {
++            ret = retain_extern_members(memctx, dom, group_name, group_sid,
++                                        &userdns, &nuserdns);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_TRACE_INTERNAL,
++                      "retain_extern_members failed: %d:[%s].\n",
++                      ret, sss_strerror(ret));
++            }
++        }
++    }
++
+     ret = sysdb_attrs_get_el(attrs,
+                     opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
+     if (ret != EOK) {
+-- 
+1.9.3
+
diff --git a/SOURCES/0148-IPA-do-not-try-to-add-override-gid-twice.patch b/SOURCES/0148-IPA-do-not-try-to-add-override-gid-twice.patch
new file mode 100644
index 0000000..fd32d86
--- /dev/null
+++ b/SOURCES/0148-IPA-do-not-try-to-add-override-gid-twice.patch
@@ -0,0 +1,42 @@
+From b52b26176c92f3b06dba5598428c70c0cde13fd1 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 2 Dec 2014 21:10:01 +0100
+Subject: [PATCH 1/2] IPA: do not try to add override gid twice
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+By default user and group overrides use the same attribute name for the
+GID and this cause SSSD machinery to add the same value twice which
+cause an error in ldb_add() or ldm_modify().
+
+Related to https://fedorahosted.org/sssd/ticket/2514
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/db/sysdb_views.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 8cc279af6c72f3e7ab2917d997f84a33a05e91b9..c735a7bd8588a80743d40438d010db5912f47bb5 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -525,8 +525,14 @@ errno_t sysdb_store_override(struct sss_domain_info *domain,
+             goto done;
+         }
+ 
+-        /* TODO: add nameAlias for case-insentitive searches */
+         for (c = 0; c < attrs->num; c++) {
++            /* Set num_values to 1 because by default user and group overrides
++             * use the same attribute name for the GID and this cause SSSD
++             * machinery to add the same value twice */
++            if (attrs->a[c].num_values > 1
++                    && strcmp(attrs->a[c].name, SYSDB_GIDNUM) == 0) {
++                attrs->a[c].num_values = 1;
++            }
+             msg->elements[c] = attrs->a[c];
+             msg->elements[c].flags = LDB_FLAG_MOD_ADD;
+         }
+-- 
+1.9.3
+
diff --git a/SOURCES/0149-IPA-handle-GID-overrides-for-MPG-domains-on-clients.patch b/SOURCES/0149-IPA-handle-GID-overrides-for-MPG-domains-on-clients.patch
new file mode 100644
index 0000000..465ac9e
--- /dev/null
+++ b/SOURCES/0149-IPA-handle-GID-overrides-for-MPG-domains-on-clients.patch
@@ -0,0 +1,62 @@
+From 034dcabb40e654a95f3714d871db471ff7bf97f8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 4 Dec 2014 12:50:03 +0100
+Subject: [PATCH 2/2] IPA: handle GID overrides for MPG domains on clients
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves https://fedorahosted.org/sssd/ticket/2514
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 6d5b45edf20f720f5b97f0ed5c8ec591c580de0d..55450c7029391a99bfc33b8446765f71c4d0928a 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1618,6 +1618,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     char *realm;
+     char *upn = NULL;
+     gid_t gid;
++    gid_t orig_gid = 0;
+     TALLOC_CTX *tmp_ctx;
+     const char *sid_str;
+     const char *tmp_str;
+@@ -1796,6 +1797,31 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+             gid = 0;
+             if (dom->mpg == false) {
+                 gid = attrs->a.user.pw_gid;
++            } else {
++                /* The extdom plugin always returns the objects with the
++                 * default view applied. Since the GID is handled specially
++                 * for MPG domains we have add any overridden GID separately.
++                 */
++                ret = sysdb_attrs_get_uint32_t(attrs->sysdb_attrs,
++                                               ORIGINALAD_PREFIX SYSDB_GIDNUM,
++                                               &orig_gid);
++                if (ret == EOK || ret == ENOENT) {
++                    if ((orig_gid != 0 && orig_gid != attrs->a.user.pw_gid)
++                            || attrs->a.user.pw_uid != attrs->a.user.pw_gid) {
++                        ret = sysdb_attrs_add_uint32(attrs->sysdb_attrs,
++                                                     SYSDB_GIDNUM,
++                                                     attrs->a.user.pw_gid);
++                        if (ret != EOK) {
++                            DEBUG(SSSDBG_OP_FAILURE,
++                                  "sysdb_attrs_add_uint32 failed.\n");
++                            goto done;
++                        }
++                    }
++                } else {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sysdb_attrs_get_uint32_t failed.\n");
++                    goto done;
++                }
+             }
+ 
+             ret = sysdb_transaction_start(dom->sysdb);
+-- 
+1.9.3
+
diff --git a/SOURCES/0150-simple-access-provider-non-existing-object.patch b/SOURCES/0150-simple-access-provider-non-existing-object.patch
new file mode 100644
index 0000000..1fffdb9
--- /dev/null
+++ b/SOURCES/0150-simple-access-provider-non-existing-object.patch
@@ -0,0 +1,96 @@
+From 79f128801d598ca57a6acebade01136525a47e00 Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Wed, 4 Jun 2014 17:41:31 +0100
+Subject: [PATCH] simple access provider: non-existing object
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2519
+
+Not existing user/group in simple_allow_users/simple_allow_groups should not
+imply access denied.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/simple/simple_access_check.c | 35 +++++++++++++++++++++---------
+ 1 file changed, 25 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/simple/simple_access_check.c b/src/providers/simple/simple_access_check.c
+index 13c66d58f71225a6c458c19e7fb9d26fd15c08ea..d6662871948afffa2cd822614a671149d2f3bf1a 100644
+--- a/src/providers/simple/simple_access_check.c
++++ b/src/providers/simple/simple_access_check.c
+@@ -24,6 +24,11 @@
+ #include "util/sss_utf8.h"
+ #include "db/sysdb.h"
+ 
++#define NON_EXIST_USR_ALLOW "The user %s does not exist. Possible typo in simple_allow_users.\n"
++#define NON_EXIST_USR_DENY  "The user %s does not exist. Possible typo in simple_deny_users.\n"
++#define NON_EXIST_GRP_ALLOW "The group %s does not exist. Possible typo in simple_allow_groups.\n"
++#define NON_EXIST_GRP_DENY  "The group %s does not exist. Possible typo in simple_deny_groups.\n"
++
+ static bool
+ is_posix(const struct ldb_message *group)
+ {
+@@ -53,9 +58,11 @@ simple_check_users(struct simple_ctx *ctx, const char *username,
+             domain = find_domain_by_object_name(ctx->domain,
+                                                 ctx->allow_users[i]);
+             if (domain == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Invalid user %s!\n",
+-                                            ctx->allow_users[i]);
+-                return EINVAL;
++                DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_USR_ALLOW,
++                      ctx->allow_users[i]);
++                sss_log(SSS_LOG_CRIT, NON_EXIST_USR_ALLOW,
++                        ctx->allow_users[i]);
++                continue;
+             }
+ 
+             if (sss_string_equal(domain->case_sensitive, username,
+@@ -86,8 +93,10 @@ simple_check_users(struct simple_ctx *ctx, const char *username,
+             domain = find_domain_by_object_name(ctx->domain,
+                                                 ctx->deny_users[i]);
+             if (domain == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Invalid user %s!\n",
+-                                            ctx->deny_users[i]);
++                DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_USR_DENY,
++                      ctx->deny_users[i]);
++                sss_log(SSS_LOG_CRIT, NON_EXIST_USR_DENY,
++                        ctx->deny_users[i]);
+                 return EINVAL;
+             }
+ 
+@@ -125,9 +134,12 @@ simple_check_groups(struct simple_ctx *ctx, const char **group_names,
+             domain = find_domain_by_object_name(ctx->domain,
+                                                 ctx->allow_groups[i]);
+             if (domain == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Invalid group %s!\n",
+-                                            ctx->allow_groups[i]);
+-                return EINVAL;
++                DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_GRP_ALLOW,
++                      ctx->allow_groups[i]);
++                sss_log(SSS_LOG_CRIT, NON_EXIST_GRP_ALLOW,
++                        ctx->allow_groups[i]);
++
++                continue;
+             }
+ 
+             for(j = 0; group_names[j]; j++) {
+@@ -158,8 +170,11 @@ simple_check_groups(struct simple_ctx *ctx, const char **group_names,
+             domain = find_domain_by_object_name(ctx->domain,
+                                                 ctx->deny_groups[i]);
+             if (domain == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Invalid group %s!\n",
+-                                            ctx->deny_groups[i]);
++                DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_GRP_DENY,
++                      ctx->deny_groups[i]);
++                sss_log(SSS_LOG_CRIT, NON_EXIST_GRP_DENY,
++                        ctx->deny_groups[i]);
++
+                 return EINVAL;
+             }
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0151-libwbclient-initialize-some-return-values.patch b/SOURCES/0151-libwbclient-initialize-some-return-values.patch
new file mode 100644
index 0000000..6bcb02d
--- /dev/null
+++ b/SOURCES/0151-libwbclient-initialize-some-return-values.patch
@@ -0,0 +1,101 @@
+From 082e13dba488ebb2b948d6a362095153714b669f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 19 Dec 2014 11:21:41 +0100
+Subject: [PATCH] libwbclient: initialize some return values
+
+Some callers of libwbclient functions expects the return values are
+initialized even it the functions returns an error. This patch adds some
+initializations to meet this requirement.
+
+Resolves https://fedorahosted.org/sssd/ticket/2537
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/sss_client/libwbclient/wbc_pam_sssd.c | 36 +++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/src/sss_client/libwbclient/wbc_pam_sssd.c b/src/sss_client/libwbclient/wbc_pam_sssd.c
+index 893a5c16cf0e020e0570ea838d96fa82292373fa..174cf1310fad0243036fe591978cc89700903896 100644
+--- a/src/sss_client/libwbclient/wbc_pam_sssd.c
++++ b/src/sss_client/libwbclient/wbc_pam_sssd.c
+@@ -45,6 +45,10 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
+                  struct wbcAuthUserInfo **info,
+                  struct wbcAuthErrorInfo **error)
+ {
++    if (error != NULL) {
++        *error = NULL;
++    }
++
+     WBC_SSSD_NOT_IMPLEMENTED;
+ }
+ 
+@@ -52,6 +56,10 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
+ wbcErr wbcCheckTrustCredentials(const char *domain,
+                 struct wbcAuthErrorInfo **error)
+ {
++    if (error != NULL) {
++        *error = NULL;
++    }
++
+     WBC_SSSD_NOT_IMPLEMENTED;
+ }
+ 
+@@ -59,6 +67,10 @@ wbcErr wbcCheckTrustCredentials(const char *domain,
+ wbcErr wbcChangeTrustCredentials(const char *domain,
+                  struct wbcAuthErrorInfo **error)
+ {
++    if (error != NULL) {
++        *error = NULL;
++    }
++
+     WBC_SSSD_NOT_IMPLEMENTED;
+ }
+ 
+@@ -102,6 +114,14 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
+                    enum wbcPasswordChangeRejectReason *reject_reason,
+                    struct wbcUserPasswordPolicyInfo **policy)
+ {
++    if (error != NULL) {
++        *error = NULL;
++    }
++
++    if (policy != NULL) {
++        *policy = NULL;
++    }
++
+     WBC_SSSD_NOT_IMPLEMENTED;
+ }
+ 
+@@ -129,6 +149,18 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
+             struct wbcAuthErrorInfo **error,
+             struct wbcUserPasswordPolicyInfo **policy)
+ {
++    if (info != NULL) {
++        *info = NULL;
++    }
++
++    if (error != NULL) {
++        *error = NULL;
++    }
++
++    if (policy != NULL) {
++        *policy = NULL;
++    }
++
+     WBC_SSSD_NOT_IMPLEMENTED;
+ }
+ 
+@@ -137,6 +169,10 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
+                           struct wbcCredentialCacheInfo **info,
+                           struct wbcAuthErrorInfo **error)
+ {
++    if (error != NULL) {
++        *error = NULL;
++    }
++
+     WBC_SSSD_NOT_IMPLEMENTED;
+ }
+ 
+-- 
+1.9.3
+
diff --git a/SOURCES/0152-GPO-Ignore-ENOENT-result-from-sysdb_gpo_get_gpo_resu.patch b/SOURCES/0152-GPO-Ignore-ENOENT-result-from-sysdb_gpo_get_gpo_resu.patch
new file mode 100644
index 0000000..f951b5c
--- /dev/null
+++ b/SOURCES/0152-GPO-Ignore-ENOENT-result-from-sysdb_gpo_get_gpo_resu.patch
@@ -0,0 +1,37 @@
+From 2f38a6fe31be1619f4725733f388b99e64f9c668 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 6 Jan 2015 13:14:35 +0100
+Subject: [PATCH 152/160] GPO: Ignore ENOENT result from
+ sysdb_gpo_get_gpo_result_setting()
+
+https://fedorahosted.org/sssd/ticket/2542
+
+If the GPO result object was missing completely, we would error out with
+a fatal error code. It's more user-friendly to treat the missing object
+as if the requested attribute was missing on the provider level.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit fc2cc91a5b645180e53d46436b0d08011aac8d74)
+---
+ src/providers/ad/ad_gpo.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 62715861c91484fa2a57e7cc13ba403c9096d9a7..4f8497809bfe962672a99f26de7b61f9f89ac6fa 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -1339,7 +1339,10 @@ parse_policy_setting_value(TALLOC_CTX *mem_ctx,
+     char **sids_list = NULL;
+ 
+     ret = sysdb_gpo_get_gpo_result_setting(mem_ctx, domain, key, &value);
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_FUNC, "No previous GPO result\n");
++        value = NULL;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Cannot retrieve settings from sysdb for key: '%s' [%d][%s].\n",
+               key, ret, sss_strerror(ret));
+-- 
+2.1.0
+
diff --git a/SOURCES/0153-GPO-Set-libsmb-debugging-to-stderr.patch b/SOURCES/0153-GPO-Set-libsmb-debugging-to-stderr.patch
new file mode 100644
index 0000000..1af59b9
--- /dev/null
+++ b/SOURCES/0153-GPO-Set-libsmb-debugging-to-stderr.patch
@@ -0,0 +1,34 @@
+From 0af3ec742fd3d160d8b6ccc81a368e851456d61c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 6 Jan 2015 16:54:44 +0100
+Subject: [PATCH 153/160] GPO: Set libsmb debugging to stderr
+
+libsmb logs to stdout by default. It's much more reasonable to log to
+stderr by default.
+
+Please also note:
+    https://bugzilla.samba.org/show_bug.cgi?id=11036
+and:
+    https://fedorahosted.org/sssd/ticket/2544
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit bb7ddd2be9847bfb07395341c7623da1b104b8a6)
+---
+ src/providers/ad/ad_gpo_child.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c
+index 4bb48c0479400ebeeca287acfcb1573c69a76b90..c6eb52f06b1daadb083bd4c9efb299a12031d4d5 100644
+--- a/src/providers/ad/ad_gpo_child.c
++++ b/src/providers/ad/ad_gpo_child.c
+@@ -601,6 +601,7 @@ perform_smb_operations(int cached_gpt_version,
+         goto done;
+     }
+ 
++    smbc_setOptionDebugToStderr(smbc_ctx, 1);
+     smbc_setFunctionAuthData(smbc_ctx, sssd_krb_get_auth_data_fn);
+     smbc_setOptionUseKerberos(smbc_ctx, 1);
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0154-UTIL-Allow-dup-ing-child-pipe-to-a-different-FD.patch b/SOURCES/0154-UTIL-Allow-dup-ing-child-pipe-to-a-different-FD.patch
new file mode 100644
index 0000000..d0888b1
--- /dev/null
+++ b/SOURCES/0154-UTIL-Allow-dup-ing-child-pipe-to-a-different-FD.patch
@@ -0,0 +1,193 @@
+From df95d21e5253cec8745329567ab8050bfcd52333 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 7 Jan 2015 10:36:12 +0100
+Subject: [PATCH 154/160] UTIL: Allow dup-ing child pipe to a different FD
+
+Related to:
+    https://fedorahosted.org/sssd/ticket/2544
+
+Adds a new function exec_child_ex and moves setting the extra_argv[]
+to exec_child_ex() along with specifying the input and output fds.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 16cb0969f0a9ea71524d852077d6a480740d4f12)
+---
+ src/providers/ad/ad_gpo.c               |  2 +-
+ src/providers/ipa/ipa_selinux.c         |  3 +--
+ src/providers/krb5/krb5_child_handler.c |  8 ++++----
+ src/providers/ldap/sdap_child_helpers.c |  3 +--
+ src/tests/cmocka/test_child_common.c    | 11 ++++++-----
+ src/util/child_common.c                 | 22 ++++++++++++++++------
+ src/util/child_common.h                 | 12 ++++++++++--
+ 7 files changed, 39 insertions(+), 22 deletions(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 4f8497809bfe962672a99f26de7b61f9f89ac6fa..1ae62e7c4727702d5338258046e89e4b654904eb 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3963,7 +3963,7 @@ gpo_fork_child(struct tevent_req *req)
+     if (pid == 0) { /* child */
+         err = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+-                         GPO_CHILD, gpo_child_debug_fd, NULL);
++                         GPO_CHILD, gpo_child_debug_fd);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec gpo_child: [%d][%s].\n",
+               err, strerror(err));
+         return err;
+diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
+index c4e70cfcb0748988d91fc1db57cf5a30d5365be4..133b679b6d518704ebb2bd901c64ac48170c9a0b 100644
+--- a/src/providers/ipa/ipa_selinux.c
++++ b/src/providers/ipa/ipa_selinux.c
+@@ -1049,8 +1049,7 @@ static errno_t selinux_fork_child(struct selinux_child_state *state)
+     if (pid == 0) { /* child */
+         ret = exec_child(state,
+                          pipefd_to_child, pipefd_from_child,
+-                         SELINUX_CHILD, selinux_child_debug_fd,
+-                         NULL);
++                         SELINUX_CHILD, selinux_child_debug_fd);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec selinux_child: [%d][%s].\n",
+               ret, sss_strerror(ret));
+         return ret;
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 1454d220fb294abc339df6e862154012a03fdca0..633cd917737d3f39526b049cc3d930b67f8b5c66 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -305,10 +305,10 @@ static errno_t fork_child(struct tevent_req *req)
+     pid = fork();
+ 
+     if (pid == 0) { /* child */
+-        err = exec_child(state,
+-                         pipefd_to_child, pipefd_from_child,
+-                         KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
+-                         k5c_extra_args);
++        err = exec_child_ex(state,
++                            pipefd_to_child, pipefd_from_child,
++                            KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
++                            k5c_extra_args, STDIN_FILENO, STDOUT_FILENO);
+         if (err != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec KRB5 child: [%d][%s].\n",
+                       err, strerror(err));
+diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c
+index b60891d2b41f9a359856eb22174128d7f07559fb..40010989021eb7cf77b96876b2d1c4119ed39163 100644
+--- a/src/providers/ldap/sdap_child_helpers.c
++++ b/src/providers/ldap/sdap_child_helpers.c
+@@ -108,8 +108,7 @@ static errno_t sdap_fork_child(struct tevent_context *ev,
+     if (pid == 0) { /* child */
+         err = exec_child(child,
+                          pipefd_to_child, pipefd_from_child,
+-                         LDAP_CHILD, ldap_child_debug_fd,
+-                         NULL);
++                         LDAP_CHILD, ldap_child_debug_fd);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec LDAP child: [%d][%s].\n",
+                                     err, strerror(err));
+         return err;
+diff --git a/src/tests/cmocka/test_child_common.c b/src/tests/cmocka/test_child_common.c
+index 112ed0ad97294bc45eac7c2124155e6b1908ad92..348b3e6c354d724fac12939c8bd785bbb993e667 100644
+--- a/src/tests/cmocka/test_child_common.c
++++ b/src/tests/cmocka/test_child_common.c
+@@ -89,7 +89,7 @@ void test_exec_child(void **state)
+         ret = exec_child(child_tctx,
+                          child_tctx->pipefd_to_child,
+                          child_tctx->pipefd_from_child,
+-                         CHILD_DIR"/"TEST_BIN, 2, NULL);
++                         CHILD_DIR"/"TEST_BIN, 2);
+         assert_int_equal(ret, EOK);
+     } else {
+             do {
+@@ -128,10 +128,11 @@ void test_exec_child_extra_args(void **state)
+     child_pid = fork();
+     assert_int_not_equal(child_pid, -1);
+     if (child_pid == 0) {
+-        ret = exec_child(child_tctx,
+-                         child_tctx->pipefd_to_child,
+-                         child_tctx->pipefd_from_child,
+-                         CHILD_DIR"/"TEST_BIN, 2, extra_args);
++        ret = exec_child_ex(child_tctx,
++                            child_tctx->pipefd_to_child,
++                            child_tctx->pipefd_from_child,
++                            CHILD_DIR"/"TEST_BIN, 2, extra_args,
++                            STDIN_FILENO, STDOUT_FILENO);
+         assert_int_equal(ret, EOK);
+     } else {
+             do {
+diff --git a/src/util/child_common.c b/src/util/child_common.c
+index 9710630f9773ae02258e4f0dd609a3d74978c8f4..7975a839499370a4a29d9fbc59f815d7da1f63dd 100644
+--- a/src/util/child_common.c
++++ b/src/util/child_common.c
+@@ -729,17 +729,18 @@ fail:
+     return ret;
+ }
+ 
+-errno_t exec_child(TALLOC_CTX *mem_ctx,
+-                   int *pipefd_to_child, int *pipefd_from_child,
+-                   const char *binary, int debug_fd,
+-                   const char *extra_argv[])
++errno_t exec_child_ex(TALLOC_CTX *mem_ctx,
++                      int *pipefd_to_child, int *pipefd_from_child,
++                      const char *binary, int debug_fd,
++                      const char *extra_argv[],
++                      int child_in_fd, int child_out_fd)
+ {
+     int ret;
+     errno_t err;
+     char **argv;
+ 
+     close(pipefd_to_child[1]);
+-    ret = dup2(pipefd_to_child[0], STDIN_FILENO);
++    ret = dup2(pipefd_to_child[0], child_in_fd);
+     if (ret == -1) {
+         err = errno;
+         DEBUG(SSSDBG_CRIT_FAILURE,
+@@ -748,7 +749,7 @@ errno_t exec_child(TALLOC_CTX *mem_ctx,
+     }
+ 
+     close(pipefd_from_child[0]);
+-    ret = dup2(pipefd_from_child[1], STDOUT_FILENO);
++    ret = dup2(pipefd_from_child[1], child_out_fd);
+     if (ret == -1) {
+         err = errno;
+         DEBUG(SSSDBG_CRIT_FAILURE,
+@@ -770,6 +771,15 @@ errno_t exec_child(TALLOC_CTX *mem_ctx,
+     return err;
+ }
+ 
++errno_t exec_child(TALLOC_CTX *mem_ctx,
++                   int *pipefd_to_child, int *pipefd_from_child,
++                   const char *binary, int debug_fd)
++{
++    return exec_child_ex(mem_ctx, pipefd_to_child, pipefd_from_child,
++                         binary, debug_fd, NULL,
++                         STDIN_FILENO, STDOUT_FILENO);
++}
++
+ void child_cleanup(int readfd, int writefd)
+ {
+     int ret;
+diff --git a/src/util/child_common.h b/src/util/child_common.h
+index e659388ece3677b7746c159d7de3e86171bb4146..369de71a13449beb185e5bc682c8871625fe6027 100644
+--- a/src/util/child_common.h
++++ b/src/util/child_common.h
+@@ -112,10 +112,18 @@ void child_sig_handler(struct tevent_context *ev,
+                        int count, void *__siginfo, void *pvt);
+ 
+ /* Never returns EOK, ether returns an error, or doesn't return on success */
++errno_t exec_child_ex(TALLOC_CTX *mem_ctx,
++                      int *pipefd_to_child, int *pipefd_from_child,
++                      const char *binary, int debug_fd,
++                      const char *extra_argv[],
++                      int child_in_fd, int child_out_fd);
++
++/* Same as exec_child_ex() except child_in_fd is set to STDIN_FILENO and
++ * child_out_fd is set to STDOUT_FILENO and extra_argv is always NULL.
++ */
+ errno_t exec_child(TALLOC_CTX *mem_ctx,
+                    int *pipefd_to_child, int *pipefd_from_child,
+-                   const char *binary, int debug_fd,
+-                   const char *extra_argv[]);
++                   const char *binary, int debug_fd);
+ 
+ void child_cleanup(int readfd, int writefd);
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0155-GPO-Don-t-use-stdout-for-output-in-gpo_child.patch b/SOURCES/0155-GPO-Don-t-use-stdout-for-output-in-gpo_child.patch
new file mode 100644
index 0000000..7eefa07
--- /dev/null
+++ b/SOURCES/0155-GPO-Don-t-use-stdout-for-output-in-gpo_child.patch
@@ -0,0 +1,92 @@
+From 3ec755f9b2db95fa05cd38ca32a0dddb255014f8 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 7 Jan 2015 10:42:09 +0100
+Subject: [PATCH 155/160] GPO: Don't use stdout for output in gpo_child
+
+Resolves:
+    https://fedorahosted.org/sssd/ticket/2544
+
+Use a dedicated fd instead to work around
+https://bugzilla.samba.org/show_bug.cgi?id=11036
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit f00a61b6079d8de81432077a59daf015d85800d2)
+---
+ src/providers/ad/ad_gpo.c       | 7 ++++---
+ src/providers/ad/ad_gpo.h       | 4 ++++
+ src/providers/ad/ad_gpo_child.c | 7 ++++---
+ 3 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 1ae62e7c4727702d5338258046e89e4b654904eb..083fc8c2cde36bb15d1a1becd3ddac383a4008fe 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3961,9 +3961,10 @@ gpo_fork_child(struct tevent_req *req)
+     pid = fork();
+ 
+     if (pid == 0) { /* child */
+-        err = exec_child(state,
+-                         pipefd_to_child, pipefd_from_child,
+-                         GPO_CHILD, gpo_child_debug_fd);
++        err = exec_child_ex(state,
++                            pipefd_to_child, pipefd_from_child,
++                            GPO_CHILD, gpo_child_debug_fd, NULL,
++                            STDIN_FILENO, AD_GPO_CHILD_OUT_FILENO);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec gpo_child: [%d][%s].\n",
+               err, strerror(err));
+         return err;
+diff --git a/src/providers/ad/ad_gpo.h b/src/providers/ad/ad_gpo.h
+index 77051aadaed7858cce808b5c6c51f0be515d9800..9fd590a2b262b66c1efd493d8736774bdfa61b40 100644
+--- a/src/providers/ad/ad_gpo.h
++++ b/src/providers/ad/ad_gpo.h
+@@ -23,6 +23,10 @@
+ #ifndef AD_GPO_H_
+ #define AD_GPO_H_
+ 
++#include "providers/ad/ad_access.h"
++
++#define AD_GPO_CHILD_OUT_FILENO 3
++
+ /*
+  * This pair of functions provides client-side GPO processing.
+  *
+diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c
+index c6eb52f06b1daadb083bd4c9efb299a12031d4d5..27f0db3ec2504e55886094a35cda1f536a7494ee 100644
+--- a/src/providers/ad/ad_gpo_child.c
++++ b/src/providers/ad/ad_gpo_child.c
+@@ -33,6 +33,7 @@
+ #include "util/util.h"
+ #include "util/child_common.h"
+ #include "providers/dp_backend.h"
++#include "providers/ad/ad_gpo.h"
+ #include "sss_cli.h"
+ 
+ #define SMB_BUFFER_SIZE 65536
+@@ -778,7 +779,7 @@ main(int argc, const char *argv[])
+ 
+     errno = 0;
+ 
+-    written = sss_atomic_write_s(STDOUT_FILENO, resp->buf, resp->size);
++    written = sss_atomic_write_s(AD_GPO_CHILD_OUT_FILENO, resp->buf, resp->size);
+     if (written == -1) {
+         ret = errno;
+         DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret,
+@@ -793,13 +794,13 @@ main(int argc, const char *argv[])
+     }
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "gpo_child completed successfully\n");
+-    close(STDOUT_FILENO);
++    close(AD_GPO_CHILD_OUT_FILENO);
+     talloc_free(main_ctx);
+     return EXIT_SUCCESS;
+ 
+ fail:
+     DEBUG(SSSDBG_CRIT_FAILURE, "gpo_child failed!\n");
+-    close(STDOUT_FILENO);
++    close(AD_GPO_CHILD_OUT_FILENO);
+     talloc_free(main_ctx);
+     return EXIT_FAILURE;
+ }
+-- 
+2.1.0
+
diff --git a/SOURCES/0156-GPO-Extract-server-hostname-after-connecting.patch b/SOURCES/0156-GPO-Extract-server-hostname-after-connecting.patch
new file mode 100644
index 0000000..16bdd8f
--- /dev/null
+++ b/SOURCES/0156-GPO-Extract-server-hostname-after-connecting.patch
@@ -0,0 +1,111 @@
+From f0af52e320e8f1b062701b2eb36b49915a4e8194 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 6 Jan 2015 13:03:34 +0100
+Subject: [PATCH 156/160] GPO: Extract server hostname after connecting
+
+https://fedorahosted.org/sssd/ticket/2543
+
+The LDAP URI is not valid prior to connecting to LDAP. Moreover,
+reconnecting to a different server might invalidate the URI.
+
+Move reading the URI after the connection has been established.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit ccff8e75940963a0f68f86efcddc37133318abfa)
+---
+ src/providers/ad/ad_gpo.c | 58 +++++++++++++++++++++++------------------------
+ 1 file changed, 29 insertions(+), 29 deletions(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 083fc8c2cde36bb15d1a1becd3ddac383a4008fe..375ef1d8a7df13911831a55fed5d5a425daaa996 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -1489,8 +1489,6 @@ ad_gpo_access_send(TALLOC_CTX *mem_ctx,
+     struct tevent_req *req;
+     struct tevent_req *subreq;
+     struct ad_gpo_access_state *state;
+-    char *server_uri;
+-    LDAPURLDesc *lud;
+     errno_t ret;
+     int hret;
+     hash_key_t key;
+@@ -1580,33 +1578,6 @@ ad_gpo_access_send(TALLOC_CTX *mem_ctx,
+         goto immediately;
+     }
+ 
+-    /* extract server_hostname from server_uri */
+-    server_uri = state->conn->service->uri;
+-    ret = ldap_url_parse(server_uri, &lud);
+-    if (ret != LDAP_SUCCESS) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Failed to parse ldap URI (%s)!\n", server_uri);
+-        ret = EINVAL;
+-        goto immediately;
+-    }
+-
+-    if (lud->lud_host == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "The LDAP URI (%s) did not contain a host name\n", server_uri);
+-        ldap_free_urldesc(lud);
+-        ret = EINVAL;
+-        goto immediately;
+-    }
+-
+-    state->server_hostname = talloc_strdup(state, lud->lud_host);
+-    ldap_free_urldesc(lud);
+-    if (!state->server_hostname) {
+-        ret = ENOMEM;
+-        goto immediately;
+-    }
+-    DEBUG(SSSDBG_TRACE_ALL, "server_hostname from uri: %s\n",
+-          state->server_hostname);
+-
+     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE,
+@@ -1666,6 +1637,8 @@ ad_gpo_connect_done(struct tevent_req *subreq)
+     char *domain_dn;
+     int dp_error;
+     errno_t ret;
++    char *server_uri;
++    LDAPURLDesc *lud;
+ 
+     const char *attrs[] = {AD_AT_DN, AD_AT_UAC, NULL};
+ 
+@@ -1702,6 +1675,33 @@ ad_gpo_connect_done(struct tevent_req *subreq)
+         }
+     }
+ 
++    /* extract server_hostname from server_uri */
++    server_uri = state->conn->service->uri;
++    ret = ldap_url_parse(server_uri, &lud);
++    if (ret != LDAP_SUCCESS) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to parse ldap URI (%s)!\n", server_uri);
++        ret = EINVAL;
++        goto done;
++    }
++
++    if (lud->lud_host == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "The LDAP URI (%s) did not contain a host name\n", server_uri);
++        ldap_free_urldesc(lud);
++        ret = EINVAL;
++        goto done;
++    }
++
++    state->server_hostname = talloc_strdup(state, lud->lud_host);
++    ldap_free_urldesc(lud);
++    if (!state->server_hostname) {
++        ret = ENOMEM;
++        goto done;
++    }
++    DEBUG(SSSDBG_TRACE_ALL, "server_hostname from uri: %s\n",
++          state->server_hostname);
++
+     sam_account_name = sss_krb5_get_primary(state, "%S$", state->ad_hostname);
+     if (sam_account_name == NULL) {
+         ret = ENOMEM;
+-- 
+2.1.0
+
diff --git a/SOURCES/0157-IPA-add-get_be_acct_req_for_user_name.patch b/SOURCES/0157-IPA-add-get_be_acct_req_for_user_name.patch
new file mode 100644
index 0000000..a76ed19
--- /dev/null
+++ b/SOURCES/0157-IPA-add-get_be_acct_req_for_user_name.patch
@@ -0,0 +1,64 @@
+From 6c8052a571a74ab67d371a624e561ecdc50744af Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 10 Dec 2014 15:02:15 +0100
+Subject: [PATCH 157/160] IPA: add get_be_acct_req_for_user_name()
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit d32b165fad7b89462f49c82349e1df5a2343afa2)
+---
+ src/providers/ipa/ipa_id.h    |  5 +++++
+ src/providers/ipa/ipa_views.c | 13 +++++++++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index 9d219f281847df0ba4ac24061e598eb6915f9c38..2bb5e0d38f42d4bbb04854dfb04804fecf6257e8 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -87,6 +87,11 @@ errno_t get_be_acct_req_for_uuid(TALLOC_CTX *mem_ctx, const char *uuid,
+                                  const char *domain_name,
+                                  struct be_acct_req **_ar);
+ 
++errno_t get_be_acct_req_for_user_name(TALLOC_CTX *mem_ctx,
++                                      const char *user_name,
++                                      const char *domain_name,
++                                      struct be_acct_req **_ar);
++
+ struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
+                                             struct tevent_context *ev,
+                                             struct sdap_id_ctx *sdap_id_ctx,
+diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
+index c768186d7cf5e5a997e2ca27a167b62c8dc99b3f..ccaea69563728a5cecc202709da5dab51747c040 100644
+--- a/src/providers/ipa/ipa_views.c
++++ b/src/providers/ipa/ipa_views.c
+@@ -177,6 +177,10 @@ static errno_t get_be_acct_req_for_xyz(TALLOC_CTX *mem_ctx, const char *val,
+         ar->entry_type = BE_REQ_BY_UUID;
+         ar->filter_type = BE_FILTER_UUID;
+         break;
++    case BE_REQ_USER:
++        ar->entry_type = BE_REQ_USER;
++        ar->filter_type = BE_FILTER_NAME;
++        break;
+     default:
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported request type [%d].\n", type);
+         talloc_free(ar);
+@@ -213,6 +217,15 @@ errno_t get_be_acct_req_for_uuid(TALLOC_CTX *mem_ctx, const char *uuid,
+                                    _ar);
+ }
+ 
++errno_t get_be_acct_req_for_user_name(TALLOC_CTX *mem_ctx,
++                                      const char *user_name,
++                                      const char *domain_name,
++                                      struct be_acct_req **_ar)
++{
++    return get_be_acct_req_for_xyz(mem_ctx, user_name, domain_name, BE_REQ_USER,
++                                   _ar);
++}
++
+ struct ipa_get_ad_override_state {
+     struct tevent_context *ev;
+     struct sdap_id_ctx *sdap_id_ctx;
+-- 
+2.1.0
+
diff --git a/SOURCES/0158-IPA-resolve-ghost-members-if-a-non-default-view-is-a.patch b/SOURCES/0158-IPA-resolve-ghost-members-if-a-non-default-view-is-a.patch
new file mode 100644
index 0000000..2ef66f7
--- /dev/null
+++ b/SOURCES/0158-IPA-resolve-ghost-members-if-a-non-default-view-is-a.patch
@@ -0,0 +1,288 @@
+From f20163d0e2076cbdfe48975a8ad38d471d8c5386 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 10 Dec 2014 15:03:18 +0100
+Subject: [PATCH 158/160] IPA: resolve ghost members if a non-default view is
+ applied
+
+Related to https://fedorahosted.org/sssd/ticket/2481
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 765d9075bb1e10ae0f09b6c2701bfd50aeb423d4)
+---
+ src/providers/ipa/ipa_id.c            | 212 ++++++++++++++++++++++++++++++++++
+ src/providers/ipa/ipa_subdomains_id.c |   1 +
+ 2 files changed, 213 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index 5665a1835e8b0ab18325bfc68a8d8b5650730943..4df6ed0e8ee1e9886151703f424b4580db8799a4 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -144,6 +144,150 @@ static void ipa_account_info_done(struct tevent_req *req)
+     sdap_handler_done(breq, dp_error, ret, error_text);
+ }
+ 
++struct ipa_resolve_user_list_state {
++    struct tevent_context *ev;
++    struct sdap_id_ctx *sdap_id_ctx;
++    struct be_req *be_req;
++    struct ldb_message_element *users;
++    const char *domain_name;
++    size_t user_idx;
++
++    int dp_error;
++};
++
++static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req);
++static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq);
++
++static struct tevent_req *
++ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
++                           struct be_req *be_req,
++                           struct sdap_id_ctx *sdap_id_ctx,
++                           const char *domain_name,
++                           struct ldb_message_element *users)
++{
++    int ret;
++    struct tevent_req *req;
++    struct ipa_resolve_user_list_state *state;
++
++    req = tevent_req_create(memctx, &state,
++                            struct ipa_resolve_user_list_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
++        return NULL;
++    }
++
++    state->ev = ev;
++    state->sdap_id_ctx = sdap_id_ctx;
++    state->be_req = be_req;
++    state->domain_name = domain_name;
++    state->users = users;
++    state->user_idx = 0;
++    state->dp_error = DP_ERR_FATAL;
++
++    ret = ipa_resolve_user_list_get_user_step(req);
++    if (ret == EAGAIN) {
++        return req;
++    } else if (ret == EOK) {
++        state->dp_error = DP_ERR_OK;
++        tevent_req_done(req);
++    } else {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "ipa_resolve_user_list_get_user_step failed.\n");
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, ev);
++    return req;
++}
++
++static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req)
++{
++    int ret;
++    struct tevent_req *subreq;
++    struct be_acct_req *ar;
++    struct ipa_resolve_user_list_state *state = tevent_req_data(req,
++                                            struct ipa_resolve_user_list_state);
++
++    if (state->user_idx >= state->users->num_values) {
++        return EOK;
++    }
++
++    ret = get_be_acct_req_for_user_name(state,
++                            (char *) state->users->values[state->user_idx].data,
++                            state->domain_name, &ar);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_user_name failed.\n");
++        return ret;
++    }
++
++    DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value);
++
++    subreq = sdap_handle_acct_req_send(state, state->be_req, ar,
++                                       state->sdap_id_ctx,
++                                       state->sdap_id_ctx->opts->sdom,
++                                       state->sdap_id_ctx->conn, true);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct_req_send failed.\n");
++        return ENOMEM;
++    }
++
++    tevent_req_set_callback(subreq, ipa_resolve_user_list_get_user_done, req);
++
++    return EAGAIN;
++}
++
++static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_resolve_user_list_state *state = tevent_req_data(req,
++                                            struct ipa_resolve_user_list_state);
++    int ret;
++
++    ret = sdap_handle_acct_req_recv(subreq, &state->dp_error, NULL, NULL);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct request failed: %d\n", ret);
++        goto done;
++    }
++
++    state->user_idx++;
++
++    ret = ipa_resolve_user_list_get_user_step(req);
++    if (ret == EAGAIN) {
++        return;
++    }
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "ipa_resolve_user_list_get_user_step failed.\n");
++    }
++
++done:
++    if (ret == EOK) {
++        state->dp_error = DP_ERR_OK;
++        tevent_req_done(req);
++    } else {
++        if (state->dp_error == DP_ERR_OK) {
++            state->dp_error = DP_ERR_FATAL;
++        }
++        tevent_req_error(req, ret);
++    }
++    return;
++}
++
++static int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error)
++{
++    struct ipa_resolve_user_list_state *state = tevent_req_data(req,
++                                            struct ipa_resolve_user_list_state);
++
++    if (dp_error) {
++        *dp_error = state->dp_error;
++    }
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    return EOK;
++}
++
+ struct ipa_id_get_account_info_state {
+     struct tevent_context *ev;
+     struct ipa_id_ctx *ipa_ctx;
+@@ -157,6 +301,7 @@ struct ipa_id_get_account_info_state {
+ 
+     struct sysdb_attrs *override_attrs;
+     struct ldb_message *obj_msg;
++    struct ldb_message_element *ghosts;
+     int dp_error;
+ };
+ 
+@@ -166,6 +311,7 @@ static errno_t ipa_id_get_account_info_get_original_step(struct tevent_req *req,
+                                                         struct be_acct_req *ar);
+ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq);
+ static void ipa_id_get_account_info_done(struct tevent_req *subreq);
++static void ipa_id_get_user_list_done(struct tevent_req *subreq);
+ 
+ static struct tevent_req *
+ ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+@@ -405,6 +551,16 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
+         goto fail;
+     }
+ 
++    if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_GROUP
++            && state->ipa_ctx->view_name != NULL
++            && strcmp(state->ipa_ctx->view_name,
++                      SYSDB_DEFAULT_VIEW_NAME) != 0) {
++        /* check for ghost members because ghost members are not allowed if a
++         * view other than the default view is applied.*/
++
++        state->ghosts = ldb_msg_find_element(state->obj_msg, SYSDB_GHOST);
++    }
++
+     if (state->override_attrs == NULL) {
+         uuid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_UUID, NULL);
+         if (uuid == NULL) {
+@@ -457,6 +613,21 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
+         }
+     }
+ 
++    if (state->ghosts != NULL) {
++        /* Resolve ghost members */
++        subreq = ipa_resolve_user_list_send(state, state->ev, state->be_req,
++                                            state->ipa_ctx->sdap_id_ctx,
++                                            state->domain->name,
++                                            state->ghosts);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list_send failed.\n");
++            ret = ENOMEM;
++            goto fail;
++        }
++        tevent_req_set_callback(subreq, ipa_id_get_user_list_done, req);
++        return;
++    }
++
+     state->dp_error = DP_ERR_OK;
+     tevent_req_done(req);
+     return;
+@@ -508,6 +679,47 @@ static void ipa_id_get_account_info_done(struct tevent_req *subreq)
+         goto fail;
+     }
+ 
++    if (state->ghosts != NULL) {
++        /* Resolve ghost members */
++        subreq = ipa_resolve_user_list_send(state, state->ev, state->be_req,
++                                            state->ipa_ctx->sdap_id_ctx,
++                                            state->domain->name,
++                                            state->ghosts);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list_send failed.\n");
++            ret = ENOMEM;
++            goto fail;
++        }
++        tevent_req_set_callback(subreq, ipa_id_get_user_list_done, req);
++        return;
++    }
++
++    state->dp_error = DP_ERR_OK;
++    tevent_req_done(req);
++    return;
++
++fail:
++    state->dp_error = dp_error;
++    tevent_req_error(req, ret);
++    return;
++}
++
++static void ipa_id_get_user_list_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    int dp_error = DP_ERR_FATAL;
++    int ret;
++
++    ret = ipa_resolve_user_list_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "IPA resolve user list %d\n", ret);
++        goto fail;
++    }
++
+     state->dp_error = DP_ERR_OK;
+     tevent_req_done(req);
+     return;
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index ce5a6d1a1048eda4d8b7017bd92bc7ee76e66ef9..cf0cddf6884295268b30fc8e0209b543c1699297 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -862,6 +862,7 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+                             SYSDB_SID_STR,
+                             SYSDB_OBJECTCLASS,
+                             SYSDB_UUID,
++                            SYSDB_GHOST,
+                             NULL };
+     char *name;
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0159-sysdb-fix-group-members-with-overridden-names.patch b/SOURCES/0159-sysdb-fix-group-members-with-overridden-names.patch
new file mode 100644
index 0000000..1e1b376
--- /dev/null
+++ b/SOURCES/0159-sysdb-fix-group-members-with-overridden-names.patch
@@ -0,0 +1,144 @@
+From 092b3c062c3568d1a01766d71a25004ee3cfc64e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 12 Jan 2015 18:36:42 +0100
+Subject: [PATCH 159/160] sysdb: fix group members with overridden names
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit fbcdc08722aa8ed17c4b114e01fbb37c02cfb2fe)
+---
+ src/db/sysdb.h       |  1 +
+ src/db/sysdb_views.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 63 insertions(+), 11 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index b1e057107cc6e3d4ce7b7bb8e821a2414c3424a7..9e33fee37a352498ed0c987dc2ae0da3500d63d5 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -210,6 +210,7 @@
+ 
+ #define SYSDB_GRSRC_ATTRS {SYSDB_NAME, SYSDB_GIDNUM, \
+                            SYSDB_MEMBERUID, \
++                           SYSDB_MEMBER, \
+                            SYSDB_GHOST, \
+                            SYSDB_DEFAULT_ATTRS, \
+                            SYSDB_SID_STR, \
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index c735a7bd8588a80743d40438d010db5912f47bb5..717edf20a447003568060cf4d32bf8d47bd93e63 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -1268,6 +1268,10 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+     const char *override_dn_str;
+     struct ldb_dn *override_dn;
+     const char *memberuid;
++    const char *orig_name;
++    char *orig_domain;
++    char *val;
++    struct sss_domain_info *orig_dom;
+ 
+     members = ldb_msg_find_element(obj, SYSDB_MEMBER);
+     if (members == NULL || members->num_values == 0) {
+@@ -1306,6 +1310,12 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+             goto done;
+         }
+ 
++        if (ldb_msg_find_attr_as_uint64(member_obj->msgs[0],
++                                        SYSDB_UIDNUM, 0) == 0) {
++            /* Skip non-POSIX-user members i.e. groups and non-POSIX users */
++            continue;
++        }
++
+         override_dn_str = ldb_msg_find_attr_as_string(member_obj->msgs[0],
+                                                       SYSDB_OVERRIDE_DN, NULL);
+         if (override_dn_str == NULL) {
+@@ -1324,6 +1334,16 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+             goto done;
+         }
+ 
++        orig_name = ldb_msg_find_attr_as_string(member_obj->msgs[0],
++                                                SYSDB_NAME,
++                                                NULL);
++        if (orig_name == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Object [%s] has no name.\n",
++                  ldb_dn_get_linearized(member_obj->msgs[0]->dn));
++            ret = EINVAL;
++            goto done;
++        }
++
+         memberuid = NULL;
+         if (ldb_dn_compare(member_obj->msgs[0]->dn, override_dn) != 0) {
+             DEBUG(SSSDBG_TRACE_ALL, "Checking override for object [%s].\n",
+@@ -1347,29 +1367,60 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+             memberuid = ldb_msg_find_attr_as_string(override_obj->msgs[0],
+                                                     SYSDB_NAME,
+                                                     NULL);
++
++            if (memberuid != NULL) {
++                ret = sss_parse_name(tmp_ctx, domain->names, orig_name,
++                                     &orig_domain, NULL);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                         "sss_parse_name failed to split original name [%s].\n",
++                         orig_name);
++                    goto done;
++                }
++
++                if (orig_domain != NULL) {
++                    orig_dom = find_domain_by_name(get_domains_head(domain),
++                                                   orig_domain, true);
++                    if (orig_dom == NULL) {
++                        DEBUG(SSSDBG_CRIT_FAILURE,
++                              "Cannot find domain with name [%s].\n",
++                              orig_domain);
++                        ret = EINVAL;
++                        goto done;
++                    }
++                    memberuid = sss_get_domain_name(tmp_ctx, memberuid,
++                                                    orig_dom);
++                    if (memberuid == NULL) {
++                        DEBUG(SSSDBG_OP_FAILURE,
++                              "sss_get_domain_name failed.\n");
++                        ret = ENOMEM;
++                        goto done;
++                    }
++                }
++            }
+         }
+ 
+         if (memberuid == NULL) {
+             DEBUG(SSSDBG_TRACE_ALL, "No override name available.\n");
+ 
+-            memberuid = ldb_msg_find_attr_as_string(member_obj->msgs[0],
+-                                                    SYSDB_NAME,
+-                                                    NULL);
+-            if (memberuid == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Object [%s] has no name.\n",
+-                      ldb_dn_get_linearized(member_obj->msgs[0]->dn));
+-                ret = EINVAL;
+-                goto done;
+-            }
++            memberuid = orig_name;
+         }
+ 
+-        ret = ldb_msg_add_string(obj, OVERRIDE_PREFIX SYSDB_MEMBERUID,
+-                                 memberuid);
++        val = talloc_strdup(obj, memberuid);
++        if (val == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        ret = ldb_msg_add_string(obj, OVERRIDE_PREFIX SYSDB_MEMBERUID, val);
+         if (ret != LDB_SUCCESS) {
+             DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+             ret = sysdb_error_to_errno(ret);
+             goto done;
+         }
++        DEBUG(SSSDBG_TRACE_ALL, "Added [%s] to [%s].\n", memberuid,
++                                OVERRIDE_PREFIX SYSDB_MEMBERUID);
+ 
+         /* Free all temporary data of the current member to avoid memory usage
+          * spikes. All temporary data should be allocated below member_dn. */
+-- 
+2.1.0
+
diff --git a/SOURCES/0160-IPA-ipa_resolve_user_list_send-take-care-of-override.patch b/SOURCES/0160-IPA-ipa_resolve_user_list_send-take-care-of-override.patch
new file mode 100644
index 0000000..d025570
--- /dev/null
+++ b/SOURCES/0160-IPA-ipa_resolve_user_list_send-take-care-of-override.patch
@@ -0,0 +1,89 @@
+From a74c81b88afe4fe592527cc137504cb3d78d4660 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 13 Jan 2015 11:03:37 +0100
+Subject: [PATCH 160/160] IPA: ipa_resolve_user_list_send() take care of
+ overrides
+
+Currently ipa_resolve_user_list_send() only looks up the related user
+objects but do not check for overrides. This patch tries to fix this.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit eab17959df71341073f946c533f59fc5e593b35c)
+---
+ src/providers/ipa/ipa_id.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index 4df6ed0e8ee1e9886151703f424b4580db8799a4..3d6861eeb562683518d425616b0e5c413cddba0b 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -146,7 +146,7 @@ static void ipa_account_info_done(struct tevent_req *req)
+ 
+ struct ipa_resolve_user_list_state {
+     struct tevent_context *ev;
+-    struct sdap_id_ctx *sdap_id_ctx;
++    struct ipa_id_ctx *ipa_ctx;
+     struct be_req *be_req;
+     struct ldb_message_element *users;
+     const char *domain_name;
+@@ -161,7 +161,7 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq);
+ static struct tevent_req *
+ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+                            struct be_req *be_req,
+-                           struct sdap_id_ctx *sdap_id_ctx,
++                           struct ipa_id_ctx *ipa_ctx,
+                            const char *domain_name,
+                            struct ldb_message_element *users)
+ {
+@@ -177,7 +177,7 @@ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+     }
+ 
+     state->ev = ev;
+-    state->sdap_id_ctx = sdap_id_ctx;
++    state->ipa_ctx = ipa_ctx;
+     state->be_req = be_req;
+     state->domain_name = domain_name;
+     state->users = users;
+@@ -221,10 +221,8 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req)
+ 
+     DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value);
+ 
+-    subreq = sdap_handle_acct_req_send(state, state->be_req, ar,
+-                                       state->sdap_id_ctx,
+-                                       state->sdap_id_ctx->opts->sdom,
+-                                       state->sdap_id_ctx->conn, true);
++    subreq = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx,
++                                          state->be_req, ar);
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct_req_send failed.\n");
+         return ENOMEM;
+@@ -243,7 +241,7 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq)
+                                             struct ipa_resolve_user_list_state);
+     int ret;
+ 
+-    ret = sdap_handle_acct_req_recv(subreq, &state->dp_error, NULL, NULL);
++    ret = ipa_id_get_account_info_recv(subreq, &state->dp_error);
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct request failed: %d\n", ret);
+@@ -616,7 +614,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
+     if (state->ghosts != NULL) {
+         /* Resolve ghost members */
+         subreq = ipa_resolve_user_list_send(state, state->ev, state->be_req,
+-                                            state->ipa_ctx->sdap_id_ctx,
++                                            state->ipa_ctx,
+                                             state->domain->name,
+                                             state->ghosts);
+         if (subreq == NULL) {
+@@ -682,7 +680,7 @@ static void ipa_id_get_account_info_done(struct tevent_req *subreq)
+     if (state->ghosts != NULL) {
+         /* Resolve ghost members */
+         subreq = ipa_resolve_user_list_send(state, state->ev, state->be_req,
+-                                            state->ipa_ctx->sdap_id_ctx,
++                                            state->ipa_ctx,
+                                             state->domain->name,
+                                             state->ghosts);
+         if (subreq == NULL) {
+-- 
+2.1.0
+
diff --git a/SOURCES/0161-IPA-do-not-look-up-overrides-on-client-with-default-.patch b/SOURCES/0161-IPA-do-not-look-up-overrides-on-client-with-default-.patch
new file mode 100644
index 0000000..bd6c53b
--- /dev/null
+++ b/SOURCES/0161-IPA-do-not-look-up-overrides-on-client-with-default-.patch
@@ -0,0 +1,154 @@
+From 7d4d2a29a210964024f971708e82c441034d49a7 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 4 Dec 2014 13:26:32 +0100
+Subject: [PATCH 161/167] IPA: do not look up overrides on client with default
+ view
+
+The IPA extdom plugin returns the data with the default view already
+applied hence it is on needed to look up the override data if the client
+has the default view assigned.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit d8ceb194023a2cdc8bc183acc322e9a7fb6fe2b1)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 63 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 49 insertions(+), 14 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 55450c7029391a99bfc33b8446765f71c4d0928a..1d9a79a383e47fcdd37f30a24327ae76facea5b9 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -888,11 +888,13 @@ struct ipa_s2n_get_groups_state {
+     int exop_timeout;
+     struct resp_attrs *attrs;
+     struct sss_domain_info *obj_domain;
++    struct sysdb_attrs *override_attrs;
+ };
+ 
+ static errno_t ipa_s2n_get_groups_step(struct tevent_req *req);
+ static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq);
+ static void ipa_s2n_get_groups_next(struct tevent_req *subreq);
++static errno_t ipa_s2n_get_groups_save_step(struct tevent_req *req);
+ 
+ static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
+                                                   struct tevent_context *ev,
+@@ -921,6 +923,7 @@ static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
+     state->req_input.inp.name = NULL;
+     state->exop_timeout = exop_timeout;
+     state->attrs = NULL;
++    state->override_attrs = NULL;
+ 
+     ret = ipa_s2n_get_groups_step(req);
+     if (ret != EOK) {
+@@ -1018,6 +1021,18 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
+         goto fail;
+     }
+ 
++    if (strcmp(state->ipa_ctx->view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
++        ret = ipa_s2n_get_groups_save_step(req);
++        if (ret == EOK) {
++            tevent_req_done(req);
++        } else if (ret != EAGAIN) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_save_step failed.\n");
++            goto fail;
++        }
++
++        return;
++    }
++
+     ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
+                                  &sid_str);
+     if (ret != EOK) {
+@@ -1059,39 +1074,55 @@ static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq)
+                                                       struct tevent_req);
+     struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+                                                struct ipa_s2n_get_groups_state);
+-    struct sysdb_attrs *override_attrs = NULL;
+ 
+-    ret = ipa_get_ad_override_recv(subreq, NULL, state, &override_attrs);
++    ret = ipa_get_ad_override_recv(subreq, NULL, state, &state->override_attrs);
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
+         goto fail;
+     }
+ 
++    ret = ipa_s2n_get_groups_save_step(req);
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else if (ret != EAGAIN) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_save_step failed.\n");
++        goto fail;
++    }
++
++    return;
++
++fail:
++    tevent_req_error(req,ret);
++    return;
++}
++
++static errno_t ipa_s2n_get_groups_save_step(struct tevent_req *req)
++{
++    int ret;
++    struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
++                                               struct ipa_s2n_get_groups_state);
++
+     ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs,
+-                               NULL, state->ipa_ctx->view_name, override_attrs);
++                               NULL, state->ipa_ctx->view_name,
++                               state->override_attrs);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+-        goto fail;
++        return ret;
+     }
+ 
+     state->group_idx++;
+     if (state->group_list[state->group_idx] == NULL) {
+-        tevent_req_done(req);
+-        return;
++        return EOK;
+     }
+ 
+     ret = ipa_s2n_get_groups_step(req);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_step failed.\n");
+-        goto fail;
++        return ret;
+     }
+ 
+-    return;
+-
+-fail:
+-    tevent_req_error(req,ret);
+-    return;
++    return EAGAIN;
+ }
+ 
+ static int ipa_s2n_get_groups_recv(struct tevent_req *req)
+@@ -1484,7 +1515,9 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+         ret = ENOENT;
+     }
+ 
+-    if (ret == ENOENT) {
++    if (ret == ENOENT
++            || strcmp(state->ipa_ctx->view_name,
++                      SYSDB_DEFAULT_VIEW_NAME) == 0) {
+         ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
+                                    state->simple_attrs, NULL, NULL);
+         if (ret != EOK) {
+@@ -2046,7 +2079,9 @@ static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
+         goto fail;
+     }
+ 
+-    if (state->override_attrs == NULL) {
++    if (state->override_attrs == NULL
++            && strcmp(state->ipa_ctx->view_name,
++                      SYSDB_DEFAULT_VIEW_NAME) != 0) {
+         subreq = ipa_get_ad_override_send(state, state->ev,
+                            state->ipa_ctx->sdap_id_ctx,
+                            state->ipa_ctx->ipa_options,
+-- 
+2.1.0
+
diff --git a/SOURCES/0162-IPA-make-version-check-more-precise.patch b/SOURCES/0162-IPA-make-version-check-more-precise.patch
new file mode 100644
index 0000000..11be584
--- /dev/null
+++ b/SOURCES/0162-IPA-make-version-check-more-precise.patch
@@ -0,0 +1,41 @@
+From 8eb022f5a34e86b091c62fb0c9b30834021f1e23 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 5 Dec 2014 11:03:48 +0100
+Subject: [PATCH 162/167] IPA: make version check more precise
+
+The call protected by the check does not only expect the version 1 of
+the extdom plugin is used but a specific response type as well. Since
+version 1 can return older response types as well we want to be on the
+safe side.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 2fc12875f7d51248799016c19c1298b85e06a286)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 1d9a79a383e47fcdd37f30a24327ae76facea5b9..b02387a827b7da27d944db8f7fa326f153e12715 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -759,7 +759,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
+             attrs->a.user.pw_uid = uid;
+             attrs->a.user.pw_gid = gid;
+ 
+-            if (is_v1) {
++            if (is_v1 && type == RESP_USER_GROUPLIST) {
+                 ret = add_v1_user_data(ber, attrs);
+                 if (ret != EOK) {
+                     DEBUG(SSSDBG_OP_FAILURE, "add_v1_user_data failed.\n");
+@@ -798,7 +798,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
+ 
+             attrs->a.group.gr_gid = gid;
+ 
+-            if (is_v1) {
++            if (is_v1 && type == RESP_GROUP_MEMBERS) {
+                 ret = add_v1_group_data(ber, attrs);
+                 if (ret != EOK) {
+                     DEBUG(SSSDBG_OP_FAILURE, "add_v1_group_data failed.\n");
+-- 
+2.1.0
+
diff --git a/SOURCES/0163-IPA-add-missing-break.patch b/SOURCES/0163-IPA-add-missing-break.patch
new file mode 100644
index 0000000..0be9ae7
--- /dev/null
+++ b/SOURCES/0163-IPA-add-missing-break.patch
@@ -0,0 +1,29 @@
+From 24a53fe7f04c3d230b090efd76bc43692d4e2d78 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 5 Dec 2014 11:06:26 +0100
+Subject: [PATCH 163/167] IPA: add missing break
+
+The current request already returned the SID, we do not need to request
+it separately.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit e6046d23b3e90102fb3c796737ced03fb5a60fea)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index b02387a827b7da27d944db8f7fa326f153e12715..68f4cb7d8ff778342c5280652f0a62753c7c7b2c 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1451,6 +1451,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+ 
+                 return;
+             }
++            break;
+         }
+ 
+         if (state->req_input->type == REQ_INP_SECID
+-- 
+2.1.0
+
diff --git a/SOURCES/0164-IPA-process_members-optionally-return-missing-member.patch b/SOURCES/0164-IPA-process_members-optionally-return-missing-member.patch
new file mode 100644
index 0000000..c121189
--- /dev/null
+++ b/SOURCES/0164-IPA-process_members-optionally-return-missing-member.patch
@@ -0,0 +1,154 @@
+From c74de0bbed7729b44567ca1cf364ddca94a2acbf Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 5 Dec 2014 11:11:49 +0100
+Subject: [PATCH 164/167] IPA: process_members() optionally return missing
+ members list
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 942ebb62c8df766a22271103abd518ddae02ea3a)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 85 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 67 insertions(+), 18 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 68f4cb7d8ff778342c5280652f0a62753c7c7b2c..bc476b469d02ea5f80d7e792693f5d25db889b74 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1222,7 +1222,8 @@ fail:
+ 
+ static errno_t process_members(struct sss_domain_info *domain,
+                                struct sysdb_attrs *group_attrs,
+-                               char **members)
++                               char **members,
++                               TALLOC_CTX *mem_ctx, char ***_missing_members)
+ {
+     int ret;
+     size_t c;
+@@ -1231,9 +1232,12 @@ static errno_t process_members(struct sss_domain_info *domain,
+     const char *dn_str;
+     struct sss_domain_info *obj_domain;
+     struct sss_domain_info *parent_domain;
++    char **missing_members = NULL;
++    size_t miss_count = 0;
+ 
+     if (members == NULL) {
+         DEBUG(SSSDBG_TRACE_INTERNAL, "No members\n");
++        *_missing_members = NULL;
+         return EOK;
+     }
+ 
+@@ -1243,6 +1247,17 @@ static errno_t process_members(struct sss_domain_info *domain,
+         return ENOMEM;
+     }
+ 
++    if (_missing_members != NULL && mem_ctx != NULL) {
++        /* count members */
++        for (c = 0; members[c] != NULL; c++);
++        missing_members = talloc_zero_array(tmp_ctx, char *, c + 1);
++        if (missing_members == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_array_zero failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
+     parent_domain = get_domains_head(domain);
+ 
+     for (c = 0; members[c] != NULL; c++) {
+@@ -1256,27 +1271,46 @@ static errno_t process_members(struct sss_domain_info *domain,
+         ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], NULL,
+                                         &msg);
+         if (ret == EOK) {
+-            dn_str = ldb_dn_get_linearized(msg->dn);
+-            if (dn_str == NULL) {
+-                DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
+-                goto done;
+-            }
++            if (group_attrs != NULL) {
++                dn_str = ldb_dn_get_linearized(msg->dn);
++                if (dn_str == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
++                    goto done;
++                }
+ 
+-            DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n",
+-                                    members[c], dn_str);
++                DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n",
++                                        members[c], dn_str);
+ 
+-            ret = sysdb_attrs_add_string(group_attrs, SYSDB_MEMBER, dn_str);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+-                goto done;
++                ret = sysdb_attrs_add_string(group_attrs, SYSDB_MEMBER, dn_str);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sysdb_attrs_add_string failed.\n");
++                    goto done;
++                }
+             }
+         } else if (ret == ENOENT) {
+-            DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n", members[c]);
++            if (group_attrs != NULL) {
++                DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n",
++                                        members[c]);
+ 
+-            ret = sysdb_attrs_add_string(group_attrs, SYSDB_GHOST, members[c]);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+-                goto done;
++                ret = sysdb_attrs_add_string(group_attrs, SYSDB_GHOST,
++                                             members[c]);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sysdb_attrs_add_string failed.\n");
++                    goto done;
++                }
++            }
++
++            if (missing_members != NULL) {
++                missing_members[miss_count] = talloc_strdup(missing_members,
++                                                            members[c]);
++                if (missing_members[miss_count] == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                    ret = ENOMEM;
++                    goto done;
++                }
++                miss_count++;
+             }
+         } else {
+             DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
+@@ -1284,6 +1318,21 @@ static errno_t process_members(struct sss_domain_info *domain,
+         }
+     }
+ 
++    if (_missing_members != NULL)  {
++        if (miss_count == 0) {
++            *_missing_members = NULL;
++        } else {
++            if (mem_ctx != NULL) {
++                *_missing_members = talloc_steal(mem_ctx, missing_members);
++            } else {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Missing memory context for missing members list.\n");
++                ret = EINVAL;
++                goto done;
++            }
++        }
++    }
++
+     ret = EOK;
+ done:
+     talloc_free(tmp_ctx);
+@@ -1986,7 +2035,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+             }
+ 
+             ret = process_members(dom, attrs->sysdb_attrs,
+-                                  attrs->a.group.gr_mem);
++                                  attrs->a.group.gr_mem, NULL, NULL);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
+                 goto done;
+-- 
+2.1.0
+
diff --git a/SOURCES/0165-IPA-rename-ipa_s2n_get_groups_send-to-ipa_s2n_get_fq.patch b/SOURCES/0165-IPA-rename-ipa_s2n_get_groups_send-to-ipa_s2n_get_fq.patch
new file mode 100644
index 0000000..c0ac0e6
--- /dev/null
+++ b/SOURCES/0165-IPA-rename-ipa_s2n_get_groups_send-to-ipa_s2n_get_fq.patch
@@ -0,0 +1,304 @@
+From a1f99b4609c29bf92ad717f7f21a62582fe24e1f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 9 Dec 2014 17:04:30 +0100
+Subject: [PATCH 165/167] IPA: rename ipa_s2n_get_groups_send() to
+ ipa_s2n_get_fqlist_send()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit f1f22df95996390f63266ebacb624e521d934592)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 100 +++++++++++++++++++--------------------
+ 1 file changed, 50 insertions(+), 50 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index bc476b469d02ea5f80d7e792693f5d25db889b74..505c2325f2a74e26816bb59ad3c7d4810cc64dbf 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -877,38 +877,38 @@ done:
+     return ret;
+ }
+ 
+-struct ipa_s2n_get_groups_state {
++struct ipa_s2n_get_fqlist_state {
+     struct tevent_context *ev;
+     struct ipa_id_ctx *ipa_ctx;
+     struct sss_domain_info *dom;
+     struct sdap_handle *sh;
+     struct req_input req_input;
+-    char **group_list;
+-    size_t group_idx;
++    char **fqname_list;
++    size_t fqname_idx;
+     int exop_timeout;
+     struct resp_attrs *attrs;
+     struct sss_domain_info *obj_domain;
+     struct sysdb_attrs *override_attrs;
+ };
+ 
+-static errno_t ipa_s2n_get_groups_step(struct tevent_req *req);
+-static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq);
+-static void ipa_s2n_get_groups_next(struct tevent_req *subreq);
+-static errno_t ipa_s2n_get_groups_save_step(struct tevent_req *req);
++static errno_t ipa_s2n_get_fqlist_step(struct tevent_req *req);
++static void ipa_s2n_get_fqlist_get_override_done(struct tevent_req *subreq);
++static void ipa_s2n_get_fqlist_next(struct tevent_req *subreq);
++static errno_t ipa_s2n_get_fqlist_save_step(struct tevent_req *req);
+ 
+-static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
++static struct tevent_req *ipa_s2n_get_fqlist_send(TALLOC_CTX *mem_ctx,
+                                                   struct tevent_context *ev,
+                                                   struct ipa_id_ctx *ipa_ctx,
+                                                   struct sss_domain_info *dom,
+                                                   struct sdap_handle *sh,
+                                                   int exop_timeout,
+-                                                  char **group_list)
++                                                  char **fqname_list)
+ {
+     int ret;
+-    struct ipa_s2n_get_groups_state *state;
++    struct ipa_s2n_get_fqlist_state *state;
+     struct tevent_req *req;
+ 
+-    req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_get_groups_state);
++    req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_get_fqlist_state);
+     if (req == NULL) {
+         return NULL;
+     }
+@@ -917,17 +917,17 @@ static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
+     state->ipa_ctx = ipa_ctx;
+     state->dom = dom;
+     state->sh = sh;
+-    state->group_list = group_list;
+-    state->group_idx = 0;
++    state->fqname_list = fqname_list;
++    state->fqname_idx = 0;
+     state->req_input.type = REQ_INP_NAME;
+     state->req_input.inp.name = NULL;
+     state->exop_timeout = exop_timeout;
+     state->attrs = NULL;
+     state->override_attrs = NULL;
+ 
+-    ret = ipa_s2n_get_groups_step(req);
++    ret = ipa_s2n_get_fqlist_step(req);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_step failed.\n");
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_fqlist_step failed.\n");
+         goto done;
+     }
+ 
+@@ -940,25 +940,25 @@ done:
+     return req;
+ }
+ 
+-static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
++static errno_t ipa_s2n_get_fqlist_step(struct tevent_req *req)
+ {
+     int ret;
+-    struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+-                                               struct ipa_s2n_get_groups_state);
++    struct ipa_s2n_get_fqlist_state *state = tevent_req_data(req,
++                                               struct ipa_s2n_get_fqlist_state);
+     struct berval *bv_req;
+     struct tevent_req *subreq;
+     struct sss_domain_info *parent_domain;
+-    char *group_name = NULL;
++    char *short_name = NULL;
+     char *domain_name = NULL;
+ 
+     parent_domain = get_domains_head(state->dom);
+ 
+     ret = sss_parse_name(state, parent_domain->names,
+-                         state->group_list[state->group_idx],
+-                         &domain_name, &group_name);
++                         state->fqname_list[state->fqname_idx],
++                         &domain_name, &short_name);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n",
+-                                    state->group_list[state->group_idx],
++                                    state->fqname_list[state->fqname_idx],
+                                     ret, sss_strerror(ret));
+         return ret;
+     }
+@@ -974,7 +974,7 @@ static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
+         state->obj_domain = parent_domain;
+     }
+ 
+-    state->req_input.inp.name = group_name;
++    state->req_input.inp.name = short_name;
+ 
+     ret = s2n_encode_request(state, state->obj_domain->name, BE_REQ_GROUP,
+                              REQ_FULL_WITH_MEMBERS,
+@@ -990,18 +990,18 @@ static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
+         DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
+         return ENOMEM;
+     }
+-    tevent_req_set_callback(subreq, ipa_s2n_get_groups_next, req);
++    tevent_req_set_callback(subreq, ipa_s2n_get_fqlist_next, req);
+ 
+     return EOK;
+ }
+ 
+-static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
++static void ipa_s2n_get_fqlist_next(struct tevent_req *subreq)
+ {
+     int ret;
+     struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                       struct tevent_req);
+-    struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+-                                               struct ipa_s2n_get_groups_state);
++    struct ipa_s2n_get_fqlist_state *state = tevent_req_data(req,
++                                               struct ipa_s2n_get_fqlist_state);
+     char *retoid = NULL;
+     struct berval *retdata = NULL;
+     const char *sid_str;
+@@ -1022,11 +1022,11 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
+     }
+ 
+     if (strcmp(state->ipa_ctx->view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
+-        ret = ipa_s2n_get_groups_save_step(req);
++        ret = ipa_s2n_get_fqlist_save_step(req);
+         if (ret == EOK) {
+             tevent_req_done(req);
+         } else if (ret != EAGAIN) {
+-            DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_save_step failed.\n");
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_fqlist_save_step failed.\n");
+             goto fail;
+         }
+ 
+@@ -1058,7 +1058,7 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
+         ret = ENOMEM;
+         goto fail;
+     }
+-    tevent_req_set_callback(subreq, ipa_s2n_get_groups_get_override_done, req);
++    tevent_req_set_callback(subreq, ipa_s2n_get_fqlist_get_override_done, req);
+ 
+     return;
+ 
+@@ -1067,13 +1067,13 @@ fail:
+     return;
+ }
+ 
+-static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq)
++static void ipa_s2n_get_fqlist_get_override_done(struct tevent_req *subreq)
+ {
+     int ret;
+     struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                       struct tevent_req);
+-    struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+-                                               struct ipa_s2n_get_groups_state);
++    struct ipa_s2n_get_fqlist_state *state = tevent_req_data(req,
++                                               struct ipa_s2n_get_fqlist_state);
+ 
+     ret = ipa_get_ad_override_recv(subreq, NULL, state, &state->override_attrs);
+     talloc_zfree(subreq);
+@@ -1082,11 +1082,11 @@ static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq)
+         goto fail;
+     }
+ 
+-    ret = ipa_s2n_get_groups_save_step(req);
++    ret = ipa_s2n_get_fqlist_save_step(req);
+     if (ret == EOK) {
+         tevent_req_done(req);
+     } else if (ret != EAGAIN) {
+-        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_save_step failed.\n");
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_fqlist_save_step failed.\n");
+         goto fail;
+     }
+ 
+@@ -1097,11 +1097,11 @@ fail:
+     return;
+ }
+ 
+-static errno_t ipa_s2n_get_groups_save_step(struct tevent_req *req)
++static errno_t ipa_s2n_get_fqlist_save_step(struct tevent_req *req)
+ {
+     int ret;
+-    struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+-                                               struct ipa_s2n_get_groups_state);
++    struct ipa_s2n_get_fqlist_state *state = tevent_req_data(req,
++                                               struct ipa_s2n_get_fqlist_state);
+ 
+     ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs,
+                                NULL, state->ipa_ctx->view_name,
+@@ -1111,21 +1111,21 @@ static errno_t ipa_s2n_get_groups_save_step(struct tevent_req *req)
+         return ret;
+     }
+ 
+-    state->group_idx++;
+-    if (state->group_list[state->group_idx] == NULL) {
++    state->fqname_idx++;
++    if (state->fqname_list[state->fqname_idx] == NULL) {
+         return EOK;
+     }
+ 
+-    ret = ipa_s2n_get_groups_step(req);
++    ret = ipa_s2n_get_fqlist_step(req);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_step failed.\n");
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_fqlist_step failed.\n");
+         return ret;
+     }
+ 
+     return EAGAIN;
+ }
+ 
+-static int ipa_s2n_get_groups_recv(struct tevent_req *req)
++static int ipa_s2n_get_fqlist_recv(struct tevent_req *req)
+ {
+     TEVENT_REQ_RETURN_ON_ERROR(req);
+ 
+@@ -1426,7 +1426,7 @@ done:
+     return ret;
+ }
+ 
+-static void ipa_s2n_get_groups_done(struct tevent_req  *subreq);
++static void ipa_s2n_get_fqlist_done(struct tevent_req  *subreq);
+ static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq);
+ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+ {
+@@ -1485,17 +1485,17 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+             }
+ 
+             if (missing_groups != NULL) {
+-                subreq = ipa_s2n_get_groups_send(state, state->ev,
++                subreq = ipa_s2n_get_fqlist_send(state, state->ev,
+                                                  state->ipa_ctx, state->dom,
+                                                  state->sh, state->exop_timeout,
+                                                  missing_groups);
+                 if (subreq == NULL) {
+                     DEBUG(SSSDBG_OP_FAILURE,
+-                          "ipa_s2n_get_groups_send failed.\n");
++                          "ipa_s2n_get_fqlist_send failed.\n");
+                     ret = ENOMEM;
+                     goto done;
+                 }
+-                tevent_req_set_callback(subreq, ipa_s2n_get_groups_done,
++                tevent_req_set_callback(subreq, ipa_s2n_get_fqlist_done,
+                                         req);
+ 
+                 return;
+@@ -2089,7 +2089,7 @@ done:
+     return ret;
+ }
+ 
+-static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
++static void ipa_s2n_get_fqlist_done(struct tevent_req  *subreq)
+ {
+     int ret;
+     struct tevent_req *req = tevent_req_callback_data(subreq,
+@@ -2099,10 +2099,10 @@ static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
+     const char *sid_str;
+     struct be_acct_req *ar;
+ 
+-    ret = ipa_s2n_get_groups_recv(subreq);
++    ret = ipa_s2n_get_fqlist_recv(subreq);
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "s2n get_groups request failed.\n");
++        DEBUG(SSSDBG_OP_FAILURE, "s2n get_fqlist request failed.\n");
+         tevent_req_error(req, ret);
+         return;
+     }
+-- 
+2.1.0
+
diff --git a/SOURCES/0166-IPA-resolve-missing-members.patch b/SOURCES/0166-IPA-resolve-missing-members.patch
new file mode 100644
index 0000000..205d27f
--- /dev/null
+++ b/SOURCES/0166-IPA-resolve-missing-members.patch
@@ -0,0 +1,137 @@
+From 7dfe969cb2c9e116eaeb1813e2c1adb80195944e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 5 Dec 2014 11:12:42 +0100
+Subject: [PATCH 166/167] IPA: resolve missing members
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 3cd287313d93e29f9754feb46017dba2a039affd)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 62 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 48 insertions(+), 14 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 505c2325f2a74e26816bb59ad3c7d4810cc64dbf..0aa12f371e8aa0d58311391a27c668aa929a5b80 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -886,6 +886,8 @@ struct ipa_s2n_get_fqlist_state {
+     char **fqname_list;
+     size_t fqname_idx;
+     int exop_timeout;
++    int entry_type;
++    enum request_types request_type;
+     struct resp_attrs *attrs;
+     struct sss_domain_info *obj_domain;
+     struct sysdb_attrs *override_attrs;
+@@ -897,12 +899,14 @@ static void ipa_s2n_get_fqlist_next(struct tevent_req *subreq);
+ static errno_t ipa_s2n_get_fqlist_save_step(struct tevent_req *req);
+ 
+ static struct tevent_req *ipa_s2n_get_fqlist_send(TALLOC_CTX *mem_ctx,
+-                                                  struct tevent_context *ev,
+-                                                  struct ipa_id_ctx *ipa_ctx,
+-                                                  struct sss_domain_info *dom,
+-                                                  struct sdap_handle *sh,
+-                                                  int exop_timeout,
+-                                                  char **fqname_list)
++                                                struct tevent_context *ev,
++                                                struct ipa_id_ctx *ipa_ctx,
++                                                struct sss_domain_info *dom,
++                                                struct sdap_handle *sh,
++                                                int exop_timeout,
++                                                int entry_type,
++                                                enum request_types request_type,
++                                                char **fqname_list)
+ {
+     int ret;
+     struct ipa_s2n_get_fqlist_state *state;
+@@ -922,6 +926,8 @@ static struct tevent_req *ipa_s2n_get_fqlist_send(TALLOC_CTX *mem_ctx,
+     state->req_input.type = REQ_INP_NAME;
+     state->req_input.inp.name = NULL;
+     state->exop_timeout = exop_timeout;
++    state->entry_type = entry_type;
++    state->request_type = request_type;
+     state->attrs = NULL;
+     state->override_attrs = NULL;
+ 
+@@ -976,8 +982,8 @@ static errno_t ipa_s2n_get_fqlist_step(struct tevent_req *req)
+ 
+     state->req_input.inp.name = short_name;
+ 
+-    ret = s2n_encode_request(state, state->obj_domain->name, BE_REQ_GROUP,
+-                             REQ_FULL_WITH_MEMBERS,
++    ret = s2n_encode_request(state, state->obj_domain->name, state->entry_type,
++                             state->request_type,
+                              &state->req_input, &bv_req);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "s2n_encode_request failed.\n");
+@@ -1439,7 +1445,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+     struct berval *retdata = NULL;
+     struct resp_attrs *attrs = NULL;
+     struct berval *bv_req = NULL;
+-    char **missing_groups = NULL;
++    char **missing_list = NULL;
+     struct ldb_dn **group_dn_list = NULL;
+     const char *sid_str;
+     struct be_acct_req *ar;
+@@ -1478,17 +1484,46 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+         if (attrs->response_type == RESP_USER_GROUPLIST) {
+             ret = get_group_dn_list(state, state->dom,
+                                     attrs->ngroups, attrs->groups,
+-                                    &group_dn_list, &missing_groups);
++                                    &group_dn_list, &missing_list);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE, "get_group_dn_list failed.\n");
+                 goto done;
+             }
+ 
+-            if (missing_groups != NULL) {
++            if (missing_list != NULL) {
+                 subreq = ipa_s2n_get_fqlist_send(state, state->ev,
+                                                  state->ipa_ctx, state->dom,
+                                                  state->sh, state->exop_timeout,
+-                                                 missing_groups);
++                                                 BE_REQ_GROUP,
++                                                 REQ_FULL_WITH_MEMBERS,
++                                                 missing_list);
++                if (subreq == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "ipa_s2n_get_fqlist_send failed.\n");
++                    ret = ENOMEM;
++                    goto done;
++                }
++                tevent_req_set_callback(subreq, ipa_s2n_get_fqlist_done,
++                                        req);
++
++                return;
++            }
++            break;
++        } else if (attrs->response_type == RESP_GROUP_MEMBERS) {
++            ret = process_members(state->dom, NULL, attrs->a.group.gr_mem,
++                                  state, &missing_list);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
++                goto done;
++            }
++
++            if (missing_list != NULL) {
++                subreq = ipa_s2n_get_fqlist_send(state, state->ev,
++                                                 state->ipa_ctx, state->dom,
++                                                 state->sh, state->exop_timeout,
++                                                 BE_REQ_USER,
++                                                 REQ_FULL_WITH_MEMBERS,
++                                                 missing_list);
+                 if (subreq == NULL) {
+                     DEBUG(SSSDBG_OP_FAILURE,
+                           "ipa_s2n_get_fqlist_send failed.\n");
+@@ -1503,8 +1538,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
+             break;
+         }
+ 
+-        if (state->req_input->type == REQ_INP_SECID
+-                || attrs->response_type == RESP_GROUP_MEMBERS) {
++        if (state->req_input->type == REQ_INP_SECID) {
+             /* We already know the SID, we do not have to read it. */
+             break;
+         }
+-- 
+2.1.0
+
diff --git a/SOURCES/0167-IPA-set-SYSDB_INITGR_EXPIRE-for-RESP_USER_GROUPLIST.patch b/SOURCES/0167-IPA-set-SYSDB_INITGR_EXPIRE-for-RESP_USER_GROUPLIST.patch
new file mode 100644
index 0000000..a0f093b
--- /dev/null
+++ b/SOURCES/0167-IPA-set-SYSDB_INITGR_EXPIRE-for-RESP_USER_GROUPLIST.patch
@@ -0,0 +1,42 @@
+From d9da43cb6ec9aff5aa1a760e50f3bcbf54307d25 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 9 Dec 2014 17:48:46 +0100
+Subject: [PATCH 167/167] IPA: set SYSDB_INITGR_EXPIRE for RESP_USER_GROUPLIST
+
+Since RESP_USER_GROUPLIST contains all group memberships it is
+effectively an initgroups request hence SYSDB_INITGR_EXPIRE will be set.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 62d919aea98edd1095f6a22241903d4c045b46ed)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 0aa12f371e8aa0d58311391a27c668aa929a5b80..e7c2d9bb97908746eb5ab6cacc6fc58d353dea06 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1911,6 +1911,20 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 }
+             }
+ 
++            if (attrs->response_type == RESP_USER_GROUPLIST) {
++                /* Since RESP_USER_GROUPLIST contains all group memberships it
++                 * is effectively an initgroups request hence
++                 * SYSDB_INITGR_EXPIRE will be set.*/
++                ret = sysdb_attrs_add_time_t(attrs->sysdb_attrs,
++                                             SYSDB_INITGR_EXPIRE,
++                                             time(NULL) + timeout);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sysdb_attrs_add_time_t failed.\n");
++                    goto done;
++                }
++            }
++
+             gid = 0;
+             if (dom->mpg == false) {
+                 gid = attrs->a.user.pw_gid;
+-- 
+2.1.0
+
diff --git a/SOURCES/0168-krb5_child-Return-ERR_NETWORK_IO-on-KRB5_KDCREP_SKEW.patch b/SOURCES/0168-krb5_child-Return-ERR_NETWORK_IO-on-KRB5_KDCREP_SKEW.patch
new file mode 100644
index 0000000..b52cb4d
--- /dev/null
+++ b/SOURCES/0168-krb5_child-Return-ERR_NETWORK_IO-on-KRB5_KDCREP_SKEW.patch
@@ -0,0 +1,28 @@
+From 6bc93a28d5638ea4e76be699f507a76fa3e357ff Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 14 Jan 2015 11:03:14 +0100
+Subject: [PATCH 168/168] krb5_child: Return ERR_NETWORK_IO on KRB5_KDCREP_SKEW
+
+Previously, we were only handling KRB5KRB_AP_ERR_SKEW
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 9b2cd4e5e451c07cb2f04cdbaea2b94ccb5fb2ee)
+---
+ src/providers/krb5/krb5_child.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 9645f1aefbbaaf7fda511bb9650722109403d9df..39cd62846e3c58d65a87f670768cf699ae191f14 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -1072,6 +1072,7 @@ static errno_t map_krb5_error(krb5_error_code kerr)
+     case KRB5_LIBOS_CANTREADPWD:
+         return ERR_NO_CREDS;
+ 
++    case KRB5_KDCREP_SKEW:
+     case KRB5KRB_AP_ERR_SKEW:
+     case KRB5_KDC_UNREACH:
+     case KRB5_REALM_CANT_RESOLVE:
+-- 
+2.1.0
+
diff --git a/SOURCES/0169-krb5-fix-entry-order-in-MEMORY-keytab.patch b/SOURCES/0169-krb5-fix-entry-order-in-MEMORY-keytab.patch
new file mode 100644
index 0000000..6abefe7
--- /dev/null
+++ b/SOURCES/0169-krb5-fix-entry-order-in-MEMORY-keytab.patch
@@ -0,0 +1,203 @@
+From 7c20e30182e3b5f7f8ebcd8174bded4dcc2f89a8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 15 Jan 2015 10:38:33 +0100
+Subject: [PATCH 169/169] krb5: fix entry order in MEMORY keytab
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Since krb5_kt_add_entry() adds new entries at the beginning of a MEMORY
+type keytab and not at the end a simple copy into a MEMORY type keytab
+will revert the order of the keytab entries. Since e.g. the sssd_krb5
+man page give hints about where to add entries into keytab files to help
+SSSD to find a right entry we have to keep the order when coping a
+keytab into a MEMORY type keytab. This patch fixes this by doing a
+second copy to retain the original order.
+
+Resolves https://fedorahosted.org/sssd/ticket/2557
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit 24df1487413d13248dcc70d2548a763930da4c65)
+---
+ src/providers/krb5/krb5_keytab.c | 118 +++++++++++++++++++++++++++++----------
+ 1 file changed, 90 insertions(+), 28 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_keytab.c b/src/providers/krb5/krb5_keytab.c
+index 855f69419611b863a7aea79e2788272f819b0736..ec8d6502d89c0d7f75c28b151523d235b6bc131d 100644
+--- a/src/providers/krb5/krb5_keytab.c
++++ b/src/providers/krb5/krb5_keytab.c
+@@ -25,20 +25,78 @@
+ #include "util/util.h"
+ #include "util/sss_krb5.h"
+ 
++static krb5_error_code do_keytab_copy(krb5_context kctx, krb5_keytab s_keytab,
++                                      krb5_keytab d_keytab)
++{
++    krb5_error_code kerr;
++    krb5_error_code kt_err;
++    krb5_kt_cursor cursor;
++    krb5_keytab_entry entry;
++
++    memset(&cursor, 0, sizeof(cursor));
++    kerr = krb5_kt_start_seq_get(kctx, s_keytab, &cursor);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error reading keytab.\n");
++        return kerr;
++    }
++
++    memset(&entry, 0, sizeof(entry));
++    while ((kt_err = krb5_kt_next_entry(kctx, s_keytab, &entry,
++                                        &cursor)) == 0) {
++        kerr = krb5_kt_add_entry(kctx, d_keytab, &entry);
++        if (kerr != 0) {
++            DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_add_entry failed.\n");
++            kt_err = krb5_kt_end_seq_get(kctx, s_keytab, &cursor);
++            if (kt_err != 0) {
++                DEBUG(SSSDBG_TRACE_ALL,
++                      "krb5_kt_end_seq_get failed with [%d], ignored.\n",
++                      kt_err);
++            }
++            return kerr;
++        }
++
++        kerr = sss_krb5_free_keytab_entry_contents(kctx, &entry);
++        if (kerr != 0) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Failed to free keytab entry.\n");
++            kt_err = krb5_kt_end_seq_get(kctx, s_keytab, &cursor);
++            if (kt_err != 0) {
++                DEBUG(SSSDBG_TRACE_ALL,
++                      "krb5_kt_end_seq_get failed with [%d], ignored.\n",
++                      kt_err);
++            }
++            return kerr;
++        }
++        memset(&entry, 0, sizeof(entry));
++    }
++
++    kerr = krb5_kt_end_seq_get(kctx, s_keytab, &cursor);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_kt_end_seq_get failed.\n");
++        return kerr;
++    }
++
++    /* check if we got any errors from krb5_kt_next_entry */
++    if (kt_err != 0 && kt_err != KRB5_KT_END) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "error reading keytab.\n");
++        return kt_err;
++    }
++
++    return 0;
++}
++
+ krb5_error_code copy_keytab_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
+                                         char *inp_keytab_file,
+                                         char **_mem_name,
+                                         krb5_keytab *_mem_keytab)
+ {
+     krb5_error_code kerr;
+-    krb5_error_code kt_err;
+     krb5_keytab keytab = NULL;
+     krb5_keytab mem_keytab = NULL;
+-    krb5_kt_cursor cursor;
+-    krb5_keytab_entry entry;
++    krb5_keytab tmp_mem_keytab = NULL;
+     char keytab_name[MAX_KEYTAB_NAME_LEN];
+     char *sep;
+     char *mem_name = NULL;
++    char *tmp_mem_name = NULL;
+     char *keytab_file;
+     char default_keytab_name[MAX_KEYTAB_NAME_LEN];
+ 
+@@ -103,6 +161,13 @@ krb5_error_code copy_keytab_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
+         goto done;
+     }
+ 
++    tmp_mem_name = talloc_asprintf(mem_ctx, "MEMORY:%s.tmp", sep + 1);
++    if (tmp_mem_name == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++        kerr = KRB5KRB_ERR_GENERIC;
++        goto done;
++    }
++
+     kerr = krb5_kt_resolve(kctx, mem_name, &mem_keytab);
+     if (kerr != 0) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "error resolving keytab [%s].\n",
+@@ -110,38 +175,29 @@ krb5_error_code copy_keytab_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
+         goto done;
+     }
+ 
+-    memset(&cursor, 0, sizeof(cursor));
+-    kerr = krb5_kt_start_seq_get(kctx, keytab, &cursor);
++    kerr = krb5_kt_resolve(kctx, tmp_mem_name, &tmp_mem_keytab);
+     if (kerr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "error reading keytab [%s].\n", keytab_file);
++        DEBUG(SSSDBG_CRIT_FAILURE, "error resolving keytab [%s].\n",
++                                    tmp_mem_name);
+         goto done;
+     }
+ 
+-    memset(&entry, 0, sizeof(entry));
+-    while ((kt_err = krb5_kt_next_entry(kctx, keytab, &entry, &cursor)) == 0) {
+-        kerr = krb5_kt_add_entry(kctx, mem_keytab, &entry);
+-        if (kerr != 0) {
+-            DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_add_entry failed.\n");
+-            goto done;
+-        }
+-
+-        kerr = sss_krb5_free_keytab_entry_contents(kctx, &entry);
+-        if (kerr != 0) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Failed to free keytab entry.\n");
+-        }
+-        memset(&entry, 0, sizeof(entry));
+-    }
+-
+-    kerr = krb5_kt_end_seq_get(kctx, keytab, &cursor);
++    kerr = do_keytab_copy(kctx, keytab, tmp_mem_keytab);
+     if (kerr != 0) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_kt_end_seq_get failed.\n");
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy keytab [%s] into [%s].\n",
++                                    keytab_file, tmp_mem_name);
+         goto done;
+     }
+ 
+-    /* check if we got any errors from krb5_kt_next_entry */
+-    if (kt_err != 0 && kt_err != KRB5_KT_END) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "error reading keytab [%s].\n", keytab_file);
+-        kerr = KRB5KRB_ERR_GENERIC;
++    /* krb5_kt_add_entry() adds new entries into MEMORY keytabs at the
++     * beginning and not at the end as for FILE keytabs. Since we want to keep
++     * the processing order we have to copy the MEMORY keytab again to retain
++     * the order from the FILE keytab. */
++
++    kerr = do_keytab_copy(kctx, tmp_mem_keytab, mem_keytab);
++    if (kerr != 0) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy keytab [%s] into [%s].\n",
++                                    tmp_mem_name, mem_name);
+         goto done;
+     }
+ 
+@@ -153,12 +209,18 @@ krb5_error_code copy_keytab_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
+     kerr = 0;
+ done:
+ 
++    talloc_free(tmp_mem_name);
++
+     if (kerr != 0) {
+         talloc_free(mem_name);
+     }
+ 
++    if (tmp_mem_keytab != NULL && krb5_kt_close(kctx, tmp_mem_keytab) != 0) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "krb5_kt_close failed.\n");
++    }
++
+     if (keytab != NULL && krb5_kt_close(kctx, keytab) != 0) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "krb5_kt_close failed");
++        DEBUG(SSSDBG_MINOR_FAILURE, "krb5_kt_close failed.\n");
+     }
+ 
+     return kerr;
+-- 
+2.1.0
+
diff --git a/SOURCES/0170-nss-make-fill_orig-multi-value-aware.patch b/SOURCES/0170-nss-make-fill_orig-multi-value-aware.patch
new file mode 100644
index 0000000..e823d9d
--- /dev/null
+++ b/SOURCES/0170-nss-make-fill_orig-multi-value-aware.patch
@@ -0,0 +1,301 @@
+From 42cd56abee7c8403c585db2d85a0d32f141b05a6 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 20 Jan 2015 12:48:19 +0100
+Subject: [PATCH 170/172] nss: make fill_orig() multi-value aware
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 5f4d896ec8e06476f4282b562b1044de14c48ecf)
+---
+ src/responder/nss/nsssrv_cmd.c  |  86 ++++++++++++++++++++------
+ src/tests/cmocka/test_nss_srv.c | 131 +++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 197 insertions(+), 20 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index c523dafc9455a07f3b0fd1f9db00bee551358a84..b49807e3e349942c0617253fdf45b4ad43ba2ee1 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4612,13 +4612,14 @@ static errno_t fill_orig(struct sss_packet *packet,
+ {
+     int ret;
+     TALLOC_CTX *tmp_ctx;
+-    const char *tmp_str;
+     uint8_t *body;
+     size_t blen;
+     size_t pctr = 0;
+     size_t c;
++    size_t d;
+     size_t sum;
+     size_t found;
++    size_t array_size;
+     size_t extra_attrs_count = 0;
+     const char **extra_attrs_list = NULL;
+     const char *orig_attr_list[] = {SYSDB_SID_STR,
+@@ -4637,6 +4638,8 @@ static errno_t fill_orig(struct sss_packet *packet,
+     struct sized_string *keys;
+     struct sized_string *vals;
+     struct nss_ctx *nctx;
++    struct ldb_message_element *el;
++    struct ldb_val *val;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -4652,10 +4655,9 @@ static errno_t fill_orig(struct sss_packet *packet,
+                 extra_attrs_count++);
+     }
+ 
+-    keys = talloc_array(tmp_ctx, struct sized_string,
+-                        sizeof(orig_attr_list) + extra_attrs_count);
+-    vals = talloc_array(tmp_ctx, struct sized_string,
+-                        sizeof(orig_attr_list) + extra_attrs_count);
++    array_size = sizeof(orig_attr_list) + extra_attrs_count;
++    keys = talloc_array(tmp_ctx, struct sized_string, array_size);
++    vals = talloc_array(tmp_ctx, struct sized_string, array_size);
+     if (keys == NULL || vals == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+         ret = ENOMEM;
+@@ -4665,26 +4667,72 @@ static errno_t fill_orig(struct sss_packet *packet,
+     sum = 0;
+     found = 0;
+     for (c = 0; orig_attr_list[c] != NULL; c++) {
+-        tmp_str = ldb_msg_find_attr_as_string(msg, orig_attr_list[c], NULL);
+-        if (tmp_str != NULL) {
+-            to_sized_string(&keys[found], orig_attr_list[c]);
+-            sum += keys[found].len;
+-            to_sized_string(&vals[found], tmp_str);
+-            sum += vals[found].len;
++        el = ldb_msg_find_element(msg, orig_attr_list[c]);
++        if (el != NULL &&  el->num_values > 0) {
++            if (el->num_values > 1) {
++                array_size += el->num_values;
++                keys = talloc_realloc(tmp_ctx, keys, struct sized_string,
++                                      array_size);
++                vals = talloc_realloc(tmp_ctx, vals, struct sized_string,
++                                      array_size);
++                if (keys == NULL || vals == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++                    ret = ENOMEM;
++                    goto done;
++                }
++            }
++            for (d = 0; d < el->num_values; d++) {
++                to_sized_string(&keys[found], orig_attr_list[c]);
++                sum += keys[found].len;
++                val = &(el->values[d]);
++                if (val == NULL || val->data == NULL
++                        || val->data[val->length] != '\0') {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Unexpected attribute value found for [%s].\n",
++                          orig_attr_list[c]);
++                    ret = EINVAL;
++                    goto done;
++                }
++                to_sized_string(&vals[found], (const char *)val->data);
++                sum += vals[found].len;
+ 
+-            found++;
++                found++;
++            }
+         }
+     }
+ 
+     for (c = 0; c < extra_attrs_count; c++) {
+-        tmp_str = ldb_msg_find_attr_as_string(msg, extra_attrs_list[c], NULL);
+-        if (tmp_str != NULL) {
+-            to_sized_string(&keys[found], extra_attrs_list[c]);
+-            sum += keys[found].len;
+-            to_sized_string(&vals[found], tmp_str);
+-            sum += vals[found].len;
++        el = ldb_msg_find_element(msg, extra_attrs_list[c]);
++        if (el != NULL &&  el->num_values > 0) {
++            if (el->num_values > 1) {
++                array_size += el->num_values;
++                keys = talloc_realloc(tmp_ctx, keys, struct sized_string,
++                                      array_size);
++                vals = talloc_realloc(tmp_ctx, vals, struct sized_string,
++                                      array_size);
++                if (keys == NULL || vals == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++                    ret = ENOMEM;
++                    goto done;
++                }
++            }
++            for (d = 0; d < el->num_values; d++) {
++                to_sized_string(&keys[found], extra_attrs_list[c]);
++                sum += keys[found].len;
++                val = &(el->values[d]);
++                if (val == NULL || val->data == NULL
++                        || val->data[val->length] != '\0') {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Unexpected attribute value found for [%s].\n",
++                          orig_attr_list[c]);
++                    ret = EINVAL;
++                    goto done;
++                }
++                to_sized_string(&vals[found], (const char *)val->data);
++                sum += vals[found].len;
+ 
+-            found++;
++                found++;
++            }
+         }
+     }
+ 
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index c318d94be867bbb9991de288cdae45d2ddc29b24..d7825e4384a4cc91407ed4bc66a1e190d558369f 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -52,7 +52,8 @@ struct nss_test_ctx {
+     bool ncache_hit;
+ };
+ 
+-const char *global_extra_attrs[] = {"phone", "mobile", NULL};
++const char *global_extra_attrs[] = {"phone", "mobile", SYSDB_ORIG_MEMBEROF,
++                                    NULL};
+ 
+ struct nss_test_ctx *nss_test_ctx;
+ 
+@@ -1946,6 +1947,132 @@ void test_nss_getorigbyname_extra_attrs(void **state)
+     assert_int_equal(ret, EOK);
+ }
+ 
++
++static int test_nss_getorigbyname_multi_check(uint32_t status, uint8_t *body,
++                                              size_t blen)
++{
++    const char *s;
++    enum sss_id_type id_type;
++    size_t rp = 2 * sizeof(uint32_t);
++
++    assert_int_equal(status, EOK);
++
++    SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp);
++    assert_int_equal(id_type, SSS_ID_TYPE_UID);
++
++    /* Sequence of null terminated strings */
++    s = (char *) body+rp;
++    assert_string_equal(s, SYSDB_SID_STR);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "S-1-2-3-4");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_NAME);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "orig_name");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_UIDNUM);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "1234");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, SYSDB_ORIG_MEMBEROF);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "cn=abc");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, SYSDB_ORIG_MEMBEROF);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "cn=def");
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, SYSDB_ORIG_MEMBEROF);
++    rp += strlen(s) + 1;
++    assert_true(rp < blen);
++
++    s = (char *) body+rp;
++    assert_string_equal(s, "cn=123");
++    rp += strlen(s) + 1;
++    assert_int_equal(rp, blen);
++
++    return EOK;
++}
++void test_nss_getorigbyname_multi_value_attrs(void **state)
++{
++    errno_t ret;
++    struct sysdb_attrs *attrs;
++
++    attrs = sysdb_new_attrs(nss_test_ctx);
++    assert_non_null(attrs);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, "S-1-2-3-4");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, ORIGINALAD_PREFIX SYSDB_NAME,
++                                 "orig_name");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_uint32(attrs, ORIGINALAD_PREFIX SYSDB_UIDNUM, 1234);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_MEMBEROF, "cn=abc");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_MEMBEROF, "cn=def");
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_MEMBEROF, "cn=123");
++    assert_int_equal(ret, EOK);
++
++    /* Prime the cache with a valid user */
++    ret = sysdb_add_user(nss_test_ctx->tctx->dom,
++                         "testuserorigmulti", 3456, 7890,
++                         "test user orig multi value",
++                         "/home/testuserorigextra", "/bin/sh", NULL,
++                         attrs, 300, 0);
++    assert_int_equal(ret, EOK);
++
++    mock_input_user_or_group("testuserorigmulti");
++    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETORIGBYNAME);
++    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
++
++    /* Query for that user, call a callback when command finishes */
++    set_cmd_cb(test_nss_getorigbyname_multi_check);
++    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETORIGBYNAME,
++                          nss_test_ctx->nss_cmds);
++    assert_int_equal(ret, EOK);
++
++    /* Wait until the test finishes with EOK */
++    ret = test_ev_loop(nss_test_ctx->tctx);
++    assert_int_equal(ret, EOK);
++}
++
+ void nss_test_setup(void **state)
+ {
+     struct sss_test_conf_param params[] = {
+@@ -2096,6 +2223,8 @@ int main(int argc, const char *argv[])
+                                  nss_test_setup, nss_test_teardown),
+         unit_test_setup_teardown(test_nss_getorigbyname_extra_attrs,
+                                  nss_test_setup_extra_attr, nss_test_teardown),
++        unit_test_setup_teardown(test_nss_getorigbyname_multi_value_attrs,
++                                 nss_test_setup_extra_attr, nss_test_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.1.0
+
diff --git a/SOURCES/0171-nss-refactor-fill_orig.patch b/SOURCES/0171-nss-refactor-fill_orig.patch
new file mode 100644
index 0000000..1b3ecbe
--- /dev/null
+++ b/SOURCES/0171-nss-refactor-fill_orig.patch
@@ -0,0 +1,184 @@
+From a122ee37841392ceb8332d51728b54f9656225bc Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 20 Jan 2015 13:50:16 +0100
+Subject: [PATCH 171/172] nss: refactor fill_orig()
+
+The two loops in fill_orig were almost identical.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit a4d64002b5ca763622bde240d27797d361ba0388)
+---
+ src/responder/nss/nsssrv_cmd.c | 133 ++++++++++++++++++++---------------------
+ 1 file changed, 66 insertions(+), 67 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index b49807e3e349942c0617253fdf45b4ad43ba2ee1..6b9988548cdb25873e0c59503595e42d69b8d8e1 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4605,6 +4605,61 @@ static errno_t fill_sid(struct sss_packet *packet,
+     return EOK;
+ }
+ 
++static errno_t process_attr_list(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++                                 const char **attr_list,
++                                 struct sized_string **_keys,
++                                 struct sized_string **_vals,
++                                 size_t *array_size, size_t *sum, size_t *found)
++{
++    size_t c;
++    size_t d;
++    struct sized_string *keys;
++    struct sized_string *vals;
++    struct ldb_val *val;
++    struct ldb_message_element *el;
++
++    keys = *_keys;
++    vals = *_vals;
++
++    for (c = 0; attr_list[c] != NULL; c++) {
++        el = ldb_msg_find_element(msg, attr_list[c]);
++        if (el != NULL &&  el->num_values > 0) {
++            if (el->num_values > 1) {
++                *array_size += el->num_values;
++                keys = talloc_realloc(mem_ctx, keys, struct sized_string,
++                                      *array_size);
++                vals = talloc_realloc(mem_ctx, vals, struct sized_string,
++                                      *array_size);
++                if (keys == NULL || vals == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++                    return ENOMEM;
++                }
++            }
++            for (d = 0; d < el->num_values; d++) {
++                to_sized_string(&keys[*found], attr_list[c]);
++                *sum += keys[*found].len;
++                val = &(el->values[d]);
++                if (val == NULL || val->data == NULL
++                        || val->data[val->length] != '\0') {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Unexpected attribute value found for [%s].\n",
++                          attr_list[c]);
++                    return EINVAL;
++                }
++                to_sized_string(&vals[*found], (const char *)val->data);
++                *sum += vals[*found].len;
++
++                (*found)++;
++            }
++        }
++    }
++
++    *_keys = keys;
++    *_vals = vals;
++
++    return EOK;
++}
++
+ static errno_t fill_orig(struct sss_packet *packet,
+                          struct resp_ctx *rctx,
+                          enum sss_id_type id_type,
+@@ -4616,7 +4671,6 @@ static errno_t fill_orig(struct sss_packet *packet,
+     size_t blen;
+     size_t pctr = 0;
+     size_t c;
+-    size_t d;
+     size_t sum;
+     size_t found;
+     size_t array_size;
+@@ -4638,8 +4692,6 @@ static errno_t fill_orig(struct sss_packet *packet,
+     struct sized_string *keys;
+     struct sized_string *vals;
+     struct nss_ctx *nctx;
+-    struct ldb_message_element *el;
+-    struct ldb_val *val;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -4666,73 +4718,20 @@ static errno_t fill_orig(struct sss_packet *packet,
+ 
+     sum = 0;
+     found = 0;
+-    for (c = 0; orig_attr_list[c] != NULL; c++) {
+-        el = ldb_msg_find_element(msg, orig_attr_list[c]);
+-        if (el != NULL &&  el->num_values > 0) {
+-            if (el->num_values > 1) {
+-                array_size += el->num_values;
+-                keys = talloc_realloc(tmp_ctx, keys, struct sized_string,
+-                                      array_size);
+-                vals = talloc_realloc(tmp_ctx, vals, struct sized_string,
+-                                      array_size);
+-                if (keys == NULL || vals == NULL) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+-                    ret = ENOMEM;
+-                    goto done;
+-                }
+-            }
+-            for (d = 0; d < el->num_values; d++) {
+-                to_sized_string(&keys[found], orig_attr_list[c]);
+-                sum += keys[found].len;
+-                val = &(el->values[d]);
+-                if (val == NULL || val->data == NULL
+-                        || val->data[val->length] != '\0') {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Unexpected attribute value found for [%s].\n",
+-                          orig_attr_list[c]);
+-                    ret = EINVAL;
+-                    goto done;
+-                }
+-                to_sized_string(&vals[found], (const char *)val->data);
+-                sum += vals[found].len;
+ 
+-                found++;
+-            }
+-        }
++    ret = process_attr_list(tmp_ctx, msg, orig_attr_list, &keys, &vals,
++                            &array_size, &sum, &found);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "process_attr_list failed.\n");
++        goto done;
+     }
+ 
+-    for (c = 0; c < extra_attrs_count; c++) {
+-        el = ldb_msg_find_element(msg, extra_attrs_list[c]);
+-        if (el != NULL &&  el->num_values > 0) {
+-            if (el->num_values > 1) {
+-                array_size += el->num_values;
+-                keys = talloc_realloc(tmp_ctx, keys, struct sized_string,
+-                                      array_size);
+-                vals = talloc_realloc(tmp_ctx, vals, struct sized_string,
+-                                      array_size);
+-                if (keys == NULL || vals == NULL) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+-                    ret = ENOMEM;
+-                    goto done;
+-                }
+-            }
+-            for (d = 0; d < el->num_values; d++) {
+-                to_sized_string(&keys[found], extra_attrs_list[c]);
+-                sum += keys[found].len;
+-                val = &(el->values[d]);
+-                if (val == NULL || val->data == NULL
+-                        || val->data[val->length] != '\0') {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Unexpected attribute value found for [%s].\n",
+-                          orig_attr_list[c]);
+-                    ret = EINVAL;
+-                    goto done;
+-                }
+-                to_sized_string(&vals[found], (const char *)val->data);
+-                sum += vals[found].len;
+-
+-                found++;
+-            }
++    if (extra_attrs_count != 0) {
++        ret = process_attr_list(tmp_ctx, msg, extra_attrs_list, &keys, &vals,
++                                &array_size, &sum, &found);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "process_attr_list failed.\n");
++            goto done;
+         }
+     }
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0172-nss-Add-original-DN-and-memberOf-to-origbyname-reque.patch b/SOURCES/0172-nss-Add-original-DN-and-memberOf-to-origbyname-reque.patch
new file mode 100644
index 0000000..0c1ed1c
--- /dev/null
+++ b/SOURCES/0172-nss-Add-original-DN-and-memberOf-to-origbyname-reque.patch
@@ -0,0 +1,57 @@
+From ac9d460c61bf3bdb3aed5d96541d7e5baf8d9648 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 20 Jan 2015 12:51:57 +0100
+Subject: [PATCH 172/172] nss: Add original DN and memberOf to origbyname
+ request
+
+IPA HBAC evaluation relies on the original values for DN and memberOf
+attributes.
+
+Resolves https://fedorahosted.org/sssd/ticket/2560
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 7543052f562f157f7b17fdc46a6777d80c0cb3bd)
+---
+ src/responder/nss/nsssrv_cmd.c  | 4 ++++
+ src/tests/cmocka/test_nss_srv.c | 3 +--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 6b9988548cdb25873e0c59503595e42d69b8d8e1..324688eeeb90109a31391d01a9e1cd96707da7ed 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4160,6 +4160,8 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
+                                    SYSDB_AD_ACCOUNT_EXPIRES,
+                                    SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                    SYSDB_SSH_PUBKEY,
++                                   SYSDB_ORIG_DN,
++                                   SYSDB_ORIG_MEMBEROF,
+                                    SYSDB_DEFAULT_ATTRS, NULL};
+     const char **attrs;
+     bool user_found = false;
+@@ -4688,6 +4690,8 @@ static errno_t fill_orig(struct sss_packet *packet,
+                                     SYSDB_AD_ACCOUNT_EXPIRES,
+                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                     SYSDB_SSH_PUBKEY,
++                                    SYSDB_ORIG_DN,
++                                    SYSDB_ORIG_MEMBEROF,
+                                     NULL};
+     struct sized_string *keys;
+     struct sized_string *vals;
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index d7825e4384a4cc91407ed4bc66a1e190d558369f..ba84fccf718c1a3f4a8ff20a54d8e82c2aa58a1e 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -52,8 +52,7 @@ struct nss_test_ctx {
+     bool ncache_hit;
+ };
+ 
+-const char *global_extra_attrs[] = {"phone", "mobile", SYSDB_ORIG_MEMBEROF,
+-                                    NULL};
++const char *global_extra_attrs[] = {"phone", "mobile", NULL};
+ 
+ struct nss_test_ctx *nss_test_ctx;
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0173-Open-the-PAC-socket-from-krb5_child-before-dropping-.patch b/SOURCES/0173-Open-the-PAC-socket-from-krb5_child-before-dropping-.patch
new file mode 100644
index 0000000..a78837d
--- /dev/null
+++ b/SOURCES/0173-Open-the-PAC-socket-from-krb5_child-before-dropping-.patch
@@ -0,0 +1,83 @@
+From 8e650486102cb0c60f54e43acecacffdf3858ada Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 20 Jan 2015 18:06:49 +0100
+Subject: [PATCH 173/173] Open the PAC socket from krb5_child before dropping
+ root
+
+The PAC responder by default allows only connections from the root user.
+This patch opens the socket to the PAC responder before the krb5_child
+drops privileges so the connection seemingly comes from root.
+
+https://fedorahosted.org/sssd/ticket/2559
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 858e750c3d4fe54e50616a1ed1e101469503c070)
+---
+ src/providers/krb5/krb5_child.c |  8 ++++++++
+ src/sss_client/common.c         | 13 +++++++++++++
+ src/sss_client/sss_cli.h        |  6 ++++++
+ 3 files changed, 27 insertions(+)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 39cd62846e3c58d65a87f670768cf699ae191f14..4c2f81fb122baa42e38e6f3d0ec5e2cf80ac5fa6 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -2305,6 +2305,14 @@ static krb5_error_code privileged_krb5_setup(struct krb5_req *kr,
+         }
+     }
+ 
++    if (kr->send_pac) {
++        ret = sss_pac_check_and_open();
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot open the PAC responder socket\n");
++            /* Not fatal */
++        }
++    }
++
+     return 0;
+ }
+ 
+diff --git a/src/sss_client/common.c b/src/sss_client/common.c
+index 7c4bb7ab8769a72f943158366f358b108bfc3bdc..1b0fb1223f3509ef0b5aaf4a53851b868e12d6f0 100644
+--- a/src/sss_client/common.c
++++ b/src/sss_client/common.c
+@@ -749,6 +749,19 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
+     }
+ }
+ 
++int sss_pac_check_and_open(void)
++{
++    enum sss_status ret;
++    int errnop;
++
++    ret = sss_cli_check_socket(&errnop, SSS_PAC_SOCKET_NAME);
++    if (ret != SSS_STATUS_SUCCESS) {
++        return EIO;
++    }
++
++    return EOK;
++}
++
+ int sss_pac_make_request(enum sss_cli_command cmd,
+                          struct sss_cli_req_data *rd,
+                          uint8_t **repbuf, size_t *replen,
+diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
+index 2d909311cf2fa508a187ee4a29a45eae681dc705..6286077fcf25aead1dfcba5c6483e4ff8ae63b9f 100644
+--- a/src/sss_client/sss_cli.h
++++ b/src/sss_client/sss_cli.h
+@@ -511,6 +511,12 @@ int sss_pam_make_request(enum sss_cli_command cmd,
+                          int *errnop);
+ void sss_pam_close_fd(void);
+ 
++/* Checks access to the PAC responder and opens the socket, if available.
++ * Required for processes like krb5_child that need to open the socket
++ * before dropping privs.
++ */
++int sss_pac_check_and_open(void);
++
+ int sss_pac_make_request(enum sss_cli_command cmd,
+                          struct sss_cli_req_data *rd,
+                          uint8_t **repbuf, size_t *replen,
+-- 
+2.1.0
+
diff --git a/SOURCES/0174-views-fix-GID-overrride-for-mpg-domains.patch b/SOURCES/0174-views-fix-GID-overrride-for-mpg-domains.patch
new file mode 100644
index 0000000..9d5d603
--- /dev/null
+++ b/SOURCES/0174-views-fix-GID-overrride-for-mpg-domains.patch
@@ -0,0 +1,67 @@
+From 4663b9a486964533183533046f7093e9a3a9b75b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 21 Jan 2015 12:35:00 +0100
+Subject: [PATCH 174/176] views: fix GID overrride for mpg domains
+
+When adding a user sysdb internally adds a value to SYSDB_GIDNUM for
+mpg domain which might cause conflicts with the one we added to users
+git GID overrides. With this patch the override GID is added after the
+user is created but in the same transaction
+
+Releted to https://fedorahosted.org/sssd/ticket/2514
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit ba818cc39dfe94c2b8613f4badf7912811f0f737)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index e7c2d9bb97908746eb5ab6cacc6fc58d353dea06..a9c2f1ae3955bc3d2707bbcd186609a8d76b6169 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1748,6 +1748,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     char **del_groups_dns;
+     bool in_transaction = false;
+     int tret;
++    struct sysdb_attrs *gid_override_attrs = NULL;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -1939,7 +1940,16 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 if (ret == EOK || ret == ENOENT) {
+                     if ((orig_gid != 0 && orig_gid != attrs->a.user.pw_gid)
+                             || attrs->a.user.pw_uid != attrs->a.user.pw_gid) {
+-                        ret = sysdb_attrs_add_uint32(attrs->sysdb_attrs,
++
++                        gid_override_attrs = sysdb_new_attrs(tmp_ctx);
++                        if (gid_override_attrs == NULL) {
++                            DEBUG(SSSDBG_OP_FAILURE,
++                                  "sysdb_new_attrs failed.\n");
++                            ret = ENOMEM;
++                            goto done;
++                        }
++
++                        ret = sysdb_attrs_add_uint32(gid_override_attrs,
+                                                      SYSDB_GIDNUM,
+                                                      attrs->a.user.pw_gid);
+                         if (ret != EOK) {
+@@ -1973,6 +1983,15 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 goto done;
+             }
+ 
++            if (gid_override_attrs != NULL) {
++                ret = sysdb_set_user_attr(dom, name, gid_override_attrs,
++                                          SYSDB_MOD_REP);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n");
++                    goto done;
++                }
++            }
++
+             if (attrs->response_type == RESP_USER_GROUPLIST) {
+                 ret = get_sysdb_grouplist(tmp_ctx, dom->sysdb, dom, name,
+                                           &sysdb_grouplist);
+-- 
+2.1.0
+
diff --git a/SOURCES/0175-IPA-properly-handle-mixed-case-trusted-domains.patch b/SOURCES/0175-IPA-properly-handle-mixed-case-trusted-domains.patch
new file mode 100644
index 0000000..08b0a46
--- /dev/null
+++ b/SOURCES/0175-IPA-properly-handle-mixed-case-trusted-domains.patch
@@ -0,0 +1,214 @@
+From f3ddfba05798b694768316c82d609dec29e31642 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 22 Jan 2015 17:03:00 +0100
+Subject: [PATCH 175/176] IPA: properly handle mixed-case trusted domains
+
+In the SSSD cache domain names are handled case-sensitive. As a result
+fully-qualified names in RDN contain the domain part in the original
+spelling. When IPA client lookup up group-memberships on the IPA server
+via the extdom plugin the names returned are all lower case. To make
+sure new DNs are generated correctly the domain part must adjusted.
+
+Related to https://fedorahosted.org/sssd/ticket/2159
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 16 +++++++--
+ src/tests/cmocka/test_utils.c    | 44 ++++++++++++++++++++++++
+ src/util/domain_info_utils.c     | 72 ++++++++++++++++++++++++++++++++++++++++
+ src/util/util.h                  |  3 ++
+ 4 files changed, 133 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index a9c2f1ae3955bc3d2707bbcd186609a8d76b6169..997d0dce8d3225f83bbce506d349e4a8705e1e95 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1749,6 +1749,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     bool in_transaction = false;
+     int tret;
+     struct sysdb_attrs *gid_override_attrs = NULL;
++    char ** exop_grouplist;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -2000,8 +2001,19 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                     goto done;
+                 }
+ 
+-                ret = diff_string_lists(tmp_ctx, attrs->groups, sysdb_grouplist,
+-                                        &add_groups, &del_groups, NULL);
++                /* names returned by extdom exop will be all lower case, since
++                 * we handle domain names case sensitve in the cache we have
++                 * to make sure we use the right case. */
++                ret = fix_domain_in_name_list(tmp_ctx, dom, attrs->groups,
++                                              &exop_grouplist);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "fix_domain_name failed.\n");
++                    goto done;
++                }
++
++                ret = diff_string_lists(tmp_ctx, exop_grouplist,
++                                        sysdb_grouplist, &add_groups,
++                                        &del_groups, NULL);
+                 if (ret != EOK) {
+                     DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n");
+                     goto done;
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index 5dc00c4cc9707776fabda50ad1eab8e582b16c0f..dc6e35dc02204714c5befbf4d67e7e7cbd8f4af1 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -1030,6 +1030,48 @@ void test_sss_write_krb5_conf_snippet(void **state)
+     free(path);
+ }
+ 
++
++void test_fix_domain_in_name_list(void **state)
++{
++    struct name_init_test_ctx *test_ctx;
++
++    int ret;
++    struct sss_domain_info *sd;
++    struct sss_domain_info *dom;
++    const char *in[] = { "abc@test.case.dom", "def@TEST.case.DOM", NULL};
++    char **out = NULL;
++
++    test_ctx = talloc_get_type(*state, struct name_init_test_ctx);
++    assert_non_null(test_ctx);
++
++    ret = confdb_get_domains(test_ctx->confdb, &dom);
++    assert_int_equal(ret, EOK);
++
++    ret = sss_names_init(dom, test_ctx->confdb, NULL, &dom->names);
++    assert_int_equal(ret, EOK);
++
++    sd = talloc_zero(test_ctx, struct sss_domain_info);
++    assert_non_null(sd);
++    sd->name = talloc_strdup(sd, "TesT.CasE.DoM");
++    assert_non_null(sd->name);
++    sd->names = dom->names;
++    DLIST_ADD(dom->subdomains, sd);
++    sd->parent = dom;
++
++    ret = fix_domain_in_name_list(test_ctx, dom, discard_const(in), &out);
++    assert_int_equal(ret, EOK);
++    assert_non_null(out);
++    assert_non_null(out[0]);
++    assert_string_equal(out[0], "abc@TesT.CasE.DoM");
++    assert_non_null(out[1]);
++    assert_string_equal(out[1], "def@TesT.CasE.DoM");
++    assert_null(out[2]);
++
++    talloc_free(out);
++    talloc_free(sd);
++    talloc_free(dom);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -1078,6 +1120,8 @@ int main(int argc, const char *argv[])
+                                  setup_add_strings_lists,
+                                  teardown_add_strings_lists),
+         unit_test(test_sss_write_krb5_conf_snippet),
++        unit_test_setup_teardown(test_fix_domain_in_name_list,
++                                 confdb_test_setup, confdb_test_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index e04b905768078c503168f27327f974c0f19a6775..e0f1120e3c96757b0ad623b7dd6d43af2e643589 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -777,3 +777,75 @@ done:
+ 
+     return ret;
+ }
++
++errno_t fix_domain_in_name_list(TALLOC_CTX *mem_ctx,
++                                struct sss_domain_info *dom,
++                                char **in, char ***_out)
++{
++    int ret;
++    size_t c;
++    TALLOC_CTX *tmp_ctx;
++    char **out;
++    struct sss_domain_info *head;
++    struct sss_domain_info *out_domain;
++    char *in_name;
++    char *in_domain;
++
++    head = get_domains_head(dom);
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    /* count elements */
++    for (c = 0; in[c] != NULL; c++);
++
++    out = talloc_zero_array(tmp_ctx, char *, c + 1);
++    if (out == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    for (c = 0; in[c] != NULL; c++) {
++        ret = sss_parse_name(tmp_ctx, head->names, in[c], &in_domain,
++                              &in_name);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sss_parse_name failed for [%s].\n",
++                                      in[c]);
++            goto done;
++        }
++
++        if (in_domain == NULL) {
++            out[c] = talloc_strdup(out, in_name);
++        } else {
++            out_domain = find_domain_by_name(head, in_domain, true);
++            if (out_domain == NULL) {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Cannot find domain with name [%s].\n", in_domain);
++                ret = EINVAL;
++                goto done;
++            }
++
++            out[c] = sss_tc_fqname(out, head->names, out_domain, in_name);
++        }
++
++        if (out[c] == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "%s failed.\n",
++                  in_domain == NULL ? "talloc_strdup" : "sss_tc_fqname");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    *_out = talloc_steal(mem_ctx, out);
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
+diff --git a/src/util/util.h b/src/util/util.h
+index 45efd1aef94c2e058a435933e7c41adaecc676e2..23624c8156a053bc6c30bda9796029af3da62d3a 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -589,6 +589,9 @@ errno_t get_dom_names(TALLOC_CTX *mem_ctx,
+                       char ***_dom_names,
+                       int *_dom_names_count);
+ 
++errno_t fix_domain_in_name_list(TALLOC_CTX *mem_ctx,
++                                struct sss_domain_info *dom,
++                                char **in, char ***_out);
+ /* from util_lock.c */
+ errno_t sss_br_lock_file(int fd, size_t start, size_t len,
+                          int num_tries, useconds_t wait);
+-- 
+2.1.0
+
diff --git a/SOURCES/0176-nss-fix-SID-lookups.patch b/SOURCES/0176-nss-fix-SID-lookups.patch
new file mode 100644
index 0000000..28b9dfc
--- /dev/null
+++ b/SOURCES/0176-nss-fix-SID-lookups.patch
@@ -0,0 +1,40 @@
+From 660d1493ad63cc39f99e3d2fb981598fab404b82 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 22 Jan 2015 18:30:04 +0100
+Subject: [PATCH 176/176] nss: fix SID lookups
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+https://fedorahosted.org/sssd/ticket/2566
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/responder/nss/nsssrv_cmd.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 324688eeeb90109a31391d01a9e1cd96707da7ed..da24ce1730999518b2e1bc52604940ee979072e3 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4503,8 +4503,16 @@ static errno_t nss_cmd_getbysid_search(struct nss_dom_ctx *dctx)
+                 DEBUG(SSSDBG_MINOR_FAILURE,
+                       "Cannot set negative cache for %s\n", cmdctx->secid);
+             }
++
++            return ENOENT;
+         }
+-        return ENOENT;
++
++        dctx->res = talloc_zero(cmdctx, struct ldb_result);
++        if (dctx->res == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
++            return ENOMEM;
++        }
++        /* Fall through and call the backend */
+     } else if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache!\n");
+         return EIO;
+-- 
+2.1.0
+
diff --git a/SOURCES/0177-sysdb-remove-ghosts-in-all-sub-domains-as-well.patch b/SOURCES/0177-sysdb-remove-ghosts-in-all-sub-domains-as-well.patch
new file mode 100644
index 0000000..2f46254
--- /dev/null
+++ b/SOURCES/0177-sysdb-remove-ghosts-in-all-sub-domains-as-well.patch
@@ -0,0 +1,39 @@
+From 8a18e0f42e45a29ca78f5ec2c21987cd8df3474d Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 23 Jan 2015 14:39:07 +0100
+Subject: [PATCH 177/177] sysdb: remove ghosts in all sub-domains as well
+
+If a user is a member is a group in a different sub-domain, e.g with
+universal groups in AD, the ghost attribute might not be properly
+removed from the group object if the user is resolved. The reason is
+that only groups from the domain of the user were search for ghost
+attributes. This patch increases the search-base to all sub-domains of
+the configured SSSD domain.
+
+Resolves https://fedorahosted.org/sssd/ticket/2567
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit fc2146c108e28d50bbf691925cedf9592142dd14)
+---
+ src/db/sysdb_ops.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index b12540b68d1c81c419455416294f3449dd84914e..0c254d8cdad1144c32aad7e470fa2a35cd24b38b 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -1219,8 +1219,9 @@ sysdb_remove_ghostattr_from_groups(struct sss_domain_info *domain,
+         ERROR_OUT(ret, EINVAL, done);
+     }
+ 
+-    tmpdn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+-                            SYSDB_TMPL_GROUP_BASE, domain->name);
++    /* To cover cross-domain group-membership we must search in all
++     * sub-domains. */
++    tmpdn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, SYSDB_BASE);
+     if (!tmpdn) {
+         ret = ENOMEM;
+         goto done;
+-- 
+2.1.0
+
diff --git a/SOURCES/0178-IPA-Rename-user_dom-into-obj_dom.patch b/SOURCES/0178-IPA-Rename-user_dom-into-obj_dom.patch
new file mode 100644
index 0000000..f6032a8
--- /dev/null
+++ b/SOURCES/0178-IPA-Rename-user_dom-into-obj_dom.patch
@@ -0,0 +1,113 @@
+From 943d1b32aeb8cbddccbe3a499504ec07955937b5 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 30 Oct 2014 17:38:19 +0100
+Subject: [PATCH 178/181] IPA: Rename user_dom into obj_dom
+
+There was a variable in the IPA subdomain code named user_dom, however,
+it was used in code that processes both users and groups, which was
+confusing.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains_id.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index cf0cddf6884295268b30fc8e0209b543c1699297..79285548d9470b34d66b366367fb69ef57710f83 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -539,7 +539,7 @@ struct ipa_get_ad_acct_state {
+     struct ipa_id_ctx *ipa_ctx;
+     struct be_req *be_req;
+     struct be_acct_req *ar;
+-    struct sss_domain_info *user_dom;
++    struct sss_domain_info *obj_dom;
+     char *object_sid;
+     struct sysdb_attrs *override_attrs;
+     struct ldb_message *obj_msg;
+@@ -581,15 +581,15 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
+     state->override_attrs = override_attrs;
+ 
+     /* This can only be a subdomain request, verify subdomain */
+-    state->user_dom = find_domain_by_name(ipa_ctx->sdap_id_ctx->be->domain,
+-                                          ar->domain, true);
+-    if (state->user_dom == NULL) {
++    state->obj_dom = find_domain_by_name(ipa_ctx->sdap_id_ctx->be->domain,
++                                         ar->domain, true);
++    if (state->obj_dom == NULL) {
+         ret = EINVAL;
+         goto fail;
+     }
+ 
+     /* Let's see if this subdomain has a ad_id_ctx */
+-    ad_id_ctx = ipa_get_ad_id_ctx(ipa_ctx, state->user_dom);
++    ad_id_ctx = ipa_get_ad_id_ctx(ipa_ctx, state->obj_dom);
+     if (ad_id_ctx == NULL) {
+         ret = EINVAL;
+         goto fail;
+@@ -604,7 +604,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
+     switch (state->ar->entry_type & BE_REQ_TYPE_MASK) {
+     case BE_REQ_INITGROUPS:
+     case BE_REQ_GROUP:
+-        clist = ad_gc_conn_list(req, ad_id_ctx, state->user_dom);
++        clist = ad_gc_conn_list(req, ad_id_ctx, state->obj_dom);
+         if (clist == NULL) {
+             ret = ENOMEM;
+             goto fail;
+@@ -621,7 +621,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
+     }
+ 
+     /* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */
+-    sdom = sdap_domain_get(sdap_id_ctx->opts, state->user_dom);
++    sdom = sdap_domain_get(sdap_id_ctx->opts, state->obj_dom);
+     if (sdom == NULL) {
+         ret = EIO;
+         goto fail;
+@@ -988,7 +988,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
+         return;
+     }
+ 
+-    ret = get_object_from_cache(state, state->user_dom, state->ar,
++    ret = get_object_from_cache(state, state->obj_dom, state->ar,
+                                 &state->obj_msg);
+     if (ret == ENOENT) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Object not found, ending request\n");
+@@ -999,7 +999,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
+         goto fail;
+     }
+ 
+-    ret = apply_subdomain_homedir(state, state->user_dom,
++    ret = apply_subdomain_homedir(state, state->obj_dom,
+                                   state->obj_msg);
+     if (ret != EOK && ret != ENOENT) {
+         DEBUG(SSSDBG_OP_FAILURE,
+@@ -1024,7 +1024,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
+         }
+ 
+         ret = get_be_acct_req_for_sid(state, state->object_sid,
+-                                      state->user_dom->name, &ar);
++                                      state->obj_dom->name, &ar);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
+             goto fail;
+@@ -1103,7 +1103,7 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+     if (state->override_attrs != NULL) {
+         /* We are in ipa-server-mode, so the view is the default view by
+          * definition. */
+-        ret = sysdb_apply_default_override(state->user_dom,
++        ret = sysdb_apply_default_override(state->obj_dom,
+                                            state->override_attrs,
+                                            state->obj_msg->dn);
+         if (ret != EOK) {
+@@ -1121,7 +1121,7 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+      * users. */
+     subreq = ipa_get_ad_memberships_send(state, state->ev, state->ar,
+                                          state->ipa_ctx->server_mode,
+-                                         state->user_dom,
++                                         state->obj_dom,
+                                          state->ipa_ctx->sdap_id_ctx,
+                                          state->ipa_ctx->server_mode->realm);
+     if (subreq == NULL) {
+-- 
+2.1.0
+
diff --git a/SOURCES/0179-IPA-resolve-IPA-group-memberships-for-AD-users.patch b/SOURCES/0179-IPA-resolve-IPA-group-memberships-for-AD-users.patch
new file mode 100644
index 0000000..b5f9b2f
--- /dev/null
+++ b/SOURCES/0179-IPA-resolve-IPA-group-memberships-for-AD-users.patch
@@ -0,0 +1,107 @@
+From a3fc740fbfbfd5a2771a3872cf03287879c957c3 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 22 Jan 2015 21:20:25 +0100
+Subject: [PATCH 179/181] IPA: resolve IPA group-memberships for AD users
+
+So far only for initgroups requests the IPA group memberships where
+resolved for AD users and due to
+6fac5e5f0c54a0f92872ce1450606cfcb577a920 those memberships are not
+overridden by other request. But it turned out that the originalMemberOf
+attributes related to the IPA group memberships can be overridden by
+user lookups.  Since the originalMemberOf attribute is important in the
+HBAC evaluation this patch makes sure that the originalMemberOf
+attribute is not removed but updated during user lookups.
+
+Related to https://fedorahosted.org/sssd/ticket/2560
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 63748c69a2c6785d949c82f94749704e0408e5a7)
+---
+ src/providers/ipa/ipa_subdomains_ext_groups.c |  3 +-
+ src/providers/ipa/ipa_subdomains_id.c         | 44 +++++++++++++++++++++++++--
+ 2 files changed, 44 insertions(+), 3 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
+index 6feca44de537f4c721bfe4ea5e3fde1b946e4aac..b9690bdb682a9348340d22d4b24f0f284671610d 100644
+--- a/src/providers/ipa/ipa_subdomains_ext_groups.c
++++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
+@@ -452,7 +452,8 @@ struct tevent_req *ipa_get_ad_memberships_send(TALLOC_CTX *mem_ctx,
+     state->domain = domain;
+     state->dp_error = -1;
+ 
+-    if ((ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS
++    if (((ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS
++            && (ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_USER)
+             || ar->filter_type != BE_FILTER_NAME) {
+         DEBUG(SSSDBG_OP_FAILURE, "Unsupported request type.\n");
+         ret = EINVAL;
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 79285548d9470b34d66b366367fb69ef57710f83..c8714a216daff7506f00248e25c281529d0479c4 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -1099,6 +1099,8 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+                                                 struct ipa_get_ad_acct_state);
+     errno_t ret;
+     struct tevent_req *subreq;
++    const char *obj_name;
++    int entry_type;
+ 
+     if (state->override_attrs != NULL) {
+         /* We are in ipa-server-mode, so the view is the default view by
+@@ -1112,13 +1114,51 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+         }
+     }
+ 
+-    if ((state->ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS) {
++    entry_type = (state->ar->entry_type & BE_REQ_TYPE_MASK);
++    if (entry_type != BE_REQ_INITGROUPS
++            && entry_type != BE_REQ_USER
++            && entry_type != BE_REQ_BY_SECID) {
+         tevent_req_done(req);
+         return EOK;
+     }
+ 
++    /* Replace ID with name in search filter */
++    if ((entry_type == BE_REQ_USER && state->ar->filter_type == BE_FILTER_IDNUM)
++            || entry_type == BE_REQ_BY_SECID) {
++        if (state->obj_msg == NULL) {
++            ret = get_object_from_cache(state, state->obj_dom, state->ar,
++                                        &state->obj_msg);
++            if (ret == ENOENT) {
++                DEBUG(SSSDBG_MINOR_FAILURE,
++                      "Object not found, ending request\n");
++                tevent_req_done(req);
++                return EOK;
++            } else if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n");
++                return ret;
++            }
++        }
++
++        obj_name = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_NAME,
++                                               NULL);
++        if (obj_name == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Cached object has no name.\n");
++            return EINVAL;
++        }
++
++        state->ar->filter_value = talloc_strdup(state->ar, obj_name);
++        if (state->ar->filter_value == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++            return ENOMEM;
++        }
++        state->ar->filter_type = BE_FILTER_NAME;
++        state->ar->entry_type = BE_REQ_USER;
++    }
++
++
+     /* For initgroups request we have to check IPA group memberships of AD
+-     * users. */
++     * users. This has to be done for other user-request as well to make sure
++     * IPA related attributes are not overwritten. */
+     subreq = ipa_get_ad_memberships_send(state, state->ev, state->ar,
+                                          state->ipa_ctx->server_mode,
+                                          state->obj_dom,
+-- 
+2.1.0
+
diff --git a/SOURCES/0180-IPA-process_members-add-ghosts-only-once.patch b/SOURCES/0180-IPA-process_members-add-ghosts-only-once.patch
new file mode 100644
index 0000000..6b795c2
--- /dev/null
+++ b/SOURCES/0180-IPA-process_members-add-ghosts-only-once.patch
@@ -0,0 +1,38 @@
+From 11277f49cabdf4b7b49dba05dc4db9c2e5ffe53b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 21 Jan 2015 16:33:59 +0100
+Subject: [PATCH 180/181] IPA: process_members() add ghosts only once
+
+Since ghost entries might not be properly removed on the IPA server
+(https://fedorahosted.org/sssd/ticket/2567) chances are that during
+extdom group lookups a single user is returned multiple time. This patch
+removes the duplicates before trying to write the data to the cache.
+
+Related to https://fedorahosted.org/sssd/ticket/2159
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 60f11e2fa1f63cd40ebace525ad823b0360fac94)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 997d0dce8d3225f83bbce506d349e4a8705e1e95..6f8d5687d66717ba62e83da27dd6b23bc12151fb 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1299,8 +1299,10 @@ static errno_t process_members(struct sss_domain_info *domain,
+                 DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n",
+                                         members[c]);
+ 
+-                ret = sysdb_attrs_add_string(group_attrs, SYSDB_GHOST,
+-                                             members[c]);
++                /* There were cases where the server returned the same user
++                 * multiple times */
++                ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST,
++                                                  members[c]);
+                 if (ret != EOK) {
+                     DEBUG(SSSDBG_OP_FAILURE,
+                           "sysdb_attrs_add_string failed.\n");
+-- 
+2.1.0
+
diff --git a/SOURCES/0181-IPA-Use-attr-s-dom-for-users-too.patch b/SOURCES/0181-IPA-Use-attr-s-dom-for-users-too.patch
new file mode 100644
index 0000000..83f9296
--- /dev/null
+++ b/SOURCES/0181-IPA-Use-attr-s-dom-for-users-too.patch
@@ -0,0 +1,61 @@
+From 8ffc33de4e1ea85159ee72178efafaac060a8c3b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 26 Jan 2015 20:29:37 +0100
+Subject: [PATCH 181/181] IPA: Use attr's dom for users, too
+
+The 'dom' pointer points to domain of the main object being saved. In
+case of group, dom points to the domain where the group resides. But
+when saving members, each members might be from a different domain, so we
+need to find every member's domain based on the attributes.
+
+Also don't use Yoda style in conditions.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit b2c5e98def89a0c3d16f5cf7e07ce2020338b540)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 6f8d5687d66717ba62e83da27dd6b23bc12151fb..35bd303d4aa3651e80c70297507bdc85d05bfbde 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1819,6 +1819,17 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+         }
+     }
+ 
++    if (strcmp(dom->name, attrs->domain_name) != 0) {
++        dom = find_domain_by_name(get_domains_head(dom),
++                                  attrs->domain_name, true);
++        if (dom == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                    "Cannot find domain: [%s]\n", attrs->domain_name);
++            ret = EINVAL;
++            goto done;
++        }
++    }
++
+     switch (attrs->response_type) {
+         case RESP_USER:
+         case RESP_USER_GROUPLIST:
+@@ -2057,17 +2068,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+         case RESP_GROUP_MEMBERS:
+             type = SYSDB_MEMBER_GROUP;
+ 
+-            if (0 != strcmp(dom->name, attrs->domain_name)) {
+-                dom = find_domain_by_name(get_domains_head(dom),
+-                                          attrs->domain_name, true);
+-                if (dom == NULL) {
+-                    DEBUG(SSSDBG_OP_FAILURE,
+-                          "Cannot find domain: [%s]\n", attrs->domain_name);
+-                    ret = EINVAL;
+-                    goto done;
+-                }
+-            }
+-
+             if (name == NULL) {
+                 name = attrs->a.group.gr_name;
+             }
+-- 
+2.1.0
+
diff --git a/SOURCES/0182-SELINUX-Call-setuid-0-setgid-0-to-also-set-the-real-.patch b/SOURCES/0182-SELINUX-Call-setuid-0-setgid-0-to-also-set-the-real-.patch
new file mode 100644
index 0000000..92e600e
--- /dev/null
+++ b/SOURCES/0182-SELINUX-Call-setuid-0-setgid-0-to-also-set-the-real-.patch
@@ -0,0 +1,53 @@
+From a77f0b5c39b1f6c497b2b5c6c072d2f4f6e7a745 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 26 Jan 2015 15:15:29 +0100
+Subject: [PATCH 182/183] SELINUX: Call setuid(0)/setgid(0) to also set the
+ real IDs to root
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+https://fedorahosted.org/sssd/ticket/2564
+
+libselinux uses many access(2) calls and access() uses the real UID,
+not the effective UID for the check. Therefore, the setuid selinux_child,
+which only has effective UID of root would fail the check.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+(cherry picked from commit 486f0d5227a9b81815aaaf7d9a2c39aafcbfdf6a)
+---
+ src/providers/ipa/selinux_child.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
+index a38ffcb26f890349f47478063103e603fe6304cf..bda89c847dc160e1d667d333ee515cf7260e7db8 100644
+--- a/src/providers/ipa/selinux_child.c
++++ b/src/providers/ipa/selinux_child.c
+@@ -197,7 +197,23 @@ int main(int argc, const char *argv[])
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n");
+     DEBUG(SSSDBG_TRACE_INTERNAL,
+-          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
++          "Running with effective IDs: [%"SPRIuid"][%"SPRIgid"].\n",
++          geteuid(), getegid());
++
++    /* libsemanage calls access(2) which works with real IDs, not effective.
++     * We need to switch also the real ID to 0.
++     */
++    if (getuid() != 0) {
++        setuid(0);
++    }
++
++    if (getgid() != 0) {
++        setgid(0);
++    }
++
++    DEBUG(SSSDBG_TRACE_INTERNAL,
++          "Running with real IDs [%"SPRIuid"][%"SPRIgid"].\n",
++          getuid(), getgid());
+ 
+     main_ctx = talloc_new(NULL);
+     if (main_ctx == NULL) {
+-- 
+2.1.0
+
diff --git a/SOURCES/0183-SELINUX-Set-and-reset-umask-when-caling-set_seuser-f.patch b/SOURCES/0183-SELINUX-Set-and-reset-umask-when-caling-set_seuser-f.patch
new file mode 100644
index 0000000..2753cc8
--- /dev/null
+++ b/SOURCES/0183-SELINUX-Set-and-reset-umask-when-caling-set_seuser-f.patch
@@ -0,0 +1,72 @@
+From 20dd4c33d226862d124b2f010181550e820df5f8 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 27 Jan 2015 11:12:18 +0100
+Subject: [PATCH 183/183] SELINUX: Set and reset umask when caling set_seuser
+ from deamon code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+https://fedorahosted.org/sssd/ticket/2563
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+(cherry picked from commit 8f78b6442f3176ee43aa06704a3adb9f4ac625d6)
+---
+ src/providers/ipa/selinux_child.c | 18 +++++++++++++++++-
+ src/util/util.h                   |  4 ++++
+ 2 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
+index bda89c847dc160e1d667d333ee515cf7260e7db8..d4670389667607972dd6f072b5ddfda5973e082b 100644
+--- a/src/providers/ipa/selinux_child.c
++++ b/src/providers/ipa/selinux_child.c
+@@ -135,6 +135,22 @@ static errno_t prepare_response(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++static int sc_set_seuser(const char *login_name, const char *seuser_name,
++                         const char *mls)
++{
++    int ret;
++    mode_t old_mask;
++
++    /* This is a workaround for
++     * https://bugzilla.redhat.com/show_bug.cgi?id=1186422 to make sure
++     * the directories are created with the expected permissions
++     */
++    old_mask = umask(0);
++    ret = set_seuser(login_name, seuser_name, mls);
++    umask(old_mask);
++    return ret;
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int opt;
+@@ -256,7 +272,7 @@ int main(int argc, const char *argv[])
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "performing selinux operations\n");
+ 
+-    ret = set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range);
++    ret = sc_set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set SELinux login context.\n");
+         goto fail;
+diff --git a/src/util/util.h b/src/util/util.h
+index 23624c8156a053bc6c30bda9796029af3da62d3a..bf3a9a057aed77e93949370f8651af2631d91432 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -628,6 +628,10 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+ errno_t restore_creds(struct sss_creds *saved_creds);
+ 
+ /* from sss_semanage.c */
++/* Please note that libsemange relies on files and directories created with
++ * certain permissions. Therefore the caller should make sure the umask is
++ * not too restricted (especially when called from the daemon code).
++ */
+ int set_seuser(const char *login_name, const char *seuser_name,
+                const char *mlsrange);
+ int del_seuser(const char *login_name);
+-- 
+2.1.0
+
diff --git a/SOURCES/0184-LDAP-Add-UUID-when-saving-incomplete-groups.patch b/SOURCES/0184-LDAP-Add-UUID-when-saving-incomplete-groups.patch
new file mode 100644
index 0000000..5a0250d
--- /dev/null
+++ b/SOURCES/0184-LDAP-Add-UUID-when-saving-incomplete-groups.patch
@@ -0,0 +1,171 @@
+From 1c1551628ca2d1f7a6cc0938f0cf79c2b2ce6e8b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 27 Jan 2015 16:02:33 +0100
+Subject: [PATCH 184/188] LDAP: Add UUID when saving incomplete groups
+
+Related to:
+https://fedorahosted.org/sssd/ticket/2571
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 108db0e3b9e06e530364ef8228634f5e3f6bd3b5)
+---
+ src/db/sysdb.h                                |  1 +
+ src/db/sysdb_ops.c                            |  6 ++++++
+ src/providers/ldap/sdap_async_initgroups.c    | 16 +++++++++++++---
+ src/providers/ldap/sdap_async_initgroups_ad.c |  2 +-
+ src/tests/sysdb-tests.c                       | 16 ++++++++--------
+ 5 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 9e33fee37a352498ed0c987dc2ae0da3500d63d5..cf6028acb806d5d4eedf4cf0680cf4ac9fd6368d 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -797,6 +797,7 @@ int sysdb_add_incomplete_group(struct sss_domain_info *domain,
+                                gid_t gid,
+                                const char *original_dn,
+                                const char *sid_str,
++                               const char *uuid,
+                                bool posix,
+                                time_t now);
+ 
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 0c254d8cdad1144c32aad7e470fa2a35cd24b38b..6085762dcc5585114dd3049dd3a365856cb6b190 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -1610,6 +1610,7 @@ int sysdb_add_incomplete_group(struct sss_domain_info *domain,
+                                gid_t gid,
+                                const char *original_dn,
+                                const char *sid_str,
++                               const char *uuid,
+                                bool posix,
+                                time_t now)
+ {
+@@ -1656,6 +1657,11 @@ int sysdb_add_incomplete_group(struct sss_domain_info *domain,
+         if (ret) goto done;
+     }
+ 
++    if (uuid) {
++        ret = sysdb_attrs_add_string(attrs, SYSDB_UUID, uuid);
++        if (ret) goto done;
++    }
++
+     ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
+ 
+ done:
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index d3e080013ec99c18648c6a57e478d50eb3b666f1..6b3179d2d6bb30b3b00aa35b07da42de3cf08a34 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -41,6 +41,7 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+     int i, mi, ai;
+     const char *groupname;
+     const char *original_dn;
++    const char *uuid = NULL;
+     char **missing;
+     gid_t gid;
+     int ret;
+@@ -191,15 +192,24 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+                                              &original_dn);
+                 if (ret) {
+                     DEBUG(SSSDBG_FUNC_DATA,
+-                          "The group has no name original DN\n");
++                          "The group has no original DN\n");
+                     original_dn = NULL;
+                 }
+ 
++                ret = sysdb_attrs_get_string(ldap_groups[ai],
++                                             SYSDB_UUID,
++                                             &uuid);
++                if (ret) {
++                    DEBUG(SSSDBG_FUNC_DATA,
++                          "The group has no UUID\n");
++                    uuid = NULL;
++                }
++
+                 DEBUG(SSSDBG_TRACE_INTERNAL,
+                       "Adding fake group %s to sysdb\n", groupname);
+                 ret = sysdb_add_incomplete_group(domain, groupname, gid,
+-                                                 original_dn, sid_str, posix,
+-                                                 now);
++                                                 original_dn, sid_str,
++                                                 uuid, posix, now);
+                 if (ret != EOK) {
+                     goto done;
+                 }
+diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
+index a533279f680d5cabc096cb9e64cfdb1057c5c799..1b8c8d981ea14ac0fca0903f16296c8a6701c5dd 100644
+--- a/src/providers/ldap/sdap_async_initgroups_ad.c
++++ b/src/providers/ldap/sdap_async_initgroups_ad.c
+@@ -929,7 +929,7 @@ static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq)
+              * it will replace this temporary entry. */
+             name = sid;
+             ret = sysdb_add_incomplete_group(domain, name, gid,
+-                                             NULL, sid, false, now);
++                                             NULL, sid, NULL, false, now);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_MINOR_FAILURE, "Could not create incomplete "
+                                              "group: [%s]\n", strerror(ret));
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index 0c49d0ca7ca89d772f2a7df2ddd4acc20c4e312c..a78cf713fbe165204708bcf787b998acab0b7ca5 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -266,7 +266,7 @@ static int test_add_incomplete_group(struct test_data *data)
+     int ret;
+ 
+     ret = sysdb_add_incomplete_group(data->ctx->domain, data->groupname,
+-                                     data->gid, NULL, NULL, true, 0);
++                                     data->gid, NULL, NULL, NULL, true, 0);
+     return ret;
+ }
+ 
+@@ -3986,8 +3986,8 @@ START_TEST(test_odd_characters)
+     /* ===== Groups ===== */
+ 
+     /* Add */
+-    ret = sysdb_add_incomplete_group(test_ctx->domain,
+-                                     odd_groupname, 20000, NULL, NULL, true, 0);
++    ret = sysdb_add_incomplete_group(test_ctx->domain, odd_groupname,
++                                     20000, NULL, NULL, NULL, true, 0);
+     fail_unless(ret == EOK, "sysdb_add_incomplete_group error [%d][%s]",
+                             ret, strerror(ret));
+ 
+@@ -4143,8 +4143,8 @@ START_TEST(test_SSS_LDB_SEARCH)
+     fail_if(nonexist_dn == NULL, "sysdb_group_dn failed");
+ 
+     /* Add */
+-    ret = sysdb_add_incomplete_group(test_ctx->domain,
+-                                     groupname, 20000, NULL, NULL, true, 0);
++    ret = sysdb_add_incomplete_group(test_ctx->domain, groupname,
++                                     20000, NULL, NULL, NULL, true, 0);
+     fail_unless(ret == EOK, "sysdb_add_incomplete_group error [%d][%s]",
+                 ret, strerror(ret));
+ 
+@@ -4935,14 +4935,14 @@ START_TEST(test_sysdb_original_dn_case_insensitive)
+     ret = sysdb_add_incomplete_group(test_ctx->domain,
+                                      "case_sensitive_group1", 29000,
+                                      "cn=case_sensitive_group1,cn=example,cn=com",
+-                                     NULL, true, 0);
++                                     NULL, NULL, true, 0);
+     fail_unless(ret == EOK, "sysdb_add_incomplete_group error [%d][%s]",
+                             ret, strerror(ret));
+ 
+     ret = sysdb_add_incomplete_group(test_ctx->domain,
+                                      "case_sensitive_group2", 29001,
+                                      "cn=CASE_SENSITIVE_GROUP1,cn=EXAMPLE,cn=COM",
+-                                     NULL, true, 0);
++                                     NULL, NULL, true, 0);
+     fail_unless(ret == EOK, "sysdb_add_incomplete_group error [%d][%s]",
+                             ret, strerror(ret));
+ 
+@@ -4978,7 +4978,7 @@ START_TEST(test_sysdb_search_sid_str)
+     ret = sysdb_add_incomplete_group(test_ctx->domain,
+                                      "group", 29000,
+                                      "cn=group,cn=example,cn=com",
+-                                     "S-1-2-3-4", true, 0);
++                                     "S-1-2-3-4", NULL, true, 0);
+     fail_unless(ret == EOK, "sysdb_add_incomplete_group error [%d][%s]",
+                             ret, strerror(ret));
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0185-IPA-Resolve-IPA-user-groups-overrideDN-in-non-defaul.patch b/SOURCES/0185-IPA-Resolve-IPA-user-groups-overrideDN-in-non-defaul.patch
new file mode 100644
index 0000000..d50be0a
--- /dev/null
+++ b/SOURCES/0185-IPA-Resolve-IPA-user-groups-overrideDN-in-non-defaul.patch
@@ -0,0 +1,395 @@
+From 85d5f67d94ea38a3dc920b3fe85aba7385930b81 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 26 Jan 2015 23:25:17 +0100
+Subject: [PATCH 185/188] IPA: Resolve IPA user groups' overrideDN in
+ non-default view
+
+When the client is in a non-default view, we need to store the override
+data, in particular the overrideDN as well.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2571
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit b2c3722b9a1eaf265f6b102043958f6d4378788c)
+---
+ src/providers/ipa/ipa_id.c | 318 ++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 311 insertions(+), 7 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index 3d6861eeb562683518d425616b0e5c413cddba0b..cc6abcf8721e3f05526bf62063f0cbdc7c1c257b 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -286,6 +286,239 @@ static int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error)
+     return EOK;
+ }
+ 
++struct ipa_initgr_get_overrides_state {
++    struct tevent_context *ev;
++    struct ipa_id_ctx *ipa_ctx;
++    struct sss_domain_info *user_dom;
++    const char *realm;
++
++    struct ldb_message **groups;
++    size_t group_count;
++    size_t group_idx;
++    struct be_acct_req *ar;
++
++    int dp_error;
++};
++
++static int ipa_initgr_get_overrides_step(struct tevent_req *req);
++
++static struct tevent_req *
++ipa_initgr_get_overrides_send(TALLOC_CTX *memctx,
++                             struct tevent_context *ev,
++                             struct ipa_id_ctx *ipa_ctx,
++                             struct sss_domain_info *user_dom,
++                             size_t groups_count,
++                             struct ldb_message **groups)
++{
++    int ret;
++    struct tevent_req *req;
++    struct ipa_initgr_get_overrides_state *state;
++
++    req = tevent_req_create(memctx, &state,
++                            struct ipa_initgr_get_overrides_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
++        return NULL;
++    }
++    state->ev = ev;
++    state->ipa_ctx = ipa_ctx;
++    state->user_dom = user_dom;
++    state->groups = groups;
++    state->group_count = groups_count;
++    state->group_idx = 0;
++    state->ar = NULL;
++    state->realm = dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
++                                     IPA_KRB5_REALM);
++    if (state->realm == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm for IPA?\n");
++        ret = EINVAL;
++        goto done;
++    }
++
++    ret = ipa_initgr_get_overrides_step(req);
++done:
++    if (ret == EOK) {
++        tevent_req_done(req);
++        tevent_req_post(req, ev);
++    } else if (ret != EAGAIN) {
++        tevent_req_error(req, ret);
++        tevent_req_post(req, ev);
++    }
++
++    return req;
++}
++
++static void ipa_initgr_get_overrides_override_done(struct tevent_req *subreq);
++
++static int ipa_initgr_get_overrides_step(struct tevent_req *req)
++{
++    int ret;
++    struct tevent_req *subreq;
++    const char *ipa_uuid;
++    struct ipa_initgr_get_overrides_state *state = tevent_req_data(req,
++                                        struct ipa_initgr_get_overrides_state);
++
++    DEBUG(SSSDBG_TRACE_LIBS,
++          "Processing group %zu/%zu\n", state->group_idx, state->group_count);
++
++    if (state->group_idx >= state->group_count) {
++        return EOK;
++    }
++
++    ipa_uuid = ldb_msg_find_attr_as_string(state->groups[state->group_idx],
++                                            SYSDB_UUID, NULL);
++    if (ipa_uuid == NULL) {
++        /* This should never happen, the search filter used to get the list
++         * of groups includes "uuid=*"
++         */
++        DEBUG(SSSDBG_OP_FAILURE, "A group with no UUID, error!\n");
++        return EINVAL;
++    }
++
++    talloc_free(state->ar); /* Avoid spiking memory with many groups */
++
++    ret = get_be_acct_req_for_uuid(state, ipa_uuid,
++                                   state->user_dom->name, &state->ar);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
++        return ret;
++    }
++
++    DEBUG(SSSDBG_TRACE_LIBS, "Fetching group %s\n", ipa_uuid);
++
++    subreq = ipa_get_ad_override_send(state, state->ev,
++                                      state->ipa_ctx->sdap_id_ctx,
++                                      state->ipa_ctx->ipa_options,
++                                      state->realm,
++                                      state->ipa_ctx->view_name,
++                                      state->ar);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
++        return ENOMEM;
++    }
++    tevent_req_set_callback(subreq,
++                            ipa_initgr_get_overrides_override_done, req);
++    return EAGAIN;
++}
++
++static void ipa_initgr_get_overrides_override_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_initgr_get_overrides_state *state = tevent_req_data(req,
++                                        struct ipa_initgr_get_overrides_state);
++    int ret;
++    struct sysdb_attrs *override_attrs;
++
++    ret = ipa_get_ad_override_recv(subreq, &state->dp_error, state,
++                                   &override_attrs);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    ret = sysdb_store_override(state->user_dom, state->ipa_ctx->view_name,
++                               SYSDB_MEMBER_GROUP,
++                               override_attrs,
++                               state->groups[state->group_idx]->dn);
++    talloc_free(override_attrs);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_override failed.\n");
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    state->group_idx++;
++
++    ret = ipa_initgr_get_overrides_step(req);
++    if (ret == EAGAIN) {
++        return;
++    } else if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++static int ipa_initgr_get_overrides_recv(struct tevent_req *req, int *dp_error)
++{
++    struct ipa_initgr_get_overrides_state *state = tevent_req_data(req,
++                                        struct ipa_initgr_get_overrides_state);
++
++    if (dp_error) {
++        *dp_error = state->dp_error;
++    }
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++    return EOK;
++}
++
++/* Given a user name, retrieve an array of group UUIDs of groups that have
++ * no overrideDN attribute but do have an UUID attribute.
++ */
++static errno_t ipa_id_get_group_uuids(TALLOC_CTX *mem_ctx,
++                                      struct sysdb_ctx *sysdb,
++                                      const char *username,
++                                      size_t *_msgs_count,
++                                      struct ldb_message ***_msgs)
++{
++    const char *filter;
++    TALLOC_CTX *tmp_ctx;
++    char **uuid_list = NULL;
++    errno_t ret;
++    struct ldb_dn *base_dn;
++    const char *attrs[] = { SYSDB_UUID, NULL };
++    size_t msgs_count;
++    struct ldb_message **msgs;
++
++    tmp_ctx = talloc_new(mem_ctx);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    filter = talloc_asprintf(tmp_ctx,
++                             "(&(objectclass=%s)(!(%s=*))(%s=*))",
++                             SYSDB_GROUP_CLASS, SYSDB_OVERRIDE_DN,
++                             SYSDB_UUID);
++    if (filter == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    base_dn = sysdb_base_dn(sysdb, tmp_ctx);
++    if (base_dn == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sysdb_search_entry(tmp_ctx, sysdb, base_dn,
++                             LDB_SCOPE_SUBTREE, filter, attrs,
++                             &msgs_count, &msgs);
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "No groups without %s in sysdb\n", SYSDB_OVERRIDE_DN);
++        ret = EOK;
++        goto done;
++    } else if (ret != EOK) {
++        goto done;
++    }
++
++    uuid_list = talloc_zero_array(tmp_ctx, char *, msgs_count);
++    if (uuid_list == NULL) {
++        goto done;
++    }
++
++    *_msgs_count = msgs_count;
++    *_msgs = talloc_steal(mem_ctx, msgs);
++    ret = EOK;
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ struct ipa_id_get_account_info_state {
+     struct tevent_context *ev;
+     struct ipa_id_ctx *ipa_ctx;
+@@ -300,6 +533,11 @@ struct ipa_id_get_account_info_state {
+     struct sysdb_attrs *override_attrs;
+     struct ldb_message *obj_msg;
+     struct ldb_message_element *ghosts;
++
++    struct ldb_message **user_groups;
++    size_t group_cnt;
++    size_t group_idx;
++
+     int dp_error;
+ };
+ 
+@@ -519,6 +757,8 @@ static errno_t ipa_id_get_account_info_get_original_step(struct tevent_req *req,
+     return EOK;
+ }
+ 
++static void ipa_id_get_user_groups_done(struct tevent_req *subreq);
++
+ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
+ {
+     struct tevent_req *req = tevent_req_callback_data(subreq,
+@@ -549,16 +789,28 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
+         goto fail;
+     }
+ 
+-    if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_GROUP
+-            && state->ipa_ctx->view_name != NULL
+-            && strcmp(state->ipa_ctx->view_name,
+-                      SYSDB_DEFAULT_VIEW_NAME) != 0) {
+-        /* check for ghost members because ghost members are not allowed if a
+-         * view other than the default view is applied.*/
++    if (state->ipa_ctx->view_name != NULL &&
++            strcmp(state->ipa_ctx->view_name, SYSDB_DEFAULT_VIEW_NAME) != 0) {
+ 
+-        state->ghosts = ldb_msg_find_element(state->obj_msg, SYSDB_GHOST);
++        if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_GROUP) {
++            /* check for ghost members because ghost members are not allowed
++             * if a view other than the default view is applied.*/
++            state->ghosts = ldb_msg_find_element(state->obj_msg, SYSDB_GHOST);
++        } else if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == \
++                        BE_REQ_INITGROUPS) {
++            /* Get UUID list of groups that have no overrideDN set. */
++            ret = ipa_id_get_group_uuids(state, state->sysdb,
++                                         state->ar->filter_value,
++                                         &state->group_cnt,
++                                         &state->user_groups);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "Cannot get UUID list: %d\n", ret);
++                goto fail;
++            }
++        }
+     }
+ 
++
+     if (state->override_attrs == NULL) {
+         uuid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_UUID, NULL);
+         if (uuid == NULL) {
+@@ -626,6 +878,19 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
+         return;
+     }
+ 
++    if (state->user_groups != NULL) {
++        subreq = ipa_initgr_get_overrides_send(state, state->ev, state->ipa_ctx,
++                                              state->domain, state->group_cnt,
++                                              state->user_groups);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list_send failed.\n");
++            ret = ENOMEM;
++            goto fail;
++        }
++        tevent_req_set_callback(subreq, ipa_id_get_user_groups_done, req);
++        return;
++    }
++
+     state->dp_error = DP_ERR_OK;
+     tevent_req_done(req);
+     return;
+@@ -692,6 +957,19 @@ static void ipa_id_get_account_info_done(struct tevent_req *subreq)
+         return;
+     }
+ 
++    if (state->user_groups != NULL) {
++        subreq = ipa_initgr_get_overrides_send(state, state->ev, state->ipa_ctx,
++                                              state->domain, state->group_cnt,
++                                              state->user_groups);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list_send failed.\n");
++            ret = ENOMEM;
++            goto fail;
++        }
++        tevent_req_set_callback(subreq, ipa_id_get_user_groups_done, req);
++        return;
++    }
++
+     state->dp_error = DP_ERR_OK;
+     tevent_req_done(req);
+     return;
+@@ -728,6 +1006,32 @@ fail:
+     return;
+ }
+ 
++static void ipa_id_get_user_groups_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    struct ipa_id_get_account_info_state *state = tevent_req_data(req,
++                                          struct ipa_id_get_account_info_state);
++    int dp_error = DP_ERR_FATAL;
++    int ret;
++
++    ret = ipa_initgr_get_overrides_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "IPA resolve user groups %d\n", ret);
++        goto fail;
++    }
++
++    state->dp_error = DP_ERR_OK;
++    tevent_req_done(req);
++    return;
++
++fail:
++    state->dp_error = dp_error;
++    tevent_req_error(req, ret);
++    return;
++}
++
+ static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error)
+ {
+     struct ipa_id_get_account_info_state *state = tevent_req_data(req,
+-- 
+2.1.0
+
diff --git a/SOURCES/0186-ipa_s2n_save_objects-properly-handle-fully-qualified.patch b/SOURCES/0186-ipa_s2n_save_objects-properly-handle-fully-qualified.patch
new file mode 100644
index 0000000..9ffeed2
--- /dev/null
+++ b/SOURCES/0186-ipa_s2n_save_objects-properly-handle-fully-qualified.patch
@@ -0,0 +1,34 @@
+From a79ca19a29c08de2ba42b8ce7b48244730896cfc Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 28 Jan 2015 11:44:37 +0100
+Subject: [PATCH 186/188] ipa_s2n_save_objects: properly handle fully-qualified
+ group names
+
+Check if the given name is already fully-qualified instead of adding a
+domain name unconditionally.
+
+Related to https://fedorahosted.org/sssd/ticket/2529
+       and https://fedorahosted.org/sssd/ticket/2524
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 9ad346318dc2cc5d5a340d8d981ddfdcc6f632da)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 35bd303d4aa3651e80c70297507bdc85d05bfbde..18f2a867df3ad705008537843ea94e38dab0006e 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -2074,7 +2074,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+ 
+             if (IS_SUBDOMAIN(dom)) {
+                 /* we always use the fully qualified name for subdomain users */
+-                name = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
++                name = sss_get_domain_name(tmp_ctx, name, dom);
+                 if (!name) {
+                     DEBUG(SSSDBG_OP_FAILURE, "failed to format user name,\n");
+                     ret = ENOMEM;
+-- 
+2.1.0
+
diff --git a/SOURCES/0187-AD-use-GC-for-SID-requests-as-well.patch b/SOURCES/0187-AD-use-GC-for-SID-requests-as-well.patch
new file mode 100644
index 0000000..37bedb3
--- /dev/null
+++ b/SOURCES/0187-AD-use-GC-for-SID-requests-as-well.patch
@@ -0,0 +1,104 @@
+From 4517ac5121054f0f14dbcb977f0844d49817f4b8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 28 Jan 2015 14:04:45 +0100
+Subject: [PATCH 187/188] AD: use GC for SID requests as well
+
+If a universal group is looked up by SID the cross-domain members must
+be resolved with the help of the Global Catalog.
+
+Related to https://fedorahosted.org/sssd/ticket/2514
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 561ed2fd03bab04cfdddbc09c4b48563c9d9b87e)
+---
+ src/providers/ipa/ipa_subdomains_id.c |  1 +
+ src/providers/ldap/ldap_id.c          | 38 ++++++++++++++++++++++++++---------
+ 2 files changed, 29 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index c8714a216daff7506f00248e25c281529d0479c4..0508e14b690c144f4bace9ed14a326ac724eb910 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -603,6 +603,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
+      */
+     switch (state->ar->entry_type & BE_REQ_TYPE_MASK) {
+     case BE_REQ_INITGROUPS:
++    case BE_REQ_BY_SECID:
+     case BE_REQ_GROUP:
+         clist = ad_gc_conn_list(req, ad_id_ctx, state->obj_dom);
+         if (clist == NULL) {
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index 2e58f4e49eb33a85cbb8b4144c69004c6b5b312b..5ce462d77867f115fe5c0214fcb95b72a4370472 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -33,6 +33,7 @@
+ #include "providers/ldap/sdap_async.h"
+ #include "providers/ldap/sdap_idmap.h"
+ #include "providers/ldap/sdap_users.h"
++#include "providers/ad/ad_common.h"
+ 
+ /* =Users-Related-Functions-(by-name,by-uid)============================== */
+ 
+@@ -1745,6 +1746,8 @@ static void get_user_and_group_groups_done(struct tevent_req *subreq)
+     struct get_user_and_group_state *state = tevent_req_data(req,
+                                                struct get_user_and_group_state);
+     int ret;
++    struct ad_id_ctx *ad_id_ctx;
++    struct sdap_id_conn_ctx *user_conn;
+ 
+     ret = groups_get_recv(subreq, &state->dp_error, &state->sdap_ret);
+     talloc_zfree(subreq);
+@@ -1764,8 +1767,22 @@ static void get_user_and_group_groups_done(struct tevent_req *subreq)
+ 
+     /* Now the search finished fine but did not find an entry.
+      * Retry with users. */
++
++    user_conn = state->conn;
++    /* Prefer LDAP over GC for users */
++    if (state->id_ctx->opts->schema_type == SDAP_SCHEMA_AD
++            && state->sdom->pvt != NULL) {
++        ad_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
++        if (ad_id_ctx != NULL &&  ad_id_ctx->ldap_ctx != NULL
++                && state->conn == ad_id_ctx->gc_ctx) {
++            DEBUG(SSSDBG_TRACE_ALL,
++                  "Switching to LDAP connection for user lookup.\n");
++            user_conn = ad_id_ctx->ldap_ctx;
++        }
++    }
++
+     subreq = users_get_send(req, state->ev, state->id_ctx,
+-                            state->sdom, state->conn,
++                            state->sdom, user_conn,
+                             state->filter_val, state->filter_type, NULL,
+                             state->attrs_type, state->noexist_delete);
+     if (subreq == NULL) {
+@@ -1792,16 +1809,17 @@ static void get_user_and_group_users_done(struct tevent_req *subreq)
+         tevent_req_error(req, ret);
+         return;
+     }
+-
+     if (state->sdap_ret == ENOENT) {
+-        /* The search ran to completion, but nothing was found.
+-         * Delete the existing entry, if any. */
+-        ret = sysdb_delete_by_sid(state->sysdb, state->domain,
+-                                  state->filter_val);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE, "Could not delete entry by SID!\n");
+-            tevent_req_error(req, ret);
+-            return;
++        if (state->noexist_delete == true) {
++            /* The search ran to completion, but nothing was found.
++             * Delete the existing entry, if any. */
++            ret = sysdb_delete_by_sid(state->sysdb, state->domain,
++                                      state->filter_val);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "Could not delete entry by SID!\n");
++                tevent_req_error(req, ret);
++                return;
++            }
+         }
+     } else if (state->sdap_ret != EOK) {
+         tevent_req_error(req, EIO);
+-- 
+2.1.0
+
diff --git a/SOURCES/0188-fill_id-fix-LE-BE-issue-with-wrong-data-type.patch b/SOURCES/0188-fill_id-fix-LE-BE-issue-with-wrong-data-type.patch
new file mode 100644
index 0000000..98ecf55
--- /dev/null
+++ b/SOURCES/0188-fill_id-fix-LE-BE-issue-with-wrong-data-type.patch
@@ -0,0 +1,45 @@
+From d5c7e81dac95073613c8f8b12280ed001d4ed3b1 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 29 Jan 2015 20:31:19 +0100
+Subject: [PATCH 188/188] fill_id() fix LE/BE issue with wrong data type
+
+Related to https://fedorahosted.org/sssd/ticket/1588
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 866ab45027c83fafb7f7f45d34d3e1e7721b77dc)
+---
+ src/responder/nss/nsssrv_cmd.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index da24ce1730999518b2e1bc52604940ee979072e3..c03e5db846ec5b889cab5c2c37a40ef2ae229306 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4867,18 +4867,20 @@ static errno_t fill_id(struct sss_packet *packet,
+     uint8_t *body;
+     size_t blen;
+     size_t pctr = 0;
+-    uint64_t id;
++    uint64_t tmp_id;
++    uint32_t id;
+ 
+     if (id_type == SSS_ID_TYPE_GID) {
+-        id = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
++        tmp_id = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
+     } else {
+-        id = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
++        tmp_id = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
+     }
+ 
+-    if (id == 0 || id >= UINT32_MAX) {
++    if (tmp_id == 0 || tmp_id >= UINT32_MAX) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid POSIX ID.\n");
+         return EINVAL;
+     }
++    id = (uint32_t) tmp_id;
+ 
+     ret = sss_packet_grow(packet, 4 * sizeof(uint32_t));
+     if (ret != EOK) {
+-- 
+2.1.0
+
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
index 82408f1..72599fc 100644
--- a/SPECS/sssd.spec
+++ b/SPECS/sssd.spec
@@ -1,14 +1,29 @@
+%global rhel7_minor %(%{__grep} -o "7.[0-9]*" /etc/redhat-release |%{__sed} -s 's/7.//')
+
 # we don't want to provide private python extension libs
-%define __provides_exclude_from %{python_sitearch}/.*\.so$
+%define __provides_exclude_from %{python_sitearch}/.*\.so$|%{_libdir}/%{name}/modules/libwbclient.so.*$
 %define _hardened_build 1
 
+%if (0%{?fedora} >= 17 || 0%{?rhel} >= 7)
+    %global with_cifs_utils_plugin 1
+%else
+    %global with_cifs_utils_plugin_option --disable-cifs-idmap-plugin
+%endif
+
 # Determine the location of the LDB modules directory
 %global ldb_modulesdir %(pkg-config --variable=modulesdir ldb)
-%global ldb_version 1.1.16
+%global ldb_version 1.1.17
+
+%global with_krb5_localauth_plugin 1
+
+%global libwbc_alternatives_suffix %nil
+%if 0%{?__isa_bits} == 64
+%global libwbc_alternatives_suffix -64
+%endif
 
 Name: sssd
-Version: 1.11.2
-Release: 68%{?dist}.6
+Version: 1.12.2
+Release: 58%{?dist}
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
@@ -17,136 +32,194 @@ Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 ### Patches ###
-Patch0001: 0001-SYSDB-Skip-malformed-netgroup-attribute.patch
-Patch0002: 0002-monitor-Specific-error-message-for-missing-sssd.conf.patch
-Patch0003: 0003-AD-Fix-a-typo-in-the-man-page.patch
-Patch0004: 0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch
-Patch0005: 0005-SSSD-Improved-domain-detection.patch
-Patch0006: 0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch
-Patch0007: 0007-do-not-use-default_domain_suffix-with-autofs.patch
-Patch0008: 0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch
-Patch0009: 0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch
-Patch0010: 0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch
-Patch0011: 0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch
-Patch0012: 0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch
-Patch0013: 0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch
-Patch0014: 0014-failover-check-dns_domain-if-primary-servers-lookup-.patch
-Patch0015: 0015-NSS-Set-packet-length-for-initgroups.patch
-Patch0016: 0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch
-Patch0017: 0017-AD-use-LDAP-for-group-lookups.patch
-Patch0018: 0018-idmap-add-API-to-free-allocated-SIDs.patch
-Patch0019: 0019-free-idmapped-SIDs-correctly.patch
-Patch0020: 0020-free-idmapped-dom-SIDs-correctly.patch
-Patch0021: 0021-free-idmapped-smb-SIDs-correctly.patch
-Patch0022: 0022-free-idmapped-binary-SIDs-correctly.patch
-Patch0023: 0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch
-Patch0024: 0024-ad-refactor-tokengroups-initgroups.patch
-Patch0025: 0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch
-Patch0026: 0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch
-Patch0027: 0027-AD-cross-domain-membership-fix.patch
-Patch0028: 0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch
-Patch0029: 0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch
-Patch0030: 0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch
-Patch0031: 0031-Bump-sss_idmap-version-to-3-0-3.patch
-Patch0032: 0032-AD-Refresh-subdomain-data-structures-on-startup.patch
-Patch0033: 0033-IPA-Refresh-subdomain-data-structures-on-startup.patch
-Patch0034: 0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch
-Patch0035: 0035-sss_cache-initialize-names-member-of-sss_domain_info.patch
-Patch0036: 0036-sss_cache-fix-case-sensitivity-issue.patch
-Patch0037: 0037-Add-sysdb_attrs_add_lc_name_alias.patch
-Patch0038: 0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch
-Patch0039: 0039-Use-lower-case-name-for-case-insensitive-searches.patch
-Patch0040: 0040-Add-new-option-ldap_group_type.patch
-Patch0041: 0041-Add-sysdb_attrs_get_int32_t.patch
-Patch0042: 0042-IPA-fix-for-recent-AD-group-membership-changes.patch
-Patch0043: 0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch
-Patch0044: 0044-pac-fix-double-free.patch
-Patch0045: 0045-pac-fix-potential-memory-leaks.patch
-Patch0046: 0046-responder-Set-forest-attribute-in-AD-domains.patch
-Patch0047: 0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch
-Patch0048: 0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch
-Patch0049: 0049-UTIL-Inherit-parent-domain-s-default_shell.patch
-Patch0050: 0050-NSS-Use-plain-user-name-when-expanding-homedir.patch
-Patch0051: 0051-simple-access-match-objects-using-flat-name.patch
-Patch0052: 0052-simple-access-refresh-master-domain-info.patch
-Patch0053: 0053-NSS-add-support-for-subdomain_homedir.patch
-Patch0054: 0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch
-Patch0055: 0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch
-Patch0056: 0056-MAN-Fix-a-typo.patch
-Patch0057: 0057-LDAP-Fix-error-check.patch
-Patch0058: 0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch
-Patch0059: 0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch
-Patch0060: 0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch
-Patch0061: 0061-krb5-hint-to-increase-krb5_auth_timeout.patch
-Patch0062: 0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch
-Patch0063: 0063-sudo-memset-tm-when-converting-time-attributes.patch
-Patch0064: 0064-AD-Don-t-mark-domain-as-enumerated-twice.patch
-Patch0065: 0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch
-Patch0066: 0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch
-Patch0067: 0067-LDAP-Add-enum-request-with-custom-connection.patch
-Patch0068: 0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch
-Patch0069: 0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch
-Patch0070: 0070-DB-Add-sss_ldb_el_to_string_list.patch
-Patch0071: 0071-AD-Establish-cross-domain-memberships-after-enumerat.patch
-Patch0072: 0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch
-Patch0073: 0073-MAN-clarify-which-shell-option-takes-precedence.patch
-Patch0074: 0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch
-Patch0075: 0075-LDAP-require-attribute-groupType-for-AD-groups.patch
-Patch0076: 0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch
-Patch0077: 0077-Revert-NSS-add-support-for-subdomain_homedir.patch
-Patch0078: 0078-AD-support-for-subdomain_homedir.patch
-Patch0079: 0079-MAN-update-of-subdomain_homedir-usage.patch
-Patch0080: 0080-utils-handling-NULL-params-in-sss_parse_name.patch
-Patch0081: 0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch
-Patch0082: 0082-AD-Only-download-domains-that-are-set-to-enumerate.patch
-Patch0083: 0083-AD-Remove-dead-code.patch
-Patch0084: 0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch
-Patch0085: 0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch
-Patch0086: 0086-IPA-Default-to-krb5_use_fast-try.patch
-Patch0087: 0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch
-Patch0088: 0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch
-Patch0089: 0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch
-Patch0090: 0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch
-Patch0091: 0091-LDAP-Setup-periodic-task-only-once.patch
-Patch0092: 0092-UTIL-Sanitize-whitespaces.patch
-Patch0093: 0093-IDMAP-add-sss_idmap_check_collision-_ex.patch
-Patch0094: 0094-IPA-refactor-idmap-code-and-add-test.patch
-Patch0095: 0095-IPA-check-ranges-for-collisions-before-saving-them.patch
-Patch0096: 0096-OPTS-Allow-using-defaults-for-blobs.patch
-Patch0097: 0097-DP-Provide-separate-dp_copy_defaults-function.patch
-Patch0098: 0098-MAN-Clarify-the-ldap_access_filter-option-further.patch
-Patch0099: 0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch
-Patch0100: 0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch
-Patch0101: 0101-libsss_idmap-bump-version-info.patch
-Patch0102: 0102-config-API-add-missing-subdomain-target-to-AD-provid.patch
-Patch0103: 0103-SUDO-AD-provider.patch
-Patch0104: 0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch
-Patch0105: 0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch
-Patch0106: 0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch
-Patch0107: 0107-IPA-Use-GC-for-AD-initgroup-requests.patch
-Patch0108: 0108-AD-Only-connect-to-GC-for-subdomain-users.patch
-Patch0109: 0109-MAN-Clarify-the-GC-support-a-bit.patch
-Patch0110: 0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch
-Patch0111: 0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch
-Patch0112: 0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch
-Patch0113: 0113-IPA-Write-SELinux-usernames-in-the-right-case.patch
-Patch0114: 0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch
-Patch0115: 0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch
-Patch0116: 0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch
-Patch0117: 0117-krb5-child-add-revert_changepw_options.patch
-Patch0118: 0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch
-Patch0119: 0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch
-Patch0120: 0120-AD-connect-to-forest-root-when-downloading-the-list-.patch
-Patch0121: 0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch
-Patch0122: 0122-AD-Do-not-remove-non-root-domains-when-looking-up-ro.patch
-Patch0123: 0123-AD-Provider-bug-fix-uninitialized-variable.patch
-Patch0124: 0124-AD-Provider-bugfix-use-after-free.patch
-Patch0125: 0125-ipa-subdomains-provider-make-sure-search-by-SID-work.patch
-Patch0126: 0126-tests-Remove-tests-that-check-creating-public-direct.patch
-Patch0127: 0127-IPA-handle-searches-by-SID-in-apply_subdomain_homedi.patch
-Patch0128: 0128-LDAP-Ignore-returned-referrals-if-referral-support-i.patch
-Patch0129: 0129-Ignore-referrals-in-deref-and-ASQ-too.patch
-Patch0130: 0130-IPA-Use-GC-for-group-lookups-in-server-mode.patch
+Patch0001:  0001-util-Move-semanage-related-functions-to-src-util.patch
+Patch0002:  0002-sss_semanage-Add-mlsrange-parameter-to-set_seuser.patch
+Patch0003:  0003-IPA-Use-set_seuser-instead-of-writing-selinux-login-.patch
+Patch0004:  0004-SSSD-Add-the-options-to-specify-a-UID-and-GID-to-run.patch
+Patch0005:  0005-SSSD-Chown-the-log-files.patch
+Patch0006:  0006-UTIL-Use-a-custom-PID_PATH-and-DB_PATH-when-unit-tes.patch
+Patch0007:  0007-TESTS-Unit-tests-can-use-confdb-without-using-sysdb.patch
+Patch0008:  0008-TESTS-Add-std-gnu99-to-cwrap-tests-CFLAGS.patch
+Patch0009:  0009-TESTS-Unit-tests-for-server_setup.patch
+Patch0010:  0010-RPM-Package-the-libsss_semanage.so-library.patch
+Patch0011:  0011-ipa-fix-issues-with-older-servers-not-supporting-vie.patch
+Patch0012:  0012-ipa-improve-error-reporting-for-extdom-LDAP-exop.patch
+Patch0013:  0013-BUILD-Fix-automake-warning.patch
+Patch0014:  0014-test_server-Fix-waiting-for-background-process.patch
+Patch0015:  0015-ipa_subdomains_handler_master_done-initialize-reply_.patch
+Patch0016:  0016-Fix-debug-messages-trailing.patch
+Patch0017:  0017-IPA-Handle-NULL-members-in-process_members.patch
+Patch0018:  0018-SPEC-Print-testsuite-log-for-failed-test.patch
+Patch0019:  0019-MAN-PAGE-modified-sssd-ldap.5.xml-for-sssd-ticket-24.patch
+Patch0020:  0020-NSS-Possibility-to-use-any-shells-in-allowed_shells.patch
+Patch0021:  0021-GPO-Terminate-request-on-error.patch
+Patch0022:  0022-pyhbac-pysss-fix-reference-leaks.patch
+Patch0023:  0023-UTIL-Add-a-function-to-convert-id_t-from-a-number-or.patch
+Patch0024:  0024-BUILD-Add-a-config-option-for-sssd-user-own-private-.patch
+Patch0025:  0025-RPM-Change-file-ownership-to-sssd.sssd.patch
+Patch0026:  0026-SSSD-Load-a-user-to-run-a-service-as-from-configurat.patch
+Patch0027:  0027-SBUS-Chown-the-sbus-socket-if-needed.patch
+Patch0028:  0028-SBUS-Allow-connections-from-other-UIDs.patch
+Patch0029:  0029-BE-Own-the-sbus-socket-as-the-SSSD-user.patch
+Patch0030:  0030-MONITOR-Allow-confdb-to-be-accessed-by-nonroot-user.patch
+Patch0031:  0031-SYSDB-Allow-calling-chown-on-the-sysdb-file-from-mon.patch
+Patch0032:  0032-NSS-Run-as-a-user-specified-by-monitor.patch
+Patch0033:  0033-responder_common-Create-fd-for-pipe-in-helper.patch
+Patch0034:  0034-TEST-Unit-test-for-create_pipe_fd.patch
+Patch0035:  0035-responders-Do-not-initialize-pipe-fd-if-already-pres.patch
+Patch0036:  0036-PAM-Create-pipe-file-descriptors-before-privileges-a.patch
+Patch0037:  0037-PAM-Run-pam-responder-as-nonroot.patch
+Patch0038:  0038-AUTOFS-Run-the-autofs-responder-as-the-SSSD-user.patch
+Patch0039:  0039-PAC-Run-the-pac-responder-as-the-SSSD-user.patch
+Patch0040:  0040-SUDO-Run-the-sudo-responder-as-the-SSSD-user.patch
+Patch0041:  0041-SSH-Run-the-ssh-responder-as-the-SSSD-user.patch
+Patch0042:  0042-SBUS-Fix-error-handling-after-closing-container.patch
+Patch0043:  0043-TESTS-Add-tests-for-the-views-related-option-maps.patch
+Patch0044:  0044-RESPONDERS-refactor-create_pipe_fd.patch
+Patch0045:  0045-RESPONDERS-Don-t-hard-code-umask-value-in-utility-fu.patch
+Patch0046:  0046-RESPONDERS-Set-default-value-for-umask.patch
+Patch0047:  0047-nss-group-enumeration-fix.patch
+Patch0048:  0048-nss-preserve-service-name-in-getsrv-call.patch
+Patch0049:  0049-sdap_print_server-use-getpeername-to-get-server-addr.patch
+Patch0050:  0050-IPA-Don-t-fail-the-request-when-BE-doesn-t-find-the-.patch
+Patch0051:  0051-memberof-check-for-empty-arrays-to-avoid-segfaults.patch
+Patch0052:  0052-CONFDB-Detect-fix-misconf-opt-refresh_expired_interv.patch
+Patch0053:  0053-NSS-disable-midpoint-refresh-for-netgroups.patch
+Patch0054:  0054-IPA-use-ipaUserGroup-object-class-for-groups.patch
+Patch0055:  0055-Add-add_strings_lists-utility-function.patch
+Patch0056:  0056-IPA-inherit-ldap_user_extra_attrs-to-AD-subdomains.patch
+Patch0057:  0057-Add-parse_attr_list_ex-helper-function.patch
+Patch0058:  0058-nss-parse-user_attributes-option.patch
+Patch0059:  0059-nss-return-user_attributes-in-origbyname-request.patch
+Patch0060:  0060-sysdb_get_user_attr_with_views-add-mandatory-overrid.patch
+Patch0061:  0061-sysdb_add_overrides_to_object-add-new-parameter-and-.patch
+Patch0062:  0062-Views-apply-user-SSH-public-key-override.patch
+Patch0063:  0063-Add-test-for-sysdb_add_overrides_to_object.patch
+Patch0064:  0064-Add-ssh-pubkey-to-origbyname-request.patch
+Patch0065:  0065-BUILD-Install-ldap_child-and-as-setuid-if-running-un.patch
+Patch0066:  0066-LDAP-Move-sss_krb5_verify_keytab_ex-to-ldap_child.patch
+Patch0067:  0067-LDAP-read-the-correct-data-type-from-ldap_child-s-in.patch
+Patch0068:  0068-LDAP-Drop-privileges-after-kinit-in-ldap_child.patch
+Patch0069:  0069-UTIL-Remove-code-duplication-of-struct-io.patch
+Patch0070:  0070-UTIL-Remove-more-code-duplication-setting-up-child-p.patch
+Patch0071:  0071-IPA-Move-setting-the-SELinux-context-to-a-child-proc.patch
+Patch0072:  0072-test_sysdb_views-Use-unique-directory-for-cache.patch
+Patch0073:  0073-selinux_child-Do-not-ignore-return-values.patch
+Patch0074:  0074-IPA-Store-right-username-to-selinux-child-context.patch
+Patch0075:  0075-PAM-Remove-authtok-from-PAM-stack-with-OTP.patch
+Patch0076:  0076-Revert-LDAP-Remove-unused-option-ldap_user_uuid.patch
+Patch0077:  0077-Revert-LDAP-Remove-unused-option-ldap_group_uuid.patch
+Patch0078:  0078-Fix-uuid-defaults.patch
+Patch0079:  0079-Revert-LDAP-Change-defaults-for-ldap_user-group_obje.patch
+Patch0080:  0080-LDAP-Disable-token-groups-by-default.patch
+Patch0081:  0081-proxy-Do-not-try-to-store-same-alias-twice.patch
+Patch0082:  0082-PROXY-Preserve-service-name-in-proxy-provider.patch
+Patch0083:  0083-BUILD-Install-krb5_child-as-suid-if-running-under-no.patch
+Patch0084:  0084-KRB5-Drop-privileges-in-the-child-not-the-back-end.patch
+Patch0085:  0085-KRB5-Move-ccache-related-functions-to-krb5_ccache.c.patch
+Patch0086:  0086-KRB5-Move-checking-for-illegal-RE-to-krb5_utils.c.patch
+Patch0087:  0087-KRB5-Move-all-ccache-operations-to-krb5_child.c.patch
+Patch0088:  0088-KRB5-Do-not-switch_creds-if-already-the-specified-us.patch
+Patch0089:  0089-BUILD-Use-separate-chown-to-make-changing-ownership-.patch
+Patch0090:  0090-BUILD-Make-chown-of-files-to-sssd-user-non-fatal.patch
+Patch0091:  0091-BUILD-Touch-files-in-DESTDIR.patch
+Patch0092:  0092-BE-Become-a-regular-user-after-initialization.patch
+Patch0093:  0093-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-speci.patch
+Patch0094:  0094-MAN-page-edit-for-ldap_use_tokengroups.patch
+Patch0095:  0095-sysdb-add-sysdb_search_object_by_uuid.patch
+Patch0096:  0096-ipa-add-split_ipa_anchor.patch
+Patch0097:  0097-LDAP-add-support-for-lookups-by-UUID.patch
+Patch0098:  0098-LDAP-always-store-UUID-if-available.patch
+Patch0099:  0099-ipa-add-get_be_acct_req_for_uuid.patch
+Patch0100:  0100-IPA-make-get_object_from_cache-public.patch
+Patch0101:  0101-IPA-check-overrrides-for-IPA-users-as-well.patch
+Patch0102:  0102-Enable-views-for-all-domains.patch
+Patch0103:  0103-MAN-Update-case_sensitive-Preserving-in-man-pages.patch
+Patch0104:  0104-Man-debug_timestamps-and-debug_microseconds.patch
+Patch0105:  0105-sss_client-Extract-destroying-of-mmap-cache-to-funct.patch
+Patch0106:  0106-sss_client-Fix-race-condition-in-memory-cache.patch
+Patch0107:  0107-IPA-Handle-IPA-groups-returned-from-extop-plugin.patch
+Patch0108:  0108-Fix-KRB5_CONF_PATH.patch
+Patch0109:  0109-AD-IPA-add-krb5_confd_path-configuration-option.patch
+Patch0110:  0110-test-Wrong-parameter-type-in-sss_parse_name_check.patch
+Patch0111:  0111-util-Special-case-PCRE_ERROR_NOMATCH-in-sss_parse_na.patch
+Patch0112:  0112-util-sss_get_domain_name-regex-mismatch-not-fatal.patch
+Patch0113:  0113-sysdb-add-sysdb_delete_view_tree.patch
+Patch0114:  0114-sysdb-add-sysdb_invalidate_overrides.patch
+Patch0115:  0115-views-allow-view-name-change-at-startup.patch
+Patch0116:  0116-PAM-Check-for-trusted-domain-before-sending-the-requ.patch
+Patch0117:  0117-PAM-Move-is_uid_trusted-from-pam_ctx-to-preq.patch
+Patch0118:  0118-krb5-make-krb5-provider-view-aware.patch
+Patch0119:  0119-IPA-only-update-view-data-if-it-really-changed.patch
+Patch0120:  0120-krb5-do-not-fail-if-checking-the-old-ccache-failed.patch
+Patch0121:  0121-test-avoid-leaks-in-leak-tests.patch
+Patch0122:  0122-krb5-add-copy_ccache_into_memory.patch
+Patch0123:  0123-krb5-add-copy_keytab_into_memory.patch
+Patch0124:  0124-ldap_child-copy-keytab-into-memory-to-drop-privilege.patch
+Patch0125:  0125-krb5_child-become-user-earlier.patch
+Patch0126:  0126-TESTS-Basic-child-tests.patch
+Patch0127:  0127-Add-extra_args-to-exec_child.patch
+Patch0128:  0128-KRB5-Create-the-fast-ccache-in-a-child-process.patch
+Patch0129:  0129-KRB5-Relax-DEBUG-message.patch
+Patch0130:  0130-IPA-Do-not-append-domain-name-to-fq-name.patch
+Patch0131:  0131-TESTS-Build-test_child-even-without-cmocka.patch
+Patch0132:  0132-sss_client-Work-around-glibc-bug.patch
+Patch0133:  0133-Skip-CHAUTHTOK_PRELIM-when-using-OTPs.patch
+Patch0134:  0134-PAM-Domain-names-are-case-insensitive.patch
+Patch0135:  0135-PAM-Missing-argument-to-domains-should-fail-auth.patch
+Patch0136:  0136-MAN-Misspelled-username-in-pam_trusted_users-is-not-.patch
+Patch0137:  0137-RESPONDER-Log-failures-to-resolve-user-names-in-csv_.patch
+Patch0138:  0138-KRB5-Check-FAST-kinit-errors-using-get_tgt_times.patch
+Patch0139:  0139-MAN-Clarify-ad_gpo_map-options.patch
+Patch0140:  0140-krb5_child-Initialize-REALM-earlier.patch
+Patch0141:  0141-TESTS-sysdb_delete_by_sid-test-return-value.patch
+Patch0142:  0142-NSS-nss_cmd_getbysid_search-return-ENOENT.patch
+Patch0143:  0143-SYSDB-sysdb_search_object_by_sid-returns-ENOENT.patch
+Patch0144:  0144-handle-KRB5KRB_ERR_GENERIC-as-unspecific-error.patch
+Patch0145:  0145-IPA-verify-group-memberships-of-trusted-domain-users.patch
+Patch0146:  0146-IPA-properly-handle-groups-from-different-domains.patch
+Patch0147:  0147-LDAP-retain-external-members.patch
+Patch0148:  0148-IPA-do-not-try-to-add-override-gid-twice.patch
+Patch0149:  0149-IPA-handle-GID-overrides-for-MPG-domains-on-clients.patch
+Patch0150:  0150-simple-access-provider-non-existing-object.patch
+Patch0151:  0151-libwbclient-initialize-some-return-values.patch
+Patch0152:  0152-GPO-Ignore-ENOENT-result-from-sysdb_gpo_get_gpo_resu.patch
+Patch0153:  0153-GPO-Set-libsmb-debugging-to-stderr.patch
+Patch0154:  0154-UTIL-Allow-dup-ing-child-pipe-to-a-different-FD.patch
+Patch0155:  0155-GPO-Don-t-use-stdout-for-output-in-gpo_child.patch
+Patch0156:  0156-GPO-Extract-server-hostname-after-connecting.patch
+Patch0157:  0157-IPA-add-get_be_acct_req_for_user_name.patch
+Patch0158:  0158-IPA-resolve-ghost-members-if-a-non-default-view-is-a.patch
+Patch0159:  0159-sysdb-fix-group-members-with-overridden-names.patch
+Patch0160:  0160-IPA-ipa_resolve_user_list_send-take-care-of-override.patch
+Patch0161:  0161-IPA-do-not-look-up-overrides-on-client-with-default-.patch
+Patch0162:  0162-IPA-make-version-check-more-precise.patch
+Patch0163:  0163-IPA-add-missing-break.patch
+Patch0164:  0164-IPA-process_members-optionally-return-missing-member.patch
+Patch0165:  0165-IPA-rename-ipa_s2n_get_groups_send-to-ipa_s2n_get_fq.patch
+Patch0166:  0166-IPA-resolve-missing-members.patch
+Patch0167:  0167-IPA-set-SYSDB_INITGR_EXPIRE-for-RESP_USER_GROUPLIST.patch
+Patch0168:  0168-krb5_child-Return-ERR_NETWORK_IO-on-KRB5_KDCREP_SKEW.patch
+Patch0169:  0169-krb5-fix-entry-order-in-MEMORY-keytab.patch
+Patch0170:  0170-nss-make-fill_orig-multi-value-aware.patch
+Patch0171:  0171-nss-refactor-fill_orig.patch
+Patch0172:  0172-nss-Add-original-DN-and-memberOf-to-origbyname-reque.patch
+Patch0173:  0173-Open-the-PAC-socket-from-krb5_child-before-dropping-.patch
+Patch0174:  0174-views-fix-GID-overrride-for-mpg-domains.patch
+Patch0175:  0175-IPA-properly-handle-mixed-case-trusted-domains.patch
+Patch0176:  0176-nss-fix-SID-lookups.patch
+Patch0177:  0177-sysdb-remove-ghosts-in-all-sub-domains-as-well.patch
+Patch0178:  0178-IPA-Rename-user_dom-into-obj_dom.patch
+Patch0179:  0179-IPA-resolve-IPA-group-memberships-for-AD-users.patch
+Patch0180:  0180-IPA-process_members-add-ghosts-only-once.patch
+Patch0181:  0181-IPA-Use-attr-s-dom-for-users-too.patch
+Patch0182:  0182-SELINUX-Call-setuid-0-setgid-0-to-also-set-the-real-.patch
+Patch0183:  0183-SELINUX-Set-and-reset-umask-when-caling-set_seuser-f.patch
+Patch0184:  0184-LDAP-Add-UUID-when-saving-incomplete-groups.patch
+Patch0185:  0185-IPA-Resolve-IPA-user-groups-overrideDN-in-non-defaul.patch
+Patch0186:  0186-ipa_s2n_save_objects-properly-handle-fully-qualified.patch
+Patch0187:  0187-AD-use-GC-for-SID-requests-as-well.patch
+Patch0188:  0188-fill_id-fix-LE-BE-issue-with-wrong-data-type.patch
 
 
 ### Dependencies ###
@@ -165,6 +238,7 @@ Requires: python-sssdconfig = %{version}-%{release}
 %global pipepath %{sssdstatedir}/pipes
 %global mcpath %{sssdstatedir}/mc
 %global pubconfpath %{sssdstatedir}/pubconf
+%global gpocachepath %{sssdstatedir}/gpo_cache
 
 ### Build Dependencies ###
 
@@ -176,10 +250,12 @@ BuildRequires: popt-devel
 BuildRequires: libtalloc-devel
 BuildRequires: libtevent-devel
 BuildRequires: libtdb-devel
+
+# LDB needs a strict version match to build
 BuildRequires: libldb-devel = %{ldb_version}
 BuildRequires: libdhash-devel >= 0.4.2
 BuildRequires: libcollection-devel
-BuildRequires: libini_config-devel >= 1.0.0.1
+BuildRequires: libini_config-devel >= 1.1.0-24
 BuildRequires: dbus-devel
 BuildRequires: dbus-libs
 BuildRequires: openldap-devel
@@ -190,7 +266,11 @@ BuildRequires: pcre-devel
 BuildRequires: libxslt
 BuildRequires: libxml2
 BuildRequires: docbook-style-xsl
-BuildRequires: krb5-devel >= 1.10
+%if (0%{?with_krb5_localauth_plugin} == 1)
+BuildRequires: krb5-devel >= 1.12
+%else
+BuildRequires: krb5-devel
+%endif
 BuildRequires: c-ares-devel
 BuildRequires: python-devel
 BuildRequires: check-devel
@@ -207,6 +287,12 @@ BuildRequires: diffstat
 BuildRequires: findutils
 BuildRequires: samba4-devel >= 4.0.0-59beta2
 BuildRequires: selinux-policy-targeted
+BuildRequires: systemd-devel
+BuildRequires: libsmbclient-devel
+%if (0%{?with_cifs_utils_plugin} == 1)
+BuildRequires: cifs-utils-devel
+%endif
+BuildRequires: libnfsidmap-devel
 
 %description
 Provides a set of daemons to manage access to remote directories and
@@ -226,14 +312,20 @@ License: GPLv3+
 Conflicts: selinux-policy < 3.10.0-46
 Conflicts: sssd < 1.10.0-8%{?dist}.beta2
 # Requires
+
+# LDB needs a strict version match to run
+# This protects against
+# "sssd[XXX]: ldb: module version mismatch in src/ldb_modules/memberof.c"
 Requires: libldb%{?_isa} = %{ldb_version}
+
 Requires: libtdb%{?_isa} >= 1.1.3
 Requires: sssd-client%{?_isa} = %{version}-%{release}
 Requires: libsss_idmap%{?_isa} = %{version}-%{release}
-Requires: libini_config >= 1.0.0.1
+Requires: libini_config >= 1.1.0-24
 Requires(post): systemd-units chkconfig
 Requires(preun): systemd-units chkconfig
 Requires(postun): systemd-units chkconfig
+Requires(pre): shadow-utils
 
 
 ### Provides ###
@@ -255,6 +347,8 @@ Group: Applications/System
 License: LGPLv3+
 Requires(post): /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
+Requires(post):  /usr/sbin/alternatives
+Requires(preun): /usr/sbin/alternatives
 
 %description client
 Provides the libraries needed by the PAM and NSS stacks to connect to the SSSD
@@ -303,6 +397,7 @@ License: GPLv3+
 Conflicts: sssd < 1.10.0-8.beta2
 Requires: cyrus-sasl-gssapi%{?_isa}
 Requires: sssd-common = %{version}-%{release}
+Requires(pre): shadow-utils
 
 %description krb5-common
 Provides helper processes that the LDAP and Kerberos back ends can use for
@@ -342,10 +437,8 @@ Requires: sssd-common = %{version}-%{release}
 Requires: sssd-krb5-common = %{version}-%{release}
 Requires: libipa_hbac%{?_isa} = %{version}-%{release}
 Requires: bind-utils
-# RHEL 5 is too old to support the PAC responder
-%if !0%{?is_rhel5}
 Requires: sssd-common-pac = %{version}-%{release}
-%endif
+Requires(pre): shadow-utils
 
 %description ipa
 Provides the IPA back end that the SSSD can utilize to fetch identity data
@@ -359,10 +452,10 @@ Conflicts: sssd < 1.10.0-8.beta2
 Requires: sssd-common = %{version}-%{release}
 Requires: sssd-krb5-common = %{version}-%{release}
 Requires: bind-utils
-# RHEL 5 is too old to support the PAC responder
-%if !0%{?is_rhel5}
 Requires: sssd-common-pac = %{version}-%{release}
-%endif
+# In order for libwbclient to be upgraded before sssd-ad and sets up the
+# alternatives symlink
+Requires: libwbclient
 
 %description ad
 Provides the Active Directory back end that the SSSD can utilize to fetch
@@ -456,6 +549,56 @@ Requires: libsss_nss_idmap = %{version}-%{release}
 The libsss_nss_idmap-python contains the bindings so that libsss_nss_idmap can
 be used by Python applications.
 
+%package dbus
+Summary: The D-Bus responder of the SSSD
+Group: Applications/System
+License: GPLv3+
+BuildRequires: augeas-devel
+Requires: sssd-common = %{version}-%{release}
+
+%description dbus
+Provides the D-Bus responder of the SSSD, called the InfoPipe, that allows
+the information from the SSSD to be transmitted over the system bus.
+
+%package -n libsss_simpleifp
+Summary: The SSSD D-Bus responder helper library
+Group: Development/Libraries
+License: GPLv3+
+Requires: dbus-libs
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_simpleifp
+Provides library that simplifies D-Bus API for the SSSD InfoPipe responder.
+
+%package -n libsss_simpleifp-devel
+Summary: The SSSD D-Bus responder helper library
+Group: Development/Libraries
+License: GPLv3+
+Requires: dbus-devel
+Requires: libsss_simpleifp = %{version}-%{release}
+
+%description -n libsss_simpleifp-devel
+Provides library that simplifies D-Bus API for the SSSD InfoPipe responder.
+
+%package libwbclient
+Summary: The SSSD libwbclient implementation
+Group: Applications/System
+License: GPLv3+ and LGPLv3+
+Conflicts: libwbclient < 4.1.12
+
+%description libwbclient
+The SSSD libwbclient implementation.
+
+%package libwbclient-devel
+Summary: Development libraries for the SSSD libwbclient implementation
+Group:  Development/Libraries
+License: GPLv3+ and LGPLv3+
+Conflicts: libwbclient-devel < 4.1.12
+
+%description libwbclient-devel
+Development libraries for the SSSD libwbclient implementation.
+
 %prep
 # Update timestamps on the files touched by a patch, to avoid non-equal
 # .pyc/.pyo files across the multilib peers within a build, where "Level"
@@ -486,20 +629,28 @@ autoreconf -ivf
     --with-pipe-path=%{pipepath} \
     --with-pubconf-path=%{pubconfpath} \
     --with-mcache-path=%{mcpath} \
+    --with-gpo-cache-path=%{gpocachepath} \
     --with-init-dir=%{_initrddir} \
     --with-krb5-rcache-dir=%{_localstatedir}/cache/krb5rcache \
     --enable-nsslibdir=%{_libdir} \
     --enable-pammoddir=%{_libdir}/security \
     --enable-ldb-version-check \
+    --enable-nfsidmaplibdir=%{_libdir}/libnfsidmap \
     --disable-static \
     --disable-rpath \
-    --with-test-dir=/dev/shm
+    --with-sssd-user=sssd \
+    --with-test-dir=/dev/shm \
+    --with-initscript=systemd \
+    --with-syslog=journald \
+    --with-test-dir=/dev/shm \
+    --enable-sss-default-nss-plugin \
+    %{?with_cifs_utils_plugin_option}
 
 make %{?_smp_mflags} all docs
 
 %check
 export CK_TIMEOUT_MULTIPLIER=10
-make %{?_smp_mflags} check
+make %{?_smp_mflags} check VERBOSE=yes
 unset CK_TIMEOUT_MULTIPLIER
 
 %install
@@ -632,28 +783,34 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/%{name}/libsss_debug.so
 %{_libdir}/%{name}/libsss_ldap_common.so
 %{_libdir}/%{name}/libsss_util.so
+%{_libdir}/%{name}/libsss_semanage.so
 
 # 3rd party application libraries
 %{_libdir}/sssd/modules/libsss_autofs.so
 %{_libdir}/libsss_sudo.so
+%{_libdir}/libnfsidmap/sss.so
 
 %{ldb_modulesdir}/memberof.so
 %{_bindir}/sss_ssh_authorizedkeys
 %{_bindir}/sss_ssh_knownhostsproxy
 %{_sbindir}/sss_cache
+%{_libexecdir}/%{servicename}/sss_signal
 
 %dir %{sssdstatedir}
 %dir %{_localstatedir}/cache/krb5rcache
-%attr(700,root,root) %dir %{dbpath}
-%attr(755,root,root) %dir %{mcpath}
-%ghost %attr(0644,root,root) %verify(not md5 size mtime) %{mcpath}/passwd
-%ghost %attr(0644,root,root) %verify(not md5 size mtime) %{mcpath}/group
-%attr(755,root,root) %dir %{pipepath}
-%attr(755,root,root) %dir %{pubconfpath}
-%attr(700,root,root) %dir %{pipepath}/private
-%attr(750,root,root) %dir %{_var}/log/%{name}
-%attr(700,root,root) %dir %{_sysconfdir}/sssd
-%ghost %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
+%attr(700,sssd,sssd) %dir %{dbpath}
+%attr(755,sssd,sssd) %dir %{mcpath}
+%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd
+%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
+%attr(755,sssd,sssd) %dir %{pipepath}
+%attr(755,sssd,sssd) %dir %{pubconfpath}
+%attr(755,sssd,sssd) %dir %{gpocachepath}
+%attr(700,sssd,sssd) %dir %{pipepath}/private
+%attr(750,sssd,sssd) %dir %{_var}/log/%{name}
+%attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd
+%ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
+%attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d
+%config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf
 %config(noreplace) %{_sysconfdir}/logrotate.d/sssd
 %config(noreplace) %{_sysconfdir}/rwtab.d/sssd
 %dir %{_datadir}/sssd
@@ -664,6 +821,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man5/sssd.conf.5*
 %{_mandir}/man5/sssd-simple.5*
 %{_mandir}/man5/sssd-sudo.5*
+%{_mandir}/man5/sss_rpcidmapd.5*
 %{_mandir}/man8/sssd.8*
 %{_mandir}/man8/sss_cache.8*
 %{python_sitearch}/pysss.so
@@ -679,8 +837,8 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(-,root,root,-)
 %doc COPYING
 %{_libdir}/%{name}/libsss_krb5_common.so
-%{_libexecdir}/%{servicename}/ldap_child
-%{_libexecdir}/%{servicename}/krb5_child
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child
 
 %files krb5 -f sssd_krb5.lang
 %defattr(-,root,root,-)
@@ -688,25 +846,25 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/%{name}/libsss_krb5.so
 %{_mandir}/man5/sssd-krb5.5*
 
-# RHEL 5 is too old to support the PAC responder
-%if !0%{?is_rhel5}
 %files common-pac
 %defattr(-,root,root,-)
 %doc COPYING
 %{_libexecdir}/%{servicename}/sssd_pac
-%endif
 
 %files ipa -f sssd_ipa.lang
 %defattr(-,root,root,-)
 %doc COPYING
 %attr(755,root,root) %dir %{pubconfpath}/krb5.include.d
 %{_libdir}/%{name}/libsss_ipa.so
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child
 %{_mandir}/man5/sssd-ipa.5*
 
 %files ad -f sssd_ad.lang
 %defattr(-,root,root,-)
 %doc COPYING
 %{_libdir}/%{name}/libsss_ad.so
+%{_libdir}/%{name}/libsss_ad_common.so
+%{_libexecdir}/%{servicename}/gpo_child
 %{_mandir}/man5/sssd-ad.5*
 
 %files proxy
@@ -715,6 +873,33 @@ rm -rf $RPM_BUILD_ROOT
 %{_libexecdir}/%{servicename}/proxy_child
 %{_libdir}/%{name}/libsss_proxy.so
 
+%files dbus
+%defattr(-,root,root,-)
+%doc COPYING
+%{_libexecdir}/%{servicename}/sssd_ifp
+%{_mandir}/man5/sssd-ifp.5*
+# InfoPipe DBus plumbing
+%{_sysconfdir}/dbus-1/system.d/org.freedesktop.sssd.infopipe.conf
+%{_datadir}/dbus-1/system-services/org.freedesktop.sssd.infopipe.service
+%{_libdir}/%{name}/libsss_config.so
+
+%files -n libsss_simpleifp
+%defattr(-,root,root,-)
+%{_libdir}/libsss_simpleifp.so.*
+
+%files -n libsss_simpleifp-devel
+%defattr(-,root,root,-)
+%if 0%{?fedora}
+%doc sss_simpleifp_doc/html
+%endif
+%if 0%{?rhel} >= 6
+%doc sss_simpleifp_doc/html
+%endif
+%{_includedir}/sss_sifp.h
+%{_includedir}/sss_sifp_dbus.h
+%{_libdir}/libsss_simpleifp.so
+%{_libdir}/pkgconfig/sss_simpleifp.pc
+
 %files client -f sssd_client.lang
 %defattr(-,root,root,-)
 %doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
@@ -722,6 +907,13 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/security/pam_sss.so
 %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
 %{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
+%if (0%{?with_cifs_utils_plugin} == 1)
+%{_libdir}/cifs-utils/cifs_idmap_sss.so
+%ghost %{_sysconfdir}/cifs-utils/idmap-plugin
+%endif
+%if (0%{?with_krb5_localauth_plugin} == 1)
+%{_libdir}/%{name}/modules/sssd_krb5_localauth_plugin.so
+%endif
 %{_mandir}/man8/pam_sss.8*
 %{_mandir}/man8/sssd_krb5_locator_plugin.8*
 
@@ -798,6 +990,29 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(-,root,root,-)
 %{python_sitearch}/pysss_nss_idmap.so
 
+%files libwbclient
+%defattr(-,root,root,-)
+%{_libdir}/%{name}/modules/libwbclient.so.*
+
+%files libwbclient-devel
+%defattr(-,root,root,-)
+%{_includedir}/wbclient_sssd.h
+%{_libdir}/%{name}/modules/libwbclient.so
+%{_libdir}/pkgconfig/wbclient_sssd.pc
+
+%pre ipa
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%pre krb5-common
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%pre common
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+/bin/systemctl status sssd.service >/dev/null 2>&1 && touch /var/tmp/sssd.upgrade || :
+
 %post common
 if [ $1 -ge 1 ] ; then
     # Initial installation
@@ -811,13 +1026,18 @@ if [ $1 -eq 0 ]; then
     /bin/systemctl stop sssd.service > /dev/null 2>&1 || :
 fi
 
-%postun common
-/bin/systemctl daemon-reload >/dev/null 2>&1 || :
-if [ $1 -ge 1 ] ; then
-    /bin/systemctl try-restart sssd.service >/dev/null 2>&1 || :
-fi
+%if (0%{?with_cifs_utils_plugin} == 1)
+%post client
+/sbin/ldconfig
+/usr/sbin/alternatives --install /etc/cifs-utils/idmap-plugin cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so 20
 
+%preun client
+if [ $1 -eq 0 ]; then
+        /usr/sbin/alternatives --remove cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so
+fi
+%else
 %post client -p /sbin/ldconfig
+%endif
 
 %postun client -p /sbin/ldconfig
 
@@ -829,43 +1049,346 @@ fi
 
 %postun -n libsss_idmap -p /sbin/ldconfig
 
-%changelog
-* Tue Oct 14 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68.6
-- Resolves: rhbz#1152200 - Error processing universal groups with
-                           cross-domain membership in SSSD server mode
-
-* Wed May 21 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68.5
-- Rebuild for a proper dist tag, yet again, now using the correct build
-  options
-- Related: rhbz#1098608 - Expanding home directory fails when the request
-                          comes from the PAC responder
+%post libwbclient
+%{_sbindir}/update-alternatives --install %{_libdir}/libwbclient.so.0.11 \
+                                libwbclient.so.0.11%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so.0.11.0 20
+/sbin/ldconfig
 
-* Wed May 21 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68.4
-- Rebuild for a proper dist tag
-- Related: rhbz#1098608 - Expanding home directory fails when the request
-                          comes from the PAC responder
+%preun libwbclient
+if [ $1 -eq 0 ]; then
+        %{_sbindir}/update-alternatives --remove \
+                                libwbclient.so.0.11%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so.0.11.0
+fi
+/sbin/ldconfig
 
-* Wed May 21 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68.3
+%post libwbclient-devel
+%{_sbindir}/update-alternatives --install %{_libdir}/libwbclient.so \
+                                libwbclient.so%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so 20
+
+%preun libwbclient-devel
+if [ $1 -eq 0 ]; then
+        %{_sbindir}/update-alternatives --remove \
+                                libwbclient.so%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so
+fi
+
+%posttrans common
+/bin/systemctl daemon-reload >/dev/null 2>&1 || :
+if [ -f /var/tmp/sssd.upgrade ]; then
+    /bin/systemctl restart sssd.service >/dev/null 2>&1 || :
+else
+    /bin/systemctl try-restart sssd.service >/dev/null 2>&1 || :
+fi
+/usr/bin/rm -f /var/tmp/sssd.upgrade || :
+
+%changelog
+* Tue Feb  3 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-57
+- Run the restart in sssd-common posttrans
+- Explicitly require libwbclient
+- Resolves: rhbz#1187113 - sssd deamon was not running after RHEL 7.1 upgrade
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-56
+- Resolves: rhbz#1187113 - sssd deamon was not running after RHEL 7.1 upgrade
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-55
+- Fix endianess bug in fill_id()
+- Related: rhbz#1109331 - [RFE] Allow SSSD to be used with smbd shares
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-54
+- Resolves: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-53
+- Resolves: rhbz#1187192 - IPA initgroups don't work correctly in
+                           non-default view
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-52
+- Resolves: rhbz#1184982 - Need to set different umask in selinux_child
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-51
+- Bump the release number
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-50
+- Add a patch dependency
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-49
+- Process ghost members only once
+- Fix processing of universal groups with members from different domains
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-48
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Fri Jan 23 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-47
+- Resolves: rhbz#1185188 - Uncached SIDs cannot be resolved
+
+* Fri Jan 23 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-46
+- Handle GID override in MPG domains
+- Handle views with mixed-case domains
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Wed Jan 21 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-45
+- Open socket to the PAC responder in krb5_child before dropping root
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Tue Jan 20 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-44
+- Resolves: rhbz#1184140 - Users saved throug extop don't have the
+                           originalMemberOf attribute
+
+* Mon Jan 19 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-43
+- Resolves: rhbz#1182183 - pam_sss(sshd:auth): authentication failure with
+                           user from AD
+
+* Wed Jan 14 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-42
+- Resolves: rhbz#889206 - On clock skew sssd returns system error
+
+* Wed Jan 14 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-41
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Tue Jan 13 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-40
+- Resolves: rhbz#1177140 - gpo_child fails if "log level" is enabled in smb.conf
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Fri Dec 19 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-39
+- Resolves: rhbz#1175408 - SSSD should not fail authentication when only allow
+                           rules are used
+- Resolves: rhbz#1175705 - sssd-libwbclient conflicts with Samba's and causes
+                           crash in wbinfo
+                           - in addition to the patch libwbclient.so is
+                             filtered out of the Provides list of the package
+
+* Wed Dec 17 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-38
+- Resolves: rhbz#1171215 - Crash in function get_object_from_cache
+- Resolves: rhbz#1171383 - getent fails for posix group with AD users after
+                           login
+- Resolves: rhbz#1171382 - getent of AD universal group fails after group users
+                           login
+- Resolves: rhbz#1170300 - Access is not rejected for disabled domain
+- Resolves: rhbz#1162486 - Error processing external groups with
+                           getgrnam/getgrgid in the server mode
+- Resolves: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Wed Dec 17 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-37
+- Resolves: rhbz#1169459 - sssd-ad: The man page description to enable GPO HBAC
+                           Policies are unclear
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Mon Dec 15 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-35
+- Rebuild to add several forgotten Patch entries
+- Resolves: rhbz#1173482 - MAN: Document that only user names are checked
+                           for pam_trusted_users
+- Resolves: rhbz#1167324 - pam_sss domains option: User auth should fail
+                           when domains=<emtpy value>
+
+* Sun Dec 14 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-35
+- Remove Coverity warnings in krb5_child code
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Sat Dec 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-34
+- Resolves: rhbz#1173482 - MAN: Document that only user names are checked
+                           for pam_trusted_users
+- Resolves: rhbz#1167324 - pam_sss domains option: User auth should fail
+                           when domains=<emtpy value>
+
+* Sat Dec 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-33
+- Don't error out on chpass with OTPs
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Mon Dec  8 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-32
+- Resolves: rhbz#1124320 - [FJ7.0 Bug]: getgrent returns error because sss
+                           is written in nsswitch.conf as default.
+
+* Mon Dec  8 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-31
+- Resolves: rhbz#1169739 - selinuxusermap rule does not apply to trusted
+                           AD users
+- Enable running unit tests without cmocka
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Dec  3 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-30
+- krb5_child and ldap_child do not call Kerberos calls as root
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Dec  3 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-29
+- Resolves: rhbz#1168735 - The Kerberos provider is not properly views-aware
+
+* Wed Nov 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-28
+- Fix typo in libwbclient-devel alternatives invocation
+- Related: rhbz#1109331 - [RFE] Allow SSSD to be used with smbd shares
+
+* Wed Nov 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-27
+- Resolves: rhbz#1166727 - pam_sss domains option: Untrusted users from
+                           the same domain are allowed to auth.
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-26
+- Handle migrating clients between views
+- Related: rhbz#891984 - [RFE] ID Views: Support migration from the sync
+                         solution to the trust solution
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-25
+- Use alternatives for libwbclient
+- Related: rhbz#1109331 - [RFE] Allow SSSD to be used with smbd shares
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-24
+- Resolves: rhbz#1165794 - sssd does not work with custom value of option
+                           re_expression
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-23
+- Add an option that describes where to put generated krb5 files to
+- Related: rhbz#1135043 - [RFE] Implement localauth plugin for MIT krb5 1.12
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-22
+- Handle IPA group names returned from the extop plugin
+- Related: rhbz#891984 - [RFE] ID Views: Support migration from the sync
+                         solution to the trust solution
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-21
+- Resolves: rhbz#1165792 - automount segfaults in sss_nss_check_header
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-20
+- Resolves: rhbz#1163742 - "debug_timestamps = false" and "debug_microseconds
+                           = true" do not work after enabling journald
+                           with sssd.
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-19
+- Resolves: rhbz#1153593 - Manpage description of case_sensitive=preserving
+                          is incomplete
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-18
+- Support views for IPA users
+- Related: rhbz#891984 - [RFE] ID Views: Support migration from the sync
+                         solution to the trust solution
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-17
+- Update man page to clarify TGs should be disabled with a custom search base
+- Related: rhbz#1161741 - TokenGroups for LDAP provider breaks in corner cases
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-16
+- Use upstreamed patches for the rootless sssd
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-15
+- Resolves: rhbz#1153603 - Proxy Provider: Fails to lookup case sensitive
+                           users and groups with case_sensitive=preserving
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-14
+- Resolves: rhbz#1161741 - TokenGroups for LDAP provider breaks in corner cases
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-13
+- Resolves: rhbz#1162480 - dereferencing failure against openldap server
+
+* Wed Nov 12 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-12
+- Move adding the user from pretrans to pre, copy adding the user to
+  sssd-krb5-common and sssd-ipa as well in order to work around yum
+  ordering issue
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Tue Nov 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-11
+- Resolves: rhbz#1113783 - sssd should run under unprivileged user
+
+* Fri Nov  7 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-10
+- Fix two regressions in the new selinux_child process
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+- Resolves: rhbz#1132365 - Remove password from the PAM stack if OTP is used
+
+* Wed Nov  5 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-9
+- Include the ldap_child and selinux_child patches for rootless sssd
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Nov  5 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-8
+- Support overriding SSH public keys with views
+- Support extended attributes via the extop plugin
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+- Resolves: rhbz#1137010 - disable midpoint refresh for netgroups if ptask
+                           refresh is enabled
+
+* Thu Oct 30 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-7
+- Resolves: rhbz#1153518 - service lookups returned in lowercase with
+                           case_sensitive=preserving
+- Resolves: rhbz#1158809 - Enumeration shows only a single group multiple
+                           times
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-6
+- Include the responder and packaging patches for rootless sssd
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-5
+- Amend the sssd-ldap man page with info about lockout setup
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+- Resolves: rhbz#1137014 - Shell fallback mechanism in SSSD 
+- Resolves: rhbz#790854 - 4 functions with reference leaks within sssd (src/python/pyhbac.c) 
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-4
+- Fix regressions caused by views patches when SSSD is connected to a
+  pre-4.0 IPA server
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-3
+- Add the low-level server changes for running as unprivileged user
+- Package the libsss_semange library needed for SELinux label changes
+- Related: rhbz#1113783 - sssd should run under unprivileged user 
+- Resolves: rhbz#1113784 - sssd should audit selinux user map changes 
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-2
+- Use libsemanage for SELinux label changes
+- Resolves: rhbz#1113784 - sssd should audit selinux user map changes 
+
+* Mon Oct 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-1
+- Rebase SSSD to 1.12.2
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Thu Oct 09 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-2
+- Sync with upstream
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Thu Sep 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-1
+- Rebuild against ding-libs with fixed SONAME
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Tue Sep  9 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-1
+- Rebase SSSD to 1.12.1
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Fri Sep 05 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-3
+- Require ldb 2.1.17
+- Related: rhbz#1133914 - Rebase libldb to version 1.1.17 or newer
+
+* Fri Aug 08 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-2
+- Fix fully qualified IFP lookups
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Thu Jul 24 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-1
+- Rebase SSSD to 1.12.0
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Wed May 21 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-70
 - Squash in upstream review comments about the PAC patch
-- Related: rhbz#1098608 - Expanding home directory fails when the request
+- Related: rhbz#1097286 - Expanding home directory fails when the request
                           comes from the PAC responder
 
-* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68.2
+* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-69
 - Backport a patch to allow krb5-utils-test to run as root
-- Related: rhbz#1098608 - Expanding home directory fails when the request
+- Related: rhbz#1097286 - Expanding home directory fails when the request
                           comes from the PAC responder
 
-* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68.1
-- Resolves: rhbz#1098608 - Expanding home directory fails when the request
+* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68
+- Resolves: rhbz#1097286 - Expanding home directory fails when the request
                            comes from the PAC responder
 
 * Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-67
 - Fix a DEBUG message, backport two related fixes
-- Related: rhbz#1097323 - segfault in sssd_be when second domain tree
+- Related: rhbz#1090653 - segfault in sssd_be when second domain tree
                            users are queried while joined to child domain
 
 * Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-66
-- Resolves: rhbz#1097323 - segfault in sssd_be when second domain tree
+- Resolves: rhbz#1090653 - segfault in sssd_be when second domain tree
                            users are queried while joined to child domain
 
 * Wed Apr 02 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-65