diff --git a/.gitignore b/.gitignore
index 27ea61f..f71df95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1 @@
-SOURCES/cert9.db
-SOURCES/key4.db
-SOURCES/sssd-1.13.0.tar.gz
+SOURCES/sssd-1.14.0.tar.gz
diff --git a/.sssd.metadata b/.sssd.metadata
index 7e1423b..26fd024 100644
--- a/.sssd.metadata
+++ b/.sssd.metadata
@@ -1,3 +1 @@
-7f7d2513294f425b8a393a7e3f37b36634dd55de SOURCES/cert9.db
-6048e03ea386ac40bd801d41d77ece9545592ad3 SOURCES/key4.db
-f9c57cfb91d8e0e35d565a1d5b165e8f669989d2 SOURCES/sssd-1.13.0.tar.gz
+4ddb4403b07125f413181c43d8d2208c3128924d SOURCES/sssd-1.14.0.tar.gz
diff --git a/SOURCES/0001-SYSDB-Fixing-DB-update.patch b/SOURCES/0001-SYSDB-Fixing-DB-update.patch
new file mode 100644
index 0000000..f4df02a
--- /dev/null
+++ b/SOURCES/0001-SYSDB-Fixing-DB-update.patch
@@ -0,0 +1,71 @@
+From dc8e4131f73d62f23a4be7148e24315adbc550e4 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Mon, 20 Jun 2016 09:19:03 -0300
+Subject: [PATCH 01/18] SYSDB: Fixing DB update
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Functions sysdb_user_base_dn() and sysdb_group_base_dn() expect
+that struct sss_domain_info contains pointer to struct sysdb_ctx.
+This is not true in case of sysdb_upgrade functions.
+This patch fixes the situation and revert code to the state before
+12a000c8c7c07259e438fb1e992134bdd07d9a30 commit.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3023
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 311836214245600566f881ff6253594e0999008e)
+---
+ src/db/sysdb_upgrade.c | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
+index 1d2978caee4512856fb64c4798a4b031bf6a3af1..4ca8433f9d5430b038f90563c34cede02393b0b0 100644
+--- a/src/db/sysdb_upgrade.c
++++ b/src/db/sysdb_upgrade.c
+@@ -443,12 +443,23 @@ int sysdb_check_upgrade_02(struct sss_domain_info *domains,
+             goto done;
+         }
+ 
+-        users_dn = sysdb_user_base_dn(tmp_ctx, dom);
++        /*
++         * dom->sysdb->ldb is not initialized,
++         * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn()
++         */
++        users_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
++                                  SYSDB_TMPL_USER_BASE, dom->name);
+         if (!users_dn) {
+             ret = ENOMEM;
+             goto done;
+         }
+-        groups_dn = sysdb_group_base_dn(tmp_ctx, dom);
++
++        /*
++         * dom->sysdb->ldb is not initialized,
++         * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn()
++         */
++        groups_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
++                                   SYSDB_TMPL_GROUP_BASE, dom->name);
+         if (!groups_dn) {
+             ret = ENOMEM;
+             goto done;
+@@ -1045,7 +1056,12 @@ int sysdb_upgrade_10(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
+         return ret;
+     }
+ 
+-    basedn = sysdb_user_base_dn(tmp_ctx, domain);
++    /*
++     * dom->sysdb->ldb is not initialized,
++     * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn()
++     */
++    basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
++                            SYSDB_TMPL_USER_BASE, domain->name);
+     if (basedn == NULL) {
+         ret = EIO;
+         goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0001-test-common-sss_dp_get_account_recv-fix-assignment.patch b/SOURCES/0001-test-common-sss_dp_get_account_recv-fix-assignment.patch
deleted file mode 100644
index 4733a5c..0000000
--- a/SOURCES/0001-test-common-sss_dp_get_account_recv-fix-assignment.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 1b20d057dd7d4284d4c88319a12eee5845b14d8f Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 10 Jul 2015 12:37:43 +0200
-Subject: [PATCH 01/13] test common: sss_dp_get_account_recv() fix assignment
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tests/cmocka/common_mock_resp_dp.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c
-index 08d74179d8e2dc0561ea3e2d1e9b5580762ee633..a67ceee4a43184d9894c19a5c11161aca4e1caff 100644
---- a/src/tests/cmocka/common_mock_resp_dp.c
-+++ b/src/tests/cmocka/common_mock_resp_dp.c
-@@ -51,7 +51,7 @@ sss_dp_get_account_recv(TALLOC_CTX *mem_ctx,
- 
-     *dp_err = sss_mock_type(dbus_uint16_t);
-     *dp_ret = sss_mock_type(dbus_uint32_t);
--    *dp_ret = sss_mock_type(dbus_uint32_t);
-+    *err_msg = sss_mock_ptr_type(char *);
- 
-     cb = sss_mock_ptr_type(acct_cb_t);
-     if (cb) {
--- 
-2.4.3
-
diff --git a/SOURCES/0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch b/SOURCES/0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch
new file mode 100644
index 0000000..4590e63
--- /dev/null
+++ b/SOURCES/0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch
@@ -0,0 +1,33 @@
+From 36adb8fdc1e0ec14d394a2c51be16c90f4fa1acd Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 8 Jul 2016 12:16:47 +0200
+Subject: [PATCH 02/18] sssctl: Fix error handling after memory allocation
+ failure
+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 4b18d0c25471150940c1a552bc2504ff9debb703)
+---
+ src/tools/sssctl/sssctl_cache.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
+index 9f626d983a4672cf00fba6b3171b822e8f6e02bd..28de6c139d844f98f9b06844492c935696e19643 100644
+--- a/src/tools/sssctl/sssctl_cache.c
++++ b/src/tools/sssctl/sssctl_cache.c
+@@ -364,8 +364,9 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx,
+         filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(%s=%s))",
+                                  class, attr_name, filter_value);
+         talloc_free(filter_value);
+-        if (filter_value == NULL) {
++        if (filter == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
++            ret = ENOMEM;
+             goto done;
+         }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0002-tests-Move-N_ELEMENTS-definition-to-tests-common.h.patch b/SOURCES/0002-tests-Move-N_ELEMENTS-definition-to-tests-common.h.patch
deleted file mode 100644
index bc0e246..0000000
--- a/SOURCES/0002-tests-Move-N_ELEMENTS-definition-to-tests-common.h.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From fd554736d9b0e909acfcdf1aa5358423beefbe91 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 25 Mar 2015 10:03:43 +0100
-Subject: [PATCH 02/13] tests: Move N_ELEMENTS definition to tests/common.h
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Avoids code duplication
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/tests/cmocka/test_nested_groups.c | 3 ---
- src/tests/cmocka/test_nss_srv.c       | 3 ---
- src/tests/common.h                    | 2 ++
- src/tests/sbus_codegen_tests.c        | 3 ---
- 4 files changed, 2 insertions(+), 9 deletions(-)
-
-diff --git a/src/tests/cmocka/test_nested_groups.c b/src/tests/cmocka/test_nested_groups.c
-index eef9df2dc25c231cb81243f48b759e2fced1a85d..8081ff26102e53b2e453838c3a18e4560ac5317e 100644
---- a/src/tests/cmocka/test_nested_groups.c
-+++ b/src/tests/cmocka/test_nested_groups.c
-@@ -48,9 +48,6 @@
- #define GROUP_BASE_DN "cn=groups," OBJECT_BASE_DN
- #define USER_BASE_DN "cn=users," OBJECT_BASE_DN
- 
--#define N_ELEMENTS(arr) \
--    (sizeof(arr) / sizeof(arr[0]))
--
- struct nested_groups_test_ctx {
-     struct sss_test_ctx *tctx;
- 
-diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
-index d1a4c16851427a36b123f04cecee5fe5ae2d333d..3ab8d39c44a8bb8cacae20f534dcbeb6ca7dec08 100644
---- a/src/tests/cmocka/test_nss_srv.c
-+++ b/src/tests/cmocka/test_nss_srv.c
-@@ -41,9 +41,6 @@
- #define TEST_ID_PROVIDER "ldap"
- #define TEST_DOM_SID "S-1-5-21-444379608-1639770488-2995963434"
- 
--#define N_ELEMENTS(arr) \
--    (sizeof(arr) / sizeof(arr[0]))
--
- struct nss_test_ctx {
-     struct sss_test_ctx *tctx;
-     struct sss_domain_info *subdom;
-diff --git a/src/tests/common.h b/src/tests/common.h
-index 0b351f5d647a8f72bdbc399c6fe02579d4b4e1be..1c6de2c3d6eb924ba7306bd350f8546d61f30751 100644
---- a/src/tests/common.h
-+++ b/src/tests/common.h
-@@ -30,6 +30,8 @@
- #include "providers/data_provider.h"
- #include "providers/ldap/sdap.h"
- 
-+#define N_ELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
-+
- extern TALLOC_CTX *global_talloc_context;
- 
- #define check_leaks(ctx, bytes) _check_leaks((ctx), (bytes), __location__)
-diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
-index 9e9be52e84672eb3ee3afa4e13d5f60047150e98..4637b92b84459041806bb5950e969e988716bec8 100644
---- a/src/tests/sbus_codegen_tests.c
-+++ b/src/tests/sbus_codegen_tests.c
-@@ -33,9 +33,6 @@
- #include "tests/sbus_codegen_tests_generated.h"
- #include "util/util_errors.h"
- 
--#define N_ELEMENTS(arr) \
--    (sizeof(arr) / sizeof(arr[0]))
--
- /* The following 2 macros were taken from check's project source files (0.9.10)
-  * http://check.sourceforge.net/
-  */
--- 
-2.4.3
-
diff --git a/SOURCES/0003-SYSDB-Add-functions-to-look-up-multiple-entries-incl.patch b/SOURCES/0003-SYSDB-Add-functions-to-look-up-multiple-entries-incl.patch
deleted file mode 100644
index 5b07384..0000000
--- a/SOURCES/0003-SYSDB-Add-functions-to-look-up-multiple-entries-incl.patch
+++ /dev/null
@@ -1,925 +0,0 @@
-From 1d245226d88537123827dcda3fd0bd093275019d Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 24 Mar 2015 23:24:22 +0100
-Subject: [PATCH 03/13] SYSDB: Add functions to look up multiple entries
- including name and custom filter
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Adds new sysdb function:
-    - sysdb_enumpwent_filter
-    - sysdb_enumpwent_filter_with_views
-    - sysdb_enumgrent_filter
-    - sysdb_enumgrent_filter_with_views
-
-These are similar to enumeration functions, but optionally allow to
-specify a filter to be applied on user/group names. Also an additional
-custom filter can be applied.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/db/sysdb.h                      |  24 ++
- src/db/sysdb_search.c               | 252 ++++++++++++------
- src/tests/cmocka/test_sysdb_views.c | 494 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 691 insertions(+), 79 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 48dd26dd294333b265b69b28cd3b5d37f1293b43..0f745ccb1a646d77ba4ad3d714d5f4dce0a51211 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -601,10 +601,22 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
-                     struct sss_domain_info *domain,
-                     struct ldb_result **res);
- 
-+int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
-+                           struct sss_domain_info *domain,
-+                           const char *name_filter,
-+                           const char *addtl_filter,
-+                           struct ldb_result **res);
-+
- int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
-                                struct sss_domain_info *domain,
-                                struct ldb_result **res);
- 
-+int sysdb_enumpwent_filter_with_views(TALLOC_CTX *mem_ctx,
-+                                      struct sss_domain_info *domain,
-+                                      const char *name_filter,
-+                                      const char *addtl_filter,
-+                                      struct ldb_result **res);
-+
- int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
-                    struct sss_domain_info *domain,
-                    const char *name,
-@@ -619,10 +631,22 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
-                     struct sss_domain_info *domain,
-                     struct ldb_result **res);
- 
-+int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
-+                           struct sss_domain_info *domain,
-+                           const char *name_filter,
-+                           const char *addtl_filter,
-+                           struct ldb_result **res);
-+
- int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
-                                struct sss_domain_info *domain,
-                                struct ldb_result **res);
- 
-+int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx,
-+                                      struct sss_domain_info *domain,
-+                                      const char *name_filter,
-+                                      const char *addtl_filter,
-+                                      struct ldb_result **res);
-+
- struct sysdb_netgroup_ctx {
-     enum {SYSDB_NETGROUP_TRIPLE_VAL, SYSDB_NETGROUP_GROUP_VAL} type;
-     union {
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index a8dcc9f8d6617be8e8fb82a1c6360c6df9726a37..4f617b841bf3b3760d9cb05a06f4b46ea0c58ff5 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -255,44 +255,104 @@ done:
-     return ret;
- }
- 
-+static char *enum_filter(TALLOC_CTX *mem_ctx,
-+                         const char *base_filter,
-+                         const char *name_filter,
-+                         const char *addtl_filter)
-+{
-+    char *filter;
-+    TALLOC_CTX *tmp_ctx = NULL;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return NULL;
-+    }
-+
-+    if (name_filter == NULL && addtl_filter == NULL) {
-+        filter = talloc_strdup(tmp_ctx, base_filter);
-+    } else {
-+        filter = talloc_asprintf(tmp_ctx, "(&%s", base_filter);
-+
-+        if (filter != NULL && name_filter != NULL) {
-+            filter = talloc_asprintf_append(filter, "(%s=%s)",
-+                                            SYSDB_NAME, name_filter);
-+        }
-+
-+        if (filter != NULL && addtl_filter != NULL) {
-+            filter = talloc_asprintf_append(filter, "%s", addtl_filter);
-+        }
-+
-+        if (filter != NULL) {
-+            filter = talloc_asprintf_append(filter, ")");
-+        }
-+    }
-+
-+    if (filter) {
-+        talloc_steal(mem_ctx, filter);
-+    }
-+
-+    talloc_free(tmp_ctx);
-+    return filter;
-+}
-+
-+int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
-+                           struct sss_domain_info *domain,
-+                           const char *name_filter,
-+                           const char *addtl_filter,
-+                           struct ldb_result **_res)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    static const char *attrs[] = SYSDB_PW_ATTRS;
-+    char *filter = NULL;
-+    struct ldb_dn *base_dn;
-+    struct ldb_result *res;
-+    int ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (!tmp_ctx) {
-+        return ENOMEM;
-+    }
-+
-+    base_dn = sysdb_user_base_dn(tmp_ctx, domain);
-+    if (!base_dn) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    filter = enum_filter(tmp_ctx, SYSDB_PWENT_FILTER,
-+                         name_filter, addtl_filter);
-+    if (filter == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    DEBUG(SSSDBG_TRACE_LIBS, "Searching cache with [%s]\n", filter);
-+
-+    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
-+                     LDB_SCOPE_SUBTREE, attrs, "%s", filter);
-+    if (ret) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    *_res = talloc_steal(mem_ctx, res);
-+
-+done:
-+    talloc_zfree(tmp_ctx);
-+    return ret;
-+}
-+
- int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
-                     struct sss_domain_info *domain,
-                     struct ldb_result **_res)
- {
--    TALLOC_CTX *tmp_ctx;
--    static const char *attrs[] = SYSDB_PW_ATTRS;
--    struct ldb_dn *base_dn;
--    struct ldb_result *res;
--    int ret;
--
--    tmp_ctx = talloc_new(NULL);
--    if (!tmp_ctx) {
--        return ENOMEM;
--    }
--
--    base_dn = sysdb_user_base_dn(tmp_ctx, domain);
--    if (!base_dn) {
--        ret = ENOMEM;
--        goto done;
--    }
--
--    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
--                     LDB_SCOPE_SUBTREE, attrs, SYSDB_PWENT_FILTER);
--    if (ret) {
--        ret = sysdb_error_to_errno(ret);
--        goto done;
--    }
--
--    *_res = talloc_steal(mem_ctx, res);
--
--done:
--    talloc_zfree(tmp_ctx);
--    return ret;
-+    return sysdb_enumpwent_filter(mem_ctx, domain, NULL, 0, _res);
- }
- 
--int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
--                               struct sss_domain_info *domain,
--                               struct ldb_result **_res)
-+int sysdb_enumpwent_filter_with_views(TALLOC_CTX *mem_ctx,
-+                                      struct sss_domain_info *domain,
-+                                      const char *name_filter,
-+                                      const char *addtl_filter,
-+                                      struct ldb_result **_res)
- {
-     TALLOC_CTX *tmp_ctx;
-     struct ldb_result *res;
-@@ -305,7 +365,7 @@ int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
-         return ENOMEM;
-     }
- 
--    ret = sysdb_enumpwent(tmp_ctx, domain, &res);
-+    ret = sysdb_enumpwent_filter(tmp_ctx, domain, name_filter, addtl_filter, &res);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "sysdb_enumpwent failed.\n");
-         goto done;
-@@ -331,6 +391,13 @@ done:
-     return ret;
- }
- 
-+int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
-+                               struct sss_domain_info *domain,
-+                               struct ldb_result **_res)
-+{
-+    return sysdb_enumpwent_filter_with_views(mem_ctx, domain, NULL, NULL, _res);
-+}
-+
- /* groups */
- 
- static int mpg_convert(struct ldb_message *msg)
-@@ -662,57 +729,77 @@ done:
-     return ret;
- }
- 
-+int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
-+                           struct sss_domain_info *domain,
-+                           const char *name_filter,
-+                           const char *addtl_filter,
-+                           struct ldb_result **_res)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    static const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+    const char *filter = NULL;
-+    const char *base_filter;
-+    struct ldb_dn *base_dn;
-+    struct ldb_result *res;
-+    int ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (!tmp_ctx) {
-+        return ENOMEM;
-+    }
-+
-+    if (domain->mpg) {
-+        base_filter = SYSDB_GRENT_MPG_FILTER;
-+        base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
-+                                 SYSDB_DOM_BASE, domain->name);
-+    } else {
-+        base_filter = SYSDB_GRENT_FILTER;
-+        base_dn = sysdb_group_base_dn(tmp_ctx, domain);
-+    }
-+    if (!base_dn) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    filter = enum_filter(tmp_ctx, base_filter,
-+                         name_filter, addtl_filter);
-+    if (filter == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    DEBUG(SSSDBG_TRACE_LIBS, "Searching cache with [%s]\n", filter);
-+
-+    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
-+                     LDB_SCOPE_SUBTREE, attrs, "%s", filter);
-+    if (ret) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    ret = mpg_res_convert(res);
-+    if (ret) {
-+        goto done;
-+    }
-+
-+    *_res = talloc_steal(mem_ctx, res);
-+
-+done:
-+    talloc_zfree(tmp_ctx);
-+    return ret;
-+}
-+
- int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
-                     struct sss_domain_info *domain,
-                     struct ldb_result **_res)
- {
--    TALLOC_CTX *tmp_ctx;
--    static const char *attrs[] = SYSDB_GRSRC_ATTRS;
--    const char *fmt_filter;
--    struct ldb_dn *base_dn;
--    struct ldb_result *res;
--    int ret;
--
--    tmp_ctx = talloc_new(NULL);
--    if (!tmp_ctx) {
--        return ENOMEM;
--    }
--
--    if (domain->mpg) {
--        fmt_filter = SYSDB_GRENT_MPG_FILTER;
--        base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
--                                 SYSDB_DOM_BASE, domain->name);
--    } else {
--        fmt_filter = SYSDB_GRENT_FILTER;
--        base_dn = sysdb_group_base_dn(tmp_ctx, domain);
--    }
--    if (!base_dn) {
--        ret = ENOMEM;
--        goto done;
--    }
--
--    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
--                     LDB_SCOPE_SUBTREE, attrs, "%s", fmt_filter);
--    if (ret) {
--        ret = sysdb_error_to_errno(ret);
--        goto done;
--    }
--
--    ret = mpg_res_convert(res);
--    if (ret) {
--        goto done;
--    }
--
--    *_res = talloc_steal(mem_ctx, res);
--
--done:
--    talloc_zfree(tmp_ctx);
--    return ret;
-+    return sysdb_enumgrent_filter(mem_ctx, domain, NULL, 0, _res);
- }
- 
--int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
--                               struct sss_domain_info *domain,
--                               struct ldb_result **_res)
-+int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx,
-+                                      struct sss_domain_info *domain,
-+                                      const char *name_filter,
-+                                      const char *addtl_filter,
-+                                      struct ldb_result **_res)
- {
-     TALLOC_CTX *tmp_ctx;
-     struct ldb_result *res;
-@@ -725,7 +812,7 @@ int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
-         return ENOMEM;
-     }
- 
--    ret = sysdb_enumgrent(tmp_ctx, domain,&res);
-+    ret = sysdb_enumgrent_filter(tmp_ctx, domain, name_filter, addtl_filter, &res);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "sysdb_enumgrent failed.\n");
-         goto done;
-@@ -759,6 +846,13 @@ done:
-     return ret;
- }
- 
-+int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
-+                               struct sss_domain_info *domain,
-+                               struct ldb_result **_res)
-+{
-+    return sysdb_enumgrent_filter_with_views(mem_ctx, domain, NULL, NULL, _res);
-+}
-+
- int sysdb_initgroups(TALLOC_CTX *mem_ctx,
-                      struct sss_domain_info *domain,
-                      const char *name,
-diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
-index 69118cd87a172696f8220e1446df7a856e368cb6..1fb598219e9ee581e465ddbb32ba9f2544600c26 100644
---- a/src/tests/cmocka/test_sysdb_views.c
-+++ b/src/tests/cmocka/test_sysdb_views.c
-@@ -45,6 +45,7 @@
- #define TEST_USER_HOMEDIR "/home/home"
- #define TEST_USER_SHELL "/bin/shell"
- #define TEST_USER_SID "S-1-2-3-4"
-+#define TEST_GID_OVERRIDE_BASE 100
- 
- struct sysdb_test_ctx {
-     struct sysdb_ctx *sysdb;
-@@ -108,6 +109,7 @@ static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
-                            TESTS_PATH, &test_ctx->domain);
-     assert_int_equal(ret, EOK);
- 
-+    test_ctx->domain->has_views = true;
-     test_ctx->sysdb = test_ctx->domain->sysdb;
- 
-     *ctx = test_ctx;
-@@ -115,6 +117,7 @@ static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
- }
- 
- #define setup_sysdb_tests(ctx) _setup_sysdb_tests((ctx), false)
-+#define setup_sysdb_enum_tests(ctx) _setup_sysdb_tests((ctx), true)
- 
- static int test_sysdb_setup(void **state)
- {
-@@ -426,6 +429,473 @@ void test_sysdb_invalidate_overrides(void **state)
-     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));
-+
-+    ret = sysdb_delete_user(test_ctx->domain, TEST_USER_NAME, 0);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+static const char *users[] = { "alice", "bob", "barney", NULL };
-+
-+static void enum_test_user_override(struct sysdb_test_ctx *test_ctx,
-+                                    const char *name)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    struct ldb_dn *dn;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *anchor;
-+    const char *override_gecos;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    attrs = sysdb_new_attrs(tmp_ctx);
-+    assert_non_null(attrs);
-+
-+    dn = sysdb_user_dn(tmp_ctx, test_ctx->domain, name);
-+    assert_non_null(dn);
-+
-+    anchor = talloc_asprintf(tmp_ctx, "%s%s", TEST_ANCHOR_PREFIX, name);
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
-+    assert_int_equal(ret, EOK);
-+
-+    override_gecos = talloc_asprintf(attrs, "%s_GECOS_OVERRIDE", name);
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_GECOS, override_gecos);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_store_override(test_ctx->domain, TEST_VIEW_NAME,
-+                               SYSDB_MEMBER_USER, attrs, dn);
-+    assert_int_equal(ret, EOK);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+static void enum_test_add_users(struct sysdb_test_ctx *test_ctx,
-+                                const char *usernames[])
-+{
-+    int i;
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+
-+    for (i = 0; usernames[i] != NULL; i++) {
-+        attrs = talloc(test_ctx, struct sysdb_attrs);
-+        assert_non_null(attrs);
-+
-+        ret = sysdb_store_user(test_ctx->domain, usernames[i],
-+                               NULL, 0, 0, usernames[i], "/", "/bin/sh",
-+                               NULL, NULL, NULL, 1, 1234 + i);
-+        assert_int_equal(ret, EOK);
-+
-+        enum_test_user_override(test_ctx, usernames[i]);
-+
-+        talloc_free(attrs);
-+    }
-+}
-+
-+static void enum_test_del_users(struct sss_domain_info *dom,
-+                               const char *usernames[])
-+{
-+    int i;
-+    int ret;
-+
-+    for (i = 0; usernames[i] != NULL; i++) {
-+        ret = sysdb_delete_user(dom, usernames[i], 0);
-+        if (ret != EOK && ret != ENOENT) {
-+            fail();
-+        }
-+    }
-+}
-+
-+static int test_enum_users_setup(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx;
-+
-+    assert_true(leak_check_setup());
-+
-+    ret = setup_sysdb_enum_tests(&test_ctx);
-+    assert_int_equal(ret, EOK);
-+
-+    enum_test_add_users(test_ctx, users);
-+
-+    *state = (void *) test_ctx;
-+    return 0;
-+}
-+
-+static void assert_user_attrs(struct ldb_message *msg,
-+                              const char *name,
-+                              bool has_views)
-+{
-+    const char *str;
-+
-+    str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+    assert_string_equal(str, name);
-+    str = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
-+    assert_string_equal(str, name);
-+
-+    str = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_GECOS, NULL);
-+    if (has_views) {
-+        char *override;
-+
-+        assert_non_null(str);
-+        override = talloc_asprintf(msg, "%s_GECOS_OVERRIDE", name);
-+        assert_non_null(override);
-+
-+        assert_string_equal(str, override);
-+        talloc_free(override);
-+    } else {
-+        assert_null(str);
-+    }
-+}
-+
-+static int test_enum_users_teardown(void **state)
-+{
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+
-+    enum_test_del_users(test_ctx->domain, users);
-+    return test_sysdb_teardown(state);
-+}
-+
-+static void check_enumpwent(int ret, struct ldb_result *res, bool views)
-+{
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, N_ELEMENTS(users)-1);
-+    assert_user_attrs(res->msgs[0], "barney", views);
-+    assert_user_attrs(res->msgs[1], "alice", views);
-+    assert_user_attrs(res->msgs[2], "bob", views);
-+}
-+
-+static void test_sysdb_enumpwent(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+
-+    ret = sysdb_enumpwent(test_ctx, test_ctx->domain, &res);
-+    check_enumpwent(ret, res, false);
-+}
-+
-+static void test_sysdb_enumpwent_views(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+
-+    ret = sysdb_enumpwent_with_views(test_ctx, test_ctx->domain, &res);
-+    check_enumpwent(ret, res, true);
-+}
-+
-+static void test_sysdb_enumpwent_filter(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+    char *addtl_filter;
-+
-+    ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "a*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_user_attrs(res->msgs[0], "alice", false);
-+
-+    ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "b*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 2);
-+    assert_user_attrs(res->msgs[0], "barney", false);
-+    assert_user_attrs(res->msgs[1], "bob", false);
-+
-+    ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "c*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 0);
-+
-+    ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, N_ELEMENTS(users)-1);
-+
-+    /* Test searching based on time as well */
-+    addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
-+                                   SYSDB_LAST_UPDATE, 1233);
-+    ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "a*", addtl_filter, &res);
-+    talloc_free(addtl_filter);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 0);
-+
-+    addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
-+                                   SYSDB_LAST_UPDATE, 1234);
-+    ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "a*", addtl_filter, &res);
-+    talloc_free(addtl_filter);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_user_attrs(res->msgs[0], "alice", false);
-+}
-+
-+static void test_sysdb_enumpwent_filter_views(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+    char *addtl_filter;
-+
-+    ret = sysdb_enumpwent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "a*", NULL, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_user_attrs(res->msgs[0], "alice", true);
-+
-+    ret = sysdb_enumpwent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "b*", NULL, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 2);
-+    assert_user_attrs(res->msgs[0], "barney", true);
-+    assert_user_attrs(res->msgs[1], "bob", true);
-+
-+    addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
-+                                   SYSDB_LAST_UPDATE, 1235);
-+    ret = sysdb_enumpwent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "b*", addtl_filter, &res);
-+    talloc_free(addtl_filter);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_user_attrs(res->msgs[0], "bob", true);
-+
-+    ret = sysdb_enumpwent_filter_with_views(test_ctx,
-+                                            test_ctx->domain, "c*", NULL, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 0);
-+
-+    ret = sysdb_enumpwent_filter_with_views(test_ctx,
-+                                            test_ctx->domain, "*", NULL, &res);
-+    check_enumpwent(ret, res, true);
-+}
-+
-+static const char *groups[] = { "one", "two", "three", NULL };
-+
-+static void enum_test_group_override(struct sysdb_test_ctx *test_ctx,
-+                                     const char *name,
-+                                     unsigned override_gid)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    struct ldb_dn *dn;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *anchor;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    attrs = sysdb_new_attrs(tmp_ctx);
-+    assert_non_null(attrs);
-+
-+    dn = sysdb_group_dn(tmp_ctx, test_ctx->domain, name);
-+    assert_non_null(dn);
-+
-+    anchor = talloc_asprintf(tmp_ctx, "%s%s", TEST_ANCHOR_PREFIX, name);
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, override_gid);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_store_override(test_ctx->domain, TEST_VIEW_NAME,
-+                               SYSDB_MEMBER_GROUP, attrs, dn);
-+    assert_int_equal(ret, EOK);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+static void enum_test_add_groups(struct sysdb_test_ctx *test_ctx,
-+                                 const char *groupnames[])
-+{
-+    int i;
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+
-+    for (i = 0; groupnames[i] != NULL; i++) {
-+        attrs = talloc(test_ctx, struct sysdb_attrs);
-+        assert_non_null(attrs);
-+
-+        ret = sysdb_store_group(test_ctx->domain, groupnames[i],
-+                                0, NULL, 1, 1234 + i);
-+        assert_int_equal(ret, EOK);
-+
-+        enum_test_group_override(test_ctx, groupnames[i],
-+                                 TEST_GID_OVERRIDE_BASE + i);
-+        talloc_free(attrs);
-+    }
-+}
-+
-+static void enum_test_del_groups(struct sss_domain_info *dom,
-+                                 const char *groupnames[])
-+{
-+    int i;
-+    int ret;
-+
-+    for (i = 0; groupnames[i] != NULL; i++) {
-+        ret = sysdb_delete_group(dom, groupnames[i], 0);
-+        if (ret != EOK && ret != ENOENT) {
-+            fail();
-+        }
-+    }
-+}
-+
-+static int test_enum_groups_setup(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx;
-+
-+    assert_true(leak_check_setup());
-+
-+    ret = setup_sysdb_enum_tests(&test_ctx);
-+    assert_int_equal(ret, EOK);
-+
-+    enum_test_add_groups(test_ctx, groups);
-+
-+    *state = (void *) test_ctx;
-+    return 0;
-+}
-+
-+static int test_enum_groups_teardown(void **state)
-+{
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+
-+    enum_test_del_groups(test_ctx->domain, groups);
-+    return test_sysdb_teardown(state);
-+}
-+
-+static void assert_group_attrs(struct ldb_message *msg,
-+                               const char *name,
-+                               unsigned expected_override_gid)
-+{
-+    const char *str;
-+    unsigned gid;
-+
-+    str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+    assert_string_equal(str, name);
-+
-+    if (expected_override_gid) {
-+        gid = ldb_msg_find_attr_as_uint64(msg,
-+                                          OVERRIDE_PREFIX SYSDB_GIDNUM, 0);
-+        assert_int_equal(gid, expected_override_gid);
-+    }
-+}
-+
-+static void check_enumgrent(int ret, struct ldb_result *res, bool views)
-+{
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, N_ELEMENTS(groups)-1);
-+    assert_group_attrs(res->msgs[0], "three", views ? TEST_GID_OVERRIDE_BASE + 2 : 0);
-+    assert_group_attrs(res->msgs[1], "one", views ? TEST_GID_OVERRIDE_BASE : 0);
-+    assert_group_attrs(res->msgs[2], "two", views ? TEST_GID_OVERRIDE_BASE + 1 : 0);
-+}
-+
-+static void test_sysdb_enumgrent(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+
-+    ret = sysdb_enumgrent(test_ctx, test_ctx->domain, &res);
-+    check_enumgrent(ret, res, false);
-+}
-+
-+static void test_sysdb_enumgrent_views(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+
-+    ret = sysdb_enumgrent_with_views(test_ctx, test_ctx->domain, &res);
-+    check_enumgrent(ret, res, true);
-+}
-+
-+static void test_sysdb_enumgrent_filter(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+    char *addtl_filter;
-+
-+    ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "o*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_group_attrs(res->msgs[0], "one", 0);
-+
-+    ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "t*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 2);
-+    assert_group_attrs(res->msgs[0], "three", 0);
-+    assert_group_attrs(res->msgs[1], "two", 0);
-+
-+    ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "x*", 0, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 0);
-+
-+    ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "*", 0, &res);
-+    check_enumgrent(ret, res, false);
-+
-+    addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
-+                                   SYSDB_LAST_UPDATE, 1233);
-+    ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "o*", addtl_filter, &res);
-+    talloc_free(addtl_filter);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 0);
-+
-+    addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
-+                                   SYSDB_LAST_UPDATE, 1234);
-+    ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "o*", addtl_filter, &res);
-+    talloc_free(addtl_filter);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_group_attrs(res->msgs[0], "one", 0);
-+
-+}
-+
-+static void test_sysdb_enumgrent_filter_views(void **state)
-+{
-+    int ret;
-+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-+                                                        struct sysdb_test_ctx);
-+    struct ldb_result *res;
-+    char *addtl_filter;
-+
-+    ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "o*", NULL, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_group_attrs(res->msgs[0], "one", TEST_GID_OVERRIDE_BASE);
-+
-+    ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "t*", NULL, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 2);
-+    assert_group_attrs(res->msgs[0], "three", TEST_GID_OVERRIDE_BASE + 2);
-+    assert_group_attrs(res->msgs[1], "two", TEST_GID_OVERRIDE_BASE + 1);
-+
-+    addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
-+                                   SYSDB_LAST_UPDATE, 1235);
-+    ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "t*", addtl_filter, &res);
-+    talloc_free(addtl_filter);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 1);
-+    assert_group_attrs(res->msgs[0], "two", TEST_GID_OVERRIDE_BASE + 1);
-+
-+    ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "x*", NULL, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(res->count, 0);
-+
-+    ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
-+                                            "*", NULL, &res);
-+    check_enumgrent(ret, res, true);
- }
- 
- int main(int argc, const char *argv[])
-@@ -453,6 +923,30 @@ int main(int argc, const char *argv[])
-                                         test_sysdb_setup, test_sysdb_teardown),
-         cmocka_unit_test_setup_teardown(test_sysdb_invalidate_overrides,
-                                         test_sysdb_setup, test_sysdb_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumpwent,
-+                                        test_enum_users_setup,
-+                                        test_enum_users_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumpwent_views,
-+                                        test_enum_users_setup,
-+                                        test_enum_users_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumpwent_filter,
-+                                        test_enum_users_setup,
-+                                        test_enum_users_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumpwent_filter_views,
-+                                        test_enum_users_setup,
-+                                        test_enum_users_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumgrent,
-+                                        test_enum_groups_setup,
-+                                        test_enum_groups_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumgrent_views,
-+                                        test_enum_groups_setup,
-+                                        test_enum_groups_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumgrent_filter,
-+                                        test_enum_groups_setup,
-+                                        test_enum_groups_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_enumgrent_filter_views,
-+                                        test_enum_groups_setup,
-+                                        test_enum_groups_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.4.3
-
diff --git a/SOURCES/0003-sssctl-config-check-access-check-report.patch b/SOURCES/0003-sssctl-config-check-access-check-report.patch
new file mode 100644
index 0000000..3a564f8
--- /dev/null
+++ b/SOURCES/0003-sssctl-config-check-access-check-report.patch
@@ -0,0 +1,34 @@
+From 0df858e26420bc6fb49819572694fced6791d414 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Thu, 7 Jul 2016 15:43:11 +0200
+Subject: [PATCH 03/18] sssctl: config-check access check report
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Improve output when access check error
+is detected by sssctl config-check command.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 9dc66cb6b96a885f7272a3c4aa6a44d60cdce82c)
+---
+ src/tools/sssctl/sssctl_config.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c
+index fc13582accd63f58c9d8bce59c4d6e898a96b170..4f6dbcdd7d04183c65b6613efbe5ab95df19e2c7 100644
+--- a/src/tools/sssctl/sssctl_config.c
++++ b/src/tools/sssctl/sssctl_config.c
+@@ -68,7 +68,8 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
+     /* Check the file permissions */
+     ret = sss_ini_config_access_check(init_data);
+     if (ret != EOK) {
+-        printf(_("Access check on sssd.conf file failed.\n"));
++        printf(_("File ownership and permissions check failed. "
++               "Expected root:root and 0600.\n"));
+         ret = EPERM;
+         goto done;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0004-DP-Add-DP_WILDCARD-and-SSS_DP_WILDCARD_USER-SSS_DP_W.patch b/SOURCES/0004-DP-Add-DP_WILDCARD-and-SSS_DP_WILDCARD_USER-SSS_DP_W.patch
deleted file mode 100644
index 1d308d5..0000000
--- a/SOURCES/0004-DP-Add-DP_WILDCARD-and-SSS_DP_WILDCARD_USER-SSS_DP_W.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From 15dcdcf23bce2423f05c03f7c0aa61f23383d488 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 4 May 2015 12:34:32 +0200
-Subject: [PATCH 04/13] DP: Add DP_WILDCARD and
- SSS_DP_WILDCARD_USER/SSS_DP_WILDCARD_GROUP
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Extends the Data Provider interface and the responder<->Data provider
-interface with wildcard lookups.
-
-The patch uses a new "wildcard" prefix rather than reusing the existing
-user/group prefixes.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/providers/data_provider.h       |  4 ++++
- src/providers/data_provider_be.c    |  5 +++++
- src/responder/common/responder.h    |  4 +++-
- src/responder/common/responder_dp.c | 11 +++++++++++
- 4 files changed, 23 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
-index 13a700308e9c9d1a80c0310dbb1c17de33607498..510c63ce41c99314ec8fcf11fffb2e66082e8951 100644
---- a/src/providers/data_provider.h
-+++ b/src/providers/data_provider.h
-@@ -129,6 +129,7 @@
- #define BE_FILTER_SECID 4
- #define BE_FILTER_UUID 5
- #define BE_FILTER_CERT 6
-+#define BE_FILTER_WILDCARD 7
- 
- #define BE_REQ_USER          0x0001
- #define BE_REQ_GROUP         0x0002
-@@ -153,6 +154,9 @@
- #define DP_SEC_ID_LEN (sizeof(DP_SEC_ID) - 1)
- #define DP_CERT_LEN (sizeof(DP_CERT) - 1)
- 
-+#define DP_WILDCARD "wildcard"
-+#define DP_WILDCARD_LEN (sizeof(DP_WILDCARD) - 1)
-+
- #define EXTRA_NAME_IS_UPN "U"
- #define EXTRA_INPUT_MAYBE_WITH_VIEW "V"
- 
-diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
-index f5bdfb676011975defa4c5a734d420c8694f3bdd..d147630248f0a24f5a632760b55b9284a6928e40 100644
---- a/src/providers/data_provider_be.c
-+++ b/src/providers/data_provider_be.c
-@@ -1204,6 +1204,11 @@ static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
-             ret = split_name_extended(req, &filter[DP_CERT_LEN + 1],
-                                       &req->filter_value,
-                                       &req->extra_value);
-+        } else if (strncmp(filter, DP_WILDCARD"=", DP_WILDCARD_LEN + 1) == 0) {
-+            req->filter_type = BE_FILTER_WILDCARD;
-+            ret = split_name_extended(req, &filter[DP_WILDCARD_LEN + 1],
-+                                      &req->filter_value,
-+                                      &req->extra_value);
-         } else if (strcmp(filter, ENUM_INDICATOR) == 0) {
-             req->filter_type = BE_FILTER_ENUM;
-             req->filter_value = NULL;
-diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
-index bd0250d52aae1efdac3bc0847f692542c6cfb6d2..4d927cfe321bf3ad240b7c175568081ea73ab652 100644
---- a/src/responder/common/responder.h
-+++ b/src/responder/common/responder.h
-@@ -282,7 +282,9 @@ enum sss_dp_acct_type {
-     SSS_DP_SERVICES,
-     SSS_DP_SECID,
-     SSS_DP_USER_AND_GROUP,
--    SSS_DP_CERT
-+    SSS_DP_CERT,
-+    SSS_DP_WILDCARD_USER,
-+    SSS_DP_WILDCARD_GROUP,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c
-index f752c94c37fd0efa0d072ef8c567bd875a08e6f7..f7f8df04e80439d2d02df3e4d2aa4f3576997f36 100644
---- a/src/responder/common/responder_dp.c
-+++ b/src/responder/common/responder_dp.c
-@@ -528,9 +528,11 @@ sss_dp_get_account_msg(void *pvt)
- 
-     switch (info->type) {
-         case SSS_DP_USER:
-+        case SSS_DP_WILDCARD_USER:
-             be_type = BE_REQ_USER;
-             break;
-         case SSS_DP_GROUP:
-+        case SSS_DP_WILDCARD_GROUP:
-             be_type = BE_REQ_GROUP;
-             break;
-         case SSS_DP_INITGROUPS:
-@@ -574,6 +576,15 @@ sss_dp_get_account_msg(void *pvt)
-                 filter = talloc_asprintf(info, "%s=%s", DP_CERT,
-                                                info->opt_name);
-             }
-+        } else if (info->type == SSS_DP_WILDCARD_USER ||
-+                   info->type == SSS_DP_WILDCARD_GROUP) {
-+            if (info->extra) {
-+                filter = talloc_asprintf(info, "%s=%s:%s", DP_WILDCARD,
-+                                               info->opt_name, info->extra);
-+            } else {
-+                filter = talloc_asprintf(info, "%s=%s", DP_WILDCARD,
-+                                               info->opt_name);
-+            }
-         } else {
-             if (info->extra) {
-                 filter = talloc_asprintf(info, "name=%s:%s",
--- 
-2.4.3
-
diff --git a/SOURCES/0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch b/SOURCES/0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch
new file mode 100644
index 0000000..e7bf9c3
--- /dev/null
+++ b/SOURCES/0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch
@@ -0,0 +1,32 @@
+From 95939e9831fb3d9a8f464ecff3377dd6027e0321 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 10 May 2016 14:11:36 +0200
+Subject: [PATCH 04/18] FO: Set port to NOT_WORKING when trying a next server
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves: https://fedorahosted.org/sssd/ticket/3009
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit c420ce830ac0b0b288a2a887ec2cfce5c748018c)
+---
+ src/providers/fail_over.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
+index e945c9924597c7addeeb11090e1c1aee5596cb71..1d88d2aa54bfdebd4b648e2b13fa8d03e2be3973 100644
+--- a/src/providers/fail_over.c
++++ b/src/providers/fail_over.c
+@@ -1546,7 +1546,7 @@ void fo_try_next_server(struct fo_service *service)
+     service->active_server = 0;
+ 
+     if (server->port_status == PORT_WORKING) {
+-        server->port_status = PORT_NEUTRAL;
++        server->port_status = PORT_NOT_WORKING;
+     }
+ }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0005-cache_req-Extend-cache_req-with-wildcard-lookups.patch b/SOURCES/0005-cache_req-Extend-cache_req-with-wildcard-lookups.patch
deleted file mode 100644
index 40a41fb..0000000
--- a/SOURCES/0005-cache_req-Extend-cache_req-with-wildcard-lookups.patch
+++ /dev/null
@@ -1,800 +0,0 @@
-From e069e53495d77bc737abd80fb2e7799fa6245e0f Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 24 Mar 2015 23:24:50 +0100
-Subject: [PATCH 05/13] cache_req: Extend cache_req with wildcard lookups
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Adds two new functions to the cache_req API:
-    - cache_req_user_by_filter_send
-    - cache_req_group_by_filter_send
-
-These functions can be used to retrieve users or groups that match a
-specified filter.
-
-Also renames a variable to avoid constant confusion -- the variable is
-only used for debug output.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/responder/common/responder_cache_req.c  | 156 ++++++++++-
- src/responder/common/responder_cache_req.h  |  24 +-
- src/tests/cmocka/test_responder_cache_req.c | 414 +++++++++++++++++++++++++++-
- 3 files changed, 579 insertions(+), 15 deletions(-)
-
-diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c
-index dd81abadf71c5e10e7bc2ea2490429a49bdc0270..e7099f171d7ef39af7b146a524dadc38a9165e22 100644
---- a/src/responder/common/responder_cache_req.c
-+++ b/src/responder/common/responder_cache_req.c
-@@ -28,6 +28,44 @@
- #include "responder/common/responder_cache_req.h"
- #include "providers/data_provider.h"
- 
-+static errno_t updated_users_by_filter(TALLOC_CTX *mem_ctx,
-+                                       struct sss_domain_info *domain,
-+                                       const char *name_filter,
-+                                       time_t since,
-+                                       struct ldb_result **_res)
-+{
-+    int ret;
-+    char *recent_filter;
-+
-+    recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
-+                                    SYSDB_LAST_UPDATE, since);
-+    ret = sysdb_enumpwent_filter_with_views(mem_ctx, domain,
-+                                            name_filter, recent_filter,
-+                                            _res);
-+    talloc_free(recent_filter);
-+
-+    return ret;
-+}
-+
-+static errno_t updated_groups_by_filter(TALLOC_CTX *mem_ctx,
-+                                        struct sss_domain_info *domain,
-+                                        const char *name_filter,
-+                                        time_t since,
-+                                        struct ldb_result **_res)
-+{
-+    int ret;
-+    char *recent_filter;
-+
-+    recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
-+                                    SYSDB_LAST_UPDATE, since);
-+    ret = sysdb_enumgrent_filter_with_views(mem_ctx, domain,
-+                                            name_filter, recent_filter,
-+                                            _res);
-+    talloc_free(recent_filter);
-+
-+    return ret;
-+}
-+
- struct cache_req_input {
-     enum cache_req_type type;
- 
-@@ -51,6 +89,8 @@ struct cache_req_input {
- 
-     /* Fully qualified object name used in debug messages. */
-     const char *debug_fqn;
-+    /* Time when the request started. Useful for by-filter lookups */
-+    time_t req_start;
- };
- 
- struct cache_req_input *
-@@ -68,11 +108,14 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
-     }
- 
-     input->type = type;
-+    input->req_start = time(NULL);
- 
-     /* Check that input parameters match selected type. */
-     switch (input->type) {
-     case CACHE_REQ_USER_BY_NAME:
-     case CACHE_REQ_GROUP_BY_NAME:
-+    case CACHE_REQ_USER_BY_FILTER:
-+    case CACHE_REQ_GROUP_BY_FILTER:
-     case CACHE_REQ_INITGROUPS:
-         if (name == NULL) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
-@@ -121,9 +164,18 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
-     case CACHE_REQ_INITGROUPS:
-         input->dp_type = SSS_DP_INITGROUPS;
-         break;
-+
-     case CACHE_REQ_USER_BY_CERT:
-         input->dp_type = SSS_DP_CERT;
-         break;
-+
-+    case CACHE_REQ_USER_BY_FILTER:
-+        input->dp_type = SSS_DP_WILDCARD_USER;
-+        break;
-+
-+    case CACHE_REQ_GROUP_BY_FILTER:
-+        input->dp_type = SSS_DP_WILDCARD_GROUP;
-+        break;
-     }
- 
-     return input;
-@@ -157,7 +209,7 @@ cache_req_input_set_domain(struct cache_req_input *input,
- {
-     TALLOC_CTX *tmp_ctx = NULL;
-     const char *name = NULL;
--    const char *fqn = NULL;
-+    const char *debug_fqn = NULL;
-     errno_t ret;
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -171,6 +223,8 @@ cache_req_input_set_domain(struct cache_req_input *input,
-     switch (input->type) {
-     case CACHE_REQ_USER_BY_NAME:
-     case CACHE_REQ_GROUP_BY_NAME:
-+    case CACHE_REQ_USER_BY_FILTER:
-+    case CACHE_REQ_GROUP_BY_FILTER:
-     case CACHE_REQ_INITGROUPS:
-         name = sss_get_cased_name(tmp_ctx, input->orig_name,
-                                   domain->case_sensitive);
-@@ -185,8 +239,8 @@ cache_req_input_set_domain(struct cache_req_input *input,
-             goto done;
-         }
- 
--        fqn = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
--        if (fqn == NULL) {
-+        debug_fqn = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
-+        if (debug_fqn == NULL) {
-             ret = ENOMEM;
-             goto done;
-         }
-@@ -194,16 +248,16 @@ cache_req_input_set_domain(struct cache_req_input *input,
-         break;
- 
-     case CACHE_REQ_USER_BY_ID:
--        fqn = talloc_asprintf(tmp_ctx, "UID:%d@%s", input->id, domain->name);
--        if (fqn == NULL) {
-+        debug_fqn = talloc_asprintf(tmp_ctx, "UID:%d@%s", input->id, domain->name);
-+        if (debug_fqn == NULL) {
-             ret = ENOMEM;
-             goto done;
-         }
-         break;
- 
-     case CACHE_REQ_GROUP_BY_ID:
--        fqn = talloc_asprintf(tmp_ctx, "GID:%d@%s", input->id, domain->name);
--        if (fqn == NULL) {
-+        debug_fqn = talloc_asprintf(tmp_ctx, "GID:%d@%s", input->id, domain->name);
-+        if (debug_fqn == NULL) {
-             ret = ENOMEM;
-             goto done;
-         }
-@@ -211,10 +265,10 @@ cache_req_input_set_domain(struct cache_req_input *input,
-     case CACHE_REQ_USER_BY_CERT:
-         /* certificates might be quite long, only use the last 10 charcters
-          * for logging */
--        fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s",
--                              get_last_x_chars(input->cert, 10),
--                              domain->name);
--        if (fqn == NULL) {
-+        debug_fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s",
-+                                    get_last_x_chars(input->cert, 10),
-+                                    domain->name);
-+        if (debug_fqn == NULL) {
-             ret = ENOMEM;
-             goto done;
-         }
-@@ -223,7 +277,7 @@ cache_req_input_set_domain(struct cache_req_input *input,
- 
-     input->domain = domain;
-     input->dom_objname = talloc_steal(input, name);
--    input->debug_fqn = talloc_steal(input, fqn);
-+    input->debug_fqn = talloc_steal(input, debug_fqn);
- 
-     ret = EOK;
- 
-@@ -257,6 +311,10 @@ static errno_t cache_req_check_ncache(struct cache_req_input *input,
-     case CACHE_REQ_USER_BY_CERT:
-         ret = sss_ncache_check_cert(ncache, neg_timeout, input->cert);
-         break;
-+    case CACHE_REQ_USER_BY_FILTER:
-+    case CACHE_REQ_GROUP_BY_FILTER:
-+        ret = EOK;
-+        break;
-     }
- 
-     if (ret == EEXIST) {
-@@ -282,6 +340,10 @@ static void cache_req_add_to_ncache(struct cache_req_input *input,
-         ret = sss_ncache_set_group(ncache, false, input->domain,
-                                    input->dom_objname);
-         break;
-+    case CACHE_REQ_USER_BY_FILTER:
-+    case CACHE_REQ_GROUP_BY_FILTER:
-+        /* Nothing to do, adding a wildcard request to ncache doesn't
-+         * make sense */
-     case CACHE_REQ_USER_BY_ID:
-     case CACHE_REQ_GROUP_BY_ID:
-     case CACHE_REQ_USER_BY_CERT:
-@@ -308,6 +370,10 @@ static void cache_req_add_to_ncache_global(struct cache_req_input *input,
-     errno_t ret = ERR_INTERNAL;
- 
-     switch (input->type) {
-+    case CACHE_REQ_USER_BY_FILTER:
-+    case CACHE_REQ_GROUP_BY_FILTER:
-+        /* Nothing to do, adding a wildcard request to ncache doesn't
-+         * make sense */
-     case CACHE_REQ_USER_BY_NAME:
-     case CACHE_REQ_GROUP_BY_NAME:
-     case CACHE_REQ_INITGROUPS:
-@@ -377,6 +443,18 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
-         ret = sysdb_search_user_by_cert(mem_ctx, input->domain,
-                                         input->cert, &result);
-         break;
-+    case CACHE_REQ_USER_BY_FILTER:
-+        one_item_only = false;
-+        ret = updated_users_by_filter(mem_ctx, input->domain,
-+                                      input->dom_objname, input->req_start,
-+                                      &result);
-+        break;
-+    case CACHE_REQ_GROUP_BY_FILTER:
-+        one_item_only = false;
-+        ret = updated_groups_by_filter(mem_ctx, input->domain,
-+                                       input->dom_objname, input->req_start,
-+                                       &result);
-+        break;
-     }
- 
-     if (ret != EOK) {
-@@ -397,6 +475,19 @@ done:
-     return ret;
- }
- 
-+/* Return true if the request bypasses cache or false if the cache_req
-+ * code can leverage sysdb for this request.
-+ */
-+static bool cache_req_bypass_cache(struct cache_req_input *input)
-+{
-+    if (input->type == CACHE_REQ_USER_BY_FILTER ||
-+            input->type == CACHE_REQ_GROUP_BY_FILTER) {
-+        return true;
-+    }
-+
-+    return false;
-+}
-+
- struct cache_req_cache_state {
-     /* input data */
-     struct tevent_context *ev;
-@@ -504,7 +595,8 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
- 
-     state = tevent_req_data(req, struct cache_req_cache_state);
- 
--    if (state->result == NULL || state->result->count == 0) {
-+    if (state->result == NULL || state->result->count == 0 ||
-+            cache_req_bypass_cache(state->input) == true) {
-         ret = ENOENT;
-     } else {
-         if (state->input->type == CACHE_REQ_INITGROUPS) {
-@@ -1059,3 +1151,41 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
-                                           neg_timeout, cache_refresh_percent,
-                                           domain, input);
- }
-+
-+struct tevent_req *
-+cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
-+                              struct tevent_context *ev,
-+                              struct resp_ctx *rctx,
-+                              const char *domain,
-+                              const char *filter)
-+{
-+    struct cache_req_input *input;
-+
-+    input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_FILTER,
-+                                   filter, 0, NULL);
-+    if (input == NULL) {
-+        return NULL;
-+    }
-+
-+    return cache_req_steal_input_and_send(mem_ctx, ev, rctx, NULL,
-+                                          0, 0, domain, input);
-+}
-+
-+struct tevent_req *
-+cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
-+                               struct tevent_context *ev,
-+                               struct resp_ctx *rctx,
-+                               const char *domain,
-+                               const char *filter)
-+{
-+    struct cache_req_input *input;
-+
-+    input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_FILTER,
-+                                   filter, 0, NULL);
-+    if (input == NULL) {
-+        return NULL;
-+    }
-+
-+    return cache_req_steal_input_and_send(mem_ctx, ev, rctx, NULL,
-+                                          0, 0, domain, input);
-+}
-diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h
-index 84a9dde7d9df066e44b1352e0a4557f02d08cc15..9e3f88a1427f3dcbde9f81df2ec647821b7aa931 100644
---- a/src/responder/common/responder_cache_req.h
-+++ b/src/responder/common/responder_cache_req.h
-@@ -33,7 +33,9 @@ enum cache_req_type {
-     CACHE_REQ_GROUP_BY_NAME,
-     CACHE_REQ_GROUP_BY_ID,
-     CACHE_REQ_INITGROUPS,
--    CACHE_REQ_USER_BY_CERT
-+    CACHE_REQ_USER_BY_CERT,
-+    CACHE_REQ_USER_BY_FILTER,
-+    CACHE_REQ_GROUP_BY_FILTER,
- };
- 
- struct cache_req_input;
-@@ -143,4 +145,24 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
- #define cache_req_initgr_by_name_recv(mem_ctx, req, _result, _domain, _name) \
-     cache_req_recv(mem_ctx, req, _result, _domain, _name)
- 
-+struct tevent_req *
-+cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
-+                              struct tevent_context *ev,
-+                              struct resp_ctx *rctx,
-+                              const char *domain,
-+                              const char *filter);
-+
-+#define cache_req_user_by_filter_recv(mem_ctx, req, _result, _domain) \
-+    cache_req_recv(mem_ctx, req, _result, _domain, NULL)
-+
-+struct tevent_req *
-+cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
-+                              struct tevent_context *ev,
-+                              struct resp_ctx *rctx,
-+                              const char *domain,
-+                              const char *filter);
-+
-+#define cache_req_group_by_filter_recv(mem_ctx, req, _result, _domain) \
-+    cache_req_recv(mem_ctx, req, _result, _domain, NULL)
-+
- #endif /* RESPONDER_CACHE_H_ */
-diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
-index e30deed1c6bc4023a4f2154db21fe1339e9bb3c5..31b6694668607815652f45bc93210554fd2ac918 100644
---- a/src/tests/cmocka/test_responder_cache_req.c
-+++ b/src/tests/cmocka/test_responder_cache_req.c
-@@ -38,6 +38,9 @@
- #define TEST_GROUP_NAME "test-group"
- #define TEST_GROUP_ID 1000
- 
-+#define TEST_USER_NAME2 "test-user2"
-+#define TEST_GROUP_NAME2 "test-group2"
-+
- #define new_single_domain_test(test) \
-     cmocka_unit_test_setup_teardown(test_ ## test, \
-                                     test_single_domain_setup, \
-@@ -1694,6 +1697,405 @@ void test_group_by_id_missing_notfound(void **state)
-     assert_true(test_ctx->dp_called);
- }
- 
-+static void cache_req_user_by_filter_test_done(struct tevent_req *req)
-+{
-+    struct cache_req_test_ctx *ctx = NULL;
-+
-+    ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
-+
-+    ctx->tctx->error = cache_req_user_by_filter_recv(ctx, req,
-+                                                     &ctx->result,
-+                                                     &ctx->domain);
-+    talloc_zfree(req);
-+    ctx->tctx->done = true;
-+}
-+
-+void test_users_by_filter_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    const char *ldbname = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+    test_ctx->create_user = true;
-+
-+    ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME2, "pwd", 1001, 1001,
-+                           NULL, NULL, NULL, "cn="TEST_USER_NAME2",dc=test", NULL,
-+                           NULL, 1000, time(NULL));
-+    assert_int_equal(ret, EOK);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        test_ctx->tctx->dom->name,
-+                                        "test*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+
-+    assert_non_null(test_ctx->result);
-+    assert_int_equal(test_ctx->result->count, 2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_USER_NAME2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_USER_NAME);
-+}
-+
-+void test_users_by_filter_filter_old(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    const char *ldbname = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+    test_ctx->create_user = true;
-+
-+    /* This user was updated in distant past, so it wont't be reported by
-+     * the filter search */
-+    ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME2, "pwd", 1001, 1001,
-+                           NULL, NULL, NULL, "cn="TEST_USER_NAME2",dc=test", NULL,
-+                           NULL, 1000, 1);
-+    assert_int_equal(ret, EOK);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        test_ctx->tctx->dom->name,
-+                                        "test*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+
-+    assert_non_null(test_ctx->result);
-+    assert_int_equal(test_ctx->result->count, 1);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_USER_NAME);
-+}
-+
-+void test_users_by_filter_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        test_ctx->tctx->dom->name,
-+                                        "nosuchuser*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ENOENT);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+}
-+
-+static void test_users_by_filter_multiple_domains_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    const char *ldbname = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+
-+    ret = sysdb_store_user(domain, TEST_USER_NAME, "pwd", 1000, 1000,
-+                           NULL, NULL, NULL, "cn="TEST_USER_NAME",dc=test", NULL,
-+                           NULL, 1000, time(NULL));
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_store_user(domain, TEST_USER_NAME2, "pwd", 1001, 1001,
-+                           NULL, NULL, NULL, "cn="TEST_USER_NAME2",dc=test", NULL,
-+                           NULL, 1000, time(NULL));
-+    assert_int_equal(ret, EOK);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        domain->name,
-+                                        "test*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+
-+    assert_non_null(test_ctx->result);
-+    assert_int_equal(test_ctx->result->count, 2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_USER_NAME2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_USER_NAME);
-+}
-+
-+static void test_users_by_filter_multiple_domains_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        domain->name,
-+                                        "nosuchuser*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ENOENT);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+}
-+
-+static void cache_req_group_by_filter_test_done(struct tevent_req *req)
-+{
-+    struct cache_req_test_ctx *ctx = NULL;
-+
-+    ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
-+
-+    ctx->tctx->error = cache_req_group_by_filter_recv(ctx, req,
-+                                                      &ctx->result,
-+                                                      &ctx->domain);
-+    talloc_zfree(req);
-+    ctx->tctx->done = true;
-+}
-+
-+void test_groups_by_filter_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    const char *ldbname = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+    test_ctx->create_group = true;
-+
-+    ret = sysdb_store_group(test_ctx->tctx->dom, TEST_GROUP_NAME2,
-+                            1001, NULL, 1001, time(NULL));
-+    assert_int_equal(ret, EOK);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                         test_ctx->rctx,
-+                                         test_ctx->tctx->dom->name,
-+                                         "test*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+
-+    assert_non_null(test_ctx->result);
-+    assert_int_equal(test_ctx->result->count, 2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_GROUP_NAME2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_GROUP_NAME);
-+}
-+
-+void test_groups_by_filter_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        test_ctx->tctx->dom->name,
-+                                        "nosuchgroup*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ENOENT);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+}
-+
-+void test_groups_by_filter_multiple_domains_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    const char *ldbname = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+
-+    ret = sysdb_store_group(domain, TEST_GROUP_NAME,
-+                            1000, NULL, 1000, time(NULL));
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_store_group(domain, TEST_GROUP_NAME2,
-+                            1001, NULL, 1001, time(NULL));
-+    assert_int_equal(ret, EOK);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                         test_ctx->rctx,
-+                                         domain->name,
-+                                         "test*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+
-+    assert_non_null(test_ctx->result);
-+    assert_int_equal(test_ctx->result->count, 2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_GROUP_NAME2);
-+
-+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
-+                                          SYSDB_NAME, NULL);
-+    assert_non_null(ldbname);
-+    assert_string_equal(ldbname, TEST_GROUP_NAME);
-+}
-+
-+void test_groups_by_filter_multiple_domains_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    TALLOC_CTX *req_mem_ctx = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    /* Filters always go to DP */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
-+                                        test_ctx->rctx,
-+                                        domain->name,
-+                                        "nosuchgroup*");
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ENOENT);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -1741,7 +2143,17 @@ int main(int argc, const char *argv[])
-         new_single_domain_test(group_by_id_missing_found),
-         new_single_domain_test(group_by_id_missing_notfound),
-         new_multi_domain_test(group_by_id_multiple_domains_found),
--        new_multi_domain_test(group_by_id_multiple_domains_notfound)
-+        new_multi_domain_test(group_by_id_multiple_domains_notfound),
-+
-+        new_single_domain_test(users_by_filter_valid),
-+        new_single_domain_test(users_by_filter_filter_old),
-+        new_single_domain_test(users_by_filter_notfound),
-+        new_multi_domain_test(users_by_filter_multiple_domains_valid),
-+        new_multi_domain_test(users_by_filter_multiple_domains_notfound),
-+        new_single_domain_test(groups_by_filter_valid),
-+        new_single_domain_test(groups_by_filter_notfound),
-+        new_multi_domain_test(groups_by_filter_multiple_domains_valid),
-+        new_multi_domain_test(groups_by_filter_multiple_domains_notfound),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.4.3
-
diff --git a/SOURCES/0005-sssctl-Fix-format-string-for-size_t.patch b/SOURCES/0005-sssctl-Fix-format-string-for-size_t.patch
new file mode 100644
index 0000000..b2037a5
--- /dev/null
+++ b/SOURCES/0005-sssctl-Fix-format-string-for-size_t.patch
@@ -0,0 +1,37 @@
+From 8d82518980eae15d4644ce55058ed852f7f657f5 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 8 Jul 2016 13:04:10 +0200
+Subject: [PATCH 05/18] sssctl: Fix format string for size_t
+
+src/tools/sssctl/sssctl_config.c: In function 'sssctl_config_check':
+src/tools/sssctl/sssctl_config.c:93:14: warning: format '%lu' expects
+  argument of type 'long unsigned int', but argument 2 has type
+  'size_t {aka unsigned int}' [-Wformat=]
+     printf(_("Issues identified by validators: %lu\n"), num_errors);
+              ^
+src/tools/sssctl/sssctl_config.c:93:12: note: in expansion of macro '_'
+     printf(_("Issues identified by validators: %lu\n"), num_errors);
+            ^
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit cca5695e6cab64def52c009afc8f055a85f1fde4)
+---
+ src/tools/sssctl/sssctl_config.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c
+index 4f6dbcdd7d04183c65b6613efbe5ab95df19e2c7..a66d7749c4aee9bd00c0ad2d296292658ffdb9b2 100644
+--- a/src/tools/sssctl/sssctl_config.c
++++ b/src/tools/sssctl/sssctl_config.c
+@@ -91,7 +91,7 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
+     }
+ 
+     /* Output from validators */
+-    printf(_("Issues identified by validators: %lu\n"), num_errors);
++    printf(_("Issues identified by validators: %zu\n"), num_errors);
+     for (i = 0; i < num_errors; i++) {
+         printf("%s\n", strs[i]);
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0006-UTIL-Add-sss_filter_sanitize_ex.patch b/SOURCES/0006-UTIL-Add-sss_filter_sanitize_ex.patch
deleted file mode 100644
index 2c48cf8..0000000
--- a/SOURCES/0006-UTIL-Add-sss_filter_sanitize_ex.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From f736b14f1e308d67e091d3ee56ef0384d618130e Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 4 May 2015 13:10:01 +0200
-Subject: [PATCH 06/13] UTIL: Add sss_filter_sanitize_ex
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-In order to support wildcard request, we need to introduce an optionally
-relaxed version of sss_filter_sanitize that allows to select which
-characters are exempt from sanitizing.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/tests/util-tests.c |  9 +++++++++
- src/util/util.c        | 28 +++++++++++++++++++++++++---
- src/util/util.h        |  5 +++++
- 3 files changed, 39 insertions(+), 3 deletions(-)
-
-diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c
-index 3d42f0193a677200d5cb4a46805892bed978305c..bfdf078027250b8ff0ce0da2d37fbb20f391d06b 100644
---- a/src/tests/util-tests.c
-+++ b/src/tests/util-tests.c
-@@ -406,6 +406,15 @@ START_TEST(test_sss_filter_sanitize)
-                 "Expected [%s], got [%s]",
-                 has_all_expected, sanitized);
- 
-+    /* Input is reused from previous test - "\\(user)*name" */
-+    const char has_all_allow_asterisk_expected[] = "\\5c\\28user\\29*name";
-+    ret = sss_filter_sanitize_ex(test_ctx, has_all, &sanitized, "*");
-+    fail_unless(ret == EOK, "has_all error [%d][%s]",
-+                ret, strerror(ret));
-+    fail_unless(strcmp(has_all_allow_asterisk_expected, sanitized)==0,
-+                "Expected [%s], got [%s]",
-+                has_all_expected, sanitized);
-+
-     talloc_free(test_ctx);
- }
- END_TEST
-diff --git a/src/util/util.c b/src/util/util.c
-index cfd26a58b31048996e9669163b821282b219b2de..782cd026b7928e607a8980fb5f333c794feb5b1a 100644
---- a/src/util/util.c
-+++ b/src/util/util.c
-@@ -525,13 +525,15 @@ errno_t sss_hash_create(TALLOC_CTX *mem_ctx, unsigned long count,
-     return sss_hash_create_ex(mem_ctx, count, tbl, 0, 0, 0, 0, NULL, NULL);
- }
- 
--errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
--                            const char *input,
--                            char **sanitized)
-+errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx,
-+                               const char *input,
-+                               char **sanitized,
-+                               const char *ignore)
- {
-     char *output;
-     size_t i = 0;
-     size_t j = 0;
-+    char *allowed;
- 
-     /* Assume the worst-case. We'll resize it later, once */
-     output = talloc_array(mem_ctx, char, strlen(input) * 3 + 1);
-@@ -540,6 +542,19 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
-     }
- 
-     while (input[i]) {
-+        /* Even though this character might have a special meaning, if it's
-+         * expliticly allowed, just copy it and move on
-+         */
-+        if (ignore == NULL) {
-+            allowed = NULL;
-+        } else {
-+            allowed = strchr(ignore, input[i]);
-+        }
-+        if (allowed) {
-+            output[j++] = input[i++];
-+            continue;
-+        }
-+
-         switch(input[i]) {
-         case '\t':
-             output[j++] = '\\';
-@@ -587,6 +602,13 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
-+errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
-+                            const char *input,
-+                            char **sanitized)
-+{
-+    return sss_filter_sanitize_ex(mem_ctx, input, sanitized, NULL);
-+}
-+
- char *
- sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr)
- {
-diff --git a/src/util/util.h b/src/util/util.h
-index 3d90cf0d1024b93016987a4d3e8a515359fd974d..94a3ddea839f0998cb7796f1d2fe13f743de3aaf 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -485,6 +485,11 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
-                             const char *input,
-                             char **sanitized);
- 
-+errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx,
-+                               const char *input,
-+                               char **sanitized,
-+                               const char *ignore);
-+
- errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx,
-                                     const char *input,
-                                     struct sss_domain_info *dom,
--- 
-2.4.3
-
diff --git a/SOURCES/0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch b/SOURCES/0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch
new file mode 100644
index 0000000..b3e1f55
--- /dev/null
+++ b/SOURCES/0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch
@@ -0,0 +1,31 @@
+From fda4c78ca651ce478fe744f7de87c2064e80a05d Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 8 Jul 2016 13:27:47 +0200
+Subject: [PATCH 06/18] doxygen: Fix path to header file ipa_hbac.h
+
+Warning: tag INPUT: input source `src/providers/ipa/ipa_hbac.h' does not exist
+warning: source src/providers/ipa/ipa_hbac.h is not
+         a readable file or directory... skipping.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit b9b2c0836f64f375babb75d92b924f3780f20521)
+---
+ src/lib/ipa_hbac/ipa_hbac.doxy.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/lib/ipa_hbac/ipa_hbac.doxy.in b/src/lib/ipa_hbac/ipa_hbac.doxy.in
+index 6d4a92659f1974fa96b8fcfbcca0d4107e3a7dae..d1e9f995ddeffd92dad03b5d1fd18077b6aeb645 100644
+--- a/src/lib/ipa_hbac/ipa_hbac.doxy.in
++++ b/src/lib/ipa_hbac/ipa_hbac.doxy.in
+@@ -678,7 +678,7 @@ WARN_LOGFILE           =
+ # directories like "/usr/src/myproject". Separate the files or directories
+ # with spaces.
+ 
+-INPUT                  = @abs_top_srcdir@/src/providers/ipa/ipa_hbac.h
++INPUT                  = @abs_top_srcdir@/src/lib/ipa_hbac/ipa_hbac.h
+ 
+ # This tag can be used to specify the character encoding of the source files
+ # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+-- 
+2.4.11
+
diff --git a/SOURCES/0007-LDAP-Fetch-users-and-groups-using-wildcards.patch b/SOURCES/0007-LDAP-Fetch-users-and-groups-using-wildcards.patch
deleted file mode 100644
index d02553f..0000000
--- a/SOURCES/0007-LDAP-Fetch-users-and-groups-using-wildcards.patch
+++ /dev/null
@@ -1,147 +0,0 @@
-From 9604ff1731ab7bd067bef62a0df6000eca091856 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 4 May 2015 15:16:44 +0200
-Subject: [PATCH 07/13] LDAP: Fetch users and groups using wildcards
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Adds handler for the BE_FILTER_WILDCARD in the LDAP provider. So far
-it's the same code as if enumeration was used, so there are no limits.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/providers/ldap/ldap_common.h |  3 +++
- src/providers/ldap/ldap_id.c     | 50 ++++++++++++++++++++++++++++++++++++++--
- 2 files changed, 51 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
-index 424eacb1da0a6934b132ccb2a5bb175233fa1a80..8294d1db23bdca8d94a098533d93405c4d55226b 100644
---- a/src/providers/ldap/ldap_common.h
-+++ b/src/providers/ldap/ldap_common.h
-@@ -39,6 +39,9 @@
- #define LDAP_SSL_URI "ldaps://"
- #define LDAP_LDAPI_URI "ldapi://"
- 
-+/* Only the asterisk is allowed in wildcard requests */
-+#define LDAP_ALLOWED_WILDCARDS "*"
-+
- /* a fd the child process would log into */
- extern int ldap_child_debug_fd;
- 
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 3245e1b12a69483f961f01210d13654b1c7c5345..61f09fc41d3210af5044f5338dd90db67e0123a7 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -114,6 +114,14 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
-                                                           sdom->dom->name,
-                                                           sdom->dom->domain_id);
-     switch (filter_type) {
-+    case BE_FILTER_WILDCARD:
-+        attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name;
-+        ret = sss_filter_sanitize_ex(state, name, &clean_name,
-+                                     LDAP_ALLOWED_WILDCARDS);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+        break;
-     case BE_FILTER_NAME:
-         if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) {
-             attr_name = ctx->opts->user_map[SDAP_AT_USER_PRINC].name;
-@@ -388,6 +396,13 @@ 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;
-+    bool multiple_results;
-+
-+    if (state->filter_type == BE_FILTER_WILDCARD) {
-+        multiple_results = true;
-+    } else {
-+        multiple_results = false;
-+    }
- 
-     subreq = sdap_get_users_send(state, state->ev,
-                                  state->domain, state->sysdb,
-@@ -397,7 +412,7 @@ static void users_get_search(struct tevent_req *req)
-                                  state->attrs, state->filter,
-                                  dp_opt_get_int(state->ctx->opts->basic,
-                                                 SDAP_SEARCH_TIMEOUT),
--                                 false);
-+                                 multiple_results);
-     if (!subreq) {
-         tevent_req_error(req, ENOMEM);
-         return;
-@@ -508,6 +523,13 @@ static void users_get_done(struct tevent_req *subreq)
-              * group we have nothing to do here. */
-             break;
- 
-+        case BE_FILTER_WILDCARD:
-+            /* We can't know if all users are up-to-date, especially in a large
-+             * environment. Do not delete any records, let the responder fetch
-+             * the entries they are requested in
-+             */
-+            break;
-+
-         default:
-             tevent_req_error(req, EINVAL);
-             return;
-@@ -619,6 +641,14 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
-                                                           sdom->dom->domain_id);
- 
-     switch(filter_type) {
-+    case BE_FILTER_WILDCARD:
-+        attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
-+        ret = sss_filter_sanitize_ex(state, name, &clean_name,
-+                                     LDAP_ALLOWED_WILDCARDS);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+        break;
-     case BE_FILTER_NAME:
-         attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
- 
-@@ -871,6 +901,13 @@ 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;
-+    bool multiple_results;
-+
-+    if (state->filter_type == BE_FILTER_WILDCARD) {
-+        multiple_results = true;
-+    } else {
-+        multiple_results = false;
-+    }
- 
-     subreq = sdap_get_groups_send(state, state->ev,
-                                   state->sdom,
-@@ -879,7 +916,8 @@ static void groups_get_search(struct tevent_req *req)
-                                   state->attrs, state->filter,
-                                   dp_opt_get_int(state->ctx->opts->basic,
-                                                  SDAP_SEARCH_TIMEOUT),
--                                  false, state->no_members);
-+                                  multiple_results,
-+                                  state->no_members);
-     if (!subreq) {
-         tevent_req_error(req, ENOMEM);
-         return;
-@@ -953,6 +991,14 @@ static void groups_get_done(struct tevent_req *subreq)
-              * group we have nothing to do here. */
-             break;
- 
-+        case BE_FILTER_WILDCARD:
-+            /* We can't know if all groups are up-to-date, especially in
-+             * a large environment. Do not delete any records, let the
-+             * responder fetch the entries they are requested in.
-+             */
-+            break;
-+
-+
-         default:
-             tevent_req_error(req, EINVAL);
-             return;
--- 
-2.4.3
-
diff --git a/SOURCES/0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch b/SOURCES/0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch
new file mode 100644
index 0000000..0308ac2
--- /dev/null
+++ b/SOURCES/0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch
@@ -0,0 +1,31 @@
+From 3743b49557f63d0ca541103fe0929e432cde3678 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 8 Jul 2016 14:39:43 +0200
+Subject: [PATCH 07/18] ipa_hbac: Fix documentation for hbac_enable_debug
+
+src/lib/ipa_hbac/ipa_hbac.h:68: warning: expected whitespace after [ command
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit f3db22862d22821be2d566435cb0c59387343fc2)
+---
+ src/lib/ipa_hbac/ipa_hbac.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/lib/ipa_hbac/ipa_hbac.h b/src/lib/ipa_hbac/ipa_hbac.h
+index 8801c20c492caf53a089c2724c2ed4a96805904c..f9d339c058f109acdea95fa185182f08d1e8af9e 100644
+--- a/src/lib/ipa_hbac/ipa_hbac.h
++++ b/src/lib/ipa_hbac/ipa_hbac.h
+@@ -65,8 +65,8 @@ typedef void (*hbac_debug_fn_t)(const char *file, int line,
+                                 ...) HBAC_ATTRIBUTE_PRINTF(5, 6);
+ 
+ /**
+- *  HBAC uses external_debug_fn for logging messages.
+- *  @param[in|out] external_debug_void Pointer to external logging function.
++ * HBAC uses external_debug_fn for logging messages.
++ * @param[in] external_debug_fn Pointer to external logging function.
+  */
+ void hbac_enable_debug(hbac_debug_fn_t external_debug_fn);
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0008-LDAP-Add-sdap_get_and_parse_generic_send.patch b/SOURCES/0008-LDAP-Add-sdap_get_and_parse_generic_send.patch
deleted file mode 100644
index b2a8e01..0000000
--- a/SOURCES/0008-LDAP-Add-sdap_get_and_parse_generic_send.patch
+++ /dev/null
@@ -1,298 +0,0 @@
-From fceab48ac589473216067e40d8577e19a02d3b45 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 4 May 2015 16:27:06 +0200
-Subject: [PATCH 08/13] LDAP: Add sdap_get_and_parse_generic_send
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-So far we had a simple sdap_get_generic_send() request that uses the
-right defaults around the low-level sdap_get_generic_ext_send() request
-and calls the parser.
-
-This patch adds also sdap_get_and_parse_generic_send() that exposes all
-options that sdap_get_generic_ext_send() offers but also calls the
-parser.
-
-In this patch the function is not used at all.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/providers/ldap/sdap_async.c | 185 ++++++++++++++++++++++++++++------------
- src/providers/ldap/sdap_async.h |  22 +++++
- 2 files changed, 154 insertions(+), 53 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index 5263c250b8a15a98e685ca81e636def27ea05894..c5be8561a197c96f62bb2582a4d30c28de71f580 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -1656,9 +1656,8 @@ static void generic_ext_search_handler(struct tevent_req *subreq,
-     tevent_req_done(req);
- }
- 
--
--/* ==Generic Search============================================ */
--struct sdap_get_generic_state {
-+/* ==Generic Search exposing all options======================= */
-+struct sdap_get_and_parse_generic_state {
-     struct sdap_attr_map *map;
-     int map_num_attrs;
- 
-@@ -1666,10 +1665,119 @@ struct sdap_get_generic_state {
-     struct sdap_options *opts;
- };
- 
-+static void sdap_get_and_parse_generic_done(struct tevent_req *subreq);
-+static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
-+                                                      struct sdap_msg *msg,
-+                                                      void *pvt);
-+
-+struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
-+                                                   struct tevent_context *ev,
-+                                                   struct sdap_options *opts,
-+                                                   struct sdap_handle *sh,
-+                                                   const char *search_base,
-+                                                   int scope,
-+                                                   const char *filter,
-+                                                   const char **attrs,
-+                                                   struct sdap_attr_map *map,
-+                                                   int map_num_attrs,
-+                                                   int attrsonly,
-+                                                   LDAPControl **serverctrls,
-+                                                   LDAPControl **clientctrls,
-+                                                   int sizelimit,
-+                                                   int timeout,
-+                                                   bool allow_paging)
-+{
-+    struct tevent_req *req = NULL;
-+    struct tevent_req *subreq = NULL;
-+    struct sdap_get_and_parse_generic_state *state = NULL;
-+
-+    req = tevent_req_create(memctx, &state,
-+                            struct sdap_get_and_parse_generic_state);
-+    if (!req) return NULL;
-+
-+    state->map = map;
-+    state->map_num_attrs = map_num_attrs;
-+    state->opts = opts;
-+
-+    subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
-+                                       scope, filter, attrs, false, NULL,
-+                                       NULL, sizelimit, timeout, allow_paging,
-+                                       sdap_get_and_parse_generic_parse_entry, state);
-+    if (!subreq) {
-+        talloc_zfree(req);
-+        return NULL;
-+    }
-+    tevent_req_set_callback(subreq, sdap_get_and_parse_generic_done, req);
-+
-+    return req;
-+}
-+
-+static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
-+                                                      struct sdap_msg *msg,
-+                                                      void *pvt)
-+{
-+    errno_t ret;
-+    struct sysdb_attrs *attrs;
-+    struct sdap_get_and_parse_generic_state *state =
-+                talloc_get_type(pvt, struct sdap_get_and_parse_generic_state);
-+
-+    bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
-+                                               SDAP_DISABLE_RANGE_RETRIEVAL);
-+
-+    ret = sdap_parse_entry(state, sh, msg,
-+                           state->map, state->map_num_attrs,
-+                           &attrs, disable_range_rtrvl);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
-+        return ret;
-+    }
-+
-+    ret = add_to_reply(state, &state->sreply, attrs);
-+    if (ret != EOK) {
-+        talloc_free(attrs);
-+        DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
-+        return ret;
-+    }
-+
-+    /* add_to_reply steals attrs, no need to free them here */
-+    return EOK;
-+}
-+
-+static void sdap_get_and_parse_generic_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_get_and_parse_generic_state *state =
-+                tevent_req_data(req, struct sdap_get_and_parse_generic_state);
-+
-+    return generic_ext_search_handler(subreq, state->opts);
-+}
-+
-+int sdap_get_and_parse_generic_recv(struct tevent_req *req,
-+                                    TALLOC_CTX *mem_ctx,
-+                                    size_t *reply_count,
-+                                    struct sysdb_attrs ***reply)
-+{
-+    struct sdap_get_and_parse_generic_state *state = tevent_req_data(req,
-+                                     struct sdap_get_and_parse_generic_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    *reply_count = state->sreply.reply_count;
-+    *reply = talloc_steal(mem_ctx, state->sreply.reply);
-+
-+    return EOK;
-+}
-+
-+
-+/* ==Simple generic search============================================== */
-+struct sdap_get_generic_state {
-+    size_t reply_count;
-+    struct sysdb_attrs **reply;
-+};
-+
- static void sdap_get_generic_done(struct tevent_req *subreq);
--static errno_t sdap_get_generic_parse_entry(struct sdap_handle *sh,
--                                            struct sdap_msg *msg,
--                                            void *pvt);
- 
- struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-@@ -1691,16 +1799,12 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
-     req = tevent_req_create(memctx, &state, struct sdap_get_generic_state);
-     if (!req) return NULL;
- 
--    state->map = map;
--    state->map_num_attrs = map_num_attrs;
--    state->opts = opts;
--
--    subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
--                                       scope, filter, attrs, false, NULL,
--                                       NULL, 0, timeout, allow_paging,
--                                       sdap_get_generic_parse_entry, state);
--    if (!subreq) {
--        talloc_zfree(req);
-+    subreq = sdap_get_and_parse_generic_send(memctx, ev, opts, sh, search_base,
-+                                             scope, filter, attrs,
-+                                             map, map_num_attrs,
-+                                             false, NULL, NULL, 0, timeout,
-+                                             allow_paging);
-+    if (subreq == NULL) {
-         return NULL;
-     }
-     tevent_req_set_callback(subreq, sdap_get_generic_done, req);
-@@ -1708,46 +1812,21 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
-     return req;
- }
- 
--static errno_t sdap_get_generic_parse_entry(struct sdap_handle *sh,
--                                            struct sdap_msg *msg,
--                                            void *pvt)
--{
--    errno_t ret;
--    struct sysdb_attrs *attrs;
--    struct sdap_get_generic_state *state =
--                talloc_get_type(pvt, struct sdap_get_generic_state);
--
--    bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
--                                               SDAP_DISABLE_RANGE_RETRIEVAL);
--
--    ret = sdap_parse_entry(state, sh, msg,
--                           state->map, state->map_num_attrs,
--                           &attrs, disable_range_rtrvl);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_MINOR_FAILURE,
--              "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
--        return ret;
--    }
--
--    ret = add_to_reply(state, &state->sreply, attrs);
--    if (ret != EOK) {
--        talloc_free(attrs);
--        DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
--        return ret;
--    }
--
--    /* add_to_reply steals attrs, no need to free them here */
--    return EOK;
--}
--
- 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);
-+    errno_t ret;
- 
--    return generic_ext_search_handler(subreq, state->opts);
-+    ret = sdap_get_and_parse_generic_recv(subreq, state,
-+                                          &state->reply_count, &state->reply);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+    tevent_req_done(req);
- }
- 
- int sdap_get_generic_recv(struct tevent_req *req,
-@@ -1755,13 +1834,13 @@ int sdap_get_generic_recv(struct tevent_req *req,
-                           size_t *reply_count,
-                           struct sysdb_attrs ***reply)
- {
--    struct sdap_get_generic_state *state = tevent_req_data(req,
--                                            struct sdap_get_generic_state);
-+    struct sdap_get_generic_state *state =
-+                tevent_req_data(req, struct sdap_get_generic_state);
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
--    *reply_count = state->sreply.reply_count;
--    *reply = talloc_steal(mem_ctx, state->sreply.reply);
-+    *reply_count = state->reply_count;
-+    *reply = talloc_steal(mem_ctx, state->reply);
- 
-     return EOK;
- }
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index b5db64d7fa3c852fba60e07db19e823e818d29f3..b23dfc313905d01caedd1eace6bcb525481b9ebe 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -181,6 +181,28 @@ int sdap_cli_connect_recv(struct tevent_req *req,
-                           struct sdap_handle **gsh,
-                           struct sdap_server_opts **srv_opts);
- 
-+/* Exposes all options of generic send while allowing to parse by map */
-+struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
-+                                                   struct tevent_context *ev,
-+                                                   struct sdap_options *opts,
-+                                                   struct sdap_handle *sh,
-+                                                   const char *search_base,
-+                                                   int scope,
-+                                                   const char *filter,
-+                                                   const char **attrs,
-+                                                   struct sdap_attr_map *map,
-+                                                   int map_num_attrs,
-+                                                   int attrsonly,
-+                                                   LDAPControl **serverctrls,
-+                                                   LDAPControl **clientctrls,
-+                                                   int sizelimit,
-+                                                   int timeout,
-+                                                   bool allow_paging);
-+int sdap_get_and_parse_generic_recv(struct tevent_req *req,
-+                                    TALLOC_CTX *mem_ctx,
-+                                    size_t *reply_count,
-+                                    struct sysdb_attrs ***reply);
-+
- struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-                                          struct sdap_options *opts,
--- 
-2.4.3
-
diff --git a/SOURCES/0008-sssctl-Fix-warning-maybe-uninitialized.patch b/SOURCES/0008-sssctl-Fix-warning-maybe-uninitialized.patch
new file mode 100644
index 0000000..77fde17
--- /dev/null
+++ b/SOURCES/0008-sssctl-Fix-warning-maybe-uninitialized.patch
@@ -0,0 +1,63 @@
+From e64aac5e33523f8473471b945403f0d9ba74c8cf Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 8 Jul 2016 15:27:23 +0200
+Subject: [PATCH 08/18] sssctl: Fix warning maybe-uninitialized
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It looks like some special gcc optimalisation and special case
+may cause to have unitialized output argument _dom when return
+code is EOK
+
+src/tools/sssctl/sssctl_cache.c: In function ‘sssctl_print_object’:
+src/tools/sssctl/sssctl_cache.c:491:8: error: ‘dom’ may be used
+  uninitialized in this function [-Werror=maybe-uninitialized]
+     if (dom == NULL) {
+        ^
+src/tools/sssctl/sssctl_cache.c:447:15: error: ‘entry’ may be used
+  uninitialized in this function [-Werror=maybe-uninitialized]
+     *_entry = talloc_steal(mem_ctx, entry);
+               ^~~~~~~~~~~~
+src/tools/sssctl/sssctl_cache.c:412:25: note: ‘entry’ was declared here
+     struct sysdb_attrs *entry;
+                         ^~~~~
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 64d664c201916d8678b5f4bd7e1559c7ece9217d)
+---
+ src/tools/sssctl/sssctl_cache.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
+index 28de6c139d844f98f9b06844492c935696e19643..e23bb89db95217e66a441b7e4d6d32e668486cc8 100644
+--- a/src/tools/sssctl/sssctl_cache.c
++++ b/src/tools/sssctl/sssctl_cache.c
+@@ -372,15 +372,19 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx,
+ 
+         ret = sssctl_query_cache(tmp_ctx, dom->sysdb, base_dn, filter,
+                                  attrs, &entry);
+-        if (ret == EOK) {
++        switch(ret) {
++        case EOK:
+             /* Entry was found. */
+             *_entry = talloc_steal(mem_ctx, entry);
+             *_dom = dom;
+             goto done;
+-        } else if (ret == ENOENT && fqn_provided) {
+-            /* Not found but a domain was provided in input. We're done. */
+-            goto done;
+-        } else if (ret != ENOENT) {
++        case ENOENT:
++            if (fqn_provided) {
++                /* Not found but a domain was provided in input. We're done. */
++                goto done;
++            }
++            break;
++        default:
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to query cache [%d]: %s\n",
+                   ret, sss_strerror(ret));
+             goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0009-LDAP-Use-sdap_get_and_parse_generic_-_recv.patch b/SOURCES/0009-LDAP-Use-sdap_get_and_parse_generic_-_recv.patch
deleted file mode 100644
index 293d522..0000000
--- a/SOURCES/0009-LDAP-Use-sdap_get_and_parse_generic_-_recv.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-From 02813c46feb5484a2e171514c7ba9dd9b1b34006 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 4 May 2015 16:33:37 +0200
-Subject: [PATCH 09/13] LDAP: Use sdap_get_and_parse_generic_/_recv
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Using the new request sdap_get_and_parse_generic_send is a separate
-commit so that we can audit where the function is used during a code
-review.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/providers/ldap/sdap_async_groups.c | 8 ++++----
- src/providers/ldap/sdap_async_users.c  | 8 ++++----
- 2 files changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 73caa9b5bd662477cd29b5220f6b437991831578..e785307e60d0df5be96a5b2de2c07baabaf1e371 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -1870,14 +1870,14 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-           "Searching for groups with base [%s]\n",
-            state->search_bases[state->base_iter]->basedn);
- 
--    subreq = sdap_get_generic_send(
-+    subreq = sdap_get_and_parse_generic_send(
-             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,
-             state->opts->group_map, SDAP_OPTS_GROUP,
--            state->timeout,
-+            0, NULL, NULL, 0, state->timeout,
-             state->enumeration); /* If we're enumerating, we need paging */
-     if (!subreq) {
-         return ENOMEM;
-@@ -1903,8 +1903,8 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-     struct sysdb_attrs **groups;
-     char **groupnamelist;
- 
--    ret = sdap_get_generic_recv(subreq, state,
--                                &count, &groups);
-+    ret = sdap_get_and_parse_generic_recv(subreq, state,
-+                                          &count, &groups);
-     talloc_zfree(subreq);
-     if (ret) {
-         tevent_req_error(req, ret);
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index 416bedda8491fae5385e6b6a074b4cf05ae86b65..216b49477bf21481265444c5c03df0aac7ee84e4 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -688,13 +688,13 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
-           "Searching for users with base [%s]\n",
-            state->search_bases[state->base_iter]->basedn);
- 
--    subreq = sdap_get_generic_send(
-+    subreq = sdap_get_and_parse_generic_send(
-             state, state->ev, state->opts, state->sh,
-             state->search_bases[state->base_iter]->basedn,
-             state->search_bases[state->base_iter]->scope,
-             state->filter, state->attrs,
-             state->opts->user_map, state->opts->user_map_cnt,
--            state->timeout,
-+            0, NULL, NULL, 0, state->timeout,
-             state->enumeration); /* If we're enumerating, we need paging */
-     if (subreq == NULL) {
-         return ENOMEM;
-@@ -715,8 +715,8 @@ static void sdap_search_user_process(struct tevent_req *subreq)
-     struct sysdb_attrs **users;
-     bool next_base = false;
- 
--    ret = sdap_get_generic_recv(subreq, state,
--                                &count, &users);
-+    ret = sdap_get_and_parse_generic_recv(subreq, state,
-+                                          &count, &users);
-     talloc_zfree(subreq);
-     if (ret) {
-         tevent_req_error(req, ret);
--- 
-2.4.3
-
diff --git a/SOURCES/0009-NOUPSTREAM-Bundle-http-parser.patch b/SOURCES/0009-NOUPSTREAM-Bundle-http-parser.patch
new file mode 100644
index 0000000..a17b34c
--- /dev/null
+++ b/SOURCES/0009-NOUPSTREAM-Bundle-http-parser.patch
@@ -0,0 +1,2922 @@
+From bd5daccde22322d216d450f40a50c1a3d7c5a32c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 12 Jul 2016 13:36:32 +0200
+Subject: [PATCH 09/18] NOUPSTREAM: Bundle http-parser
+
+---
+ Makefile.am                            |   15 +
+ src/external/libhttp_parser.m4         |    7 +-
+ src/responder/secrets/http_parser.c    | 2469 ++++++++++++++++++++++++++++++++
+ src/responder/secrets/http_parser.h    |  362 +++++
+ src/responder/secrets/secsrv_private.h |    2 +-
+ 5 files changed, 2850 insertions(+), 5 deletions(-)
+ create mode 100644 src/responder/secrets/http_parser.c
+ create mode 100644 src/responder/secrets/http_parser.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 706b60d6a065e0a983f5a1cfbc26a78331c67d58..d05919705910fa565ff954224ce40feb5d7ff39f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1370,6 +1370,9 @@ sssd_secrets_SOURCES = \
+     $(SSSD_RESPONDER_OBJ) \
+     $(SSSD_RESOLV_OBJ) \
+     $(NULL)
++sssd_secrets_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
+ sssd_secrets_LDADD = \
+     $(HTTP_PARSER_LIBS) \
+     $(JANSSON_LIBS) \
+@@ -1379,6 +1382,18 @@ sssd_secrets_LDADD = \
+     $(CARES_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+     $(NULL)
++
++if BUNDLE_HTTP_PARSER
++sssd_secrets_CFLAGS += \
++    -DHTTP_PARSER_STRICT=1 \
++    $(NULL)
++
++sssd_secrets_SOURCES += \
++    src/responder/secrets/http_parser.c \
++    src/responder/secrets/http_parser.h \
++    $(NULL)
++endif
++
+ endif
+ 
+ sssd_be_SOURCES = \
+diff --git a/src/external/libhttp_parser.m4 b/src/external/libhttp_parser.m4
+index 504bdf0f66c95b3d224c677a205a46e6f8b44726..c4c5b0dad29da281295529be047d30e502f5de70 100644
+--- a/src/external/libhttp_parser.m4
++++ b/src/external/libhttp_parser.m4
+@@ -16,7 +16,6 @@ AS_IF([test x"$found_http_parser" != xyes],
+                                     [-L$sss_extra_libdir -lhttp_parser])
+                       ],
+                       [-L$sss_extra_libdir -lhttp_parser_strict])],
+-        [AC_MSG_ERROR([
+-You must have the header file http_parse.h installed to build sssd
+-with secrets responder. If you want to build sssd without secret responder
+-then specify --without-secrets when running configure.])])])
++        [AC_MSG_WARN([Will use bundled http-parser])])])
++
++AM_CONDITIONAL([BUNDLE_HTTP_PARSER], [test x"$HTTP_PARSER_LIBS" = x])
+diff --git a/src/responder/secrets/http_parser.c b/src/responder/secrets/http_parser.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..3c896ffadcc0dbf13942457d32c77d15bfec33e7
+--- /dev/null
++++ b/src/responder/secrets/http_parser.c
+@@ -0,0 +1,2469 @@
++/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
++ *
++ * Additional changes are licensed under the same terms as NGINX and
++ * copyright Joyent, Inc. and other Node contributors. All rights reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++#include "http_parser.h"
++#include <assert.h>
++#include <stddef.h>
++#include <ctype.h>
++#include <stdlib.h>
++#include <string.h>
++#include <limits.h>
++
++#ifndef ULLONG_MAX
++# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
++#endif
++
++#ifndef MIN
++# define MIN(a,b) ((a) < (b) ? (a) : (b))
++#endif
++
++#ifndef ARRAY_SIZE
++# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
++#endif
++
++#ifndef BIT_AT
++# define BIT_AT(a, i)                                                \
++  (!!((unsigned int) (a)[(unsigned int) (i) >> 3] &                  \
++   (1 << ((unsigned int) (i) & 7))))
++#endif
++
++#ifndef ELEM_AT
++# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
++#endif
++
++#define SET_ERRNO(e)                                                 \
++do {                                                                 \
++  parser->http_errno = (e);                                          \
++} while(0)
++
++#define CURRENT_STATE() p_state
++#define UPDATE_STATE(V) p_state = (enum state) (V);
++#define RETURN(V)                                                    \
++do {                                                                 \
++  parser->state = CURRENT_STATE();                                   \
++  return (V);                                                        \
++} while (0);
++#define REEXECUTE()                                                  \
++  goto reexecute;                                                    \
++
++
++#ifdef __GNUC__
++# define LIKELY(X) __builtin_expect(!!(X), 1)
++# define UNLIKELY(X) __builtin_expect(!!(X), 0)
++#else
++# define LIKELY(X) (X)
++# define UNLIKELY(X) (X)
++#endif
++
++
++/* Run the notify callback FOR, returning ER if it fails */
++#define CALLBACK_NOTIFY_(FOR, ER)                                    \
++do {                                                                 \
++  assert(HTTP_PARSER_ERRNO(parser) == HPE_OK);                       \
++                                                                     \
++  if (LIKELY(settings->on_##FOR)) {                                  \
++    parser->state = CURRENT_STATE();                                 \
++    if (UNLIKELY(0 != settings->on_##FOR(parser))) {                 \
++      SET_ERRNO(HPE_CB_##FOR);                                       \
++    }                                                                \
++    UPDATE_STATE(parser->state);                                     \
++                                                                     \
++    /* We either errored above or got paused; get out */             \
++    if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {             \
++      return (ER);                                                   \
++    }                                                                \
++  }                                                                  \
++} while (0)
++
++/* Run the notify callback FOR and consume the current byte */
++#define CALLBACK_NOTIFY(FOR)            CALLBACK_NOTIFY_(FOR, p - data + 1)
++
++/* Run the notify callback FOR and don't consume the current byte */
++#define CALLBACK_NOTIFY_NOADVANCE(FOR)  CALLBACK_NOTIFY_(FOR, p - data)
++
++/* Run data callback FOR with LEN bytes, returning ER if it fails */
++#define CALLBACK_DATA_(FOR, LEN, ER)                                 \
++do {                                                                 \
++  assert(HTTP_PARSER_ERRNO(parser) == HPE_OK);                       \
++                                                                     \
++  if (FOR##_mark) {                                                  \
++    if (LIKELY(settings->on_##FOR)) {                                \
++      parser->state = CURRENT_STATE();                               \
++      if (UNLIKELY(0 !=                                              \
++                   settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \
++        SET_ERRNO(HPE_CB_##FOR);                                     \
++      }                                                              \
++      UPDATE_STATE(parser->state);                                   \
++                                                                     \
++      /* We either errored above or got paused; get out */           \
++      if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {           \
++        return (ER);                                                 \
++      }                                                              \
++    }                                                                \
++    FOR##_mark = NULL;                                               \
++  }                                                                  \
++} while (0)
++
++/* Run the data callback FOR and consume the current byte */
++#define CALLBACK_DATA(FOR)                                           \
++    CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
++
++/* Run the data callback FOR and don't consume the current byte */
++#define CALLBACK_DATA_NOADVANCE(FOR)                                 \
++    CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
++
++/* Set the mark FOR; non-destructive if mark is already set */
++#define MARK(FOR)                                                    \
++do {                                                                 \
++  if (!FOR##_mark) {                                                 \
++    FOR##_mark = p;                                                  \
++  }                                                                  \
++} while (0)
++
++/* Don't allow the total size of the HTTP headers (including the status
++ * line) to exceed HTTP_MAX_HEADER_SIZE.  This check is here to protect
++ * embedders against denial-of-service attacks where the attacker feeds
++ * us a never-ending header that the embedder keeps buffering.
++ *
++ * This check is arguably the responsibility of embedders but we're doing
++ * it on the embedder's behalf because most won't bother and this way we
++ * make the web a little safer.  HTTP_MAX_HEADER_SIZE is still far bigger
++ * than any reasonable request or response so this should never affect
++ * day-to-day operation.
++ */
++#define COUNT_HEADER_SIZE(V)                                         \
++do {                                                                 \
++  parser->nread += (V);                                              \
++  if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) {            \
++    SET_ERRNO(HPE_HEADER_OVERFLOW);                                  \
++    goto error;                                                      \
++  }                                                                  \
++} while (0)
++
++
++#define PROXY_CONNECTION "proxy-connection"
++#define CONNECTION "connection"
++#define CONTENT_LENGTH "content-length"
++#define TRANSFER_ENCODING "transfer-encoding"
++#define UPGRADE "upgrade"
++#define CHUNKED "chunked"
++#define KEEP_ALIVE "keep-alive"
++#define CLOSE "close"
++
++
++static const char *method_strings[] =
++  {
++#define XX(num, name, string) #string,
++  HTTP_METHOD_MAP(XX)
++#undef XX
++  };
++
++
++/* Tokens as defined by rfc 2616. Also lowercases them.
++ *        token       = 1*<any CHAR except CTLs or separators>
++ *     separators     = "(" | ")" | "<" | ">" | "@"
++ *                    | "," | ";" | ":" | "\" | <">
++ *                    | "/" | "[" | "]" | "?" | "="
++ *                    | "{" | "}" | SP | HT
++ */
++static const char tokens[256] = {
++/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
++        0,       0,       0,       0,       0,       0,       0,       0,
++/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
++        0,       0,       0,       0,       0,       0,       0,       0,
++/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
++        0,       0,       0,       0,       0,       0,       0,       0,
++/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
++        0,       0,       0,       0,       0,       0,       0,       0,
++/*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
++        0,      '!',      0,      '#',     '$',     '%',     '&',    '\'',
++/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
++        0,       0,      '*',     '+',      0,      '-',     '.',      0,
++/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
++       '0',     '1',     '2',     '3',     '4',     '5',     '6',     '7',
++/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
++       '8',     '9',      0,       0,       0,       0,       0,       0,
++/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
++        0,      'a',     'b',     'c',     'd',     'e',     'f',     'g',
++/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
++       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',
++/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
++       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',
++/*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
++       'x',     'y',     'z',      0,       0,       0,      '^',     '_',
++/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
++       '`',     'a',     'b',     'c',     'd',     'e',     'f',     'g',
++/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
++       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',
++/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
++       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',
++/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
++       'x',     'y',     'z',      0,      '|',      0,      '~',       0 };
++
++
++static const int8_t unhex[256] =
++  {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
++  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
++  };
++
++
++#if HTTP_PARSER_STRICT
++# define T(v) 0
++#else
++# define T(v) v
++#endif
++
++
++static const uint8_t normal_url_char[32] = {
++/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
++        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,
++/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
++        0    | T(2)   |   0    |   0    | T(16)  |   0    |   0    |   0,
++/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
++        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,
++/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
++        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,
++/*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
++        0    |   2    |   4    |   0    |   16   |   32   |   64   |  128,
++/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |   0,
++/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
++/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
++        1    |   2    |   4    |   8    |   16   |   32   |   64   |   0, };
++
++#undef T
++
++enum state
++  { s_dead = 1 /* important that this is > 0 */
++
++  , s_start_req_or_res
++  , s_res_or_resp_H
++  , s_start_res
++  , s_res_H
++  , s_res_HT
++  , s_res_HTT
++  , s_res_HTTP
++  , s_res_first_http_major
++  , s_res_http_major
++  , s_res_first_http_minor
++  , s_res_http_minor
++  , s_res_first_status_code
++  , s_res_status_code
++  , s_res_status_start
++  , s_res_status
++  , s_res_line_almost_done
++
++  , s_start_req
++
++  , s_req_method
++  , s_req_spaces_before_url
++  , s_req_schema
++  , s_req_schema_slash
++  , s_req_schema_slash_slash
++  , s_req_server_start
++  , s_req_server
++  , s_req_server_with_at
++  , s_req_path
++  , s_req_query_string_start
++  , s_req_query_string
++  , s_req_fragment_start
++  , s_req_fragment
++  , s_req_http_start
++  , s_req_http_H
++  , s_req_http_HT
++  , s_req_http_HTT
++  , s_req_http_HTTP
++  , s_req_first_http_major
++  , s_req_http_major
++  , s_req_first_http_minor
++  , s_req_http_minor
++  , s_req_line_almost_done
++
++  , s_header_field_start
++  , s_header_field
++  , s_header_value_discard_ws
++  , s_header_value_discard_ws_almost_done
++  , s_header_value_discard_lws
++  , s_header_value_start
++  , s_header_value
++  , s_header_value_lws
++
++  , s_header_almost_done
++
++  , s_chunk_size_start
++  , s_chunk_size
++  , s_chunk_parameters
++  , s_chunk_size_almost_done
++
++  , s_headers_almost_done
++  , s_headers_done
++
++  /* Important: 's_headers_done' must be the last 'header' state. All
++   * states beyond this must be 'body' states. It is used for overflow
++   * checking. See the PARSING_HEADER() macro.
++   */
++
++  , s_chunk_data
++  , s_chunk_data_almost_done
++  , s_chunk_data_done
++
++  , s_body_identity
++  , s_body_identity_eof
++
++  , s_message_done
++  };
++
++
++#define PARSING_HEADER(state) (state <= s_headers_done)
++
++
++enum header_states
++  { h_general = 0
++  , h_C
++  , h_CO
++  , h_CON
++
++  , h_matching_connection
++  , h_matching_proxy_connection
++  , h_matching_content_length
++  , h_matching_transfer_encoding
++  , h_matching_upgrade
++
++  , h_connection
++  , h_content_length
++  , h_transfer_encoding
++  , h_upgrade
++
++  , h_matching_transfer_encoding_chunked
++  , h_matching_connection_token_start
++  , h_matching_connection_keep_alive
++  , h_matching_connection_close
++  , h_matching_connection_upgrade
++  , h_matching_connection_token
++
++  , h_transfer_encoding_chunked
++  , h_connection_keep_alive
++  , h_connection_close
++  , h_connection_upgrade
++  };
++
++enum http_host_state
++  {
++    s_http_host_dead = 1
++  , s_http_userinfo_start
++  , s_http_userinfo
++  , s_http_host_start
++  , s_http_host_v6_start
++  , s_http_host
++  , s_http_host_v6
++  , s_http_host_v6_end
++  , s_http_host_v6_zone_start
++  , s_http_host_v6_zone
++  , s_http_host_port_start
++  , s_http_host_port
++};
++
++/* Macros for character classes; depends on strict-mode  */
++#define CR                  '\r'
++#define LF                  '\n'
++#define LOWER(c)            (unsigned char)(c | 0x20)
++#define IS_ALPHA(c)         (LOWER(c) >= 'a' && LOWER(c) <= 'z')
++#define IS_NUM(c)           ((c) >= '0' && (c) <= '9')
++#define IS_ALPHANUM(c)      (IS_ALPHA(c) || IS_NUM(c))
++#define IS_HEX(c)           (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
++#define IS_MARK(c)          ((c) == '-' || (c) == '_' || (c) == '.' || \
++  (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
++  (c) == ')')
++#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
++  (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
++  (c) == '$' || (c) == ',')
++
++#define STRICT_TOKEN(c)     (tokens[(unsigned char)c])
++
++#if HTTP_PARSER_STRICT
++#define TOKEN(c)            (tokens[(unsigned char)c])
++#define IS_URL_CHAR(c)      (BIT_AT(normal_url_char, (unsigned char)c))
++#define IS_HOST_CHAR(c)     (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
++#else
++#define TOKEN(c)            ((c == ' ') ? ' ' : tokens[(unsigned char)c])
++#define IS_URL_CHAR(c)                                                         \
++  (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
++#define IS_HOST_CHAR(c)                                                        \
++  (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
++#endif
++
++/**
++ * Verify that a char is a valid visible (printable) US-ASCII
++ * character or %x80-FF
++ **/
++#define IS_HEADER_CHAR(ch)                                                     \
++  (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127))
++
++#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
++
++
++#if HTTP_PARSER_STRICT
++# define STRICT_CHECK(cond)                                          \
++do {                                                                 \
++  if (cond) {                                                        \
++    SET_ERRNO(HPE_STRICT);                                           \
++    goto error;                                                      \
++  }                                                                  \
++} while (0)
++# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
++#else
++# define STRICT_CHECK(cond)
++# define NEW_MESSAGE() start_state
++#endif
++
++
++/* Map errno values to strings for human-readable output */
++#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
++static struct {
++  const char *name;
++  const char *description;
++} http_strerror_tab[] = {
++  HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
++};
++#undef HTTP_STRERROR_GEN
++
++int http_message_needs_eof(const http_parser *parser);
++
++/* Our URL parser.
++ *
++ * This is designed to be shared by http_parser_execute() for URL validation,
++ * hence it has a state transition + byte-for-byte interface. In addition, it
++ * is meant to be embedded in http_parser_parse_url(), which does the dirty
++ * work of turning state transitions URL components for its API.
++ *
++ * This function should only be invoked with non-space characters. It is
++ * assumed that the caller cares about (and can detect) the transition between
++ * URL and non-URL states by looking for these.
++ */
++static enum state
++parse_url_char(enum state s, const char ch)
++{
++  if (ch == ' ' || ch == '\r' || ch == '\n') {
++    return s_dead;
++  }
++
++#if HTTP_PARSER_STRICT
++  if (ch == '\t' || ch == '\f') {
++    return s_dead;
++  }
++#endif
++
++  switch (s) {
++    case s_req_spaces_before_url:
++      /* Proxied requests are followed by scheme of an absolute URI (alpha).
++       * All methods except CONNECT are followed by '/' or '*'.
++       */
++
++      if (ch == '/' || ch == '*') {
++        return s_req_path;
++      }
++
++      if (IS_ALPHA(ch)) {
++        return s_req_schema;
++      }
++
++      break;
++
++    case s_req_schema:
++      if (IS_ALPHA(ch)) {
++        return s;
++      }
++
++      if (ch == ':') {
++        return s_req_schema_slash;
++      }
++
++      break;
++
++    case s_req_schema_slash:
++      if (ch == '/') {
++        return s_req_schema_slash_slash;
++      }
++
++      break;
++
++    case s_req_schema_slash_slash:
++      if (ch == '/') {
++        return s_req_server_start;
++      }
++
++      break;
++
++    case s_req_server_with_at:
++      if (ch == '@') {
++        return s_dead;
++      }
++
++    /* FALLTHROUGH */
++    case s_req_server_start:
++    case s_req_server:
++      if (ch == '/') {
++        return s_req_path;
++      }
++
++      if (ch == '?') {
++        return s_req_query_string_start;
++      }
++
++      if (ch == '@') {
++        return s_req_server_with_at;
++      }
++
++      if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
++        return s_req_server;
++      }
++
++      break;
++
++    case s_req_path:
++      if (IS_URL_CHAR(ch)) {
++        return s;
++      }
++
++      switch (ch) {
++        case '?':
++          return s_req_query_string_start;
++
++        case '#':
++          return s_req_fragment_start;
++      }
++
++      break;
++
++    case s_req_query_string_start:
++    case s_req_query_string:
++      if (IS_URL_CHAR(ch)) {
++        return s_req_query_string;
++      }
++
++      switch (ch) {
++        case '?':
++          /* allow extra '?' in query string */
++          return s_req_query_string;
++
++        case '#':
++          return s_req_fragment_start;
++      }
++
++      break;
++
++    case s_req_fragment_start:
++      if (IS_URL_CHAR(ch)) {
++        return s_req_fragment;
++      }
++
++      switch (ch) {
++        case '?':
++          return s_req_fragment;
++
++        case '#':
++          return s;
++      }
++
++      break;
++
++    case s_req_fragment:
++      if (IS_URL_CHAR(ch)) {
++        return s;
++      }
++
++      switch (ch) {
++        case '?':
++        case '#':
++          return s;
++      }
++
++      break;
++
++    default:
++      break;
++  }
++
++  /* We should never fall out of the switch above unless there's an error */
++  return s_dead;
++}
++
++size_t http_parser_execute (http_parser *parser,
++                            const http_parser_settings *settings,
++                            const char *data,
++                            size_t len)
++{
++  char c, ch;
++  int8_t unhex_val;
++  const char *p = data;
++  const char *header_field_mark = 0;
++  const char *header_value_mark = 0;
++  const char *url_mark = 0;
++  const char *body_mark = 0;
++  const char *status_mark = 0;
++  enum state p_state = (enum state) parser->state;
++  const unsigned int lenient = parser->lenient_http_headers;
++
++  /* We're in an error state. Don't bother doing anything. */
++  if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
++    return 0;
++  }
++
++  if (len == 0) {
++    switch (CURRENT_STATE()) {
++      case s_body_identity_eof:
++        /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
++         * we got paused.
++         */
++        CALLBACK_NOTIFY_NOADVANCE(message_complete);
++        return 0;
++
++      case s_dead:
++      case s_start_req_or_res:
++      case s_start_res:
++      case s_start_req:
++        return 0;
++
++      default:
++        SET_ERRNO(HPE_INVALID_EOF_STATE);
++        return 1;
++    }
++  }
++
++
++  if (CURRENT_STATE() == s_header_field)
++    header_field_mark = data;
++  if (CURRENT_STATE() == s_header_value)
++    header_value_mark = data;
++  switch (CURRENT_STATE()) {
++  case s_req_path:
++  case s_req_schema:
++  case s_req_schema_slash:
++  case s_req_schema_slash_slash:
++  case s_req_server_start:
++  case s_req_server:
++  case s_req_server_with_at:
++  case s_req_query_string_start:
++  case s_req_query_string:
++  case s_req_fragment_start:
++  case s_req_fragment:
++    url_mark = data;
++    break;
++  case s_res_status:
++    status_mark = data;
++    break;
++  default:
++    break;
++  }
++
++  for (p=data; p != data + len; p++) {
++    ch = *p;
++
++    if (PARSING_HEADER(CURRENT_STATE()))
++      COUNT_HEADER_SIZE(1);
++
++reexecute:
++    switch (CURRENT_STATE()) {
++
++      case s_dead:
++        /* this state is used after a 'Connection: close' message
++         * the parser will error out if it reads another message
++         */
++        if (LIKELY(ch == CR || ch == LF))
++          break;
++
++        SET_ERRNO(HPE_CLOSED_CONNECTION);
++        goto error;
++
++      case s_start_req_or_res:
++      {
++        if (ch == CR || ch == LF)
++          break;
++        parser->flags = 0;
++        parser->content_length = ULLONG_MAX;
++
++        if (ch == 'H') {
++          UPDATE_STATE(s_res_or_resp_H);
++
++          CALLBACK_NOTIFY(message_begin);
++        } else {
++          parser->type = HTTP_REQUEST;
++          UPDATE_STATE(s_start_req);
++          REEXECUTE();
++        }
++
++        break;
++      }
++
++      case s_res_or_resp_H:
++        if (ch == 'T') {
++          parser->type = HTTP_RESPONSE;
++          UPDATE_STATE(s_res_HT);
++        } else {
++          if (UNLIKELY(ch != 'E')) {
++            SET_ERRNO(HPE_INVALID_CONSTANT);
++            goto error;
++          }
++
++          parser->type = HTTP_REQUEST;
++          parser->method = HTTP_HEAD;
++          parser->index = 2;
++          UPDATE_STATE(s_req_method);
++        }
++        break;
++
++      case s_start_res:
++      {
++        parser->flags = 0;
++        parser->content_length = ULLONG_MAX;
++
++        switch (ch) {
++          case 'H':
++            UPDATE_STATE(s_res_H);
++            break;
++
++          case CR:
++          case LF:
++            break;
++
++          default:
++            SET_ERRNO(HPE_INVALID_CONSTANT);
++            goto error;
++        }
++
++        CALLBACK_NOTIFY(message_begin);
++        break;
++      }
++
++      case s_res_H:
++        STRICT_CHECK(ch != 'T');
++        UPDATE_STATE(s_res_HT);
++        break;
++
++      case s_res_HT:
++        STRICT_CHECK(ch != 'T');
++        UPDATE_STATE(s_res_HTT);
++        break;
++
++      case s_res_HTT:
++        STRICT_CHECK(ch != 'P');
++        UPDATE_STATE(s_res_HTTP);
++        break;
++
++      case s_res_HTTP:
++        STRICT_CHECK(ch != '/');
++        UPDATE_STATE(s_res_first_http_major);
++        break;
++
++      case s_res_first_http_major:
++        if (UNLIKELY(ch < '0' || ch > '9')) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_major = ch - '0';
++        UPDATE_STATE(s_res_http_major);
++        break;
++
++      /* major HTTP version or dot */
++      case s_res_http_major:
++      {
++        if (ch == '.') {
++          UPDATE_STATE(s_res_first_http_minor);
++          break;
++        }
++
++        if (!IS_NUM(ch)) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_major *= 10;
++        parser->http_major += ch - '0';
++
++        if (UNLIKELY(parser->http_major > 999)) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        break;
++      }
++
++      /* first digit of minor HTTP version */
++      case s_res_first_http_minor:
++        if (UNLIKELY(!IS_NUM(ch))) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_minor = ch - '0';
++        UPDATE_STATE(s_res_http_minor);
++        break;
++
++      /* minor HTTP version or end of request line */
++      case s_res_http_minor:
++      {
++        if (ch == ' ') {
++          UPDATE_STATE(s_res_first_status_code);
++          break;
++        }
++
++        if (UNLIKELY(!IS_NUM(ch))) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_minor *= 10;
++        parser->http_minor += ch - '0';
++
++        if (UNLIKELY(parser->http_minor > 999)) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        break;
++      }
++
++      case s_res_first_status_code:
++      {
++        if (!IS_NUM(ch)) {
++          if (ch == ' ') {
++            break;
++          }
++
++          SET_ERRNO(HPE_INVALID_STATUS);
++          goto error;
++        }
++        parser->status_code = ch - '0';
++        UPDATE_STATE(s_res_status_code);
++        break;
++      }
++
++      case s_res_status_code:
++      {
++        if (!IS_NUM(ch)) {
++          switch (ch) {
++            case ' ':
++              UPDATE_STATE(s_res_status_start);
++              break;
++            case CR:
++              UPDATE_STATE(s_res_line_almost_done);
++              break;
++            case LF:
++              UPDATE_STATE(s_header_field_start);
++              break;
++            default:
++              SET_ERRNO(HPE_INVALID_STATUS);
++              goto error;
++          }
++          break;
++        }
++
++        parser->status_code *= 10;
++        parser->status_code += ch - '0';
++
++        if (UNLIKELY(parser->status_code > 999)) {
++          SET_ERRNO(HPE_INVALID_STATUS);
++          goto error;
++        }
++
++        break;
++      }
++
++      case s_res_status_start:
++      {
++        if (ch == CR) {
++          UPDATE_STATE(s_res_line_almost_done);
++          break;
++        }
++
++        if (ch == LF) {
++          UPDATE_STATE(s_header_field_start);
++          break;
++        }
++
++        MARK(status);
++        UPDATE_STATE(s_res_status);
++        parser->index = 0;
++        break;
++      }
++
++      case s_res_status:
++        if (ch == CR) {
++          UPDATE_STATE(s_res_line_almost_done);
++          CALLBACK_DATA(status);
++          break;
++        }
++
++        if (ch == LF) {
++          UPDATE_STATE(s_header_field_start);
++          CALLBACK_DATA(status);
++          break;
++        }
++
++        break;
++
++      case s_res_line_almost_done:
++        STRICT_CHECK(ch != LF);
++        UPDATE_STATE(s_header_field_start);
++        break;
++
++      case s_start_req:
++      {
++        if (ch == CR || ch == LF)
++          break;
++        parser->flags = 0;
++        parser->content_length = ULLONG_MAX;
++
++        if (UNLIKELY(!IS_ALPHA(ch))) {
++          SET_ERRNO(HPE_INVALID_METHOD);
++          goto error;
++        }
++
++        parser->method = (enum http_method) 0;
++        parser->index = 1;
++        switch (ch) {
++          case 'A': parser->method = HTTP_ACL; break;
++          case 'B': parser->method = HTTP_BIND; break;
++          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
++          case 'D': parser->method = HTTP_DELETE; break;
++          case 'G': parser->method = HTTP_GET; break;
++          case 'H': parser->method = HTTP_HEAD; break;
++          case 'L': parser->method = HTTP_LOCK; /* or LINK */ break;
++          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
++          case 'N': parser->method = HTTP_NOTIFY; break;
++          case 'O': parser->method = HTTP_OPTIONS; break;
++          case 'P': parser->method = HTTP_POST;
++            /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
++            break;
++          case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
++          case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
++          case 'T': parser->method = HTTP_TRACE; break;
++          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
++          default:
++            SET_ERRNO(HPE_INVALID_METHOD);
++            goto error;
++        }
++        UPDATE_STATE(s_req_method);
++
++        CALLBACK_NOTIFY(message_begin);
++
++        break;
++      }
++
++      case s_req_method:
++      {
++        const char *matcher;
++        if (UNLIKELY(ch == '\0')) {
++          SET_ERRNO(HPE_INVALID_METHOD);
++          goto error;
++        }
++
++        matcher = method_strings[parser->method];
++        if (ch == ' ' && matcher[parser->index] == '\0') {
++          UPDATE_STATE(s_req_spaces_before_url);
++        } else if (ch == matcher[parser->index]) {
++          ; /* nada */
++        } else if (IS_ALPHA(ch)) {
++
++          switch (parser->method << 16 | parser->index << 8 | ch) {
++#define XX(meth, pos, ch, new_meth) \
++            case (HTTP_##meth << 16 | pos << 8 | ch): \
++              parser->method = HTTP_##new_meth; break;
++
++            XX(POST,      1, 'U', PUT)
++            XX(POST,      1, 'A', PATCH)
++            XX(CONNECT,   1, 'H', CHECKOUT)
++            XX(CONNECT,   2, 'P', COPY)
++            XX(MKCOL,     1, 'O', MOVE)
++            XX(MKCOL,     1, 'E', MERGE)
++            XX(MKCOL,     2, 'A', MKACTIVITY)
++            XX(MKCOL,     3, 'A', MKCALENDAR)
++            XX(SUBSCRIBE, 1, 'E', SEARCH)
++            XX(REPORT,    2, 'B', REBIND)
++            XX(POST,      1, 'R', PROPFIND)
++            XX(PROPFIND,  4, 'P', PROPPATCH)
++            XX(PUT,       2, 'R', PURGE)
++            XX(LOCK,      1, 'I', LINK)
++            XX(UNLOCK,    2, 'S', UNSUBSCRIBE)
++            XX(UNLOCK,    2, 'B', UNBIND)
++            XX(UNLOCK,    3, 'I', UNLINK)
++#undef XX
++
++            default:
++              SET_ERRNO(HPE_INVALID_METHOD);
++              goto error;
++          }
++        } else if (ch == '-' &&
++                   parser->index == 1 &&
++                   parser->method == HTTP_MKCOL) {
++          parser->method = HTTP_MSEARCH;
++        } else {
++          SET_ERRNO(HPE_INVALID_METHOD);
++          goto error;
++        }
++
++        ++parser->index;
++        break;
++      }
++
++      case s_req_spaces_before_url:
++      {
++        if (ch == ' ') break;
++
++        MARK(url);
++        if (parser->method == HTTP_CONNECT) {
++          UPDATE_STATE(s_req_server_start);
++        }
++
++        UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
++        if (UNLIKELY(CURRENT_STATE() == s_dead)) {
++          SET_ERRNO(HPE_INVALID_URL);
++          goto error;
++        }
++
++        break;
++      }
++
++      case s_req_schema:
++      case s_req_schema_slash:
++      case s_req_schema_slash_slash:
++      case s_req_server_start:
++      {
++        switch (ch) {
++          /* No whitespace allowed here */
++          case ' ':
++          case CR:
++          case LF:
++            SET_ERRNO(HPE_INVALID_URL);
++            goto error;
++          default:
++            UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
++            if (UNLIKELY(CURRENT_STATE() == s_dead)) {
++              SET_ERRNO(HPE_INVALID_URL);
++              goto error;
++            }
++        }
++
++        break;
++      }
++
++      case s_req_server:
++      case s_req_server_with_at:
++      case s_req_path:
++      case s_req_query_string_start:
++      case s_req_query_string:
++      case s_req_fragment_start:
++      case s_req_fragment:
++      {
++        switch (ch) {
++          case ' ':
++            UPDATE_STATE(s_req_http_start);
++            CALLBACK_DATA(url);
++            break;
++          case CR:
++          case LF:
++            parser->http_major = 0;
++            parser->http_minor = 9;
++            UPDATE_STATE((ch == CR) ?
++              s_req_line_almost_done :
++              s_header_field_start);
++            CALLBACK_DATA(url);
++            break;
++          default:
++            UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
++            if (UNLIKELY(CURRENT_STATE() == s_dead)) {
++              SET_ERRNO(HPE_INVALID_URL);
++              goto error;
++            }
++        }
++        break;
++      }
++
++      case s_req_http_start:
++        switch (ch) {
++          case 'H':
++            UPDATE_STATE(s_req_http_H);
++            break;
++          case ' ':
++            break;
++          default:
++            SET_ERRNO(HPE_INVALID_CONSTANT);
++            goto error;
++        }
++        break;
++
++      case s_req_http_H:
++        STRICT_CHECK(ch != 'T');
++        UPDATE_STATE(s_req_http_HT);
++        break;
++
++      case s_req_http_HT:
++        STRICT_CHECK(ch != 'T');
++        UPDATE_STATE(s_req_http_HTT);
++        break;
++
++      case s_req_http_HTT:
++        STRICT_CHECK(ch != 'P');
++        UPDATE_STATE(s_req_http_HTTP);
++        break;
++
++      case s_req_http_HTTP:
++        STRICT_CHECK(ch != '/');
++        UPDATE_STATE(s_req_first_http_major);
++        break;
++
++      /* first digit of major HTTP version */
++      case s_req_first_http_major:
++        if (UNLIKELY(ch < '1' || ch > '9')) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_major = ch - '0';
++        UPDATE_STATE(s_req_http_major);
++        break;
++
++      /* major HTTP version or dot */
++      case s_req_http_major:
++      {
++        if (ch == '.') {
++          UPDATE_STATE(s_req_first_http_minor);
++          break;
++        }
++
++        if (UNLIKELY(!IS_NUM(ch))) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_major *= 10;
++        parser->http_major += ch - '0';
++
++        if (UNLIKELY(parser->http_major > 999)) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        break;
++      }
++
++      /* first digit of minor HTTP version */
++      case s_req_first_http_minor:
++        if (UNLIKELY(!IS_NUM(ch))) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_minor = ch - '0';
++        UPDATE_STATE(s_req_http_minor);
++        break;
++
++      /* minor HTTP version or end of request line */
++      case s_req_http_minor:
++      {
++        if (ch == CR) {
++          UPDATE_STATE(s_req_line_almost_done);
++          break;
++        }
++
++        if (ch == LF) {
++          UPDATE_STATE(s_header_field_start);
++          break;
++        }
++
++        /* XXX allow spaces after digit? */
++
++        if (UNLIKELY(!IS_NUM(ch))) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        parser->http_minor *= 10;
++        parser->http_minor += ch - '0';
++
++        if (UNLIKELY(parser->http_minor > 999)) {
++          SET_ERRNO(HPE_INVALID_VERSION);
++          goto error;
++        }
++
++        break;
++      }
++
++      /* end of request line */
++      case s_req_line_almost_done:
++      {
++        if (UNLIKELY(ch != LF)) {
++          SET_ERRNO(HPE_LF_EXPECTED);
++          goto error;
++        }
++
++        UPDATE_STATE(s_header_field_start);
++        break;
++      }
++
++      case s_header_field_start:
++      {
++        if (ch == CR) {
++          UPDATE_STATE(s_headers_almost_done);
++          break;
++        }
++
++        if (ch == LF) {
++          /* they might be just sending \n instead of \r\n so this would be
++           * the second \n to denote the end of headers*/
++          UPDATE_STATE(s_headers_almost_done);
++          REEXECUTE();
++        }
++
++        c = TOKEN(ch);
++
++        if (UNLIKELY(!c)) {
++          SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
++          goto error;
++        }
++
++        MARK(header_field);
++
++        parser->index = 0;
++        UPDATE_STATE(s_header_field);
++
++        switch (c) {
++          case 'c':
++            parser->header_state = h_C;
++            break;
++
++          case 'p':
++            parser->header_state = h_matching_proxy_connection;
++            break;
++
++          case 't':
++            parser->header_state = h_matching_transfer_encoding;
++            break;
++
++          case 'u':
++            parser->header_state = h_matching_upgrade;
++            break;
++
++          default:
++            parser->header_state = h_general;
++            break;
++        }
++        break;
++      }
++
++      case s_header_field:
++      {
++        const char* start = p;
++        for (; p != data + len; p++) {
++          ch = *p;
++          c = TOKEN(ch);
++
++          if (!c)
++            break;
++
++          switch (parser->header_state) {
++            case h_general:
++              break;
++
++            case h_C:
++              parser->index++;
++              parser->header_state = (c == 'o' ? h_CO : h_general);
++              break;
++
++            case h_CO:
++              parser->index++;
++              parser->header_state = (c == 'n' ? h_CON : h_general);
++              break;
++
++            case h_CON:
++              parser->index++;
++              switch (c) {
++                case 'n':
++                  parser->header_state = h_matching_connection;
++                  break;
++                case 't':
++                  parser->header_state = h_matching_content_length;
++                  break;
++                default:
++                  parser->header_state = h_general;
++                  break;
++              }
++              break;
++
++            /* connection */
++
++            case h_matching_connection:
++              parser->index++;
++              if (parser->index > sizeof(CONNECTION)-1
++                  || c != CONNECTION[parser->index]) {
++                parser->header_state = h_general;
++              } else if (parser->index == sizeof(CONNECTION)-2) {
++                parser->header_state = h_connection;
++              }
++              break;
++
++            /* proxy-connection */
++
++            case h_matching_proxy_connection:
++              parser->index++;
++              if (parser->index > sizeof(PROXY_CONNECTION)-1
++                  || c != PROXY_CONNECTION[parser->index]) {
++                parser->header_state = h_general;
++              } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
++                parser->header_state = h_connection;
++              }
++              break;
++
++            /* content-length */
++
++            case h_matching_content_length:
++              parser->index++;
++              if (parser->index > sizeof(CONTENT_LENGTH)-1
++                  || c != CONTENT_LENGTH[parser->index]) {
++                parser->header_state = h_general;
++              } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
++                if (parser->flags & F_CONTENTLENGTH) {
++                  SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
++                  goto error;
++                }
++                parser->header_state = h_content_length;
++                parser->flags |= F_CONTENTLENGTH;
++              }
++              break;
++
++            /* transfer-encoding */
++
++            case h_matching_transfer_encoding:
++              parser->index++;
++              if (parser->index > sizeof(TRANSFER_ENCODING)-1
++                  || c != TRANSFER_ENCODING[parser->index]) {
++                parser->header_state = h_general;
++              } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
++                parser->header_state = h_transfer_encoding;
++              }
++              break;
++
++            /* upgrade */
++
++            case h_matching_upgrade:
++              parser->index++;
++              if (parser->index > sizeof(UPGRADE)-1
++                  || c != UPGRADE[parser->index]) {
++                parser->header_state = h_general;
++              } else if (parser->index == sizeof(UPGRADE)-2) {
++                parser->header_state = h_upgrade;
++              }
++              break;
++
++            case h_connection:
++            case h_content_length:
++            case h_transfer_encoding:
++            case h_upgrade:
++              if (ch != ' ') parser->header_state = h_general;
++              break;
++
++            default:
++              assert(0 && "Unknown header_state");
++              break;
++          }
++        }
++
++        COUNT_HEADER_SIZE(p - start);
++
++        if (p == data + len) {
++          --p;
++          break;
++        }
++
++        if (ch == ':') {
++          UPDATE_STATE(s_header_value_discard_ws);
++          CALLBACK_DATA(header_field);
++          break;
++        }
++
++        SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
++        goto error;
++      }
++
++      case s_header_value_discard_ws:
++        if (ch == ' ' || ch == '\t') break;
++
++        if (ch == CR) {
++          UPDATE_STATE(s_header_value_discard_ws_almost_done);
++          break;
++        }
++
++        if (ch == LF) {
++          UPDATE_STATE(s_header_value_discard_lws);
++          break;
++        }
++
++        /* FALLTHROUGH */
++
++      case s_header_value_start:
++      {
++        MARK(header_value);
++
++        UPDATE_STATE(s_header_value);
++        parser->index = 0;
++
++        c = LOWER(ch);
++
++        switch (parser->header_state) {
++          case h_upgrade:
++            parser->flags |= F_UPGRADE;
++            parser->header_state = h_general;
++            break;
++
++          case h_transfer_encoding:
++            /* looking for 'Transfer-Encoding: chunked' */
++            if ('c' == c) {
++              parser->header_state = h_matching_transfer_encoding_chunked;
++            } else {
++              parser->header_state = h_general;
++            }
++            break;
++
++          case h_content_length:
++            if (UNLIKELY(!IS_NUM(ch))) {
++              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
++              goto error;
++            }
++
++            parser->content_length = ch - '0';
++            break;
++
++          case h_connection:
++            /* looking for 'Connection: keep-alive' */
++            if (c == 'k') {
++              parser->header_state = h_matching_connection_keep_alive;
++            /* looking for 'Connection: close' */
++            } else if (c == 'c') {
++              parser->header_state = h_matching_connection_close;
++            } else if (c == 'u') {
++              parser->header_state = h_matching_connection_upgrade;
++            } else {
++              parser->header_state = h_matching_connection_token;
++            }
++            break;
++
++          /* Multi-value `Connection` header */
++          case h_matching_connection_token_start:
++            break;
++
++          default:
++            parser->header_state = h_general;
++            break;
++        }
++        break;
++      }
++
++      case s_header_value:
++      {
++        const char* start = p;
++        enum header_states h_state = (enum header_states) parser->header_state;
++        for (; p != data + len; p++) {
++          ch = *p;
++          if (ch == CR) {
++            UPDATE_STATE(s_header_almost_done);
++            parser->header_state = h_state;
++            CALLBACK_DATA(header_value);
++            break;
++          }
++
++          if (ch == LF) {
++            UPDATE_STATE(s_header_almost_done);
++            COUNT_HEADER_SIZE(p - start);
++            parser->header_state = h_state;
++            CALLBACK_DATA_NOADVANCE(header_value);
++            REEXECUTE();
++          }
++
++          if (!lenient && !IS_HEADER_CHAR(ch)) {
++            SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
++            goto error;
++          }
++
++          c = LOWER(ch);
++
++          switch (h_state) {
++            case h_general:
++            {
++              const char* p_cr;
++              const char* p_lf;
++              size_t limit = data + len - p;
++
++              limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
++
++              p_cr = (const char*) memchr(p, CR, limit);
++              p_lf = (const char*) memchr(p, LF, limit);
++              if (p_cr != NULL) {
++                if (p_lf != NULL && p_cr >= p_lf)
++                  p = p_lf;
++                else
++                  p = p_cr;
++              } else if (UNLIKELY(p_lf != NULL)) {
++                p = p_lf;
++              } else {
++                p = data + len;
++              }
++              --p;
++
++              break;
++            }
++
++            case h_connection:
++            case h_transfer_encoding:
++              assert(0 && "Shouldn't get here.");
++              break;
++
++            case h_content_length:
++            {
++              uint64_t t;
++
++              if (ch == ' ') break;
++
++              if (UNLIKELY(!IS_NUM(ch))) {
++                SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
++                parser->header_state = h_state;
++                goto error;
++              }
++
++              t = parser->content_length;
++              t *= 10;
++              t += ch - '0';
++
++              /* Overflow? Test against a conservative limit for simplicity. */
++              if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) {
++                SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
++                parser->header_state = h_state;
++                goto error;
++              }
++
++              parser->content_length = t;
++              break;
++            }
++
++            /* Transfer-Encoding: chunked */
++            case h_matching_transfer_encoding_chunked:
++              parser->index++;
++              if (parser->index > sizeof(CHUNKED)-1
++                  || c != CHUNKED[parser->index]) {
++                h_state = h_general;
++              } else if (parser->index == sizeof(CHUNKED)-2) {
++                h_state = h_transfer_encoding_chunked;
++              }
++              break;
++
++            case h_matching_connection_token_start:
++              /* looking for 'Connection: keep-alive' */
++              if (c == 'k') {
++                h_state = h_matching_connection_keep_alive;
++              /* looking for 'Connection: close' */
++              } else if (c == 'c') {
++                h_state = h_matching_connection_close;
++              } else if (c == 'u') {
++                h_state = h_matching_connection_upgrade;
++              } else if (STRICT_TOKEN(c)) {
++                h_state = h_matching_connection_token;
++              } else if (c == ' ' || c == '\t') {
++                /* Skip lws */
++              } else {
++                h_state = h_general;
++              }
++              break;
++
++            /* looking for 'Connection: keep-alive' */
++            case h_matching_connection_keep_alive:
++              parser->index++;
++              if (parser->index > sizeof(KEEP_ALIVE)-1
++                  || c != KEEP_ALIVE[parser->index]) {
++                h_state = h_matching_connection_token;
++              } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
++                h_state = h_connection_keep_alive;
++              }
++              break;
++
++            /* looking for 'Connection: close' */
++            case h_matching_connection_close:
++              parser->index++;
++              if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
++                h_state = h_matching_connection_token;
++              } else if (parser->index == sizeof(CLOSE)-2) {
++                h_state = h_connection_close;
++              }
++              break;
++
++            /* looking for 'Connection: upgrade' */
++            case h_matching_connection_upgrade:
++              parser->index++;
++              if (parser->index > sizeof(UPGRADE) - 1 ||
++                  c != UPGRADE[parser->index]) {
++                h_state = h_matching_connection_token;
++              } else if (parser->index == sizeof(UPGRADE)-2) {
++                h_state = h_connection_upgrade;
++              }
++              break;
++
++            case h_matching_connection_token:
++              if (ch == ',') {
++                h_state = h_matching_connection_token_start;
++                parser->index = 0;
++              }
++              break;
++
++            case h_transfer_encoding_chunked:
++              if (ch != ' ') h_state = h_general;
++              break;
++
++            case h_connection_keep_alive:
++            case h_connection_close:
++            case h_connection_upgrade:
++              if (ch == ',') {
++                if (h_state == h_connection_keep_alive) {
++                  parser->flags |= F_CONNECTION_KEEP_ALIVE;
++                } else if (h_state == h_connection_close) {
++                  parser->flags |= F_CONNECTION_CLOSE;
++                } else if (h_state == h_connection_upgrade) {
++                  parser->flags |= F_CONNECTION_UPGRADE;
++                }
++                h_state = h_matching_connection_token_start;
++                parser->index = 0;
++              } else if (ch != ' ') {
++                h_state = h_matching_connection_token;
++              }
++              break;
++
++            default:
++              UPDATE_STATE(s_header_value);
++              h_state = h_general;
++              break;
++          }
++        }
++        parser->header_state = h_state;
++
++        COUNT_HEADER_SIZE(p - start);
++
++        if (p == data + len)
++          --p;
++        break;
++      }
++
++      case s_header_almost_done:
++      {
++        if (UNLIKELY(ch != LF)) {
++          SET_ERRNO(HPE_LF_EXPECTED);
++          goto error;
++        }
++
++        UPDATE_STATE(s_header_value_lws);
++        break;
++      }
++
++      case s_header_value_lws:
++      {
++        if (ch == ' ' || ch == '\t') {
++          UPDATE_STATE(s_header_value_start);
++          REEXECUTE();
++        }
++
++        /* finished the header */
++        switch (parser->header_state) {
++          case h_connection_keep_alive:
++            parser->flags |= F_CONNECTION_KEEP_ALIVE;
++            break;
++          case h_connection_close:
++            parser->flags |= F_CONNECTION_CLOSE;
++            break;
++          case h_transfer_encoding_chunked:
++            parser->flags |= F_CHUNKED;
++            break;
++          case h_connection_upgrade:
++            parser->flags |= F_CONNECTION_UPGRADE;
++            break;
++          default:
++            break;
++        }
++
++        UPDATE_STATE(s_header_field_start);
++        REEXECUTE();
++      }
++
++      case s_header_value_discard_ws_almost_done:
++      {
++        STRICT_CHECK(ch != LF);
++        UPDATE_STATE(s_header_value_discard_lws);
++        break;
++      }
++
++      case s_header_value_discard_lws:
++      {
++        if (ch == ' ' || ch == '\t') {
++          UPDATE_STATE(s_header_value_discard_ws);
++          break;
++        } else {
++          switch (parser->header_state) {
++            case h_connection_keep_alive:
++              parser->flags |= F_CONNECTION_KEEP_ALIVE;
++              break;
++            case h_connection_close:
++              parser->flags |= F_CONNECTION_CLOSE;
++              break;
++            case h_connection_upgrade:
++              parser->flags |= F_CONNECTION_UPGRADE;
++              break;
++            case h_transfer_encoding_chunked:
++              parser->flags |= F_CHUNKED;
++              break;
++            default:
++              break;
++          }
++
++          /* header value was empty */
++          MARK(header_value);
++          UPDATE_STATE(s_header_field_start);
++          CALLBACK_DATA_NOADVANCE(header_value);
++          REEXECUTE();
++        }
++      }
++
++      case s_headers_almost_done:
++      {
++        STRICT_CHECK(ch != LF);
++
++        if (parser->flags & F_TRAILING) {
++          /* End of a chunked request */
++          UPDATE_STATE(s_message_done);
++          CALLBACK_NOTIFY_NOADVANCE(chunk_complete);
++          REEXECUTE();
++        }
++
++        /* Cannot use chunked encoding and a content-length header together
++           per the HTTP specification. */
++        if ((parser->flags & F_CHUNKED) &&
++            (parser->flags & F_CONTENTLENGTH)) {
++          SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
++          goto error;
++        }
++
++        UPDATE_STATE(s_headers_done);
++
++        /* Set this here so that on_headers_complete() callbacks can see it */
++        parser->upgrade =
++          ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) ==
++           (F_UPGRADE | F_CONNECTION_UPGRADE) ||
++           parser->method == HTTP_CONNECT);
++
++        /* Here we call the headers_complete callback. This is somewhat
++         * different than other callbacks because if the user returns 1, we
++         * will interpret that as saying that this message has no body. This
++         * is needed for the annoying case of recieving a response to a HEAD
++         * request.
++         *
++         * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
++         * we have to simulate it by handling a change in errno below.
++         */
++        if (settings->on_headers_complete) {
++          switch (settings->on_headers_complete(parser)) {
++            case 0:
++              break;
++
++            case 2:
++              parser->upgrade = 1;
++
++            case 1:
++              parser->flags |= F_SKIPBODY;
++              break;
++
++            default:
++              SET_ERRNO(HPE_CB_headers_complete);
++              RETURN(p - data); /* Error */
++          }
++        }
++
++        if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
++          RETURN(p - data);
++        }
++
++        REEXECUTE();
++      }
++
++      case s_headers_done:
++      {
++        int hasBody;
++        STRICT_CHECK(ch != LF);
++
++        parser->nread = 0;
++
++        hasBody = parser->flags & F_CHUNKED ||
++          (parser->content_length > 0 && parser->content_length != ULLONG_MAX);
++        if (parser->upgrade && (parser->method == HTTP_CONNECT ||
++                                (parser->flags & F_SKIPBODY) || !hasBody)) {
++          /* Exit, the rest of the message is in a different protocol. */
++          UPDATE_STATE(NEW_MESSAGE());
++          CALLBACK_NOTIFY(message_complete);
++          RETURN((p - data) + 1);
++        }
++
++        if (parser->flags & F_SKIPBODY) {
++          UPDATE_STATE(NEW_MESSAGE());
++          CALLBACK_NOTIFY(message_complete);
++        } else if (parser->flags & F_CHUNKED) {
++          /* chunked encoding - ignore Content-Length header */
++          UPDATE_STATE(s_chunk_size_start);
++        } else {
++          if (parser->content_length == 0) {
++            /* Content-Length header given but zero: Content-Length: 0\r\n */
++            UPDATE_STATE(NEW_MESSAGE());
++            CALLBACK_NOTIFY(message_complete);
++          } else if (parser->content_length != ULLONG_MAX) {
++            /* Content-Length header given and non-zero */
++            UPDATE_STATE(s_body_identity);
++          } else {
++            if (!http_message_needs_eof(parser)) {
++              /* Assume content-length 0 - read the next */
++              UPDATE_STATE(NEW_MESSAGE());
++              CALLBACK_NOTIFY(message_complete);
++            } else {
++              /* Read body until EOF */
++              UPDATE_STATE(s_body_identity_eof);
++            }
++          }
++        }
++
++        break;
++      }
++
++      case s_body_identity:
++      {
++        uint64_t to_read = MIN(parser->content_length,
++                               (uint64_t) ((data + len) - p));
++
++        assert(parser->content_length != 0
++            && parser->content_length != ULLONG_MAX);
++
++        /* The difference between advancing content_length and p is because
++         * the latter will automaticaly advance on the next loop iteration.
++         * Further, if content_length ends up at 0, we want to see the last
++         * byte again for our message complete callback.
++         */
++        MARK(body);
++        parser->content_length -= to_read;
++        p += to_read - 1;
++
++        if (parser->content_length == 0) {
++          UPDATE_STATE(s_message_done);
++
++          /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
++           *
++           * The alternative to doing this is to wait for the next byte to
++           * trigger the data callback, just as in every other case. The
++           * problem with this is that this makes it difficult for the test
++           * harness to distinguish between complete-on-EOF and
++           * complete-on-length. It's not clear that this distinction is
++           * important for applications, but let's keep it for now.
++           */
++          CALLBACK_DATA_(body, p - body_mark + 1, p - data);
++          REEXECUTE();
++        }
++
++        break;
++      }
++
++      /* read until EOF */
++      case s_body_identity_eof:
++        MARK(body);
++        p = data + len - 1;
++
++        break;
++
++      case s_message_done:
++        UPDATE_STATE(NEW_MESSAGE());
++        CALLBACK_NOTIFY(message_complete);
++        if (parser->upgrade) {
++          /* Exit, the rest of the message is in a different protocol. */
++          RETURN((p - data) + 1);
++        }
++        break;
++
++      case s_chunk_size_start:
++      {
++        assert(parser->nread == 1);
++        assert(parser->flags & F_CHUNKED);
++
++        unhex_val = unhex[(unsigned char)ch];
++        if (UNLIKELY(unhex_val == -1)) {
++          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
++          goto error;
++        }
++
++        parser->content_length = unhex_val;
++        UPDATE_STATE(s_chunk_size);
++        break;
++      }
++
++      case s_chunk_size:
++      {
++        uint64_t t;
++
++        assert(parser->flags & F_CHUNKED);
++
++        if (ch == CR) {
++          UPDATE_STATE(s_chunk_size_almost_done);
++          break;
++        }
++
++        unhex_val = unhex[(unsigned char)ch];
++
++        if (unhex_val == -1) {
++          if (ch == ';' || ch == ' ') {
++            UPDATE_STATE(s_chunk_parameters);
++            break;
++          }
++
++          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
++          goto error;
++        }
++
++        t = parser->content_length;
++        t *= 16;
++        t += unhex_val;
++
++        /* Overflow? Test against a conservative limit for simplicity. */
++        if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) {
++          SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
++          goto error;
++        }
++
++        parser->content_length = t;
++        break;
++      }
++
++      case s_chunk_parameters:
++      {
++        assert(parser->flags & F_CHUNKED);
++        /* just ignore this shit. TODO check for overflow */
++        if (ch == CR) {
++          UPDATE_STATE(s_chunk_size_almost_done);
++          break;
++        }
++        break;
++      }
++
++      case s_chunk_size_almost_done:
++      {
++        assert(parser->flags & F_CHUNKED);
++        STRICT_CHECK(ch != LF);
++
++        parser->nread = 0;
++
++        if (parser->content_length == 0) {
++          parser->flags |= F_TRAILING;
++          UPDATE_STATE(s_header_field_start);
++        } else {
++          UPDATE_STATE(s_chunk_data);
++        }
++        CALLBACK_NOTIFY(chunk_header);
++        break;
++      }
++
++      case s_chunk_data:
++      {
++        uint64_t to_read = MIN(parser->content_length,
++                               (uint64_t) ((data + len) - p));
++
++        assert(parser->flags & F_CHUNKED);
++        assert(parser->content_length != 0
++            && parser->content_length != ULLONG_MAX);
++
++        /* See the explanation in s_body_identity for why the content
++         * length and data pointers are managed this way.
++         */
++        MARK(body);
++        parser->content_length -= to_read;
++        p += to_read - 1;
++
++        if (parser->content_length == 0) {
++          UPDATE_STATE(s_chunk_data_almost_done);
++        }
++
++        break;
++      }
++
++      case s_chunk_data_almost_done:
++        assert(parser->flags & F_CHUNKED);
++        assert(parser->content_length == 0);
++        STRICT_CHECK(ch != CR);
++        UPDATE_STATE(s_chunk_data_done);
++        CALLBACK_DATA(body);
++        break;
++
++      case s_chunk_data_done:
++        assert(parser->flags & F_CHUNKED);
++        STRICT_CHECK(ch != LF);
++        parser->nread = 0;
++        UPDATE_STATE(s_chunk_size_start);
++        CALLBACK_NOTIFY(chunk_complete);
++        break;
++
++      default:
++        assert(0 && "unhandled state");
++        SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
++        goto error;
++    }
++  }
++
++  /* Run callbacks for any marks that we have leftover after we ran our of
++   * bytes. There should be at most one of these set, so it's OK to invoke
++   * them in series (unset marks will not result in callbacks).
++   *
++   * We use the NOADVANCE() variety of callbacks here because 'p' has already
++   * overflowed 'data' and this allows us to correct for the off-by-one that
++   * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
++   * value that's in-bounds).
++   */
++
++  assert(((header_field_mark ? 1 : 0) +
++          (header_value_mark ? 1 : 0) +
++          (url_mark ? 1 : 0)  +
++          (body_mark ? 1 : 0) +
++          (status_mark ? 1 : 0)) <= 1);
++
++  CALLBACK_DATA_NOADVANCE(header_field);
++  CALLBACK_DATA_NOADVANCE(header_value);
++  CALLBACK_DATA_NOADVANCE(url);
++  CALLBACK_DATA_NOADVANCE(body);
++  CALLBACK_DATA_NOADVANCE(status);
++
++  RETURN(len);
++
++error:
++  if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
++    SET_ERRNO(HPE_UNKNOWN);
++  }
++
++  RETURN(p - data);
++}
++
++
++/* Does the parser need to see an EOF to find the end of the message? */
++int
++http_message_needs_eof (const http_parser *parser)
++{
++  if (parser->type == HTTP_REQUEST) {
++    return 0;
++  }
++
++  /* See RFC 2616 section 4.4 */
++  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
++      parser->status_code == 204 ||     /* No Content */
++      parser->status_code == 304 ||     /* Not Modified */
++      parser->flags & F_SKIPBODY) {     /* response to a HEAD request */
++    return 0;
++  }
++
++  if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
++    return 0;
++  }
++
++  return 1;
++}
++
++
++int
++http_should_keep_alive (const http_parser *parser)
++{
++  if (parser->http_major > 0 && parser->http_minor > 0) {
++    /* HTTP/1.1 */
++    if (parser->flags & F_CONNECTION_CLOSE) {
++      return 0;
++    }
++  } else {
++    /* HTTP/1.0 or earlier */
++    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
++      return 0;
++    }
++  }
++
++  return !http_message_needs_eof(parser);
++}
++
++
++const char *
++http_method_str (enum http_method m)
++{
++  return ELEM_AT(method_strings, m, "<unknown>");
++}
++
++
++void
++http_parser_init (http_parser *parser, enum http_parser_type t)
++{
++  void *data = parser->data; /* preserve application data */
++  memset(parser, 0, sizeof(*parser));
++  parser->data = data;
++  parser->type = t;
++  parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
++  parser->http_errno = HPE_OK;
++}
++
++void
++http_parser_settings_init(http_parser_settings *settings)
++{
++  memset(settings, 0, sizeof(*settings));
++}
++
++const char *
++http_errno_name(enum http_errno err) {
++  assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
++  return http_strerror_tab[err].name;
++}
++
++const char *
++http_errno_description(enum http_errno err) {
++  assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
++  return http_strerror_tab[err].description;
++}
++
++static enum http_host_state
++http_parse_host_char(enum http_host_state s, const char ch) {
++  switch(s) {
++    case s_http_userinfo:
++    case s_http_userinfo_start:
++      if (ch == '@') {
++        return s_http_host_start;
++      }
++
++      if (IS_USERINFO_CHAR(ch)) {
++        return s_http_userinfo;
++      }
++      break;
++
++    case s_http_host_start:
++      if (ch == '[') {
++        return s_http_host_v6_start;
++      }
++
++      if (IS_HOST_CHAR(ch)) {
++        return s_http_host;
++      }
++
++      break;
++
++    case s_http_host:
++      if (IS_HOST_CHAR(ch)) {
++        return s_http_host;
++      }
++
++    /* FALLTHROUGH */
++    case s_http_host_v6_end:
++      if (ch == ':') {
++        return s_http_host_port_start;
++      }
++
++      break;
++
++    case s_http_host_v6:
++      if (ch == ']') {
++        return s_http_host_v6_end;
++      }
++
++    /* FALLTHROUGH */
++    case s_http_host_v6_start:
++      if (IS_HEX(ch) || ch == ':' || ch == '.') {
++        return s_http_host_v6;
++      }
++
++      if (s == s_http_host_v6 && ch == '%') {
++        return s_http_host_v6_zone_start;
++      }
++      break;
++
++    case s_http_host_v6_zone:
++      if (ch == ']') {
++        return s_http_host_v6_end;
++      }
++
++    /* FALLTHROUGH */
++    case s_http_host_v6_zone_start:
++      /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
++      if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
++          ch == '~') {
++        return s_http_host_v6_zone;
++      }
++      break;
++
++    case s_http_host_port:
++    case s_http_host_port_start:
++      if (IS_NUM(ch)) {
++        return s_http_host_port;
++      }
++
++      break;
++
++    default:
++      break;
++  }
++  return s_http_host_dead;
++}
++
++static int
++http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
++  enum http_host_state s;
++
++  const char *p;
++  size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
++
++  assert(u->field_set & (1 << UF_HOST));
++
++  u->field_data[UF_HOST].len = 0;
++
++  s = found_at ? s_http_userinfo_start : s_http_host_start;
++
++  for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
++    enum http_host_state new_s = http_parse_host_char(s, *p);
++
++    if (new_s == s_http_host_dead) {
++      return 1;
++    }
++
++    switch(new_s) {
++      case s_http_host:
++        if (s != s_http_host) {
++          u->field_data[UF_HOST].off = p - buf;
++        }
++        u->field_data[UF_HOST].len++;
++        break;
++
++      case s_http_host_v6:
++        if (s != s_http_host_v6) {
++          u->field_data[UF_HOST].off = p - buf;
++        }
++        u->field_data[UF_HOST].len++;
++        break;
++
++      case s_http_host_v6_zone_start:
++      case s_http_host_v6_zone:
++        u->field_data[UF_HOST].len++;
++        break;
++
++      case s_http_host_port:
++        if (s != s_http_host_port) {
++          u->field_data[UF_PORT].off = p - buf;
++          u->field_data[UF_PORT].len = 0;
++          u->field_set |= (1 << UF_PORT);
++        }
++        u->field_data[UF_PORT].len++;
++        break;
++
++      case s_http_userinfo:
++        if (s != s_http_userinfo) {
++          u->field_data[UF_USERINFO].off = p - buf ;
++          u->field_data[UF_USERINFO].len = 0;
++          u->field_set |= (1 << UF_USERINFO);
++        }
++        u->field_data[UF_USERINFO].len++;
++        break;
++
++      default:
++        break;
++    }
++    s = new_s;
++  }
++
++  /* Make sure we don't end somewhere unexpected */
++  switch (s) {
++    case s_http_host_start:
++    case s_http_host_v6_start:
++    case s_http_host_v6:
++    case s_http_host_v6_zone_start:
++    case s_http_host_v6_zone:
++    case s_http_host_port_start:
++    case s_http_userinfo:
++    case s_http_userinfo_start:
++      return 1;
++    default:
++      break;
++  }
++
++  return 0;
++}
++
++void
++http_parser_url_init(struct http_parser_url *u) {
++  memset(u, 0, sizeof(*u));
++}
++
++int
++http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
++                      struct http_parser_url *u)
++{
++  enum state s;
++  const char *p;
++  enum http_parser_url_fields uf, old_uf;
++  int found_at = 0;
++
++  u->port = u->field_set = 0;
++  s = is_connect ? s_req_server_start : s_req_spaces_before_url;
++  old_uf = UF_MAX;
++
++  for (p = buf; p < buf + buflen; p++) {
++    s = parse_url_char(s, *p);
++
++    /* Figure out the next field that we're operating on */
++    switch (s) {
++      case s_dead:
++        return 1;
++
++      /* Skip delimeters */
++      case s_req_schema_slash:
++      case s_req_schema_slash_slash:
++      case s_req_server_start:
++      case s_req_query_string_start:
++      case s_req_fragment_start:
++        continue;
++
++      case s_req_schema:
++        uf = UF_SCHEMA;
++        break;
++
++      case s_req_server_with_at:
++        found_at = 1;
++
++      /* FALLTROUGH */
++      case s_req_server:
++        uf = UF_HOST;
++        break;
++
++      case s_req_path:
++        uf = UF_PATH;
++        break;
++
++      case s_req_query_string:
++        uf = UF_QUERY;
++        break;
++
++      case s_req_fragment:
++        uf = UF_FRAGMENT;
++        break;
++
++      default:
++        assert(!"Unexpected state");
++        return 1;
++    }
++
++    /* Nothing's changed; soldier on */
++    if (uf == old_uf) {
++      u->field_data[uf].len++;
++      continue;
++    }
++
++    u->field_data[uf].off = p - buf;
++    u->field_data[uf].len = 1;
++
++    u->field_set |= (1 << uf);
++    old_uf = uf;
++  }
++
++  /* host must be present if there is a schema */
++  /* parsing http:///toto will fail */
++  if ((u->field_set & (1 << UF_SCHEMA)) &&
++      (u->field_set & (1 << UF_HOST)) == 0) {
++    return 1;
++  }
++
++  if (u->field_set & (1 << UF_HOST)) {
++    if (http_parse_host(buf, u, found_at) != 0) {
++      return 1;
++    }
++  }
++
++  /* CONNECT requests can only contain "hostname:port" */
++  if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
++    return 1;
++  }
++
++  if (u->field_set & (1 << UF_PORT)) {
++    /* Don't bother with endp; we've already validated the string */
++    unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
++
++    /* Ports have a max value of 2^16 */
++    if (v > 0xffff) {
++      return 1;
++    }
++
++    u->port = (uint16_t) v;
++  }
++
++  return 0;
++}
++
++void
++http_parser_pause(http_parser *parser, int paused) {
++  /* Users should only be pausing/unpausing a parser that is not in an error
++   * state. In non-debug builds, there's not much that we can do about this
++   * other than ignore it.
++   */
++  if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
++      HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
++    SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
++  } else {
++    assert(0 && "Attempting to pause parser in error state");
++  }
++}
++
++int
++http_body_is_final(const struct http_parser *parser) {
++    return parser->state == s_message_done;
++}
++
++unsigned long
++http_parser_version(void) {
++  return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
++         HTTP_PARSER_VERSION_MINOR * 0x00100 |
++         HTTP_PARSER_VERSION_PATCH * 0x00001;
++}
+diff --git a/src/responder/secrets/http_parser.h b/src/responder/secrets/http_parser.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..105ae510a8ab57509de2c68bbe1504e39ffb165e
+--- /dev/null
++++ b/src/responder/secrets/http_parser.h
+@@ -0,0 +1,362 @@
++/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++#ifndef http_parser_h
++#define http_parser_h
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Also update SONAME in the Makefile whenever you change these. */
++#define HTTP_PARSER_VERSION_MAJOR 2
++#define HTTP_PARSER_VERSION_MINOR 7
++#define HTTP_PARSER_VERSION_PATCH 0
++
++#include <sys/types.h>
++#if defined(_WIN32) && !defined(__MINGW32__) && \
++  (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
++#include <BaseTsd.h>
++#include <stddef.h>
++typedef __int8 int8_t;
++typedef unsigned __int8 uint8_t;
++typedef __int16 int16_t;
++typedef unsigned __int16 uint16_t;
++typedef __int32 int32_t;
++typedef unsigned __int32 uint32_t;
++typedef __int64 int64_t;
++typedef unsigned __int64 uint64_t;
++#else
++#include <stdint.h>
++#endif
++
++/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
++ * faster
++ */
++#ifndef HTTP_PARSER_STRICT
++# define HTTP_PARSER_STRICT 1
++#endif
++
++/* Maximium header size allowed. If the macro is not defined
++ * before including this header then the default is used. To
++ * change the maximum header size, define the macro in the build
++ * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
++ * the effective limit on the size of the header, define the macro
++ * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
++ */
++#ifndef HTTP_MAX_HEADER_SIZE
++# define HTTP_MAX_HEADER_SIZE (80*1024)
++#endif
++
++typedef struct http_parser http_parser;
++typedef struct http_parser_settings http_parser_settings;
++
++
++/* Callbacks should return non-zero to indicate an error. The parser will
++ * then halt execution.
++ *
++ * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
++ * returning '1' from on_headers_complete will tell the parser that it
++ * should not expect a body. This is used when receiving a response to a
++ * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
++ * chunked' headers that indicate the presence of a body.
++ *
++ * Returning `2` from on_headers_complete will tell parser that it should not
++ * expect neither a body nor any futher responses on this connection. This is
++ * useful for handling responses to a CONNECT request which may not contain
++ * `Upgrade` or `Connection: upgrade` headers.
++ *
++ * http_data_cb does not return data chunks. It will be called arbitrarily
++ * many times for each string. E.G. you might get 10 callbacks for "on_url"
++ * each providing just a few characters more data.
++ */
++typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
++typedef int (*http_cb) (http_parser*);
++
++
++/* Request Methods */
++#define HTTP_METHOD_MAP(XX)         \
++  XX(0,  DELETE,      DELETE)       \
++  XX(1,  GET,         GET)          \
++  XX(2,  HEAD,        HEAD)         \
++  XX(3,  POST,        POST)         \
++  XX(4,  PUT,         PUT)          \
++  /* pathological */                \
++  XX(5,  CONNECT,     CONNECT)      \
++  XX(6,  OPTIONS,     OPTIONS)      \
++  XX(7,  TRACE,       TRACE)        \
++  /* WebDAV */                      \
++  XX(8,  COPY,        COPY)         \
++  XX(9,  LOCK,        LOCK)         \
++  XX(10, MKCOL,       MKCOL)        \
++  XX(11, MOVE,        MOVE)         \
++  XX(12, PROPFIND,    PROPFIND)     \
++  XX(13, PROPPATCH,   PROPPATCH)    \
++  XX(14, SEARCH,      SEARCH)       \
++  XX(15, UNLOCK,      UNLOCK)       \
++  XX(16, BIND,        BIND)         \
++  XX(17, REBIND,      REBIND)       \
++  XX(18, UNBIND,      UNBIND)       \
++  XX(19, ACL,         ACL)          \
++  /* subversion */                  \
++  XX(20, REPORT,      REPORT)       \
++  XX(21, MKACTIVITY,  MKACTIVITY)   \
++  XX(22, CHECKOUT,    CHECKOUT)     \
++  XX(23, MERGE,       MERGE)        \
++  /* upnp */                        \
++  XX(24, MSEARCH,     M-SEARCH)     \
++  XX(25, NOTIFY,      NOTIFY)       \
++  XX(26, SUBSCRIBE,   SUBSCRIBE)    \
++  XX(27, UNSUBSCRIBE, UNSUBSCRIBE)  \
++  /* RFC-5789 */                    \
++  XX(28, PATCH,       PATCH)        \
++  XX(29, PURGE,       PURGE)        \
++  /* CalDAV */                      \
++  XX(30, MKCALENDAR,  MKCALENDAR)   \
++  /* RFC-2068, section 19.6.1.2 */  \
++  XX(31, LINK,        LINK)         \
++  XX(32, UNLINK,      UNLINK)       \
++
++enum http_method
++  {
++#define XX(num, name, string) HTTP_##name = num,
++  HTTP_METHOD_MAP(XX)
++#undef XX
++  };
++
++
++enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
++
++
++/* Flag values for http_parser.flags field */
++enum flags
++  { F_CHUNKED               = 1 << 0
++  , F_CONNECTION_KEEP_ALIVE = 1 << 1
++  , F_CONNECTION_CLOSE      = 1 << 2
++  , F_CONNECTION_UPGRADE    = 1 << 3
++  , F_TRAILING              = 1 << 4
++  , F_UPGRADE               = 1 << 5
++  , F_SKIPBODY              = 1 << 6
++  , F_CONTENTLENGTH         = 1 << 7
++  };
++
++
++/* Map for errno-related constants
++ *
++ * The provided argument should be a macro that takes 2 arguments.
++ */
++#define HTTP_ERRNO_MAP(XX)                                           \
++  /* No error */                                                     \
++  XX(OK, "success")                                                  \
++                                                                     \
++  /* Callback-related errors */                                      \
++  XX(CB_message_begin, "the on_message_begin callback failed")       \
++  XX(CB_url, "the on_url callback failed")                           \
++  XX(CB_header_field, "the on_header_field callback failed")         \
++  XX(CB_header_value, "the on_header_value callback failed")         \
++  XX(CB_headers_complete, "the on_headers_complete callback failed") \
++  XX(CB_body, "the on_body callback failed")                         \
++  XX(CB_message_complete, "the on_message_complete callback failed") \
++  XX(CB_status, "the on_status callback failed")                     \
++  XX(CB_chunk_header, "the on_chunk_header callback failed")         \
++  XX(CB_chunk_complete, "the on_chunk_complete callback failed")     \
++                                                                     \
++  /* Parsing-related errors */                                       \
++  XX(INVALID_EOF_STATE, "stream ended at an unexpected time")        \
++  XX(HEADER_OVERFLOW,                                                \
++     "too many header bytes seen; overflow detected")                \
++  XX(CLOSED_CONNECTION,                                              \
++     "data received after completed connection: close message")      \
++  XX(INVALID_VERSION, "invalid HTTP version")                        \
++  XX(INVALID_STATUS, "invalid HTTP status code")                     \
++  XX(INVALID_METHOD, "invalid HTTP method")                          \
++  XX(INVALID_URL, "invalid URL")                                     \
++  XX(INVALID_HOST, "invalid host")                                   \
++  XX(INVALID_PORT, "invalid port")                                   \
++  XX(INVALID_PATH, "invalid path")                                   \
++  XX(INVALID_QUERY_STRING, "invalid query string")                   \
++  XX(INVALID_FRAGMENT, "invalid fragment")                           \
++  XX(LF_EXPECTED, "LF character expected")                           \
++  XX(INVALID_HEADER_TOKEN, "invalid character in header")            \
++  XX(INVALID_CONTENT_LENGTH,                                         \
++     "invalid character in content-length header")                   \
++  XX(UNEXPECTED_CONTENT_LENGTH,                                      \
++     "unexpected content-length header")                             \
++  XX(INVALID_CHUNK_SIZE,                                             \
++     "invalid character in chunk size header")                       \
++  XX(INVALID_CONSTANT, "invalid constant string")                    \
++  XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
++  XX(STRICT, "strict mode assertion failed")                         \
++  XX(PAUSED, "parser is paused")                                     \
++  XX(UNKNOWN, "an unknown error occurred")
++
++
++/* Define HPE_* values for each errno value above */
++#define HTTP_ERRNO_GEN(n, s) HPE_##n,
++enum http_errno {
++  HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
++};
++#undef HTTP_ERRNO_GEN
++
++
++/* Get an http_errno value from an http_parser */
++#define HTTP_PARSER_ERRNO(p)            ((enum http_errno) (p)->http_errno)
++
++
++struct http_parser {
++  /** PRIVATE **/
++  unsigned int type : 2;         /* enum http_parser_type */
++  unsigned int flags : 8;        /* F_* values from 'flags' enum; semi-public */
++  unsigned int state : 7;        /* enum state from http_parser.c */
++  unsigned int header_state : 7; /* enum header_state from http_parser.c */
++  unsigned int index : 7;        /* index into current matcher */
++  unsigned int lenient_http_headers : 1;
++
++  uint32_t nread;          /* # bytes read in various scenarios */
++  uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
++
++  /** READ-ONLY **/
++  unsigned short http_major;
++  unsigned short http_minor;
++  unsigned int status_code : 16; /* responses only */
++  unsigned int method : 8;       /* requests only */
++  unsigned int http_errno : 7;
++
++  /* 1 = Upgrade header was present and the parser has exited because of that.
++   * 0 = No upgrade header present.
++   * Should be checked when http_parser_execute() returns in addition to
++   * error checking.
++   */
++  unsigned int upgrade : 1;
++
++  /** PUBLIC **/
++  void *data; /* A pointer to get hook to the "connection" or "socket" object */
++};
++
++
++struct http_parser_settings {
++  http_cb      on_message_begin;
++  http_data_cb on_url;
++  http_data_cb on_status;
++  http_data_cb on_header_field;
++  http_data_cb on_header_value;
++  http_cb      on_headers_complete;
++  http_data_cb on_body;
++  http_cb      on_message_complete;
++  /* When on_chunk_header is called, the current chunk length is stored
++   * in parser->content_length.
++   */
++  http_cb      on_chunk_header;
++  http_cb      on_chunk_complete;
++};
++
++
++enum http_parser_url_fields
++  { UF_SCHEMA           = 0
++  , UF_HOST             = 1
++  , UF_PORT             = 2
++  , UF_PATH             = 3
++  , UF_QUERY            = 4
++  , UF_FRAGMENT         = 5
++  , UF_USERINFO         = 6
++  , UF_MAX              = 7
++  };
++
++
++/* Result structure for http_parser_parse_url().
++ *
++ * Callers should index into field_data[] with UF_* values iff field_set
++ * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
++ * because we probably have padding left over), we convert any port to
++ * a uint16_t.
++ */
++struct http_parser_url {
++  uint16_t field_set;           /* Bitmask of (1 << UF_*) values */
++  uint16_t port;                /* Converted UF_PORT string */
++
++  struct {
++    uint16_t off;               /* Offset into buffer in which field starts */
++    uint16_t len;               /* Length of run in buffer */
++  } field_data[UF_MAX];
++};
++
++
++/* Returns the library version. Bits 16-23 contain the major version number,
++ * bits 8-15 the minor version number and bits 0-7 the patch level.
++ * Usage example:
++ *
++ *   unsigned long version = http_parser_version();
++ *   unsigned major = (version >> 16) & 255;
++ *   unsigned minor = (version >> 8) & 255;
++ *   unsigned patch = version & 255;
++ *   printf("http_parser v%u.%u.%u\n", major, minor, patch);
++ */
++unsigned long http_parser_version(void);
++
++void http_parser_init(http_parser *parser, enum http_parser_type type);
++
++
++/* Initialize http_parser_settings members to 0
++ */
++void http_parser_settings_init(http_parser_settings *settings);
++
++
++/* Executes the parser. Returns number of parsed bytes. Sets
++ * `parser->http_errno` on error. */
++size_t http_parser_execute(http_parser *parser,
++                           const http_parser_settings *settings,
++                           const char *data,
++                           size_t len);
++
++
++/* If http_should_keep_alive() in the on_headers_complete or
++ * on_message_complete callback returns 0, then this should be
++ * the last message on the connection.
++ * If you are the server, respond with the "Connection: close" header.
++ * If you are the client, close the connection.
++ */
++int http_should_keep_alive(const http_parser *parser);
++
++/* Returns a string version of the HTTP method. */
++const char *http_method_str(enum http_method m);
++
++/* Return a string name of the given error */
++const char *http_errno_name(enum http_errno err);
++
++/* Return a string description of the given error */
++const char *http_errno_description(enum http_errno err);
++
++/* Initialize all http_parser_url members to 0 */
++void http_parser_url_init(struct http_parser_url *u);
++
++/* Parse a URL; return nonzero on failure */
++int http_parser_parse_url(const char *buf, size_t buflen,
++                          int is_connect,
++                          struct http_parser_url *u);
++
++/* Pause or un-pause the parser; a nonzero value pauses */
++void http_parser_pause(http_parser *parser, int paused);
++
++/* Checks if this is the final chunk of the body. */
++int http_body_is_final(const http_parser *parser);
++
++#ifdef __cplusplus
++}
++#endif
++#endif
+diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h
+index c3b663996e138bbb14f1ab74db75398ffd0bd5c7..47ed7642cf8da5ecfc8f995199746596a12b3e1d 100644
+--- a/src/responder/secrets/secsrv_private.h
++++ b/src/responder/secrets/secsrv_private.h
+@@ -25,7 +25,7 @@
+ #include "config.h"
+ #include "responder/common/responder.h"
+ #include "responder/secrets/secsrv.h"
+-#include <http_parser.h>
++#include "http_parser.h"
+ 
+ struct sec_kvp {
+     char *name;
+-- 
+2.4.11
+
diff --git a/SOURCES/0010-LDAP-Add-sdap_lookup_type-enum.patch b/SOURCES/0010-LDAP-Add-sdap_lookup_type-enum.patch
deleted file mode 100644
index 9481f75..0000000
--- a/SOURCES/0010-LDAP-Add-sdap_lookup_type-enum.patch
+++ /dev/null
@@ -1,395 +0,0 @@
-From 179ac94a4910150b846ff1c959e766c5a31274cf Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 8 May 2015 14:49:09 +0200
-Subject: [PATCH 10/13] LDAP: Add sdap_lookup_type enum
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Change the boolan parameter of sdap_get_users_send and sdap_get_groups_send
-to a tri-state that controls whether we expect only a single entry
-(ie don't use the paging control), multiple entries with a search limit
-(wildcard request) or multiple entries with no limit (enumeration).
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/providers/ldap/ldap_auth.c         |  2 +-
- src/providers/ldap/ldap_id.c           | 16 +++++++-------
- src/providers/ldap/sdap_async.h        | 12 +++++++---
- src/providers/ldap/sdap_async_enum.c   |  4 ++--
- src/providers/ldap/sdap_async_groups.c | 40 ++++++++++++++++++++++++----------
- src/providers/ldap/sdap_async_users.c  | 32 ++++++++++++++++++++-------
- 6 files changed, 73 insertions(+), 33 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index 81717942613b4a91ebab668ba2ecfe13caab38be..217e80fd07abc41f2594d19397783683d44600cd 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -418,7 +418,7 @@ static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
-                                    sh, attrs, filter,
-                                    dp_opt_get_int(opts->basic,
-                                                   SDAP_SEARCH_TIMEOUT),
--                                   false);
-+                                   SDAP_LOOKUP_SINGLE);
-     if (!subreq) {
-         ret = ENOMEM;
-         goto done;
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 61f09fc41d3210af5044f5338dd90db67e0123a7..73840d2885ed15a7a9dae2e9175d8361c8fdfe7d 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -396,12 +396,12 @@ 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;
--    bool multiple_results;
-+    enum sdap_entry_lookup_type lookup_type;
- 
-     if (state->filter_type == BE_FILTER_WILDCARD) {
--        multiple_results = true;
-+        lookup_type = SDAP_LOOKUP_WILDCARD;
-     } else {
--        multiple_results = false;
-+        lookup_type = SDAP_LOOKUP_SINGLE;
-     }
- 
-     subreq = sdap_get_users_send(state, state->ev,
-@@ -412,7 +412,7 @@ static void users_get_search(struct tevent_req *req)
-                                  state->attrs, state->filter,
-                                  dp_opt_get_int(state->ctx->opts->basic,
-                                                 SDAP_SEARCH_TIMEOUT),
--                                 multiple_results);
-+                                 lookup_type);
-     if (!subreq) {
-         tevent_req_error(req, ENOMEM);
-         return;
-@@ -901,12 +901,12 @@ 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;
--    bool multiple_results;
-+    enum sdap_entry_lookup_type lookup_type;
- 
-     if (state->filter_type == BE_FILTER_WILDCARD) {
--        multiple_results = true;
-+        lookup_type = SDAP_LOOKUP_WILDCARD;
-     } else {
--        multiple_results = false;
-+        lookup_type = SDAP_LOOKUP_SINGLE;
-     }
- 
-     subreq = sdap_get_groups_send(state, state->ev,
-@@ -916,7 +916,7 @@ static void groups_get_search(struct tevent_req *req)
-                                   state->attrs, state->filter,
-                                   dp_opt_get_int(state->ctx->opts->basic,
-                                                  SDAP_SEARCH_TIMEOUT),
--                                  multiple_results,
-+                                  lookup_type,
-                                   state->no_members);
-     if (!subreq) {
-         tevent_req_error(req, ENOMEM);
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index b23dfc313905d01caedd1eace6bcb525481b9ebe..09bc0d65407253f93514b30877850cc38009c625 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -59,6 +59,12 @@ errno_t sdap_connect_host_recv(TALLOC_CTX *mem_ctx,
-                                struct sdap_handle **_sh);
- 
- /* Search users in LDAP, return them as attrs */
-+enum sdap_entry_lookup_type {
-+    SDAP_LOOKUP_SINGLE,         /* Direct single-user/group lookup */
-+    SDAP_LOOKUP_WILDCARD,       /* Multiple entries with a limit */
-+    SDAP_LOOKUP_ENUMERATE,      /* Fetch all entries from the server */
-+};
-+
- struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-                                          struct sss_domain_info *dom,
-@@ -68,7 +74,7 @@ struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
-                                          const char **attrs,
-                                          const char *filter,
-                                          int timeout,
--                                         bool enumeration);
-+                                         enum sdap_entry_lookup_type lookup_type);
- int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req,
-                           char **higher_usn, struct sysdb_attrs ***users,
-                           size_t *count);
-@@ -84,7 +90,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
-                                        const char **attrs,
-                                        const char *filter,
-                                        int timeout,
--                                       bool enumeration);
-+                                       enum sdap_entry_lookup_type lookup_type);
- int sdap_get_users_recv(struct tevent_req *req,
-                         TALLOC_CTX *mem_ctx, char **timestamp);
- 
-@@ -96,7 +102,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
-                                        const char **attrs,
-                                        const char *filter,
-                                        int timeout,
--                                       bool enumeration,
-+                                       enum sdap_entry_lookup_type lookup_type,
-                                        bool no_members);
- int sdap_get_groups_recv(struct tevent_req *req,
-                          TALLOC_CTX *mem_ctx, char **timestamp);
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index 35afc55f809669a44aa2beda7d87dfe62d6ec10b..f22276c3ce6f839b765bbc1602fafb010cc37d89 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -635,7 +635,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
-                                  state->attrs, state->filter,
-                                  dp_opt_get_int(state->ctx->opts->basic,
-                                                 SDAP_ENUM_SEARCH_TIMEOUT),
--                                 true);
-+                                 SDAP_LOOKUP_ENUMERATE);
-     if (!subreq) {
-         ret = ENOMEM;
-         goto fail;
-@@ -811,7 +811,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
-                                   state->attrs, state->filter,
-                                   dp_opt_get_int(state->ctx->opts->basic,
-                                                  SDAP_ENUM_SEARCH_TIMEOUT),
--                                  true, false);
-+                                  SDAP_LOOKUP_ENUMERATE, false);
-     if (!subreq) {
-         ret = ENOMEM;
-         goto fail;
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index e785307e60d0df5be96a5b2de2c07baabaf1e371..ad0354df1fce9011c68cabb6049e7feee92a44c0 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -1721,7 +1721,7 @@ struct sdap_get_groups_state {
-     const char *base_filter;
-     char *filter;
-     int timeout;
--    bool enumeration;
-+    enum sdap_entry_lookup_type lookup_type;
-     bool no_members;
- 
-     char *higher_usn;
-@@ -1752,7 +1752,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
-                                        const char **attrs,
-                                        const char *filter,
-                                        int timeout,
--                                       bool enumeration,
-+                                       enum sdap_entry_lookup_type lookup_type,
-                                        bool no_members)
- {
-     errno_t ret;
-@@ -1775,7 +1775,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
-     state->groups =  NULL;
-     state->count = 0;
-     state->timeout = timeout;
--    state->enumeration = enumeration;
-+    state->lookup_type = lookup_type;
-     state->no_members = no_members;
-     state->base_filter = filter;
-     state->base_iter = 0;
-@@ -1855,6 +1855,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
- {
-     struct tevent_req *subreq;
-     struct sdap_get_groups_state *state;
-+    bool need_paging = false;
- 
-     state = tevent_req_data(req, struct sdap_get_groups_state);
- 
-@@ -1870,6 +1871,19 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-           "Searching for groups with base [%s]\n",
-            state->search_bases[state->base_iter]->basedn);
- 
-+    switch (state->lookup_type) {
-+    case SDAP_LOOKUP_SINGLE:
-+        need_paging = false;
-+        break;
-+    /* Only requests that can return multiple entries should require
-+     * the paging control
-+     */
-+    case SDAP_LOOKUP_WILDCARD:
-+    case SDAP_LOOKUP_ENUMERATE:
-+        need_paging = true;
-+        break;
-+    }
-+
-     subreq = sdap_get_and_parse_generic_send(
-             state, state->ev, state->opts,
-             state->ldap_sh != NULL ? state->ldap_sh : state->sh,
-@@ -1878,7 +1892,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-             state->filter, state->attrs,
-             state->opts->group_map, SDAP_OPTS_GROUP,
-             0, NULL, NULL, 0, state->timeout,
--            state->enumeration); /* If we're enumerating, we need paging */
-+            need_paging);
-     if (!subreq) {
-         return ENOMEM;
-     }
-@@ -1914,14 +1928,17 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-     DEBUG(SSSDBG_TRACE_FUNC,
-           "Search for groups, returned %zu results.\n", count);
- 
--    if (!state->enumeration && count > 1) {
-+    if (state->lookup_type == SDAP_LOOKUP_SINGLE && count > 1) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
-               "Individual group search returned multiple results\n");
-         tevent_req_error(req, EINVAL);
-         return;
-     }
- 
--    if (state->enumeration || count == 0) {
-+    if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
-+            state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
-+        count == 0) {
-+        /* No users found in this search or looking up multiple entries */
-         next_base = true;
-     }
- 
-@@ -2003,7 +2020,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-      * LDAP_MATCHING_RULE_IN_CHAIN available in
-      * AD 2008 and later
-      */
--    if (!state->enumeration) {
-+    if (state->lookup_type == SDAP_LOOKUP_SINGLE) {
-         if ((state->opts->schema_type != SDAP_SCHEMA_RFC2307)
-                 && (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)
-                 && !dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
-@@ -2026,7 +2043,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-     /* If we're using LDAP_MATCHING_RULE_IN_CHAIN, start a subreq to
-      * retrieve the members so we can save them in a single step.
-      */
--    if (!state->enumeration
-+    if (state->lookup_type == SDAP_LOOKUP_SINGLE
-             && (state->opts->schema_type != SDAP_SCHEMA_RFC2307)
-             && state->opts->support_matching_rule
-             && dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
-@@ -2050,7 +2067,8 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-         return;
-     }
- 
--    if (state->enumeration
-+    if ((state->lookup_type == SDAP_LOOKUP_ENUMERATE
-+                || state->lookup_type == SDAP_LOOKUP_WILDCARD)
-             && state->opts->schema_type != SDAP_SCHEMA_RFC2307
-             && dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0) {
-         DEBUG(SSSDBG_TRACE_ALL, "Saving groups without members first "
-@@ -2069,7 +2087,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-         subreq = sdap_process_group_send(state, state->ev, state->dom,
-                                          state->sysdb, state->opts,
-                                          state->sh, state->groups[i],
--                                         state->enumeration);
-+                                         state->lookup_type == SDAP_LOOKUP_ENUMERATE);
- 
-         if (!subreq) {
-             tevent_req_error(req, ENOMEM);
-@@ -2116,7 +2134,7 @@ static void sdap_get_groups_done(struct tevent_req *subreq)
-         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
-                                state->groups, state->count,
-                                !state->dom->ignore_group_members, NULL,
--                               !state->enumeration,
-+                               state->lookup_type == SDAP_LOOKUP_SINGLE,
-                                &state->higher_usn);
-         if (ret) {
-             DEBUG(SSSDBG_OP_FAILURE, "Failed to store groups.\n");
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index 216b49477bf21481265444c5c03df0aac7ee84e4..f66ae2604c867d4a5e8d223081ece9f1e474cf73 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -606,7 +606,7 @@ struct sdap_search_user_state {
-     const char *base_filter;
-     const char *filter;
-     int timeout;
--    bool enumeration;
-+    enum sdap_entry_lookup_type lookup_type;
- 
-     char *higher_usn;
-     struct sysdb_attrs **users;
-@@ -628,7 +628,7 @@ struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
-                                          const char **attrs,
-                                          const char *filter,
-                                          int timeout,
--                                         bool enumeration)
-+                                         enum sdap_entry_lookup_type lookup_type)
- {
-     errno_t ret;
-     struct tevent_req *req;
-@@ -649,7 +649,7 @@ struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
-     state->base_filter = filter;
-     state->base_iter = 0;
-     state->search_bases = search_bases;
--    state->enumeration = enumeration;
-+    state->lookup_type = lookup_type;
- 
-     if (!state->search_bases) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -673,6 +673,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
- {
-     struct tevent_req *subreq;
-     struct sdap_search_user_state *state;
-+    bool need_paging = false;
- 
-     state = tevent_req_data(req, struct sdap_search_user_state);
- 
-@@ -688,6 +689,19 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
-           "Searching for users with base [%s]\n",
-            state->search_bases[state->base_iter]->basedn);
- 
-+    switch (state->lookup_type) {
-+    case SDAP_LOOKUP_SINGLE:
-+        need_paging = false;
-+        break;
-+    /* Only requests that can return multiple entries should require
-+     * the paging control
-+     */
-+    case SDAP_LOOKUP_WILDCARD:
-+    case SDAP_LOOKUP_ENUMERATE:
-+        need_paging = true;
-+        break;
-+    }
-+
-     subreq = sdap_get_and_parse_generic_send(
-             state, state->ev, state->opts, state->sh,
-             state->search_bases[state->base_iter]->basedn,
-@@ -695,7 +709,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
-             state->filter, state->attrs,
-             state->opts->user_map, state->opts->user_map_cnt,
-             0, NULL, NULL, 0, state->timeout,
--            state->enumeration); /* If we're enumerating, we need paging */
-+            need_paging);
-     if (subreq == NULL) {
-         return ENOMEM;
-     }
-@@ -726,8 +740,10 @@ static void sdap_search_user_process(struct tevent_req *subreq)
-     DEBUG(SSSDBG_TRACE_FUNC,
-           "Search for users, returned %zu results.\n", count);
- 
--    if (state->enumeration || count == 0) {
--        /* No users found in this search or enumerating */
-+    if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
-+            state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
-+        count == 0) {
-+        /* No users found in this search or looking up multiple entries */
-         next_base = true;
-     }
- 
-@@ -827,7 +843,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
-                                        const char **attrs,
-                                        const char *filter,
-                                        int timeout,
--                                       bool enumeration)
-+                                       enum sdap_entry_lookup_type lookup_type)
- {
-     errno_t ret;
-     struct tevent_req *req;
-@@ -842,7 +858,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
-     state->dom = dom;
- 
-     subreq = sdap_search_user_send(state, ev, dom, opts, search_bases,
--                                   sh, attrs, filter, timeout, enumeration);
-+                                   sh, attrs, filter, timeout, lookup_type);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto done;
--- 
-2.4.3
-
diff --git a/SOURCES/0010-MAN-Update-description-of-sssctl.patch b/SOURCES/0010-MAN-Update-description-of-sssctl.patch
new file mode 100644
index 0000000..4e5482c
--- /dev/null
+++ b/SOURCES/0010-MAN-Update-description-of-sssctl.patch
@@ -0,0 +1,48 @@
+From 41a8e0f463188dd6a78d44908a8601c7c7576b59 Mon Sep 17 00:00:00 2001
+From: Dan Lavu <dlavu@redhat.com>
+Date: Mon, 11 Jul 2016 12:27:34 +0200
+Subject: [PATCH 10/14] MAN: Update description of sssctl
+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 8ad1883c79fc1e356bbd2d3e4badd4af9955b9fc)
+---
+ src/man/sssctl.8.xml | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/src/man/sssctl.8.xml b/src/man/sssctl.8.xml
+index 721d0a2f7558b105c22135388757f92270265c4a..cbb632b68b145680ab94523b90180c5f76d69eb9 100644
+--- a/src/man/sssctl.8.xml
++++ b/src/man/sssctl.8.xml
+@@ -29,12 +29,11 @@
+     <refsect1 id='description'>
+         <title>DESCRIPTION</title>
+         <para>
+-            <command>sssctl</command> provides simple and unified way to obtain
+-            information about SSSD status such as active server or list of
+-            auto-discovered servers and domains or information about cached
+-            objects. It also provides tools to manage SSSD data files during
+-            troubleshooting such as a safe way to remove cache files or fetching
+-            all SSSD log files and more.
++            <command>sssctl</command> provides a simple and unified way
++            to obtain information about SSSD status, such as active server,
++            auto-discovered servers, domains and cached objects. In addition,
++            it can manage SSSD data files for troubleshooting in such a way
++            that is safe to manipulate while SSSD is running.
+         </para>
+     </refsect1>
+ 
+@@ -42,7 +41,7 @@
+         <title>AVAILABLE COMMANDS</title>
+         <para>
+             To list all available commands run <command>sssctl</command>
+-            without any parameter. To print help for selected command
++            without any parameters. To print help for selected command
+             run <command>sssctl COMMAND --help</command>.
+         </para>
+     </refsect1>
+-- 
+2.4.11
+
diff --git a/SOURCES/0011-LDAP-Add-the-wildcard_limit-option.patch b/SOURCES/0011-LDAP-Add-the-wildcard_limit-option.patch
deleted file mode 100644
index c9145af..0000000
--- a/SOURCES/0011-LDAP-Add-the-wildcard_limit-option.patch
+++ /dev/null
@@ -1,237 +0,0 @@
-From 4e795d8ff3a1d1f5cd5a7dddaf364909c60d9191 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 17 Jun 2015 16:13:51 +0200
-Subject: [PATCH 11/13] LDAP: Add the wildcard_limit option
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Adds a new wildcard_limit option that is set by default to 1000 (one
-page). This option limits the number of entries that can by default be
-returned by a wildcard search.
-
-Reviewed-by: Pavel Březina <pbrezina@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/config/etc/sssd.api.d/sssd-ldap.conf |  1 +
- src/man/sssd-ldap.5.xml                  | 17 +++++++++++++++++
- src/providers/ad/ad_opts.h               |  1 +
- src/providers/ipa/ipa_opts.h             |  1 +
- src/providers/ldap/ldap_opts.h           |  1 +
- src/providers/ldap/sdap.h                |  1 +
- src/providers/ldap/sdap_async_groups.c   |  8 +++++++-
- src/providers/ldap/sdap_async_users.c    |  8 +++++++-
- 11 files changed, 39 insertions(+), 2 deletions(-)
-
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index 4d45e42af4fa32717caa69cc621834cdffc27431..4b519eddd04cde83c209f5a1940832cc7f41c736 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -355,6 +355,7 @@ option_strings = {
-     'ldap_min_id' : _('Set lower boundary for allowed IDs from the LDAP server'),
-     'ldap_max_id' : _('Set upper boundary for allowed IDs from the LDAP server'),
-     'ldap_pwdlockout_dn' : _('DN for ppolicy queries'),
-+    'wildcard_limit' : _('How many maximum entries to fetch during a wildcard request'),
- 
-     # [provider/ldap/auth]
-     'ldap_pwd_policy' : _('Policy to evaluate the password expiration'),
-diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
-index faab3a51e54d6d498392021a8945501120870f70..b636d93108ef0a3831970d7827895c14b0f3571c 100644
---- a/src/config/etc/sssd.api.d/sssd-ad.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
-@@ -56,6 +56,7 @@ 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
-+wildcard_limit = int, 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 cfcc00f6f7ca768df861e8cf7face065f90e9e83..ab712fe55cdac6d247a085aeca5cc82d65966623 100644
---- a/src/config/etc/sssd.api.d/sssd-ipa.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
-@@ -52,6 +52,7 @@ 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
-+wildcard_limit = int, None, false
- 
- [provider/ipa/id]
- ldap_search_timeout = int, 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 c10290217b1b133792b893d9b80e2599969838a6..8fd45fd4093714f458161eb352157c845d926f06 100644
---- a/src/config/etc/sssd.api.d/sssd-ldap.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
-@@ -37,6 +37,7 @@ ldap_sasl_minssf = int, None, false
- ldap_connection_expire_timeout = int, None, false
- ldap_disable_paging = bool, None, false
- ldap_disable_range_retrieval = bool, None, false
-+wildcard_limit = int, None, false
- 
- [provider/ldap/id]
- ldap_search_timeout = int, None, false
-diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
-index f14090843fd32141ad4f491b69868aa7b2412301..9ac175f8d4a8aa01ca2434b800ebae1be88575f5 100644
---- a/src/man/sssd-ldap.5.xml
-+++ b/src/man/sssd-ldap.5.xml
-@@ -2135,6 +2135,23 @@ ldap_access_filter = (employeeType=admin)
-                     </listitem>
-                 </varlistentry>
- 
-+                <varlistentry>
-+                    <term>wildcart_limit (integer)</term>
-+                    <listitem>
-+                        <para>
-+                            Specifies an upper limit on the number of entries
-+                            that are downloaded during a wildcard lookup.
-+                        </para>
-+                        <para>
-+                            At the moment, only the InfoPipe responder supports
-+                            wildcard lookups.
-+                        </para>
-+                        <para>
-+                            Default: 1000 (often the size of one page)
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-             </variablelist>
-         </para>
-     </refsect1>
-diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
-index cb4c05d846d9abe5eedb28013ad13fff6476d431..d685edcb44c771b0afc7a232a82c21fc9d1c89f9 100644
---- a/src/providers/ad/ad_opts.h
-+++ b/src/providers/ad/ad_opts.h
-@@ -146,6 +146,7 @@ struct dp_option ad_def_ldap_opts[] = {
-     { "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
-     { "ldap_max_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
-     { "ldap_pwdlockout_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-+    { "wildcard_limit", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER},
-     DP_OPTION_TERMINATOR
- };
- 
-diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
-index 253c0715355536cc181c57beed5326a77e87e464..9576228d1bf3424c8867bda058b59c3ca6b2216b 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -157,6 +157,7 @@ struct dp_option ipa_def_ldap_opts[] = {
-     { "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
-     { "ldap_max_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
-     { "ldap_pwdlockout_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-+    { "wildcard_limit", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER},
-     DP_OPTION_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
-index c1b9bf688ef0a92046195c13a11d2c17b2419d67..9f58db5bd9eef1391e97c1890cbff94c2a5406d6 100644
---- a/src/providers/ldap/ldap_opts.h
-+++ b/src/providers/ldap/ldap_opts.h
-@@ -122,6 +122,7 @@ struct dp_option default_basic_opts[] = {
-     { "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
-     { "ldap_max_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
-     { "ldap_pwdlockout_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-+    { "wildcard_limit", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER},
-     DP_OPTION_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index d9b2d18637bdb3e7823af9d1de2c042c8134780f..444502bf7159edcf4cebe530cce8b216c737ec30 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -231,6 +231,7 @@ enum sdap_basic_opt {
-     SDAP_MIN_ID,
-     SDAP_MAX_ID,
-     SDAP_PWDLOCKOUT_DN,
-+    SDAP_WILDCARD_LIMIT,
- 
-     SDAP_OPTS_BASIC /* opts counter */
- };
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index ad0354df1fce9011c68cabb6049e7feee92a44c0..525c6fa09553d8c0232ce2317751184f83632d86 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -1856,6 +1856,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-     struct tevent_req *subreq;
-     struct sdap_get_groups_state *state;
-     bool need_paging = false;
-+    int sizelimit = 0;
- 
-     state = tevent_req_data(req, struct sdap_get_groups_state);
- 
-@@ -1873,13 +1874,18 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
- 
-     switch (state->lookup_type) {
-     case SDAP_LOOKUP_SINGLE:
-+        sizelimit = 1;
-         need_paging = false;
-         break;
-     /* Only requests that can return multiple entries should require
-      * the paging control
-      */
-     case SDAP_LOOKUP_WILDCARD:
-+        sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
-+        need_paging = true;
-+        break;
-     case SDAP_LOOKUP_ENUMERATE:
-+        sizelimit = 0;  /* unlimited */
-         need_paging = true;
-         break;
-     }
-@@ -1891,7 +1897,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-             state->search_bases[state->base_iter]->scope,
-             state->filter, state->attrs,
-             state->opts->group_map, SDAP_OPTS_GROUP,
--            0, NULL, NULL, 0, state->timeout,
-+            0, NULL, NULL, sizelimit, state->timeout,
-             need_paging);
-     if (!subreq) {
-         return ENOMEM;
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index f66ae2604c867d4a5e8d223081ece9f1e474cf73..a864a8b2187de7972aa963b355856e97f7c692a9 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -674,6 +674,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
-     struct tevent_req *subreq;
-     struct sdap_search_user_state *state;
-     bool need_paging = false;
-+    int sizelimit = 0;
- 
-     state = tevent_req_data(req, struct sdap_search_user_state);
- 
-@@ -691,13 +692,18 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
- 
-     switch (state->lookup_type) {
-     case SDAP_LOOKUP_SINGLE:
-+        sizelimit = 1;
-         need_paging = false;
-         break;
-     /* Only requests that can return multiple entries should require
-      * the paging control
-      */
-     case SDAP_LOOKUP_WILDCARD:
-+        sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
-+        need_paging = true;
-+        break;
-     case SDAP_LOOKUP_ENUMERATE:
-+        sizelimit = 0;  /* unlimited */
-         need_paging = true;
-         break;
-     }
-@@ -708,7 +714,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
-             state->search_bases[state->base_iter]->scope,
-             state->filter, state->attrs,
-             state->opts->user_map, state->opts->user_map_cnt,
--            0, NULL, NULL, 0, state->timeout,
-+            0, NULL, NULL, sizelimit, state->timeout,
-             need_paging);
-     if (subreq == NULL) {
-         return ENOMEM;
--- 
-2.4.3
-
diff --git a/SOURCES/0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch b/SOURCES/0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch
new file mode 100644
index 0000000..eafe318
--- /dev/null
+++ b/SOURCES/0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch
@@ -0,0 +1,101 @@
+From 721f83fa5661c861674c17edbb309bb9ade15892 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 4 Jul 2016 14:08:46 +0200
+Subject: [PATCH 11/14] nss-srv-tests: Fix prototype of wrapped ncache
+ functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The argument ttl was recently removed from negative cache functions
+(sss_ncache_check_user, sss_ncache_check_uid, sss_ncache_check_sid,
+sss_ncache_check_cert) but it was not removed from wrapped versions
+in nss-srv-tests. It caused a crash on machine with big endian
+and when configure wih --coverage.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 35567de112cd5d82acb582cbdb44c8652bbdfda1)
+---
+ src/tests/cmocka/test_nss_srv.c | 28 ++++++++++++----------------
+ 1 file changed, 12 insertions(+), 16 deletions(-)
+
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index 5e0398f20b9906df39371826e50a9c78675dfa74..4137e9151be561a57a8f2e674f385ecb37119255 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -151,60 +151,56 @@ int __wrap_sss_cmd_send_empty(struct cli_ctx *cctx, TALLOC_CTX *freectx)
+ }
+ 
+ /* Intercept negative cache lookups */
+-int __real_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
++int __real_sss_ncache_check_user(struct sss_nc_ctx *ctx,
+                                  struct sss_domain_info *dom, const char *name);
+ 
+-int __wrap_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
++int __wrap_sss_ncache_check_user(struct sss_nc_ctx *ctx,
+                                  struct sss_domain_info *dom, const char *name)
+ {
+     int ret;
+ 
+-    ret = __real_sss_ncache_check_user(ctx, ttl, dom, name);
++    ret = __real_sss_ncache_check_user(ctx, dom, name);
+     if (ret == EEXIST) {
+         nss_test_ctx->ncache_hits++;
+     }
+     return ret;
+ }
+ 
+-int __real_sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl,
++int __real_sss_ncache_check_uid(struct sss_nc_ctx *ctx,
+                                 struct sss_domain_info *dom, uid_t uid);
+ 
+-int __wrap_sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl,
++int __wrap_sss_ncache_check_uid(struct sss_nc_ctx *ctx,
+                                 struct sss_domain_info *dom, uid_t uid)
+ {
+     int ret;
+ 
+-    ret = __real_sss_ncache_check_uid(ctx, ttl, dom, uid);
++    ret = __real_sss_ncache_check_uid(ctx, dom, uid);
+     if (ret == EEXIST) {
+         nss_test_ctx->ncache_hits++;
+     }
+     return ret;
+ }
+ 
+-int __real_sss_ncache_check_sid(struct sss_nc_ctx *ctx,
+-                                int ttl, const char *sid);
++int __real_sss_ncache_check_sid(struct sss_nc_ctx *ctx, const char *sid);
+ 
+-int __wrap_sss_ncache_check_sid(struct sss_nc_ctx *ctx,
+-                                int ttl, const char *sid)
++int __wrap_sss_ncache_check_sid(struct sss_nc_ctx *ctx, const char *sid)
+ {
+     int ret;
+ 
+-    ret = __real_sss_ncache_check_sid(ctx, ttl, sid);
++    ret = __real_sss_ncache_check_sid(ctx, sid);
+     if (ret == EEXIST) {
+         nss_test_ctx->ncache_hits++;
+     }
+     return ret;
+ }
+ 
+-int __real_sss_ncache_check_cert(struct sss_nc_ctx *ctx,
+-                                 int ttl, const char *cert);
++int __real_sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert);
+ 
+-int __wrap_sss_ncache_check_cert(struct sss_nc_ctx *ctx,
+-                                 int ttl, const char *cert)
++int __wrap_sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert)
+ {
+     int ret;
+ 
+-    ret = __real_sss_ncache_check_cert(ctx, ttl, cert);
++    ret = __real_sss_ncache_check_cert(ctx, cert);
+     if (ret == EEXIST) {
+         nss_test_ctx->ncache_hits++;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0012-IFP-Add-wildcard-requests.patch b/SOURCES/0012-IFP-Add-wildcard-requests.patch
deleted file mode 100644
index d44b2a8..0000000
--- a/SOURCES/0012-IFP-Add-wildcard-requests.patch
+++ /dev/null
@@ -1,663 +0,0 @@
-From fe9a0097970d12ff261b7417f9e57db95957ab24 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 17 Jun 2015 13:39:43 +0200
-Subject: [PATCH 12/13] IFP: Add wildcard requests
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-    https://fedorahosted.org/sssd/ticket/2553
-
-Can be used as:
-
-dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
-        /org/freedesktop/sssd/infopipe/Users \
-        org.freedesktop.sssd.infopipe.Users.ListByName \
-        string:r\* uint32:10
-
-dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
-        /org/freedesktop/sssd/infopipe/Groups \
-        org.freedesktop.sssd.infopipe.Groups.ListByName \
-        string:r\* uint32:10
-
-dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
-        /org/freedesktop/sssd/infopipe/Users \
-        org.freedesktop.sssd.infopipe.Users.ListByDomainAndName \
-        string:ipaldap string:r\* uint32:10
-
-dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
-        /org/freedesktop/sssd/infopipe/Groups \
-        org.freedesktop.sssd.infopipe.Groups.ListByDomainAndName \
-        string:ipaldap string:r\* uint32:10
-
-By default the wildcard_limit is unset, that is, the request will return
-all cached entries that match.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/confdb/confdb.h             |   1 +
- src/man/sssd-ifp.5.xml          |  15 ++++
- src/responder/ifp/ifp_groups.c  | 175 ++++++++++++++++++++++++++++++++++++++
- src/responder/ifp/ifp_private.h |  22 +++++
- src/responder/ifp/ifp_users.c   | 184 ++++++++++++++++++++++++++++++++++++++++
- src/responder/ifp/ifpsrv.c      |  23 +++++
- src/responder/ifp/ifpsrv_util.c |  52 ++++++++++++
- 7 files changed, 472 insertions(+)
-
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index b2ec2e0b98a9be2d50009df524a1072e9b1c15c7..36df6aea268cc5c82696f20b1a65963350d5e100 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -140,6 +140,7 @@
- /* InfoPipe */
- #define CONFDB_IFP_CONF_ENTRY "config/ifp"
- #define CONFDB_IFP_USER_ATTR_LIST "user_attributes"
-+#define CONFDB_IFP_WILDCARD_LIMIT "wildcard_limit"
- 
- /* Domains */
- #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s"
-diff --git a/src/man/sssd-ifp.5.xml b/src/man/sssd-ifp.5.xml
-index 867c117edccc3c000f7d9e8456298b72ebcdf693..da247f89dd2d9d08e0b1591d4c89f52197b278df 100644
---- a/src/man/sssd-ifp.5.xml
-+++ b/src/man/sssd-ifp.5.xml
-@@ -131,6 +131,21 @@ user_attributes = +telephoneNumber, -loginShell
-                         </para>
-                     </listitem>
-                 </varlistentry>
-+
-+                <varlistentry>
-+                    <term>wildcart_limit (integer)</term>
-+                    <listitem>
-+                        <para>
-+                            Specifies an upper limit on the number of entries
-+                            that are downloaded during a wildcard lookup that
-+                            overrides caller-supplied limit.
-+                        </para>
-+                        <para>
-+                            Default: 0 (let the caller set an upper limit)
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-             </variablelist>
-     </refsect1>
- 
-diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
-index 1b581b568f14362a47b4a80eb55d2de8eb936ae3..3060035924026641cc245f2a1970db9e2646e11c 100644
---- a/src/responder/ifp/ifp_groups.c
-+++ b/src/responder/ifp/ifp_groups.c
-@@ -81,6 +81,27 @@ done:
-     return ret;
- }
- 
-+static int ifp_groups_list_copy(struct ifp_list_ctx *list_ctx,
-+                                struct ldb_result *result)
-+{
-+    size_t copy_count, i;
-+
-+    copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
-+
-+    for (i = 0; i < copy_count; i++) {
-+        list_ctx->paths[list_ctx->path_count + i] = \
-+            ifp_groups_build_path_from_msg(list_ctx->paths,
-+                                           list_ctx->dom,
-+                                           result->msgs[i]);
-+        if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
-+            return ENOMEM;
-+        }
-+    }
-+
-+    list_ctx->path_count += copy_count;
-+    return EOK;
-+}
-+
- static void ifp_groups_find_by_name_done(struct tevent_req *req);
- 
- int ifp_groups_find_by_name(struct sbus_request *sbus_req,
-@@ -221,23 +242,177 @@ done:
-     return;
- }
- 
-+static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx);
-+static void ifp_groups_list_by_name_done(struct tevent_req *req);
-+static void ifp_groups_list_by_name_reply(struct ifp_list_ctx *list_ctx);
-+
- int ifp_groups_list_by_name(struct sbus_request *sbus_req,
-                             void *data,
-                             const char *filter,
-                             uint32_t limit)
- {
-+    struct ifp_ctx *ctx;
-+    struct ifp_list_ctx *list_ctx;
-+
-+    ctx = talloc_get_type(data, struct ifp_ctx);
-+    if (ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
-+    if (list_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    return ifp_groups_list_by_name_step(list_ctx);
-+}
-+
-+static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx)
-+{
-+    struct tevent_req *req;
-+
-+    req = cache_req_group_by_filter_send(list_ctx,
-+                                        list_ctx->ctx->rctx->ev,
-+                                        list_ctx->ctx->rctx,
-+                                        list_ctx->dom->name,
-+                                        list_ctx->filter);
-+    if (req == NULL) {
-+        return ENOMEM;
-+    }
-+    tevent_req_set_callback(req,
-+                            ifp_groups_list_by_name_done, list_ctx);
-+
-     return EOK;
- }
- 
-+static void ifp_groups_list_by_name_done(struct tevent_req *req)
-+{
-+    DBusError *error;
-+    struct ifp_list_ctx *list_ctx;
-+    struct sbus_request *sbus_req;
-+    struct ldb_result *result;
-+    struct sss_domain_info *domain;
-+    errno_t ret;
-+
-+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
-+    sbus_req = list_ctx->sbus_req;
-+
-+    ret = cache_req_group_by_name_recv(sbus_req, req, &result, &domain, NULL);
-+    talloc_zfree(req);
-+    if (ret != EOK && ret != ENOENT) {
-+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
-+                               "groups by filter [%d]: %s\n", ret, sss_strerror(ret));
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+
-+    ret = ifp_groups_list_copy(list_ctx, result);
-+    if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
-+                               "Failed to copy domain result");
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+
-+    list_ctx->dom = get_next_domain(list_ctx->dom, true);
-+    if (list_ctx->dom == NULL) {
-+        return ifp_groups_list_by_name_reply(list_ctx);
-+    }
-+
-+    ret = ifp_groups_list_by_name_step(list_ctx);
-+    if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
-+                               "Failed to start next-domain search");
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+}
-+
-+static void ifp_groups_list_by_name_reply(struct ifp_list_ctx *list_ctx)
-+{
-+    iface_ifp_groups_ListByDomainAndName_finish(list_ctx->sbus_req,
-+                                               list_ctx->paths,
-+                                               list_ctx->path_count);
-+}
-+
-+static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req);
-+
- int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req,
-                                        void *data,
-                                        const char *domain,
-                                        const char *filter,
-                                        uint32_t limit)
- {
-+    struct tevent_req *req;
-+    struct ifp_ctx *ctx;
-+    struct ifp_list_ctx *list_ctx;
-+
-+    ctx = talloc_get_type(data, struct ifp_ctx);
-+    if (ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
-+    if (list_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
-+                                        domain, filter);
-+    if (req == NULL) {
-+        return ENOMEM;
-+    }
-+    tevent_req_set_callback(req,
-+                            ifp_groups_list_by_domain_and_name_done, list_ctx);
-+
-     return EOK;
- }
- 
-+static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req)
-+{
-+    DBusError *error;
-+    struct ifp_list_ctx *list_ctx;
-+    struct sbus_request *sbus_req;
-+    struct ldb_result *result;
-+    struct sss_domain_info *domain;
-+    errno_t ret;
-+
-+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
-+    sbus_req = list_ctx->sbus_req;
-+
-+    ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
-+    talloc_zfree(req);
-+    if (ret == ENOENT) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
-+                               "User not found by filter");
-+        goto done;
-+    } else if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
-+                               "groups by filter [%d]: %s\n", ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = ifp_groups_list_copy(list_ctx, result);
-+    if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
-+                               "Failed to copy domain result");
-+        goto done;
-+    }
-+
-+done:
-+    if (ret != EOK) {
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+
-+    iface_ifp_groups_ListByDomainAndName_finish(sbus_req,
-+                                                list_ctx->paths,
-+                                                list_ctx->path_count);
-+    return;
-+}
-+
- static errno_t
- ifp_groups_group_get(struct sbus_request *sbus_req,
-                      void *data,
-diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h
-index 304e4dc535aac4215cf318a0bea845c161c5f079..43519de6fef3033f1e47cecb787d6b02dc9c6e56 100644
---- a/src/responder/ifp/ifp_private.h
-+++ b/src/responder/ifp/ifp_private.h
-@@ -44,6 +44,7 @@ struct ifp_ctx {
- 
-     struct sysbus_ctx *sysbus;
-     const char **user_whitelist;
-+    uint32_t wildcard_limit;
- };
- 
- errno_t ifp_register_sbus_interface(struct sbus_connection *conn,
-@@ -84,4 +85,25 @@ ifp_get_user_extra_attributes(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx);
- bool ifp_attr_allowed(const char *whitelist[], const char *attr);
- bool ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr);
- 
-+/* Used for list calls */
-+struct ifp_list_ctx {
-+    struct sbus_request *sbus_req;
-+    const char *filter;
-+    uint32_t limit;
-+
-+    struct sss_domain_info *dom;
-+    struct ifp_ctx *ctx;
-+
-+    const char **paths;
-+    size_t path_count;
-+};
-+
-+struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
-+                                      struct ifp_ctx *ctx,
-+                                      const char *filter,
-+                                      uint32_t limit);
-+
-+size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
-+                                       size_t entries);
-+
- #endif /* _IFPSRV_PRIVATE_H_ */
-diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
-index 2ec74c30b348ac5f2b84cdc8e2dd406fd44a7da3..effefdc0435d794206dbe7358c61d2ea47760361 100644
---- a/src/responder/ifp/ifp_users.c
-+++ b/src/responder/ifp/ifp_users.c
-@@ -309,23 +309,207 @@ done:
-     return;
- }
- 
-+static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx,
-+                               struct ldb_result *result)
-+{
-+    size_t copy_count, i;
-+
-+    copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
-+
-+    for (i = 0; i < copy_count; i++) {
-+        list_ctx->paths[list_ctx->path_count + i] = \
-+                             ifp_users_build_path_from_msg(list_ctx->paths,
-+                                                           list_ctx->dom,
-+                                                           result->msgs[i]);
-+        if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
-+            return ENOMEM;
-+        }
-+    }
-+
-+    list_ctx->path_count += copy_count;
-+    return EOK;
-+}
-+
-+static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx);
-+static void ifp_users_list_by_name_done(struct tevent_req *req);
-+static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx);
-+
- int ifp_users_list_by_name(struct sbus_request *sbus_req,
-                            void *data,
-                            const char *filter,
-                            uint32_t limit)
- {
-+    struct ifp_ctx *ctx;
-+    struct ifp_list_ctx *list_ctx;
-+
-+    ctx = talloc_get_type(data, struct ifp_ctx);
-+    if (ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
-+    if (list_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    return ifp_users_list_by_name_step(list_ctx);
-+}
-+
-+static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx)
-+{
-+    struct tevent_req *req;
-+
-+    req = cache_req_user_by_filter_send(list_ctx,
-+                                        list_ctx->ctx->rctx->ev,
-+                                        list_ctx->ctx->rctx,
-+                                        list_ctx->dom->name,
-+                                        list_ctx->filter);
-+    if (req == NULL) {
-+        return ENOMEM;
-+    }
-+    tevent_req_set_callback(req,
-+                            ifp_users_list_by_name_done, list_ctx);
-+
-     return EOK;
- }
- 
-+static void ifp_users_list_by_name_done(struct tevent_req *req)
-+{
-+    DBusError *error;
-+    struct ifp_list_ctx *list_ctx;
-+    struct sbus_request *sbus_req;
-+    struct ldb_result *result;
-+    struct sss_domain_info *domain;
-+    errno_t ret;
-+
-+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
-+    sbus_req = list_ctx->sbus_req;
-+
-+    ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
-+    talloc_zfree(req);
-+    if (ret != EOK && ret != ENOENT) {
-+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
-+                               "users by filter [%d]: %s\n", ret, sss_strerror(ret));
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+
-+    ret = ifp_users_list_copy(list_ctx, result);
-+    if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
-+                               "Failed to copy domain result");
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+
-+    list_ctx->dom = get_next_domain(list_ctx->dom, true);
-+    if (list_ctx->dom == NULL) {
-+        return ifp_users_list_by_name_reply(list_ctx);
-+    }
-+
-+    ret = ifp_users_list_by_name_step(list_ctx);
-+    if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
-+                               "Failed to start next-domain search");
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+}
-+
-+static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx)
-+{
-+    iface_ifp_users_ListByName_finish(list_ctx->sbus_req,
-+                                      list_ctx->paths,
-+                                      list_ctx->path_count);
-+}
-+
-+static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req);
-+
- int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req,
-                                       void *data,
-                                       const char *domain,
-                                       const char *filter,
-                                       uint32_t limit)
- {
-+    struct tevent_req *req;
-+    struct ifp_ctx *ctx;
-+    struct ifp_list_ctx *list_ctx;
-+
-+    ctx = talloc_get_type(data, struct ifp_ctx);
-+    if (ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
-+    if (list_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
-+                                        domain, filter);
-+    if (req == NULL) {
-+        return ENOMEM;
-+    }
-+    tevent_req_set_callback(req,
-+                            ifp_users_list_by_domain_and_name_done, list_ctx);
-+
-     return EOK;
- }
- 
-+static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req)
-+{
-+    DBusError *error;
-+    struct ifp_list_ctx *list_ctx;
-+    struct sbus_request *sbus_req;
-+    struct ldb_result *result;
-+    struct sss_domain_info *domain;
-+    errno_t ret;
-+    size_t copy_count, i;
-+
-+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
-+    sbus_req = list_ctx->sbus_req;
-+
-+    ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
-+    talloc_zfree(req);
-+    if (ret == ENOENT) {
-+        error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
-+                               "User not found by filter");
-+        goto done;
-+    } else if (ret != EOK) {
-+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
-+                               "users by filter [%d]: %s\n", ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
-+
-+    for (i = 0; i < copy_count; i++) {
-+        list_ctx->paths[i] = ifp_users_build_path_from_msg(list_ctx->paths,
-+                                                           list_ctx->dom,
-+                                                           result->msgs[i]);
-+        if (list_ctx->paths[i] == NULL) {
-+            error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
-+                                   "Failed to compose object path");
-+            goto done;
-+        }
-+    }
-+
-+    list_ctx->path_count += copy_count;
-+
-+done:
-+    if (ret != EOK) {
-+        sbus_request_fail_and_finish(sbus_req, error);
-+        return;
-+    }
-+
-+    iface_ifp_users_ListByDomainAndName_finish(sbus_req,
-+                                               list_ctx->paths,
-+                                               list_ctx->path_count);
-+    return;
-+}
-+
- static errno_t
- ifp_users_user_get(struct sbus_request *sbus_req,
-                    struct ifp_ctx *ifp_ctx,
-diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
-index 631bcd266d7e06154dbf1f37f9f439119b2b8944..cdc411faa330dc2c063e52abe63cd68dbe16a5d9 100644
---- a/src/responder/ifp/ifpsrv.c
-+++ b/src/responder/ifp/ifpsrv.c
-@@ -34,6 +34,7 @@
- #include <dbus/dbus.h>
- 
- #include "util/util.h"
-+#include "util/strtonum.h"
- #include "sbus/sssd_dbus.h"
- #include "monitor/monitor_interfaces.h"
- #include "confdb/confdb.h"
-@@ -228,6 +229,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
-     int max_retries;
-     char *uid_str;
-     char *attr_list_str;
-+    char *wildcard_limit_str;
- 
-     ifp_cmds = get_ifp_cmds();
-     ret = sss_process_init(mem_ctx, ev, cdb,
-@@ -321,6 +323,27 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
-         goto fail;
-     }
- 
-+    /* A bit convoluted way until we have a confdb_get_uint32 */
-+    ret = confdb_get_string(ifp_ctx->rctx->cdb,
-+                            ifp_ctx->rctx,
-+                            CONFDB_IFP_CONF_ENTRY,
-+                            CONFDB_IFP_WILDCARD_LIMIT,
-+                            NULL, /* no limit by default */
-+                            &wildcard_limit_str);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE,
-+              "Failed to retrieve limit for a wildcard search\n");
-+        goto fail;
-+    }
-+
-+    if (wildcard_limit_str) {
-+        ifp_ctx->wildcard_limit = strtouint32(wildcard_limit_str, NULL, 10);
-+        if (errno != 0) {
-+            ret = errno;
-+            goto fail;
-+        }
-+    }
-+
-     for (iter = ifp_ctx->rctx->be_conns; iter; iter = iter->next) {
-         sbus_reconnect_init(iter->conn, max_retries,
-                             ifp_dp_reconnect_init, iter);
-diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
-index 674165ee4901115c9e17458a75fdb3536b6468c2..3b02fd06f5227e4ffc3d40ffb20fed981c5028a7 100644
---- a/src/responder/ifp/ifpsrv_util.c
-+++ b/src/responder/ifp/ifpsrv_util.c
-@@ -21,6 +21,8 @@
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
- 
-+#include <sys/param.h>
-+
- #include "db/sysdb.h"
- #include "responder/ifp/ifp_private.h"
- 
-@@ -269,3 +271,53 @@ ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr)
- {
-     return ifp_attr_allowed(ifp_ctx->user_whitelist, attr);
- }
-+
-+static uint32_t ifp_list_limit(struct ifp_ctx *ctx, uint32_t limit)
-+{
-+    if (ctx->wildcard_limit) {
-+        return MIN(ctx->wildcard_limit, limit);
-+    } else {
-+        return limit;
-+    }
-+}
-+
-+struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
-+                                      struct ifp_ctx *ctx,
-+                                      const char *filter,
-+                                      uint32_t limit)
-+{
-+    struct ifp_list_ctx *list_ctx;
-+
-+    list_ctx = talloc_zero(sbus_req, struct ifp_list_ctx);
-+    if (list_ctx == NULL) {
-+        return NULL;
-+    }
-+
-+    list_ctx->sbus_req = sbus_req;
-+    list_ctx->limit = ifp_list_limit(ctx, limit);
-+    list_ctx->ctx = ctx;
-+    list_ctx->dom = ctx->rctx->domains;
-+    list_ctx->filter = filter;
-+    list_ctx->paths = talloc_zero_array(list_ctx, const char *, limit);
-+    if (list_ctx->paths == NULL) {
-+        talloc_free(list_ctx);
-+        return NULL;
-+    }
-+
-+    return list_ctx;
-+}
-+
-+size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
-+                                       size_t entries)
-+{
-+    size_t capacity = list_ctx->limit - list_ctx->path_count;
-+
-+    if (capacity < entries) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "IFP list request has limit of %"PRIu32" entries but back end "
-+              "returned %zu entries\n", list_ctx->limit, entries);
-+        return capacity;
-+    } else {
-+        return entries;
-+    }
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0012-TOOLS-Prevent-dereference-of-null-pointer.patch b/SOURCES/0012-TOOLS-Prevent-dereference-of-null-pointer.patch
new file mode 100644
index 0000000..8ff9bfb
--- /dev/null
+++ b/SOURCES/0012-TOOLS-Prevent-dereference-of-null-pointer.patch
@@ -0,0 +1,139 @@
+From be811502403246414b99f3a8834355c53f6f0511 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 6 Jun 2016 18:15:44 +0200
+Subject: [PATCH 12/14] TOOLS: Prevent dereference of null pointer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+VAR_CHECK is called with (var, EOK, ...)
+EOK would be returned in case of "var != EOK"
+and output argument _attrs would not be initialized.
+Therefore there could be dereference of null pointer
+after calling function usermod_build_attrs.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit f9d3aec54d19a771a6eafe09ba6d445cc094bfae)
+---
+ src/tools/sss_sync_ops.c | 63 +++++++++++++++++++++---------------------------
+ 1 file changed, 28 insertions(+), 35 deletions(-)
+
+diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c
+index 7f2e3ea85d5874e3c40f53f327b400e38e430228..a23a0b8c30366d2fb68554bfed184b8fce675e2b 100644
+--- a/src/tools/sss_sync_ops.c
++++ b/src/tools/sss_sync_ops.c
+@@ -37,13 +37,6 @@
+ #define ATTR_NAME_SEP      '='
+ #define ATTR_VAL_SEP       ','
+ 
+-#define VAR_CHECK(var, val, attr, msg) do { \
+-        if (var != (val)) { \
+-            DEBUG(SSSDBG_CRIT_FAILURE, msg" attribute: %s\n", attr); \
+-            return val; \
+-        } \
+-} while(0)
+-
+ static int attr_name_val_split(TALLOC_CTX *mem_ctx, const char *nameval,
+                                char **_name, char ***_values, int *_nvals)
+ {
+@@ -200,8 +193,9 @@ static int usermod_build_attrs(TALLOC_CTX *mem_ctx,
+                                int lock,
+                                struct sysdb_attrs **_attrs)
+ {
+-    int ret;
++    int ret = EOK;
+     struct sysdb_attrs *attrs;
++    const char *attr_name = NULL;
+ 
+     attrs = sysdb_new_attrs(mem_ctx);
+     if (attrs == NULL) {
+@@ -209,60 +203,59 @@ static int usermod_build_attrs(TALLOC_CTX *mem_ctx,
+     }
+ 
+     if (shell) {
++        attr_name = SYSDB_SHELL;
+         ret = sysdb_attrs_add_string(attrs,
+-                                     SYSDB_SHELL,
++                                     attr_name,
+                                      shell);
+-        VAR_CHECK(ret, EOK, SYSDB_SHELL,
+-                  "Could not add attribute to changeset\n");
+     }
+ 
+-    if (home) {
++    if (ret == EOK && home) {
++        attr_name = SYSDB_HOMEDIR;
+         ret = sysdb_attrs_add_string(attrs,
+-                                     SYSDB_HOMEDIR,
++                                     attr_name,
+                                      home);
+-        VAR_CHECK(ret, EOK, SYSDB_HOMEDIR,
+-                  "Could not add attribute to changeset\n");
+     }
+ 
+-    if (gecos) {
++    if (ret == EOK && gecos) {
++        attr_name = SYSDB_GECOS;
+         ret = sysdb_attrs_add_string(attrs,
+-                                     SYSDB_GECOS,
++                                     attr_name,
+                                      gecos);
+-        VAR_CHECK(ret, EOK, SYSDB_GECOS,
+-                  "Could not add attribute to changeset\n");
+     }
+ 
+-    if (uid) {
++    if (ret == EOK && uid) {
++        attr_name = SYSDB_UIDNUM;
+         ret = sysdb_attrs_add_long(attrs,
+-                                   SYSDB_UIDNUM,
++                                   attr_name,
+                                    uid);
+-        VAR_CHECK(ret, EOK, SYSDB_UIDNUM,
+-                  "Could not add attribute to changeset\n");
+     }
+ 
+-    if (gid) {
++    if (ret == EOK && gid) {
++        attr_name = SYSDB_GIDNUM;
+         ret = sysdb_attrs_add_long(attrs,
+-                                   SYSDB_GIDNUM,
++                                   attr_name,
+                                    gid);
+-        VAR_CHECK(ret, EOK, SYSDB_GIDNUM,
+-                  "Could not add attribute to changeset\n");
+     }
+ 
+-    if (lock == DO_LOCK) {
++    if (ret == EOK && lock == DO_LOCK) {
++        attr_name = SYSDB_DISABLED;
+         ret = sysdb_attrs_add_string(attrs,
+-                                     SYSDB_DISABLED,
++                                     attr_name,
+                                      "true");
+-        VAR_CHECK(ret, EOK, SYSDB_DISABLED,
+-                  "Could not add attribute to changeset\n");
+     }
+ 
+-    if (lock == DO_UNLOCK) {
++    if (ret == EOK && lock == DO_UNLOCK) {
++        attr_name = SYSDB_DISABLED;
+         /* PAM code checks for 'false' value in SYSDB_DISABLED attribute */
+         ret = sysdb_attrs_add_string(attrs,
+-                                     SYSDB_DISABLED,
++                                     attr_name,
+                                      "false");
+-        VAR_CHECK(ret, EOK, SYSDB_DISABLED,
+-                  "Could not add attribute to changeset\n");
++    }
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Could not add attribute [%s] to changeset.\n", attr_name);
++        return ret;
+     }
+ 
+     *_attrs = attrs;
+-- 
+2.4.11
+
diff --git a/SOURCES/0013-KRB5-Return-right-data-provider-error-code.patch b/SOURCES/0013-KRB5-Return-right-data-provider-error-code.patch
deleted file mode 100644
index 4d2aebf..0000000
--- a/SOURCES/0013-KRB5-Return-right-data-provider-error-code.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From aac1c3031aadce0682c4e3873634e405cdd41e69 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 14 Jul 2015 12:48:47 +0200
-Subject: [PATCH 13/13] KRB5: Return right data provider error code
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2719
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/providers/krb5/krb5_wait_queue.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/krb5/krb5_wait_queue.c b/src/providers/krb5/krb5_wait_queue.c
-index 126209620dcd22889cf7bcb1cbec1890b8891b41..b4d3f903a94c9fdfffc975f1dfd10a27ab653a8d 100644
---- a/src/providers/krb5/krb5_wait_queue.c
-+++ b/src/providers/krb5/krb5_wait_queue.c
-@@ -366,7 +366,7 @@ int krb5_auth_queue_recv(struct tevent_req *req,
-     }
- 
-     if (_dp_err) {
--        *_dp_err = state->pam_status;
-+        *_dp_err = state->dp_err;
-     }
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
--- 
-2.4.3
-
diff --git a/SOURCES/0013-config-override_space-is-monitor-s-option.patch b/SOURCES/0013-config-override_space-is-monitor-s-option.patch
new file mode 100644
index 0000000..f9d2ccd
--- /dev/null
+++ b/SOURCES/0013-config-override_space-is-monitor-s-option.patch
@@ -0,0 +1,100 @@
+From 3904a70f86d793954822abc543783d57fb36c8ea Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 11 Jul 2016 13:11:41 +0200
+Subject: [PATCH 13/14] config: override_space is monitor's option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We read override_space from [sssd] not
+[nss] section.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3068
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit fc04d11c2fdde0bfe280c6030df2b1d6bf15ce63)
+---
+ src/config/SSSDConfig/__init__.py.in | 2 +-
+ src/config/SSSDConfigTest.py         | 3 ++-
+ src/config/cfg_rules.ini             | 2 +-
+ src/config/etc/sssd.api.conf         | 2 +-
+ 4 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 52af1386c7b6fc858b27d6f1d9197a7906519fc1..ebdd049e4df7ac2349293d6ce3802e7349098273 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -63,6 +63,7 @@ option_strings = {
+     'default_domain_suffix' : _('Domain to add to names without a domain component.'),
+     'user' : _('The user to drop privileges to'),
+     'certificate_verification' : _('Tune certificate verification'),
++    'override_space': _('All spaces in group or user names will be replaced with this character'),
+ 
+     # [nss]
+     'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'),
+@@ -81,7 +82,6 @@ option_strings = {
+     'shell_fallback' : _('If a shell stored in central directory is allowed but not available, use this fallback'),
+     'default_shell': _('Shell to use if the provider does not list one'),
+     'memcache_timeout': _('How long will be in-memory cache records valid'),
+-    'override_space': _('All spaces in group or user names will be replaced with this character'),
+ 
+     # [pam]
+     'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 6ec30234e24b7b48ccab6a98e1f9396990509190..5fa9bce8e6502c0ebf42671058c5e3d5de00ea0d 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -310,7 +310,8 @@ class SSSDConfigTestSSSDService(unittest.TestCase):
+             'client_idle_timeout',
+             'diag_cmd',
+             'description',
+-            'certificate_verification']
++            'certificate_verification',
++            'override_space']
+ 
+         self.assertTrue(type(options) == dict,
+                         "Options should be a dictionary")
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index d738ddf5ac5c220dbf2c3c99782368c684072e3f..ae4a9af2cdfd622e1234e26ae7285ff4e47889dc 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -38,6 +38,7 @@ option = krb5_rcache_dir
+ option = user
+ option = default_domain_suffix
+ option = certificate_verification
++option = override_space
+ 
+ [rule/allowed_nss_options]
+ validator = ini_allowed_options
+@@ -75,7 +76,6 @@ option = shell_fallback
+ option = default_shell
+ option = get_domains_timeout
+ option = memcache_timeout
+-option = override_space
+ 
+ [rule/allowed_pam_options]
+ validator = ini_allowed_options
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index 91146593d7fcda2930ff85e8ee3e889cc12af962..df6bdeb392b33a1437d790027054ee5e7b33e724 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -28,6 +28,7 @@ krb5_rcache_dir = str, None, false
+ user = str, None, false
+ default_domain_suffix = str, None, false
+ certificate_verification = str, None, false
++override_space = str, None, false
+ 
+ [nss]
+ # Name service
+@@ -49,7 +50,6 @@ shell_fallback = str, None, false
+ default_shell = str, None, false
+ get_domains_timeout = int, None, false
+ memcache_timeout = int, None, false
+-override_space = str, None, false
+ 
+ [pam]
+ # Authentication service
+-- 
+2.4.11
+
diff --git a/SOURCES/0014-config-Fix-user_attributes.patch b/SOURCES/0014-config-Fix-user_attributes.patch
new file mode 100644
index 0000000..df2c8e3
--- /dev/null
+++ b/SOURCES/0014-config-Fix-user_attributes.patch
@@ -0,0 +1,77 @@
+From 08f1019768f6fa569eccf4892e3b5b57372b971d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 11 Jul 2016 13:23:40 +0200
+Subject: [PATCH 14/14] config: Fix user_attributes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/3068
+
+Option user_attributes is also available in
+NSS responder, but not in PAC responder.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 0a172552ec16f3b84d127399551cad786da8fd9d)
+---
+ src/config/SSSDConfig/__init__.py.in | 1 +
+ src/config/cfg_rules.ini             | 2 +-
+ src/config/etc/sssd.api.conf         | 2 +-
+ 3 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index ebdd049e4df7ac2349293d6ce3802e7349098273..b5e078d0118a15c10b43fbe050176943ec90e0ee 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -82,6 +82,7 @@ option_strings = {
+     'shell_fallback' : _('If a shell stored in central directory is allowed but not available, use this fallback'),
+     'default_shell': _('Shell to use if the provider does not list one'),
+     'memcache_timeout': _('How long will be in-memory cache records valid'),
++    'user_attributes': _('List of user attributes the NSS responder is allowed to publish'),
+ 
+     # [pam]
+     'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'),
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index ae4a9af2cdfd622e1234e26ae7285ff4e47889dc..85a15be3493cf4b8c5a612b0f66ae4c86d39b1ab 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -58,6 +58,7 @@ option = description
+ option = diag_cmd
+ 
+ # Name service
++option = user_attributes
+ option = enum_cache_timeout
+ option = entry_cache_nowait_percentage
+ option = entry_negative_timeout
+@@ -192,7 +193,6 @@ option = diag_cmd
+ 
+ # PAC responder
+ option = allowed_uids
+-option = user_attributes
+ option = pac_lifetime
+ 
+ [rule/allowed_ifp_options]
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index df6bdeb392b33a1437d790027054ee5e7b33e724..2d7c5049f5e5bf9df6e5445ee6e5c62211bf1c45 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -50,6 +50,7 @@ shell_fallback = str, None, false
+ default_shell = str, None, false
+ get_domains_timeout = int, None, false
+ memcache_timeout = int, None, false
++user_attributes = str, None, false
+ 
+ [pam]
+ # Authentication service
+@@ -86,7 +87,6 @@ ca_db = str, None, false
+ [pac]
+ # PAC responder
+ allowed_uids = str, None, false
+-user_attributes = str, None, false
+ pac_lifetime = int, None, false
+ 
+ [ifp]
+-- 
+2.4.11
+
diff --git a/SOURCES/0014-nss_check_name_of_well_known_sid-improve-name-splitt.patch b/SOURCES/0014-nss_check_name_of_well_known_sid-improve-name-splitt.patch
deleted file mode 100644
index 936f1f5..0000000
--- a/SOURCES/0014-nss_check_name_of_well_known_sid-improve-name-splitt.patch
+++ /dev/null
@@ -1,183 +0,0 @@
-From f9f227bb5a7fe6e5af83debbbd892bdb4e13894d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 14 Jul 2015 14:41:34 +0200
-Subject: [PATCH 14/14] nss_check_name_of_well_known_sid() improve name
- splitting
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Currently in the default configuration
-nss_check_name_of_well_known_sid() can only split fully-qualified names
-in the user@domain.name style. DOM\user style names will cause an error
-and terminate the whole request.
-
-With this patch both styles can be handled by default, additionally if
-the name could not be split nss_check_name_of_well_known_sid() returns
-ENOENT which can be handled more gracefully by the caller.
-
-Resolves https://fedorahosted.org/sssd/ticket/2717
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
----
- src/responder/nss/nsssrv_cmd.c  |  8 ++++
- src/tests/cmocka/test_nss_srv.c | 90 ++++++++++++++++++++++++-----------------
- src/util/usertools.c            |  3 +-
- 3 files changed, 61 insertions(+), 40 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index 0129467302f16af318bbbb0a5be47ff2e235da65..b3998015fa621cad8e06a126a674f94d26158dda 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -1255,6 +1255,14 @@ static int nss_check_name_of_well_known_sid(struct nss_cmd_ctx *cmdctx,
-         return ret;
-     }
- 
-+    if (wk_dom_name == NULL || wk_name == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Unable to split [%s] in name and domain part. " \
-+              "Skipping check for well-known name.\n", full_name);
-+
-+        return ENOENT;
-+    }
-+
-     ret = name_to_well_known_sid(wk_dom_name, wk_name, &wk_sid);
-     talloc_free(wk_dom_name);
-     talloc_free(wk_name);
-diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
-index 3ab8d39c44a8bb8cacae20f534dcbeb6ca7dec08..84d3413be70bc0af433b7fd23cf7d78b4b9298f1 100644
---- a/src/tests/cmocka/test_nss_srv.c
-+++ b/src/tests/cmocka/test_nss_srv.c
-@@ -1734,63 +1734,77 @@ void test_nss_well_known_getidbysid_failure(void **state)
- void test_nss_well_known_getsidbyname(void **state)
- {
-     errno_t ret;
-+    const char *names[] = { "Cryptographic Operators@BUILTIN",
-+                            "BUILTIN\\Cryptographic Operators", NULL};
-+    size_t c;
- 
--    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
--    will_return(__wrap_sss_packet_get_body, "Cryptographic Operators@BUILTIN");
--    will_return(__wrap_sss_packet_get_body, 0);
--    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
--    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
--    will_return(test_nss_well_known_sid_check, "S-1-5-32-569");
-+    for (c = 0; names[c] != NULL; c++) {
-+        will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+        will_return(__wrap_sss_packet_get_body, names[c]);
-+        will_return(__wrap_sss_packet_get_body, 0);
-+        will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
-+        will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+        will_return(test_nss_well_known_sid_check, "S-1-5-32-569");
- 
--    set_cmd_cb(test_nss_well_known_sid_check);
--    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
--                          nss_test_ctx->nss_cmds);
--    assert_int_equal(ret, EOK);
-+        set_cmd_cb(test_nss_well_known_sid_check);
-+        ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
-+                              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);
-+        /* Wait until the test finishes with EOK */
-+        ret = test_ev_loop(nss_test_ctx->tctx);
-+        assert_int_equal(ret, EOK);
-+    }
- }
- 
- void test_nss_well_known_getsidbyname_nonexisting(void **state)
- {
-     errno_t ret;
-+    const char *names[] = { "Abc@BUILTIN", "BUILTIN\\Abc", NULL };
-+    size_t c;
- 
--    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
--    will_return(__wrap_sss_packet_get_body, "Abc@BUILTIN");
--    will_return(__wrap_sss_packet_get_body, 0);
--    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
--    will_return(test_nss_well_known_sid_check, NULL);
-+    for (c = 0; names[c] != NULL; c++) {
-+        will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+        will_return(__wrap_sss_packet_get_body, names[c]);
-+        will_return(__wrap_sss_packet_get_body, 0);
-+        will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
-+        will_return(test_nss_well_known_sid_check, NULL);
- 
--    set_cmd_cb(test_nss_well_known_sid_check);
--    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
--                          nss_test_ctx->nss_cmds);
--    assert_int_equal(ret, EOK);
-+        set_cmd_cb(test_nss_well_known_sid_check);
-+        ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
-+                              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);
-+        /* Wait until the test finishes with EOK */
-+        ret = test_ev_loop(nss_test_ctx->tctx);
-+        assert_int_equal(ret, EOK);
-+    }
- }
- 
- void test_nss_well_known_getsidbyname_special(void **state)
- {
-     errno_t ret;
-+    const char *names[] = { "CREATOR OWNER@CREATOR AUTHORITY",
-+                            "CREATOR AUTHORITY\\CREATOR OWNER", NULL };
-+    size_t c;
- 
--    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
--    will_return(__wrap_sss_packet_get_body, "CREATOR OWNER@CREATOR AUTHORITY");
--    will_return(__wrap_sss_packet_get_body, 0);
--    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
--    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
--    will_return(test_nss_well_known_sid_check, "S-1-3-0");
-+    for (c = 0; names[c] != NULL; c++) {
-+        will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+        will_return(__wrap_sss_packet_get_body, names[c]);
-+        will_return(__wrap_sss_packet_get_body, 0);
-+        will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
-+        will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+        will_return(test_nss_well_known_sid_check, "S-1-3-0");
- 
--    set_cmd_cb(test_nss_well_known_sid_check);
--    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
--                          nss_test_ctx->nss_cmds);
--    assert_int_equal(ret, EOK);
-+        set_cmd_cb(test_nss_well_known_sid_check);
-+        ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
-+                              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);
-+        /* Wait until the test finishes with EOK */
-+        ret = test_ev_loop(nss_test_ctx->tctx);
-+        assert_int_equal(ret, EOK);
-+    }
- }
- 
- static int test_nss_getorigbyname_check(uint32_t status, uint8_t *body,
-diff --git a/src/util/usertools.c b/src/util/usertools.c
-index c43d420e31c6c690628ef6179d932eaf99826fee..87a8d7411312c3a80c32374a1fd93bbf0e767a91 100644
---- a/src/util/usertools.c
-+++ b/src/util/usertools.c
-@@ -249,8 +249,7 @@ int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
-     }
- 
-     if (!re_pattern) {
--        re_pattern = talloc_strdup(tmpctx,
--                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)");
-+        re_pattern = talloc_strdup(tmpctx, IPA_AD_DEFAULT_RE);
-         if (!re_pattern) {
-             ret = ENOMEM;
-             goto done;
--- 
-2.4.3
-
diff --git a/SOURCES/0015-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch b/SOURCES/0015-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch
deleted file mode 100644
index 21b708e..0000000
--- a/SOURCES/0015-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From c7c762dc50c48cfa43551a3936dd46405e9d33ce Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 8 Jul 2015 09:01:24 -0400
-Subject: [PATCH 15/19] DYNDNS: sss_iface_addr_list_get return ENOENT
-
-If none of eligible interfaces matches ifname then ENOENT is returned.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2549
----
- src/providers/dp_dyndns.c        | 13 +++++++++++--
- src/providers/ldap/sdap_dyndns.c |  6 +++++-
- src/tests/cmocka/test_dyndns.c   | 20 ++++++++++++++++++++
- 3 files changed, 36 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 1cac3d0fae2454cea823ed640a4325f27580353f..2ac43a108ff6197d9e2662198a6da976ca348e76 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -222,8 +222,17 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
-         }
-     }
- 
--    ret = EOK;
--    *_addrlist = addrlist;
-+    if (addrlist != NULL) {
-+        /* OK, some result was found */
-+        ret = EOK;
-+        *_addrlist = addrlist;
-+    } else {
-+        /* No result was found */
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "No IPs usable for DNS was found for interface: %s.\n", ifname);
-+        ret = ENOENT;
-+    }
-+
- done:
-     freeifaddrs(ifaces);
-     return ret;
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index 0d9c9205792062378aa25aad6ac706058001433a..e99a4f6687035928f6775c38b9df6b2a06d38f38 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -502,8 +502,12 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
-     if (iface) {
-         ret = sss_iface_addr_list_get(state, iface, &state->addresses);
-         if (ret != EOK) {
--            DEBUG(SSSDBG_OP_FAILURE,
-+            DEBUG(ret == ENOENT ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE,
-                   "Cannot get list of addresses from interface %s\n", iface);
-+            /* non critical failure */
-+            if (ret == ENOENT) {
-+                ret = EOK;
-+            }
-         }
-         /* We're done. Just fake an async request completion */
-         goto done;
-diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
-index 689e333d4e68c4a2582894d06b8b7b20c76b9be8..3214e90c063ea9a4cf6f6bc6507bf4e37b7d23a4 100644
---- a/src/tests/cmocka/test_dyndns.c
-+++ b/src/tests/cmocka/test_dyndns.c
-@@ -247,6 +247,23 @@ void dyndns_test_get_multi_ifaddr(void **state)
-     assert_true(check_leaks_pop(dyndns_test_ctx) == true);
- }
- 
-+void dyndns_test_get_ifaddr_enoent(void **state)
-+{
-+    errno_t ret;
-+    struct sss_iface_addr *addrlist = NULL;
-+
-+    check_leaks_push(dyndns_test_ctx);
-+    will_return_getifaddrs("eth0", "192.168.0.1");
-+    will_return_getifaddrs("eth1", "192.168.0.2");
-+    will_return_getifaddrs(NULL, NULL); /* sentinel */
-+    ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface",
-+                                  &addrlist);
-+    assert_int_equal(ret, ENOENT);
-+    talloc_free(addrlist);
-+
-+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
-+}
-+
- void dyndns_test_ok(void **state)
- {
-     struct tevent_req *req;
-@@ -460,6 +477,9 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(dyndns_test_get_multi_ifaddr,
-                                         dyndns_test_simple_setup,
-                                         dyndns_test_teardown),
-+        cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr_enoent,
-+                                        dyndns_test_simple_setup,
-+                                        dyndns_test_teardown),
- 
-         /* Dynamic DNS update unit tests*/
-         cmocka_unit_test_setup_teardown(dyndns_test_ok,
--- 
-2.4.3
-
diff --git a/SOURCES/0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch b/SOURCES/0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch
new file mode 100644
index 0000000..47af5b0
--- /dev/null
+++ b/SOURCES/0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch
@@ -0,0 +1,42 @@
+From 7b8c9b01882788d5112b0a529bf74163805889d3 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 8 Jul 2016 13:37:10 +0200
+Subject: [PATCH 15/18] sysdb-tests: Fix cast from pointer to integer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+src/tests/sysdb-tests.c: In function 'test_sysdb_memberof_close_loop':
+src/tests/sysdb-tests.c:2740:5: warning: passing argument
+  1 of '_ck_assert_msg' makes integer from pointer without a cast
+  [enabled by default]
+     fail_unless(data->attrlist[0], "talloc_array failed.");
+     ^
+In file included from src/tests/sysdb-tests.c:23:0:
+/usr/include/check.h:237:16: note: expected 'int' but argument
+ is of type 'const char *'
+   void CK_EXPORT _ck_assert_msg (int result, const char *file,
+                  ^
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+
+(cherry picked from commit 2bb9e88328ef44eddd935c250ae12337442c5900)
+---
+ src/tests/sysdb-tests.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index 429aa39538901fe387e41eebb27662d7b958142c..bac8a8788b4fde0d6039121efead6fc20fa046f9 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -2737,7 +2737,7 @@ START_TEST (test_sysdb_memberof_close_loop)
+     fail_unless(data->attrlist != NULL, "talloc_array failed.");
+     data->attrlist[0] = test_asprintf_fqname(data, test_ctx->domain,
+                                              "testgroup%d", data->gid + 9);
+-    fail_unless(data->attrlist[0], "talloc_array failed.");
++    fail_unless(data->attrlist[0] != NULL, "talloc_array failed.");
+     data->attrlist[1] = NULL;
+ 
+     ret = test_memberof_store_group(data);
+-- 
+2.4.11
+
diff --git a/SOURCES/0016-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch b/SOURCES/0016-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch
deleted file mode 100644
index abf0e7f..0000000
--- a/SOURCES/0016-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch
+++ /dev/null
@@ -1,194 +0,0 @@
-From e1936ccbb810965e90d030c2ed8f420c084b6a22 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 8 Jul 2015 09:08:03 -0400
-Subject: [PATCH 16/19] DYNDNS: support mult. interfaces for dyndns_iface opt
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2549
----
- src/man/sssd-ad.5.xml            | 11 +++---
- src/man/sssd-ipa.5.xml           | 10 ++++--
- src/providers/dp_dyndns.c        |  6 ++++
- src/providers/dp_dyndns.h        |  4 +++
- src/providers/ldap/sdap_dyndns.c | 72 +++++++++++++++++++++++++++++++++++-----
- 5 files changed, 87 insertions(+), 16 deletions(-)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 938a443e027b9bf83c75c240a7d6b2a0876b92c8..ff43ea37066514a87934d07b141e680416dcc05b 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -754,15 +754,16 @@ ad_gpo_map_deny = +my_pam_service
-                     <listitem>
-                         <para>
-                             Optional. Applicable only when dyndns_update
--                            is true. Choose the interface whose IP address
--                            should be used for dynamic DNS updates.
--                        </para>
--                        <para>
--                            NOTE: This option currently supports only one interface.
-+                            is true. Choose the interface or a list of interfaces
-+                            whose IP addresses should be used for dynamic DNS
-+                            updates.
-                         </para>
-                         <para>
-                             Default: Use the IP address of the AD LDAP connection
-                         </para>
-+                        <para>
-+                            Example: dyndns_iface = em1, vnet1, vnet2
-+                        </para>
-                     </listitem>
-                 </varlistentry>
- 
-diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
-index 0716b6235f93965170983856b930799bfded6258..d450c2fadbb1713096ff766bf536702195cfd137 100644
---- a/src/man/sssd-ipa.5.xml
-+++ b/src/man/sssd-ipa.5.xml
-@@ -166,11 +166,12 @@
-                     <listitem>
-                         <para>
-                             Optional. Applicable only when dyndns_update
--                            is true. Choose the interface whose IP address
--                            should be used for dynamic DNS updates.
-+                            is true. Choose the interface or a list of interfaces
-+                            whose IP addresses should be used for dynamic DNS
-+                            updates.
-                         </para>
-                         <para>
--                            NOTE: This option currently supports only one interface.
-+                            NOTE: This option currently supports multiple interfaces.
-                         </para>
-                         <para>
-                             NOTE: While it is still possible to use the old
-@@ -181,6 +182,9 @@
-                         <para>
-                             Default: Use the IP address of the IPA LDAP connection
-                         </para>
-+                        <para>
-+                            Example: dyndns_iface = em1, vnet1, vnet2
-+                        </para>
-                     </listitem>
-                 </varlistentry>
- 
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 2ac43a108ff6197d9e2662198a6da976ca348e76..76562840ef1d427629e41617b871caaedab779d4 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -49,6 +49,12 @@ struct sss_iface_addr {
-     struct sockaddr_storage *addr;
- };
- 
-+void sss_iface_addr_concatenate(struct sss_iface_addr **list,
-+                                struct sss_iface_addr *list2)
-+{
-+    DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
-+}
-+
- struct sss_iface_addr *
- sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
-                    struct sockaddr_storage *ss)
-diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
-index 23b833dace58a0ecbb1e2e21963a55186f1d06a8..deba112538ad22cd7f59be07934778ee9d4361e7 100644
---- a/src/providers/dp_dyndns.h
-+++ b/src/providers/dp_dyndns.h
-@@ -128,4 +128,8 @@ nsupdate_get_addrs_recv(struct tevent_req *req,
-                         struct sss_iface_addr **_addrlist,
-                         size_t *_count);
- 
-+void
-+sss_iface_addr_concatenate(struct sss_iface_addr **list,
-+                           struct sss_iface_addr *list2);
-+
- #endif /* DP_DYNDNS_H_ */
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index e99a4f6687035928f6775c38b9df6b2a06d38f38..f5929cff3db6f724efcedeb963e3a12d04f6e1d3 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -482,6 +482,65 @@ static void sdap_dyndns_get_addrs_done(struct tevent_req *subreq);
- static errno_t sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
-                                          struct sdap_handle *sh);
- 
-+static errno_t get_ifaces_addrs(TALLOC_CTX *mem_ctx,
-+                                const char *iface,
-+                                struct sss_iface_addr **_result)
-+{
-+    struct sss_iface_addr *result_addrs = NULL;
-+    struct sss_iface_addr *intf_addrs;
-+    TALLOC_CTX *tmp_ctx;
-+    char **list_of_intfs;
-+    int num_of_intfs;
-+    errno_t ret;
-+    int i;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = split_on_separator(tmp_ctx, iface, ',', true, true, &list_of_intfs,
-+                             &num_of_intfs);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Parsing names of interfaces failed - %d:[%s].\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    for (i = 0; i < num_of_intfs; i++) {
-+        ret = sss_iface_addr_list_get(tmp_ctx, list_of_intfs[i], &intf_addrs);
-+        if (ret == EOK) {
-+            if (result_addrs != NULL) {
-+                /* If there is already an existing list, head of this existing
-+                 * list will be considered as parent talloc context for the
-+                 * new list.
-+                 */
-+                talloc_steal(result_addrs, intf_addrs);
-+            }
-+            sss_iface_addr_concatenate(&result_addrs, intf_addrs);
-+        } else if (ret == ENOENT) {
-+            /* non-critical failure */
-+            DEBUG(SSSDBG_TRACE_FUNC,
-+                  "Cannot get interface %s or there are no addresses "
-+                  "bind to it.\n", list_of_intfs[i]);
-+        } else {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Cannot get list of addresses from interface %s - %d:[%s]\n",
-+                  list_of_intfs[i], ret, sss_strerror(ret));
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+    *_result = talloc_steal(mem_ctx, result_addrs);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
- static struct tevent_req *
- sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
-                            struct tevent_context *ev,
-@@ -500,14 +559,11 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
-     }
- 
-     if (iface) {
--        ret = sss_iface_addr_list_get(state, iface, &state->addresses);
--        if (ret != EOK) {
--            DEBUG(ret == ENOENT ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE,
--                  "Cannot get list of addresses from interface %s\n", iface);
--            /* non critical failure */
--            if (ret == ENOENT) {
--                ret = EOK;
--            }
-+        ret = get_ifaces_addrs(state, iface, &state->addresses);
-+        if (ret != EOK || state->addresses == NULL) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  "get_ifaces_addrs() failed: %d:[%s]\n",
-+                  ret, sss_strerror(ret));
-         }
-         /* We're done. Just fake an async request completion */
-         goto done;
--- 
-2.4.3
-
diff --git a/SOURCES/0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch b/SOURCES/0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch
new file mode 100644
index 0000000..cdc951f
--- /dev/null
+++ b/SOURCES/0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch
@@ -0,0 +1,41 @@
+From 0686ce29cadb7875638d5f782199ea4bb186dee3 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 12 Jul 2016 16:14:04 +0200
+Subject: [PATCH 16/18] PROVIDERS: Setting right {u,g}id if unprivileged
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+be_ctx had talloc_zero() initialized uid and gid which was used
+in function dp_init(). Therefore back-end was every time started as root
+and therefore non-root responders could not communicate with back-end
+due to wrong permission of unix sockets.
+
+This patch sets right uid and gid to data-providers if sssd runs
+as non-root user.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3077
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 75dead699a19dda7d8dfca89e2f97efbf0c264a2)
+---
+ src/providers/data_provider_be.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 78efed851b2bf053ba890caa05e655431996892a..2ae713054429e789c1ba79c1f5e7a3889af3b291 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -386,6 +386,8 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx,
+ 
+     be_ctx->ev = ev;
+     be_ctx->cdb = cdb;
++    be_ctx->uid = uid;
++    be_ctx->gid = gid;
+     be_ctx->identity = talloc_asprintf(be_ctx, "%%BE_%s", be_domain);
+     be_ctx->conf_path = talloc_asprintf(be_ctx, CONFDB_DOMAIN_PATH_TMPL, be_domain);
+     if (be_ctx->identity == NULL || be_ctx->conf_path == NULL) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0017-DYNDNS-special-value-for-dyndns_iface-option.patch b/SOURCES/0017-DYNDNS-special-value-for-dyndns_iface-option.patch
deleted file mode 100644
index c7f7abc..0000000
--- a/SOURCES/0017-DYNDNS-special-value-for-dyndns_iface-option.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From 65976fe3f9db1fc9581bb00060be38c48512b672 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Tue, 14 Jul 2015 04:21:34 -0400
-Subject: [PATCH 17/19] DYNDNS: special value '*' for dyndns_iface option
-
-Option dyndns_iface has now special value '*' which implies that IPs
-from add interfaces should be sent during DDNS update.
----
- src/man/sssd-ad.5.xml     |  6 ++++--
- src/man/sssd-ipa.5.xml    |  9 ++++-----
- src/providers/dp_dyndns.c | 20 ++++++++++++++++----
- 3 files changed, 24 insertions(+), 11 deletions(-)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index ff43ea37066514a87934d07b141e680416dcc05b..3cbc10520098372d984d00425d03832d002d6672 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -756,10 +756,12 @@ ad_gpo_map_deny = +my_pam_service
-                             Optional. Applicable only when dyndns_update
-                             is true. Choose the interface or a list of interfaces
-                             whose IP addresses should be used for dynamic DNS
--                            updates.
-+                            updates. Special value <quote>*</quote> implies that
-+                            IPs from all interfaces should be used.
-                         </para>
-                         <para>
--                            Default: Use the IP address of the AD LDAP connection
-+                            Default: Use the IP addresses of the interface which
-+                            is used for AD LDAP connection
-                         </para>
-                         <para>
-                             Example: dyndns_iface = em1, vnet1, vnet2
-diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
-index d450c2fadbb1713096ff766bf536702195cfd137..2e985991fde10827aff0e7c8e67f29a009683450 100644
---- a/src/man/sssd-ipa.5.xml
-+++ b/src/man/sssd-ipa.5.xml
-@@ -168,10 +168,8 @@
-                             Optional. Applicable only when dyndns_update
-                             is true. Choose the interface or a list of interfaces
-                             whose IP addresses should be used for dynamic DNS
--                            updates.
--                        </para>
--                        <para>
--                            NOTE: This option currently supports multiple interfaces.
-+                            updates. Special value <quote>*</quote> implies that
-+                            IPs from all interfaces should be used.
-                         </para>
-                         <para>
-                             NOTE: While it is still possible to use the old
-@@ -180,7 +178,8 @@
-                             in their config file.
-                         </para>
-                         <para>
--                            Default: Use the IP address of the IPA LDAP connection
-+                            Default: Use the IP addresses of the interface which
-+                            is used for IPA LDAP connection
-                         </para>
-                         <para>
-                             Example: dyndns_iface = em1, vnet1, vnet2
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 76562840ef1d427629e41617b871caaedab779d4..03389acfba13e566540ca8b0570c0d009173575f 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -42,6 +42,9 @@
- #define DYNDNS_TIMEOUT 15
- #endif /* DYNDNS_TIMEOUT */
- 
-+/* MASK represents special value for matching all interfaces */
-+#define MASK "*"
-+
- struct sss_iface_addr {
-     struct sss_iface_addr *next;
-     struct sss_iface_addr *prev;
-@@ -171,6 +174,16 @@ ok_for_dns(struct sockaddr *sa)
-     return true;
- }
- 
-+static bool supported_address_family(sa_family_t sa_family)
-+{
-+    return sa_family == AF_INET || sa_family == AF_INET6;
-+}
-+
-+static bool matching_name(const char *ifname, const char *ifname2)
-+{
-+    return (strcmp(MASK, ifname) == 0) || (strcasecmp(ifname, ifname2) == 0);
-+}
-+
- /* Collect IP addresses associated with an interface */
- errno_t
- sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
-@@ -200,10 +213,9 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
-         if (!ifa->ifa_addr) continue;
- 
-         /* Add IP addresses to the list */
--        if ((ifa->ifa_addr->sa_family == AF_INET ||
--             ifa->ifa_addr->sa_family == AF_INET6) &&
--             strcasecmp(ifa->ifa_name, ifname) == 0 &&
--             ok_for_dns(ifa->ifa_addr)) {
-+        if (supported_address_family(ifa->ifa_addr->sa_family)
-+                && matching_name(ifname, ifa->ifa_name)
-+                && ok_for_dns(ifa->ifa_addr)) {
- 
-             /* Add this address to the IP address list */
-             address = talloc_zero(mem_ctx, struct sss_iface_addr);
--- 
-2.4.3
-
diff --git a/SOURCES/0017-config-Allow-timeout-for-all-sevices.patch b/SOURCES/0017-config-Allow-timeout-for-all-sevices.patch
new file mode 100644
index 0000000..fae8cf5
--- /dev/null
+++ b/SOURCES/0017-config-Allow-timeout-for-all-sevices.patch
@@ -0,0 +1,117 @@
+From 18b2f16e2b086509cafb453943387fff2d1b0d19 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 11 Jul 2016 13:03:28 +0200
+Subject: [PATCH 17/18] config: Allow timeout for all sevices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Allow option "timeout" for all sevices.
+Also remove unused macro CONFDB_SERVICE_TIMEOUT.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3068
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 1b9b5477027d86a2afb2e72981253d108c5398da)
+---
+ src/confdb/confdb.h          | 1 -
+ src/config/cfg_rules.ini     | 7 +++++++
+ src/config/etc/sssd.api.conf | 2 +-
+ 3 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index 54b1cbc82546a76013c35c6cd3b1924663e9bb23..cc8f66f02eb5ac10ced826326f80bbf5eda82ee1 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -58,7 +58,6 @@
+ #define CONFDB_SERVICE_DEBUG_TIMESTAMPS "debug_timestamps"
+ #define CONFDB_SERVICE_DEBUG_MICROSECONDS "debug_microseconds"
+ #define CONFDB_SERVICE_DEBUG_TO_FILES "debug_to_files"
+-#define CONFDB_SERVICE_TIMEOUT "timeout"
+ #define CONFDB_SERVICE_FORCE_TIMEOUT "force_timeout"
+ #define CONFDB_SERVICE_RECON_RETRIES "reconnection_retries"
+ #define CONFDB_SERVICE_FD_LIMIT "fd_limit"
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 85a15be3493cf4b8c5a612b0f66ae4c86d39b1ab..5c8d05a817331dd23fd7e349719bd4b44a5bdd02 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -44,6 +44,7 @@ option = override_space
+ validator = ini_allowed_options
+ section_re = ^nss$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+@@ -82,6 +83,7 @@ option = memcache_timeout
+ validator = ini_allowed_options
+ section_re = ^pam$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+@@ -115,6 +117,7 @@ option = p11_child_timeout
+ validator = ini_allowed_options
+ section_re = ^sudo$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+@@ -136,6 +139,7 @@ option = sudo_inverse_order
+ validator = ini_allowed_options
+ section_re = ^autofs$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+@@ -156,6 +160,7 @@ option = autofs_negative_timeout
+ validator = ini_allowed_options
+ section_re = ^ssh$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+@@ -178,6 +183,7 @@ option = ca_db
+ validator = ini_allowed_options
+ section_re = ^pac$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+@@ -199,6 +205,7 @@ option = pac_lifetime
+ validator = ini_allowed_options
+ section_re = ^ifp$
+ 
++option = timeout
+ option = debug
+ option = debug_level
+ option = debug_timestamps
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index 2d7c5049f5e5bf9df6e5445ee6e5c62211bf1c45..e4011a384cdb3fb3bce93494cbb278ec2622ee40 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -3,6 +3,7 @@
+ 
+ [service]
+ # Options available to all services
++timeout = int, None, false
+ debug = int, None, false
+ debug_level = int, None, false
+ debug_timestamps = bool, None, false
+@@ -20,7 +21,6 @@ diag_cmd = str, None, false
+ # Monitor service
+ services = list, str, true, nss, pam
+ domains = list, str, true
+-timeout = int, None, false
+ sbus_timeout = int, None, false
+ re_expression = str, None, false
+ full_name_format = str, None, false
+-- 
+2.4.11
+
diff --git a/SOURCES/0018-TESTS-dyndns-tests-support-AAAA-addresses.patch b/SOURCES/0018-TESTS-dyndns-tests-support-AAAA-addresses.patch
deleted file mode 100644
index aa8f434..0000000
--- a/SOURCES/0018-TESTS-dyndns-tests-support-AAAA-addresses.patch
+++ /dev/null
@@ -1,130 +0,0 @@
-From 73047b51048037689b21925f7d480ffd72a50485 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Wed, 15 Jul 2015 10:58:38 -0400
-Subject: [PATCH 18/19] TESTS: dyndns tests support AAAA addresses
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2558
----
- src/tests/cmocka/test_dyndns.c | 51 +++++++++++++++++++++++++++++++-----------
- 1 file changed, 38 insertions(+), 13 deletions(-)
-
-diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
-index 3214e90c063ea9a4cf6f6bc6507bf4e37b7d23a4..e9d42cea37472b38ae2eb900368f2ce3f409fefc 100644
---- a/src/tests/cmocka/test_dyndns.c
-+++ b/src/tests/cmocka/test_dyndns.c
-@@ -97,7 +97,9 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap)
-     struct ifaddrs *ifap_head = NULL;
-     char *name;
-     char *straddr;
-+    int ad_family;
-     struct sockaddr_in *sa;
-+    void *dst;
- 
-     while ((name = sss_mock_ptr_type(char *)) != NULL) {
-         straddr = sss_mock_ptr_type(char *);
-@@ -105,6 +107,7 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap)
-             errno = EINVAL;
-             goto fail;
-         }
-+        ad_family = sss_mock_type(int);
- 
-         ifap = talloc_zero(global_mock_context, struct ifaddrs);
-         if (ifap == NULL) {
-@@ -127,15 +130,33 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap)
- 
-         /* Do not alocate directly on ifap->ifa_addr to
-          * avoid alignment warnings */
--        sa = talloc(ifap, struct sockaddr_in);
-+        if (ad_family == AF_INET) {
-+            sa = talloc(ifap, struct sockaddr_in);
-+        } else if (ad_family == AF_INET6) {
-+            sa = (struct sockaddr_in *) talloc(ifap, struct sockaddr_in6);
-+        } else {
-+            errno = EINVAL;
-+            goto fail;
-+        }
-+
-         if (sa == NULL) {
-             errno = ENOMEM;
-             goto fail;
-         }
--        sa->sin_family = AF_INET;
-+
-+        sa->sin_family = ad_family;
-+
-+        if (ad_family == AF_INET) {
-+            dst = &sa->sin_addr;
-+        } else if (ad_family == AF_INET6) {
-+            dst = &((struct sockaddr_in6 *)sa)->sin6_addr;
-+        } else {
-+            errno = EINVAL;
-+            goto fail;
-+        }
- 
-         /* convert straddr into ifa_addr */
--        if (inet_pton(AF_INET, straddr, &sa->sin_addr) != 1) {
-+        if (inet_pton(ad_family, straddr, dst) != 1) {
-             goto fail;
-         }
- 
-@@ -167,12 +188,16 @@ static void dyndns_test_done(struct tevent_req *req)
-     ctx->tctx->done = true;
- }
- 
--void will_return_getifaddrs(const char *ifname, const char *straddr)
-+void will_return_getifaddrs(const char *ifname, const char *straddr,
-+                            int af_family)
- {
-     will_return(__wrap_getifaddrs, ifname);
-     if (ifname) {
-         will_return(__wrap_getifaddrs, straddr);
-     }
-+    if (straddr) {
-+        will_return(__wrap_getifaddrs, af_family);
-+    }
- }
- 
- void dyndns_test_get_ifaddr(void **state)
-@@ -182,9 +207,9 @@ void dyndns_test_get_ifaddr(void **state)
-     char straddr[128];
- 
-     check_leaks_push(dyndns_test_ctx);
--    will_return_getifaddrs("eth0", "192.168.0.1");
--    will_return_getifaddrs("eth1", "192.168.0.2");
--    will_return_getifaddrs(NULL, NULL); /* sentinel */
-+    will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
-+    will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
-+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
-     ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
-     assert_int_equal(ret, EOK);
- 
-@@ -212,9 +237,9 @@ void dyndns_test_get_multi_ifaddr(void **state)
-     char straddr[128];
- 
-     check_leaks_push(dyndns_test_ctx);
--    will_return_getifaddrs("eth0", "192.168.0.2");
--    will_return_getifaddrs("eth0", "192.168.0.1");
--    will_return_getifaddrs(NULL, NULL); /* sentinel */
-+    will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
-+    will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
-+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
-     ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
-     assert_int_equal(ret, EOK);
- 
-@@ -253,9 +278,9 @@ void dyndns_test_get_ifaddr_enoent(void **state)
-     struct sss_iface_addr *addrlist = NULL;
- 
-     check_leaks_push(dyndns_test_ctx);
--    will_return_getifaddrs("eth0", "192.168.0.1");
--    will_return_getifaddrs("eth1", "192.168.0.2");
--    will_return_getifaddrs(NULL, NULL); /* sentinel */
-+    will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
-+    will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
-+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
-     ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface",
-                                   &addrlist);
-     assert_int_equal(ret, ENOENT);
--- 
-2.4.3
-
diff --git a/SOURCES/0018-config-Add-config_file_version-to-schema.patch b/SOURCES/0018-config-Add-config_file_version-to-schema.patch
new file mode 100644
index 0000000..3d47710
--- /dev/null
+++ b/SOURCES/0018-config-Add-config_file_version-to-schema.patch
@@ -0,0 +1,58 @@
+From 5e8d4f0107c5e6f1836740945b610a54c216bd7f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 11 Jul 2016 13:34:03 +0200
+Subject: [PATCH 18/18] config: Add config_file_version to schema
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3068
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit aeab20358006d728a284f969f92f3890498cd651)
+---
+ src/config/SSSDConfigTest.py | 1 +
+ src/config/cfg_rules.ini     | 1 +
+ src/config/etc/sssd.api.conf | 1 +
+ 3 files changed, 3 insertions(+)
+
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 5fa9bce8e6502c0ebf42671058c5e3d5de00ea0d..332d8702d983b6ec8bf12ec781a1bbf296b552e0 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -289,6 +289,7 @@ class SSSDConfigTestSSSDService(unittest.TestCase):
+ 
+         options = service.list_options()
+         control_list = [
++            'config_file_version',
+             'services',
+             'domains',
+             'timeout',
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 5c8d05a817331dd23fd7e349719bd4b44a5bdd02..635c078436e8ca47f60e8d82341cb131469fe4c9 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -39,6 +39,7 @@ option = user
+ option = default_domain_suffix
+ option = certificate_verification
+ option = override_space
++option = config_file_version
+ 
+ [rule/allowed_nss_options]
+ validator = ini_allowed_options
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index e4011a384cdb3fb3bce93494cbb278ec2622ee40..737f0e149d56bd07b078cb83acbc43ea2ed3a057 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -19,6 +19,7 @@ diag_cmd = str, None, false
+ 
+ [sssd]
+ # Monitor service
++config_file_version = int, None, false
+ services = list, str, true, nss, pam
+ domains = list, str, true
+ sbus_timeout = int, None, false
+-- 
+2.4.11
+
diff --git a/SOURCES/0019-DYNDNS-support-for-dualstack.patch b/SOURCES/0019-DYNDNS-support-for-dualstack.patch
deleted file mode 100644
index 75f53f2..0000000
--- a/SOURCES/0019-DYNDNS-support-for-dualstack.patch
+++ /dev/null
@@ -1,437 +0,0 @@
-From 856cb96e313c164aa80915410ba758ad21cb6173 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Tue, 14 Jul 2015 09:56:59 -0400
-Subject: [PATCH 19/19] DYNDNS: support for dualstack
-
-When dyndns_iface option was not used, address of connection to LDAP
-was used. This patch proposes following change:
-  * Interface containing address of connection is found.
-  * All A and AAAA addresses of this interface are collected.
-  * Collected addresses are sent during DDNS update.
-  * Function sss_iface_addr_add() is removed.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2558
----
- src/providers/dp_dyndns.c        | 135 +++++++++++++++++++++++------
- src/providers/dp_dyndns.h        |   8 +-
- src/providers/ldap/sdap_dyndns.c |  20 ++---
- src/tests/cmocka/test_dyndns.c   | 178 +++++++++++++++++++++++++++++++++++++++
- 4 files changed, 302 insertions(+), 39 deletions(-)
-
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 03389acfba13e566540ca8b0570c0d009173575f..c254d78936f412626db0533f559350de57017618 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -58,31 +58,6 @@ void sss_iface_addr_concatenate(struct sss_iface_addr **list,
-     DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
- }
- 
--struct sss_iface_addr *
--sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
--                   struct sockaddr_storage *ss)
--{
--    struct sss_iface_addr *address;
--
--    address = talloc(mem_ctx, struct sss_iface_addr);
--    if (address == NULL) {
--        return NULL;
--    }
--
--    address->addr = talloc_memdup(address, ss,
--                                  sizeof(struct sockaddr_storage));
--    if(address->addr == NULL) {
--        talloc_zfree(address);
--        return NULL;
--    }
--
--    /* steal old dlist to the new head */
--    talloc_steal(address, *list);
--    DLIST_ADD(*list, address);
--
--    return address;
--}
--
- errno_t
- sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
-                                 struct sss_iface_addr *ifaddr_list,
-@@ -1258,3 +1233,113 @@ errno_t be_nsupdate_init_timer(struct be_nsupdate_ctx *ctx,
- 
-     return ERR_OK;
- }
-+
-+static bool match_ip(const struct sockaddr *sa,
-+                     const struct sockaddr *sb)
-+{
-+    size_t addrsize;
-+    bool res;
-+    const void *addr_a;
-+    const void *addr_b;
-+
-+    if (sa->sa_family == AF_INET) {
-+        addrsize = sizeof(struct in_addr);
-+        addr_a = (const void *) &((const struct sockaddr_in *) sa)->sin_addr;
-+        addr_b = (const void *) &((const struct sockaddr_in *) sb)->sin_addr;
-+    } else if (sa->sa_family == AF_INET6) {
-+        addrsize = sizeof(struct in6_addr);
-+        addr_a = (const void *) &((const struct sockaddr_in6 *) sa)->sin6_addr;
-+        addr_b = (const void *) &((const struct sockaddr_in6 *) sb)->sin6_addr;
-+    } else {
-+        res = false;
-+        goto done;
-+    }
-+
-+    if (sa->sa_family != sb->sa_family) {
-+        res = false;
-+        goto done;
-+    }
-+
-+    res = memcmp(addr_a, addr_b, addrsize) == 0;
-+
-+done:
-+    return res;
-+}
-+
-+static errno_t find_iface_by_addr(TALLOC_CTX *mem_ctx,
-+                                  const struct sockaddr *ss,
-+                                  const char **_iface_name)
-+{
-+    struct ifaddrs *ifaces = NULL;
-+    struct ifaddrs *ifa;
-+    errno_t ret;
-+
-+    ret = getifaddrs(&ifaces);
-+    if (ret == -1) {
-+        ret = errno;
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not read interfaces [%d][%s]\n", ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
-+
-+        /* Some interfaces don't have an ifa_addr */
-+        if (!ifa->ifa_addr) continue;
-+
-+        if (match_ip(ss, ifa->ifa_addr)) {
-+            const char *iface_name;
-+            iface_name = talloc_strdup(mem_ctx, ifa->ifa_name);
-+            if (iface_name == NULL) {
-+                ret = ENOMEM;
-+            } else {
-+                *_iface_name = iface_name;
-+                ret = EOK;
-+            }
-+            goto done;
-+        }
-+    }
-+    ret = ENOENT;
-+
-+done:
-+    freeifaddrs(ifaces);
-+    return ret;
-+}
-+
-+errno_t sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
-+                                    struct sockaddr *ss,
-+                                    struct sss_iface_addr **_iface_addrs)
-+{
-+    struct sss_iface_addr *iface_addrs;
-+    const char *iface_name = NULL;
-+    TALLOC_CTX *tmp_ctx;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = find_iface_by_addr(tmp_ctx, ss, &iface_name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, "find_iface_by_addr failed: %d:[%s]\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = sss_iface_addr_list_get(tmp_ctx, iface_name, &iface_addrs);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "sss_iface_addr_list_get failed: %d:[%s]\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+    *_iface_addrs = talloc_steal(mem_ctx, iface_addrs);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
-index deba112538ad22cd7f59be07934778ee9d4361e7..a8a20ec6f8a1a63cd8c85aaec3f54f9fddb42049 100644
---- a/src/providers/dp_dyndns.h
-+++ b/src/providers/dp_dyndns.h
-@@ -81,10 +81,6 @@ errno_t
- sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
-                         struct sss_iface_addr **_addrlist);
- 
--struct sss_iface_addr *
--sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
--                   struct sockaddr_storage *ss);
--
- errno_t
- sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
-                                 struct sss_iface_addr *ifaddr_list,
-@@ -132,4 +128,8 @@ void
- sss_iface_addr_concatenate(struct sss_iface_addr **list,
-                            struct sss_iface_addr *list2);
- 
-+errno_t
-+sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
-+                            struct sockaddr *ss,
-+                            struct sss_iface_addr **_iface_addrs);
- #endif /* DP_DYNDNS_H_ */
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index f5929cff3db6f724efcedeb963e3a12d04f6e1d3..a463a2fce08f42b325010cd37c501ef23aee173f 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -644,7 +644,6 @@ sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
- {
-     int ret;
-     int fd;
--    struct sss_iface_addr *address;
-     struct sockaddr_storage ss;
-     socklen_t ss_len = sizeof(ss);
- 
-@@ -666,20 +665,21 @@ sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
-         return ret;
-     }
- 
--    switch(ss.ss_family) {
--    case AF_INET:
--    case AF_INET6:
--        address = sss_iface_addr_add(state, &state->addresses, &ss);
--        if (address == NULL) {
--            return ENOMEM;
--        }
--        break;
--    default:
-+    if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "Connection to LDAP is neither IPv4 nor IPv6\n");
-         return EIO;
-     }
- 
-+    ret = sss_get_dualstack_addresses(state, (struct sockaddr *) &ss,
-+                                      &state->addresses);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "sss_get_dualstack_addresses failed: %d:[%s]\n",
-+              ret, sss_strerror(ret));
-+        return ret;
-+    }
-+
-     return EOK;
- }
- 
-diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
-index e9d42cea37472b38ae2eb900368f2ce3f409fefc..8118e9438e89465674155c11f4523d2313f6a59c 100644
---- a/src/tests/cmocka/test_dyndns.c
-+++ b/src/tests/cmocka/test_dyndns.c
-@@ -289,6 +289,173 @@ void dyndns_test_get_ifaddr_enoent(void **state)
-     assert_true(check_leaks_pop(dyndns_test_ctx) == true);
- }
- 
-+void dyndns_test_dualstack(void **state)
-+{
-+    errno_t ret;
-+    struct sss_iface_addr *addrlist;
-+    struct sss_iface_addr *sss_if_addrs;
-+    char straddr[128];
-+    int i;
-+
-+    check_leaks_push(dyndns_test_ctx);
-+
-+    /* getifaddrs is called twice in sss_get_dualstack_addresses() */
-+    for (i = 0; i < 2; i++) {
-+        will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
-+        will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
-+        will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
-+        will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
-+        will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
-+    }
-+
-+    struct sockaddr_in sin;
-+    memset (&sin, 0, sizeof (sin));
-+    sin.sin_family = AF_INET;
-+    sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
-+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
-+                                      (struct sockaddr *) &sin,
-+                                      &addrlist);
-+    assert_int_equal(ret, EOK);
-+
-+    sss_if_addrs = addrlist;
-+    assert_non_null(sss_if_addrs);
-+    assert_non_null(sss_if_addrs->addr);
-+    assert_non_null(sss_if_addrs->next);
-+    assert_null(sss_if_addrs->prev);
-+
-+    assert_non_null(inet_ntop(AF_INET6,
-+                              &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
-+                              straddr, INET6_ADDRSTRLEN));
-+    /* ip addresses are returned in different order */
-+    assert_string_equal(straddr, "2001:cdba::555");
-+
-+    sss_if_addrs = addrlist->next;
-+    assert_non_null(sss_if_addrs);
-+    assert_non_null(sss_if_addrs->addr);
-+    assert_null(sss_if_addrs->next);
-+    assert_non_null(sss_if_addrs->prev);
-+
-+    assert_non_null(inet_ntop(AF_INET,
-+                              &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
-+                              straddr, INET_ADDRSTRLEN));
-+    /* ip addresses are returned in different order */
-+    assert_string_equal(straddr, "192.168.0.2");
-+
-+    talloc_free(addrlist);
-+
-+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
-+}
-+
-+void dyndns_test_dualstack_multiple_addresses(void **state)
-+{
-+    errno_t ret;
-+    struct sss_iface_addr *addrlist;
-+    struct sss_iface_addr *sss_if_addrs;
-+    char straddr[128];
-+    int i;
-+
-+    check_leaks_push(dyndns_test_ctx);
-+
-+    /* getifaddrs is called twice in sss_get_dualstack_addresses() */
-+    for (i = 0; i < 2; i++) {
-+        will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
-+        will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
-+        /* loopback - invalid for dns (should be skipped) */
-+        will_return_getifaddrs("eth0", "::1", AF_INET6);
-+        /* linklocal - invalid for dns (should be skipped) */
-+        will_return_getifaddrs("eth0", "fe80::5054:ff:fe4a:65ae", AF_INET6);
-+        will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
-+        will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
-+        will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
-+    }
-+
-+    struct sockaddr_in sin;
-+    memset (&sin, 0, sizeof (sin));
-+    sin.sin_family = AF_INET;
-+    sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
-+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
-+                                      (struct sockaddr *) &sin,
-+                                      &addrlist);
-+    assert_int_equal(ret, EOK);
-+
-+    sss_if_addrs = addrlist;
-+    assert_non_null(sss_if_addrs);
-+    assert_non_null(sss_if_addrs->addr);
-+    assert_non_null(sss_if_addrs->next);
-+    assert_null(sss_if_addrs->prev);
-+
-+    assert_non_null(inet_ntop(AF_INET6,
-+                              &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
-+                              straddr, INET6_ADDRSTRLEN));
-+    /* ip addresses are returned in different order */
-+    assert_string_equal(straddr, "2001:cdba::444");
-+
-+    sss_if_addrs = sss_if_addrs->next;
-+    assert_non_null(sss_if_addrs);
-+    assert_non_null(sss_if_addrs->addr);
-+    assert_non_null(sss_if_addrs->prev);
-+    assert_non_null(sss_if_addrs->next);
-+
-+    assert_non_null(inet_ntop(AF_INET6,
-+                              &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
-+                              straddr, INET6_ADDRSTRLEN));
-+    /* ip addresses are returned in different order */
-+    assert_string_equal(straddr, "2001:cdba::555");
-+
-+    sss_if_addrs = sss_if_addrs->next;
-+    assert_non_null(sss_if_addrs);
-+    assert_non_null(sss_if_addrs->addr);
-+    assert_non_null(sss_if_addrs->next);
-+    assert_non_null(sss_if_addrs->prev);
-+
-+    assert_non_null(inet_ntop(AF_INET,
-+                              &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
-+                              straddr, INET_ADDRSTRLEN));
-+    /* ip addresses are returned in different order */
-+    assert_string_equal(straddr, "192.168.0.1");
-+
-+    sss_if_addrs = sss_if_addrs->next;
-+    assert_non_null(sss_if_addrs);
-+    assert_non_null(sss_if_addrs->addr);
-+    assert_null(sss_if_addrs->next);
-+    assert_non_null(sss_if_addrs->prev);
-+
-+    assert_non_null(inet_ntop(AF_INET,
-+                              &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
-+                              straddr, INET_ADDRSTRLEN));
-+    /* ip addresses are returned in different order */
-+    assert_string_equal(straddr, "192.168.0.2");
-+
-+    talloc_free(addrlist);
-+
-+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
-+}
-+
-+void dyndns_test_dualstack_no_iface(void **state)
-+{
-+    errno_t ret;
-+    struct sss_iface_addr *addrlist;
-+
-+    check_leaks_push(dyndns_test_ctx);
-+
-+    will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
-+    will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
-+    will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
-+    will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
-+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
-+
-+    struct sockaddr_in sin;
-+    memset (&sin, 0, sizeof (sin));
-+    sin.sin_family = AF_INET;
-+    sin.sin_addr.s_addr = inet_addr ("192.168.0.3");
-+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
-+                                      (struct sockaddr *) &sin,
-+                                      &addrlist);
-+    assert_int_equal(ret, ENOENT);
-+
-+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
-+}
-+
- void dyndns_test_ok(void **state)
- {
-     struct tevent_req *req;
-@@ -519,6 +686,17 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(dyndns_test_interval,
-                                         dyndns_test_setup,
-                                         dyndns_test_teardown),
-+
-+        /* Dynamic DNS dualstack unit tests*/
-+        cmocka_unit_test_setup_teardown(dyndns_test_dualstack,
-+                                        dyndns_test_simple_setup,
-+                                        dyndns_test_teardown),
-+        cmocka_unit_test_setup_teardown(dyndns_test_dualstack_multiple_addresses,
-+                                        dyndns_test_simple_setup,
-+                                        dyndns_test_teardown),
-+        cmocka_unit_test_setup_teardown(dyndns_test_dualstack_no_iface,
-+                                        dyndns_test_simple_setup,
-+                                        dyndns_test_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.4.3
-
diff --git a/SOURCES/0019-dyndns-Add-checks-for-NULL.patch b/SOURCES/0019-dyndns-Add-checks-for-NULL.patch
new file mode 100644
index 0000000..f038acd
--- /dev/null
+++ b/SOURCES/0019-dyndns-Add-checks-for-NULL.patch
@@ -0,0 +1,57 @@
+From b0330a760d838b30c88d6f02f0148b84093761c3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Tue, 12 Jul 2016 12:11:18 +0200
+Subject: [PATCH 19/19] dyndns: Add checks for NULL
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixes:
+https://fedorahosted.org/sssd/ticket/3076
+
+We segfaulted in this area once. This patch
+makes the code more defensive and adds
+some DEBUG messages.
+
+Normally the structures are filled in online
+and/or resolve callbacks.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ipa/ipa_dyndns.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
+index 7217c61452e7ead2949a9f7d57b2f2fc58953af1..dc910770c771d4b7a7ee62d25be7c48e16c988a7 100644
+--- a/src/providers/ipa/ipa_dyndns.c
++++ b/src/providers/ipa/ipa_dyndns.c
+@@ -162,6 +162,26 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
+     }
+     state->ipa_ctx = ctx;
+ 
++    /* The following three checks are here to prevent SEGFAULT
++     * from ticket #3076. */
++    if (ctx->service == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "service structure not initialized\n");
++        ret = EINVAL;
++        goto done;
++    }
++
++    if (ctx->service->sdap == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "sdap structure not initialized\n");
++        ret = EINVAL;
++        goto done;
++    }
++
++    if (ctx->service->sdap->uri == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "LDAP uri not set\n");
++        ret = EINVAL;
++        goto done;
++    }
++
+     if (ctx->dyndns_ctx->last_refresh + 60 > time(NULL) ||
+         ctx->dyndns_ctx->timer_in_progress) {
+         DEBUG(SSSDBG_FUNC_DATA, "Last periodic update ran recently or timer "
+-- 
+2.4.11
+
diff --git a/SOURCES/0020-VIEWS-TEST-add-null-check.patch b/SOURCES/0020-VIEWS-TEST-add-null-check.patch
deleted file mode 100644
index 912c030..0000000
--- a/SOURCES/0020-VIEWS-TEST-add-null-check.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 681fd36964b873135b2b8dd5200ddcfd1e420214 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Mon, 27 Jul 2015 17:24:45 +0200
-Subject: [PATCH 20/23] VIEWS TEST: add null-check
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tests/cmocka/test_sysdb_views.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
-index 1fb598219e9ee581e465ddbb32ba9f2544600c26..123d4c5cb613f41e1bca9e89feed701a1e86f8d3 100644
---- a/src/tests/cmocka/test_sysdb_views.c
-+++ b/src/tests/cmocka/test_sysdb_views.c
-@@ -225,10 +225,12 @@ void test_sysdb_add_overrides_to_object(void **state)
-     assert_non_null(orig);
- 
-     tmp_str = talloc_strdup(orig,  "ORIGNAME");
-+    assert_non_null(tmp_str);
-     ret = ldb_msg_add_string(orig, SYSDB_NAME, tmp_str);
-     assert_int_equal(ret, EOK);
- 
-     tmp_str = talloc_strdup(orig,  "ORIGGECOS");
-+    assert_non_null(tmp_str);
-     ret = ldb_msg_add_string(orig, SYSDB_GECOS, tmp_str);
-     assert_int_equal(ret, EOK);
- 
-@@ -236,18 +238,22 @@ void test_sysdb_add_overrides_to_object(void **state)
-     assert_non_null(override);
- 
-     tmp_str = talloc_strdup(override, "OVERRIDENAME");
-+    assert_non_null(tmp_str);
-     ret = ldb_msg_add_string(override, SYSDB_NAME, tmp_str);
-     assert_int_equal(ret, EOK);
- 
-     tmp_str = talloc_strdup(override, "OVERRIDEGECOS");
-+    assert_non_null(tmp_str);
-     ret = ldb_msg_add_string(override, SYSDB_GECOS, tmp_str);
-     assert_int_equal(ret, EOK);
- 
-     tmp_str = talloc_strdup(override, "OVERRIDEKEY1");
-+    assert_non_null(tmp_str);
-     ret = ldb_msg_add_string(override, SYSDB_SSH_PUBKEY, tmp_str);
-     assert_int_equal(ret, EOK);
- 
-     tmp_str = talloc_strdup(override, "OVERRIDEKEY2");
-+    assert_non_null(tmp_str);
-     ret = ldb_msg_add_string(override, SYSDB_SSH_PUBKEY, tmp_str);
-     assert_int_equal(ret, EOK);
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch b/SOURCES/0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch
new file mode 100644
index 0000000..331cf4d
--- /dev/null
+++ b/SOURCES/0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch
@@ -0,0 +1,42 @@
+From dad90587794fdc2112f2099d5f6cdd9e138781be Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 13 Jul 2016 20:02:47 +0200
+Subject: [PATCH 20/27] sdap: Fix ldap_rfc_2307_fallback_to_local_users
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We wrongly tried to store empty
+user attributes instead of the
+local user attributes with
+ldap_rfc_2307_fallback_to_local_users
+set to true. This gave us bad
+initgroups results and caused
+segfaults.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3045
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit aa8ec3758d885d6ae4088174369d30f8493ec898)
+---
+ src/providers/ldap/sdap_async_initgroups.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index d14563cb045a0ce34b72051744894362fc32d003..17593f0a268813662d6c7fbf658b1eb4599ce3c3 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -2893,6 +2893,9 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
+             (dp_opt_get_bool(state->opts->basic,
+                              SDAP_RFC2307_FALLBACK_TO_LOCAL_USERS) == true)) {
+             ret = sdap_fallback_local_user(state, state->shortname, -1, &usr_attrs);
++            if (ret == EOK) {
++                state->orig_user = usr_attrs[0];
++            }
+         } else {
+             ret = ENOENT;
+         }
+-- 
+2.4.11
+
diff --git a/SOURCES/0021-SYSDB-prepare-for-LOCAL-view.patch b/SOURCES/0021-SYSDB-prepare-for-LOCAL-view.patch
deleted file mode 100644
index 43ac1e7..0000000
--- a/SOURCES/0021-SYSDB-prepare-for-LOCAL-view.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-From ea6cfe4e1d7c84370bfcc86251ea10b2658b52d3 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 24 Jul 2015 09:55:28 +0200
-Subject: [PATCH 21/23] SYSDB: prepare for LOCAL view
-
-Objects doesn't have to have overrideDN specified when using LOCAL view.
-Since the view is not stored on the server we do not want to contact
-LDAP therefore we special case LOCAL view saying that it is OK that
-this attribute is missing.
-
-Preparation for:
-https://fedorahosted.org/sssd/ticket/2584
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/db/sysdb.h                      | 14 +++++++-
- src/db/sysdb_views.c                |  7 ++++
- src/providers/ipa/ipa_subdomains.c  |  3 +-
- src/tests/cmocka/test_sysdb_views.c | 66 +++++++++++++++++++++++++++++++++++++
- 4 files changed, 88 insertions(+), 2 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 0f745ccb1a646d77ba4ad3d714d5f4dce0a51211..9e28b5c6691f3710e3051d9746ac5fa47aff8424 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -157,9 +157,10 @@
- #define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires"
- #define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl"
- 
-+#define SYSDB_DEFAULT_VIEW_NAME "default"
-+#define SYSDB_LOCAL_VIEW_NAME "LOCAL" /* reserved for client-side overrides */
- #define SYSDB_VIEW_CLASS "view"
- #define SYSDB_VIEW_NAME "viewName"
--#define SYSDB_DEFAULT_VIEW_NAME "default"
- #define SYSDB_OVERRIDE_CLASS "overrride"
- #define SYSDB_OVERRIDE_ANCHOR_UUID "overrideAnchorUUID"
- #define SYSDB_OVERRIDE_USER_CLASS "userOverride"
-@@ -473,6 +474,17 @@ static inline bool is_default_view(const char *view_name)
-     }
- }
- 
-+static inline bool is_local_view(const char *view_name)
-+{
-+    /* NULL is treated as default */
-+    if (view_name != NULL
-+            && strcmp(view_name, SYSDB_LOCAL_VIEW_NAME) == 0) {
-+        return true;
-+    } else {
-+        return false;
-+    }
-+}
-+
- errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name);
- 
- errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb);
-diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
-index aadd6018f4d1e2ca33e2e00dd8b13b55a8c03f3e..1db6c892de9e4764b673608166830800744b1148 100644
---- a/src/db/sysdb_views.c
-+++ b/src/db/sysdb_views.c
-@@ -1186,9 +1186,16 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
-         override_dn_str = ldb_msg_find_attr_as_string(obj,
-                                                       SYSDB_OVERRIDE_DN, NULL);
-         if (override_dn_str == NULL) {
-+            if (is_local_view(domain->view_name)) {
-+                /* LOCAL view doesn't have to have overrideDN specified. */
-+                ret = EOK;
-+                goto done;
-+            }
-+
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Missing override DN for objext [%s].\n",
-                   ldb_dn_get_linearized(obj->dn));
-+
-             ret = ENOENT;
-             goto done;
-         }
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index cf72784473747c67d44a5d887faf867cfe62ce2b..cec8b3918b8f832e2c7376a867448fe876da6ffc 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -905,7 +905,8 @@ static void ipa_get_view_name_done(struct tevent_req *req)
-                     goto done;
-                 }
- 
--                if (!is_default_view(ctx->sd_ctx->id_ctx->view_name)) {
-+                if (!is_default_view(ctx->sd_ctx->id_ctx->view_name)
-+                        && !is_local_view(ctx->sd_ctx->id_ctx->view_name)) {
-                     /* Old view was not the default view, delete view tree */
-                     ret = sysdb_delete_view_tree(
-                                              ctx->sd_ctx->be_ctx->domain->sysdb,
-diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
-index 123d4c5cb613f41e1bca9e89feed701a1e86f8d3..83007b76a625edef67109850648b2d71645e22bb 100644
---- a/src/tests/cmocka/test_sysdb_views.c
-+++ b/src/tests/cmocka/test_sysdb_views.c
-@@ -281,6 +281,68 @@ void test_sysdb_add_overrides_to_object(void **state)
-     assert_int_equal(ldb_val_string_cmp(&el->values[1], "OVERRIDEKEY2"), 0);
- }
- 
-+void test_sysdb_add_overrides_to_object_local(void **state)
-+{
-+    int ret;
-+    struct ldb_message *orig;
-+    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");
-+    assert_non_null(tmp_str);
-+    ret = ldb_msg_add_string(orig, SYSDB_NAME, tmp_str);
-+    assert_int_equal(ret, EOK);
-+
-+    tmp_str = talloc_strdup(orig,  "ORIGGECOS");
-+    assert_non_null(tmp_str);
-+    ret = ldb_msg_add_string(orig, SYSDB_GECOS, tmp_str);
-+    assert_int_equal(ret, EOK);
-+
-+    test_ctx->domain->has_views = true;
-+    test_ctx->domain->view_name = "LOCAL";
-+
-+    ret = sysdb_add_overrides_to_object(test_ctx->domain, orig, NULL, NULL);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_sysdb_add_overrides_to_object_missing_overridedn(void **state)
-+{
-+    int ret;
-+    struct ldb_message *orig;
-+    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);
-+
-+    orig->dn = ldb_dn_new(orig, test_ctx->domain->sysdb->ldb,
-+                          "cn=somedn,dc=example,dc=com");
-+    assert_non_null(orig->dn);
-+
-+    tmp_str = talloc_strdup(orig,  "ORIGNAME");
-+    assert_non_null(tmp_str);
-+    ret = ldb_msg_add_string(orig, SYSDB_NAME, tmp_str);
-+    assert_int_equal(ret, EOK);
-+
-+    tmp_str = talloc_strdup(orig,  "ORIGGECOS");
-+    assert_non_null(tmp_str);
-+    ret = ldb_msg_add_string(orig, SYSDB_GECOS, tmp_str);
-+    assert_int_equal(ret, EOK);
-+
-+    test_ctx->domain->has_views = true;
-+    test_ctx->domain->view_name = "NON-LOCAL";
-+
-+    ret = sysdb_add_overrides_to_object(test_ctx->domain, orig, NULL, NULL);
-+    assert_int_equal(ret, ENOENT);
-+}
-+
- void test_split_ipa_anchor(void **state)
- {
-     int ret;
-@@ -923,6 +985,10 @@ int main(int argc, const char *argv[])
-                                         test_sysdb_setup, test_sysdb_teardown),
-         cmocka_unit_test_setup_teardown(test_sysdb_add_overrides_to_object,
-                                         test_sysdb_setup, test_sysdb_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_add_overrides_to_object_local,
-+                                        test_sysdb_setup, test_sysdb_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_add_overrides_to_object_missing_overridedn,
-+                                        test_sysdb_setup, test_sysdb_teardown),
-         cmocka_unit_test_setup_teardown(test_split_ipa_anchor,
-                                         test_sysdb_setup, test_sysdb_teardown),
-         cmocka_unit_test_setup_teardown(test_sysdb_delete_view_tree,
--- 
-2.4.3
-
diff --git a/SOURCES/0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch b/SOURCES/0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch
new file mode 100644
index 0000000..7ad0c30
--- /dev/null
+++ b/SOURCES/0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch
@@ -0,0 +1,56 @@
+From a2e8989fd06af0dcf4dd7b8013bda6bcb49839f0 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 12 Jul 2016 12:37:16 +0200
+Subject: [PATCH 21/27] test_utils: Clean files after
+ sss_write_krb5_conf_snippet
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The test directory was not removed (tp_test_utils-test_utils)
+because it contain the snippet for krb5_libdefaults.
+
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+(cherry picked from commit 059904af2d20debcb8ffe1c6f45b996c2c57574e)
+---
+ src/tests/cmocka/test_utils.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index fd20990ce7ac632b3b62bf84a20cc75a5ec0e968..b08b19708bb59a076a79805fa37a15924152b8e2 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -1252,6 +1252,7 @@ void test_sss_write_krb5_conf_snippet(void **state)
+     char *cwd;
+     char *path;
+     char *file;
++    char *file_krb5_libdefaults;
+ 
+     ret = sss_write_krb5_conf_snippet(NULL, false);
+     assert_int_equal(ret, EINVAL);
+@@ -1274,6 +1275,10 @@ void test_sss_write_krb5_conf_snippet(void **state)
+     ret = asprintf(&file, "%s/%s/localauth_plugin", cwd, TESTS_PATH);
+     assert_true(ret > 0);
+ 
++    ret = asprintf(&file_krb5_libdefaults,
++                   "%s/%s/krb5_libdefaults", cwd, TESTS_PATH);
++    assert_true(ret > 0);
++
+     ret = sss_write_krb5_conf_snippet(path, true);
+     assert_int_equal(ret, EOK);
+ 
+@@ -1286,7 +1291,11 @@ void test_sss_write_krb5_conf_snippet(void **state)
+     assert_int_equal(ret, EOK);
+ #endif
+ 
++    ret = unlink(file_krb5_libdefaults);
++    assert_int_equal(ret, EOK);
++
+     free(file);
++    free(file_krb5_libdefaults);
+     free(path);
+ }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch b/SOURCES/0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch
new file mode 100644
index 0000000..478a9ba
--- /dev/null
+++ b/SOURCES/0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch
@@ -0,0 +1,47 @@
+From 4ec714f1681355d95420733a40e3c37cd0bfe6ee Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 23 Jun 2016 11:58:30 +0200
+Subject: [PATCH 22/27] IPA: read ipaNTAdditionalSuffixes for master and
+ trusted domains
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 39f21d2b61685362642d42bc2f94f829671cd5ef)
+---
+ src/providers/ipa/ipa_subdomains.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index a02a65d97dde68f1da900b9fdca05c54035ce005..263d6207960c232d08114bd0163b3fd03a690685 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -40,6 +40,7 @@
+ #define IPA_SID "ipaNTSecurityIdentifier"
+ #define IPA_TRUSTED_DOMAIN_SID "ipaNTTrustedDomainSID"
+ #define IPA_RANGE_TYPE "ipaRangeType"
++#define IPA_ADDITIONAL_SUFFIXES "ipaNTAdditionalSuffixes"
+ 
+ #define IPA_BASE_ID "ipaBaseID"
+ #define IPA_ID_RANGE_SIZE "ipaIDRangeSize"
+@@ -788,7 +789,8 @@ ipa_subdomains_master_send(TALLOC_CTX *mem_ctx,
+     struct tevent_req *subreq;
+     struct tevent_req *req;
+     errno_t ret;
+-    const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_SID, NULL };
++    const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_SID,
++                            IPA_ADDITIONAL_SUFFIXES, NULL };
+ 
+     req = tevent_req_create(mem_ctx, &state,
+                             struct ipa_subdomains_master_state);
+@@ -939,7 +941,8 @@ ipa_subdomains_slave_send(TALLOC_CTX *mem_ctx,
+     struct tevent_req *req;
+     errno_t ret;
+     const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID,
+-                            IPA_TRUST_DIRECTION, NULL };
++                            IPA_TRUST_DIRECTION, IPA_ADDITIONAL_SUFFIXES,
++                            NULL };
+ 
+     req = tevent_req_create(mem_ctx, &state,
+                             struct ipa_subdomains_slave_state);
+-- 
+2.4.11
+
diff --git a/SOURCES/0022-TOOLS-add-common-command-framework.patch b/SOURCES/0022-TOOLS-add-common-command-framework.patch
deleted file mode 100644
index b5689c8..0000000
--- a/SOURCES/0022-TOOLS-add-common-command-framework.patch
+++ /dev/null
@@ -1,555 +0,0 @@
-From edb91d864b48bf6e6240fe7eee84e68cdaaf012a Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 22 Jul 2015 10:02:02 +0200
-Subject: [PATCH 22/23] TOOLS: add common command framework
-
-Add general framework to simplify creating "cmd COMMAND [OPTIONS...]"
-style tools.
-
-Preparation for:
-https://fedorahosted.org/sssd/ticket/2584
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                  |   5 +-
- src/tools/common/sss_tools.c | 406 +++++++++++++++++++++++++++++++++++++++++++
- src/tools/common/sss_tools.h |  91 ++++++++++
- 3 files changed, 501 insertions(+), 1 deletion(-)
- create mode 100644 src/tools/common/sss_tools.c
- create mode 100644 src/tools/common/sss_tools.h
-
-diff --git a/Makefile.am b/Makefile.am
-index b8cbc6df23ded1edb945a709b6dbe1c44eb54017..1edecc483c61d04562b7bfd9086146e93963b74e 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -445,7 +445,9 @@ SSSD_TOOLS_OBJ = \
-     src/tools/tools_util.c \
-     src/tools/files.c \
-     src/tools/selinux.c \
--    src/util/nscd.c
-+    src/tools/common/sss_tools.c \
-+    src/util/nscd.c \
-+    $(NULL)
- 
- SSSD_LCL_TOOLS_OBJ = \
-     src/sss_client/common.c \
-@@ -641,6 +643,7 @@ dist_noinst_HEADERS = \
-     src/lib/idmap/sss_idmap_private.h \
-     src/lib/sifp/sss_sifp_private.h \
-     src/tests/cmocka/test_utils.h \
-+    src/tools/common/sss_tools.h \
-     $(NULL)
- 
- 
-diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..6bbce3a25ddddc0b23ebc108a917a38e94981b65
---- /dev/null
-+++ b/src/tools/common/sss_tools.c
-@@ -0,0 +1,406 @@
-+/*
-+    Authors:
-+        Pavel Březina <pbrezina@redhat.com>
-+
-+    Copyright (C) 2015 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 <talloc.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <popt.h>
-+
-+#include "config.h"
-+#include "util/util.h"
-+#include "confdb/confdb.h"
-+#include "db/sysdb.h"
-+#include "tools/common/sss_tools.h"
-+
-+struct sss_cmdline {
-+    const char *exec; /* argv[0] */
-+    const char *command; /* command name */
-+    int argc; /* rest of arguments */
-+    const char **argv;
-+};
-+
-+static void sss_tool_common_opts(struct sss_tool_ctx *tool_ctx,
-+                                 int *argc, const char **argv)
-+{
-+    poptContext pc;
-+    int debug = SSSDBG_DEFAULT;
-+    int orig_argc = *argc;
-+    int opt;
-+
-+    struct poptOption options[] = {
-+        {"debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_STRIP, &debug,
-+            0, _("The debug level to run with"), NULL },
-+        POPT_TABLEEND
-+    };
-+
-+    pc = poptGetContext(argv[0], orig_argc, argv, options, 0);
-+    while ((opt = poptGetNextOpt(pc)) != -1) {
-+        /* do nothing */
-+    }
-+
-+    /* Strip common options from arguments. We will discard_const here,
-+     * since it is not worth the trouble to convert it back and forth. */
-+    *argc = poptStrippedArgv(pc, orig_argc, discard_const_p(char *, argv));
-+
-+    DEBUG_CLI_INIT(debug);
-+
-+    poptFreeContext(pc);
-+}
-+
-+static errno_t sss_tool_confdb_init(TALLOC_CTX *mem_ctx,
-+                                    struct confdb_ctx **_confdb)
-+{
-+    struct confdb_ctx *confdb;
-+    char *path;
-+    errno_t ret;
-+
-+    path = talloc_asprintf(mem_ctx, "%s/%s", DB_PATH, CONFDB_FILE);
-+    if (path == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = confdb_init(mem_ctx, &confdb, path);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Could not initialize connection to the confdb\n");
-+        talloc_free(path);
-+        return ret;
-+    }
-+
-+    if (_confdb != NULL) {
-+        *_confdb = confdb;
-+    }
-+
-+    return EOK;
-+}
-+
-+static errno_t sss_tool_domains_init(TALLOC_CTX *mem_ctx,
-+                                     struct confdb_ctx *confdb,
-+                                     struct sss_domain_info **_domains)
-+{
-+    struct sss_domain_info *domains;
-+    struct sss_domain_info *dom;
-+    errno_t ret;
-+
-+    ret = confdb_get_domains(confdb, &domains);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup domains [%d]: %s\n",
-+                                   ret, sss_strerror(ret));
-+        return ret;
-+    }
-+
-+    ret = sysdb_init(mem_ctx, domains, false);
-+    SYSDB_VERSION_ERROR(ret);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Could not initialize connection to the sysdb\n");
-+        return ret;
-+    }
-+
-+    for (dom = domains; dom != NULL; dom = get_next_domain(dom, true)) {
-+        if (!IS_SUBDOMAIN(dom)) {
-+            /* Update list of subdomains for this domain */
-+            ret = sysdb_update_subdomains(dom);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      "Failed to update subdomains for domain %s.\n",
-+                      dom->name);
-+            }
-+        }
-+    }
-+
-+    for (dom = domains; dom != NULL; dom = get_next_domain(dom, true)) {
-+        ret = sss_names_init(mem_ctx, confdb, dom->name, &dom->names);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "sss_names_init() failed\n");
-+            return ret;
-+        }
-+    }
-+
-+    *_domains = domains;
-+
-+    return ret;
-+}
-+
-+struct sss_tool_ctx *sss_tool_init(TALLOC_CTX *mem_ctx,
-+                                   int *argc, const char **argv)
-+{
-+    struct sss_tool_ctx *tool_ctx;
-+    errno_t ret;
-+
-+    tool_ctx = talloc_zero(mem_ctx, struct sss_tool_ctx);
-+    if (tool_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
-+        return NULL;
-+    }
-+
-+    sss_tool_common_opts(tool_ctx, argc, argv);
-+
-+    /* Connect to confdb. */
-+    ret = sss_tool_confdb_init(tool_ctx, &tool_ctx->confdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to open confdb [%d]: %s\n",
-+                                   ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    /* Setup domains. */
-+    ret = sss_tool_domains_init(tool_ctx, tool_ctx->confdb, &tool_ctx->domains);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup domains [%d]: %s\n",
-+                                   ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = confdb_get_string(tool_ctx->confdb, tool_ctx,
-+                            CONFDB_MONITOR_CONF_ENTRY,
-+                            CONFDB_MONITOR_DEFAULT_DOMAIN,
-+                            NULL, &tool_ctx->default_domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Cannot get the default domain [%d]: %s\n",
-+                                 ret, strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_zfree(tool_ctx);
-+    }
-+
-+    return tool_ctx;
-+}
-+
-+int sss_tool_usage(const char *tool_name,
-+                   struct sss_route_cmd *commands)
-+{
-+    int i;
-+
-+    fprintf(stderr, _("Usage:\n%s COMMAND COMMAND-ARGS\n\n"), tool_name);
-+    fprintf(stderr, _("Available commands:\n"));
-+
-+    for (i = 0; commands[i].command != NULL; i++) {
-+        fprintf(stderr, "* %s\n", commands[i].command);
-+    }
-+
-+    return EXIT_FAILURE;
-+}
-+
-+int sss_tool_route(int argc, const char **argv,
-+                   struct sss_tool_ctx *tool_ctx,
-+                   struct sss_route_cmd *commands,
-+                   void *pvt)
-+{
-+    struct sss_cmdline cmdline;
-+    const char *cmd;
-+    int i;
-+
-+    if (commands == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Bug: commands can't be NULL!\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    if (argc < 2) {
-+        return sss_tool_usage(argv[0], commands);
-+    }
-+
-+    cmd = argv[1];
-+    for (i = 0; commands[i].command != NULL; i++) {
-+        if (strcmp(commands[i].command, cmd) == 0) {
-+            cmdline.exec = argv[0];
-+            cmdline.command = argv[1];
-+            cmdline.argc = argc - 2;
-+            cmdline.argv = argv + 2;
-+
-+            return commands[i].fn(&cmdline, tool_ctx, pvt);
-+        }
-+    }
-+
-+    return sss_tool_usage(argv[0], commands);
-+}
-+
-+int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-+                     struct poptOption *options,
-+                     enum sss_tool_opt require_option,
-+                     sss_popt_fn popt_fn,
-+                     void *popt_fn_pvt,
-+                     const char *fopt_name,
-+                     const char *fopt_help,
-+                     const char **_fopt)
-+{
-+    const char *optstr;
-+    char *help;
-+    poptContext pc;
-+    int ret;
-+
-+    /* Create help option string. We always need to append command name since
-+     * we use POPT_CONTEXT_KEEP_FIRST. */
-+    optstr = options == NULL ? "" : _(" [OPTIONS...]");
-+    if (fopt_name == NULL) {
-+        help = talloc_asprintf(NULL, "%s %s%s",
-+                               cmdline->exec, cmdline->command, optstr);
-+    } else {
-+        help = talloc_asprintf(NULL, "%s %s %s%s",
-+                           cmdline->exec, cmdline->command, fopt_name, optstr);
-+    }
-+    if (help == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    /* Create popt context. This function is supposed to be called on
-+     * command argv which does not contain executable (argv[0]), therefore
-+     * we need to use KEEP_FIRST that ensures argv[0] is also processed. */
-+    pc = poptGetContext(cmdline->exec, cmdline->argc, cmdline->argv,
-+                        options, POPT_CONTEXT_KEEP_FIRST);
-+
-+    poptSetOtherOptionHelp(pc, help);
-+
-+    /* Parse options. Invoke custom function if provided. If no parsing
-+     * function is provided, print error on unknown option. */
-+    while ((ret = poptGetNextOpt(pc)) != -1) {
-+        if (popt_fn != NULL) {
-+            ret = popt_fn(pc, ret, popt_fn_pvt);
-+            if (ret != EOK) {
-+                ret = EXIT_FAILURE;
-+                goto done;
-+            }
-+        } else {
-+            fprintf(stderr, _("Invalid option %s: %s\n\n"),
-+                    poptBadOption(pc, 0), poptStrerror(ret));
-+            poptPrintHelp(pc, stderr, 0);
-+            ret = EXIT_FAILURE;
-+            goto done;
-+        }
-+    }
-+
-+    /* Parse free option which is always required if requested. */
-+    if (_fopt != NULL) {
-+        *_fopt = poptGetArg(pc);
-+        if (*_fopt == NULL) {
-+            fprintf(stderr, _("Missing option: %s\n\n"), fopt_help);
-+            poptPrintHelp(pc, stderr, 0);
-+            ret = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        /* No more arguments expected. If something follows it is an error. */
-+        if (poptGetArg(pc)) {
-+            fprintf(stderr, _("Only one free argument is expected!\n\n"));
-+            poptPrintHelp(pc, stderr, 0);
-+            ret = EXIT_FAILURE;
-+            goto done;
-+        }
-+    }
-+
-+    /* If at least one option is required and not provided, print error. */
-+    if (require_option == SSS_TOOL_OPT_REQUIRED
-+            && ((_fopt != NULL && cmdline->argc < 2) || cmdline->argc < 1)) {
-+        fprintf(stderr, _("At least one option is required!\n\n"));
-+        poptPrintHelp(pc, stderr, 0);
-+        ret = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    ret = EXIT_SUCCESS;
-+
-+done:
-+    poptFreeContext(pc);
-+    talloc_free(help);
-+    return ret;
-+}
-+
-+int sss_tool_popt(struct sss_cmdline *cmdline,
-+                  struct poptOption *options,
-+                  enum sss_tool_opt require_option,
-+                  sss_popt_fn popt_fn,
-+                  void *popt_fn_pvt)
-+{
-+    return sss_tool_popt_ex(cmdline, options, require_option,
-+                            popt_fn, popt_fn_pvt, NULL, NULL, NULL);
-+}
-+
-+int sss_tool_main(int argc, const char **argv,
-+                  struct sss_route_cmd *commands,
-+                  void *pvt)
-+{
-+    struct sss_tool_ctx *tool_ctx;
-+    uid_t uid;
-+    int ret;
-+
-+    uid = getuid();
-+    if (uid != 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Running under %d, must be root\n", uid);
-+        ERROR("%1$s must be run as root\n", argv[0]);
-+        return EXIT_FAILURE;
-+    }
-+
-+    tool_ctx = sss_tool_init(NULL, &argc, argv);
-+    if (tool_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tool context\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = sss_tool_route(argc, argv, tool_ctx, commands, pvt);
-+    talloc_free(tool_ctx);
-+
-+    return ret;
-+}
-+
-+int sss_tool_parse_name(TALLOC_CTX *mem_ctx,
-+                        struct sss_tool_ctx *tool_ctx,
-+                        const char *input,
-+                        const char **_username,
-+                        struct sss_domain_info **_domain)
-+{
-+    char *username = NULL;
-+    char *domname = NULL;
-+    struct sss_domain_info *domain;
-+    int ret;
-+
-+    ret = sss_parse_name_for_domains(mem_ctx, tool_ctx->domains,
-+                                     tool_ctx->default_domain, input,
-+                                     &domname, &username);
-+    if (ret == EAGAIN) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find domain. The domain name may "
-+              "be a subdomain that was not yet found.\n");
-+        goto done;
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    domain = find_domain_by_name(tool_ctx->domains, domname, true);
-+
-+    *_username = username;
-+    *_domain = domain;
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_zfree(username);
-+        talloc_zfree(domname);
-+    }
-+
-+    return ret;
-+}
-diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h
-new file mode 100644
-index 0000000000000000000000000000000000000000..cfe11d06e1dadf8e49efe155c8a53f99a31e97fb
---- /dev/null
-+++ b/src/tools/common/sss_tools.h
-@@ -0,0 +1,91 @@
-+/*
-+    Authors:
-+        Pavel Březina <pbrezina@redhat.com>
-+
-+    Copyright (C) 2015 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/>.
-+*/
-+
-+#ifndef _SSS_TOOLS_H_
-+#define _SSS_TOOLS_H_
-+
-+#include <talloc.h>
-+#include <popt.h>
-+
-+#include "confdb/confdb.h"
-+
-+struct sss_tool_ctx {
-+    struct confdb_ctx *confdb;
-+
-+    char *default_domain;
-+    struct sss_domain_info *domains;
-+};
-+
-+struct sss_tool_ctx *sss_tool_init(TALLOC_CTX *mem_ctx,
-+                                   int *argc, const char **argv);
-+
-+struct sss_cmdline;
-+
-+typedef int
-+(*sss_route_fn)(struct sss_cmdline *cmdline,
-+                struct sss_tool_ctx *tool_ctx,
-+                void *pvt);
-+
-+struct sss_route_cmd {
-+    const char *command;
-+    sss_route_fn fn;
-+};
-+
-+int sss_tool_usage(const char *tool_name,
-+                   struct sss_route_cmd *commands);
-+
-+int sss_tool_route(int argc, const char **argv,
-+                   struct sss_tool_ctx *tool_ctx,
-+                   struct sss_route_cmd *commands,
-+                   void *pvt);
-+
-+typedef int (*sss_popt_fn)(poptContext pc, char option, void *pvt);
-+
-+enum sss_tool_opt {
-+    SSS_TOOL_OPT_REQUIRED,
-+    SSS_TOOL_OPT_OPTIONAL
-+};
-+
-+int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-+                     struct poptOption *options,
-+                     enum sss_tool_opt require_option,
-+                     sss_popt_fn popt_fn,
-+                     void *popt_fn_pvt,
-+                     const char *free_opt_name,
-+                     const char *free_opt_help,
-+                     const char **_free_opt);
-+
-+int sss_tool_popt(struct sss_cmdline *cmdline,
-+                  struct poptOption *options,
-+                  enum sss_tool_opt require_option,
-+                  sss_popt_fn popt_fn,
-+                  void *popt_fn_pvt);
-+
-+int sss_tool_main(int argc, const char **argv,
-+                  struct sss_route_cmd *commands,
-+                  void *pvt);
-+
-+int sss_tool_parse_name(TALLOC_CTX *mem_ctx,
-+                        struct sss_tool_ctx *tool_ctx,
-+                        const char *input,
-+                        const char **_username,
-+                        struct sss_domain_info **_domain);
-+
-+#endif /* SRC_TOOLS_COMMON_SSS_TOOLS_H_ */
--- 
-2.4.3
-
diff --git a/SOURCES/0023-TOOLS-add-sss_override-for-local-overrides.patch b/SOURCES/0023-TOOLS-add-sss_override-for-local-overrides.patch
deleted file mode 100644
index ebf1051..0000000
--- a/SOURCES/0023-TOOLS-add-sss_override-for-local-overrides.patch
+++ /dev/null
@@ -1,939 +0,0 @@
-From a3b608a72f2cba3cece3a28dbc1c5d532d91ce14 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 24 Jul 2015 09:58:11 +0200
-Subject: [PATCH 23/23] TOOLS: add sss_override for local overrides
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2584
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                |  16 +-
- contrib/sssd.spec.in       |   2 +
- src/man/Makefile.am        |   1 +
- src/man/po/po4a.cfg        |   1 +
- src/man/sss_override.8.xml | 108 +++++++
- src/tools/sss_override.c   | 718 +++++++++++++++++++++++++++++++++++++++++++++
- 6 files changed, 845 insertions(+), 1 deletion(-)
- create mode 100644 src/man/sss_override.8.xml
- create mode 100644 src/tools/sss_override.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 1edecc483c61d04562b7bfd9086146e93963b74e..912bfc6641465ef5cd2ff2cce9975b4027c3218d 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -117,7 +117,9 @@ sbin_PROGRAMS = \
-     sss_groupshow \
-     sss_cache \
-     sss_debuglevel \
--    sss_seed
-+    sss_override \
-+    sss_seed \
-+    $(NULL)
- 
- sssdlibexec_PROGRAMS = \
-     sssd_nss \
-@@ -1297,6 +1299,18 @@ sss_signal_LDADD = \
-     $(SSSD_INTERNAL_LTLIBS) \
-     $(NULL)
- 
-+sss_override_SOURCES = \
-+    src/tools/sss_override.c \
-+    $(SSSD_TOOLS_OBJ) \
-+    $(NULL)
-+sss_override_LDADD = \
-+    $(TOOLS_LIBS) \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    $(NULL)
-+sss_override_CFLAGS = \
-+    $(AM_CFLAGS) \
-+    $(NULL)
-+
- if BUILD_SUDO
- sss_sudo_cli_SOURCES = \
-     src/sss_client/common.c \
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index 15f7c582cba1b9052e180596625be7dd5749599f..f050501ff9d0711a0da7f094ee968cae87a3f49b 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -837,6 +837,7 @@ rm -rf $RPM_BUILD_ROOT
- %{_sbindir}/sss_groupmod
- %{_sbindir}/sss_groupshow
- %{_sbindir}/sss_obfuscate
-+%{_sbindir}/sss_override
- %{_sbindir}/sss_debuglevel
- %{_sbindir}/sss_seed
- %{_mandir}/man8/sss_groupadd.8*
-@@ -847,6 +848,7 @@ rm -rf $RPM_BUILD_ROOT
- %{_mandir}/man8/sss_userdel.8*
- %{_mandir}/man8/sss_usermod.8*
- %{_mandir}/man8/sss_obfuscate.8*
-+%{_mandir}/man8/sss_override.8*
- %{_mandir}/man8/sss_debuglevel.8*
- %{_mandir}/man8/sss_seed.8*
- 
-diff --git a/src/man/Makefile.am b/src/man/Makefile.am
-index 1ef1da48cce74f7d1ad77e3751ee6ac3450f0259..70cadf5951f56b78ff0bfbcb303e255478af5fec 100644
---- a/src/man/Makefile.am
-+++ b/src/man/Makefile.am
-@@ -51,6 +51,7 @@ man_MANS = \
-     sssd-krb5.5 sssd-simple.5 \
-     sssd_krb5_locator_plugin.8 sss_groupshow.8 \
-     pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \
-+    sss_override.8
-     $(NULL)
- 
- if BUILD_SAMBA
-diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg
-index 25d20c6f0c23a0900469573d47ab96ebc8898e50..67e87ba7006f0bb1346e5b845428f2bed1a324db 100644
---- a/src/man/po/po4a.cfg
-+++ b/src/man/po/po4a.cfg
-@@ -11,6 +11,7 @@
- [type:docbook] sssd-sudo.5.xml $lang:$(builddir)/$lang/sssd-sudo.5.xml
- [type:docbook] sssd.8.xml $lang:$(builddir)/$lang/sssd.8.xml
- [type:docbook] sss_obfuscate.8.xml $lang:$(builddir)/$lang/sss_obfuscate.8.xml
-+[type:docbook] sss_override.8.xml $lang:$(builddir)/$lang/sss_override.8.xml
- [type:docbook] sss_useradd.8.xml $lang:$(builddir)/$lang/sss_useradd.8.xml
- [type:docbook] sssd-krb5.5.xml $lang:$(builddir)/$lang/sssd-krb5.5.xml
- [type:docbook] sss_groupadd.8.xml $lang:$(builddir)/$lang/sss_groupadd.8.xml
-diff --git a/src/man/sss_override.8.xml b/src/man/sss_override.8.xml
-new file mode 100644
-index 0000000000000000000000000000000000000000..ec9a7bb75c13f4f18ece7f5f84baede14a8a1e2e
---- /dev/null
-+++ b/src/man/sss_override.8.xml
-@@ -0,0 +1,108 @@
-+<?xml version="1.0" encoding="UTF-8"?>
-+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
-+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
-+<reference>
-+<title>SSSD Manual pages</title>
-+<refentry>
-+    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/upstream.xml" />
-+
-+    <refmeta>
-+        <refentrytitle>sss_override</refentrytitle>
-+        <manvolnum>8</manvolnum>
-+    </refmeta>
-+
-+    <refnamediv id='name'>
-+        <refname>sss_override</refname>
-+        <refpurpose>create local overrides of user and group attributes</refpurpose>
-+    </refnamediv>
-+
-+    <refsynopsisdiv id='synopsis'>
-+        <cmdsynopsis>
-+            <command>sss_override</command>
-+            <arg choice='plain'><replaceable>COMMAND</replaceable></arg>
-+            <arg choice='opt'>
-+                <replaceable>options</replaceable>
-+            </arg>
-+        </cmdsynopsis>
-+    </refsynopsisdiv>
-+
-+    <refsect1 id='description'>
-+        <title>DESCRIPTION</title>
-+        <para>
-+            <command>sss_override</command> enables to create a client-side
-+            view and allows to change selected values of specific user
-+            and groups. This change takes effect only on local machine.
-+        </para>
-+        <para>
-+            Overrides data are stored in SSSD cache. If the cache is deleted
-+            all local overrides are lost.
-+        </para>
-+    </refsect1>
-+
-+    <refsect1 id='commands'>
-+        <title>AVAILABLE COMMANDS</title>
-+        <para>
-+            Argument <emphasis>NAME</emphasis> is the name of original object
-+            in all commands. It is not possible to override
-+            <emphasis>uid</emphasis> or <emphasis>gid</emphasis> to 0.
-+        </para>
-+        <variablelist remap='IP'>
-+            <varlistentry>
-+                <term>
-+                    <option>user-add</option>
-+                    <emphasis>NAME</emphasis>
-+                    <optional><option>-n,--name</option> NAME</optional>
-+                    <optional><option>-u,--uid</option> UID</optional>
-+                    <optional><option>-g,--gid</option> GID</optional>
-+                    <optional><option>-h,--home</option> HOME</optional>
-+                    <optional><option>-s,--shell</option> SHELL</optional>
-+                    <optional><option>-c,--gecos</option> GECOS</optional>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Override attributes of an user.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>user-del</option>
-+                    <emphasis>NAME</emphasis>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Remove user overrides.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>group-add</option>
-+                    <emphasis>NAME</emphasis>
-+                    <optional><option>-n,--name</option> NAME</optional>
-+                    <optional><option>-g,--gid</option> GID</optional>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Override attributes of a group.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>group-del</option>
-+                    <emphasis>NAME</emphasis>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Remove group overrides.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+        </variablelist>
-+    </refsect1>
-+
-+    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" />
-+
-+</refentry>
-+</reference>
-diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..5e901e2e31de64dacb171337defc03d428f8ed57
---- /dev/null
-+++ b/src/tools/sss_override.c
-@@ -0,0 +1,718 @@
-+/*
-+    Authors:
-+        Pavel Březina <pbrezina@redhat.com>
-+
-+    Copyright (C) 2015 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 <stdlib.h>
-+
-+#include "util/util.h"
-+#include "db/sysdb.h"
-+#include "tools/common/sss_tools.h"
-+
-+#define LOCALVIEW SYSDB_LOCAL_VIEW_NAME
-+
-+struct override_user {
-+    const char *input_name;
-+    const char *orig_name;
-+    struct sss_domain_info *domain;
-+
-+    const char *name;
-+    uid_t uid;
-+    gid_t gid;
-+    const char *home;
-+    const char *shell;
-+    const char *gecos;
-+};
-+
-+struct override_group {
-+    const char *input_name;
-+    const char *orig_name;
-+    struct sss_domain_info *domain;
-+
-+    const char *name;
-+    gid_t gid;
-+};
-+
-+static int parse_cmdline(struct sss_cmdline *cmdline,
-+                         struct sss_tool_ctx *tool_ctx,
-+                         struct poptOption *options,
-+                         const char **_input_name,
-+                         const char **_orig_name,
-+                         struct sss_domain_info **_domain)
-+{
-+    enum sss_tool_opt require;
-+    const char *input_name;
-+    const char *orig_name;
-+    struct sss_domain_info *domain;
-+    int ret;
-+
-+    require = options == NULL ? SSS_TOOL_OPT_OPTIONAL : SSS_TOOL_OPT_REQUIRED;
-+
-+    ret = sss_tool_popt_ex(cmdline, options, require,
-+                           NULL, NULL, "NAME", _("Specify name of modified "
-+                           "object."), &input_name);
-+    if (ret != EXIT_SUCCESS) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
-+        return ret;
-+    }
-+
-+    ret = sss_tool_parse_name(tool_ctx, tool_ctx, input_name,
-+                              &orig_name, &domain);
-+    if (ret != EOK) {
-+        fprintf(stderr, _("Unable to parse name.\n"));
-+        return ret;
-+    }
-+
-+    *_input_name = input_name;
-+    *_orig_name = orig_name;
-+    *_domain = domain;
-+
-+    return EXIT_SUCCESS;
-+}
-+
-+static int parse_cmdline_user_add(struct sss_cmdline *cmdline,
-+                                  struct sss_tool_ctx *tool_ctx,
-+                                  struct override_user *user)
-+{
-+    struct poptOption options[] = {
-+        POPT_AUTOHELP
-+        {"name", 'n', POPT_ARG_STRING, &user->name, 0, _("Override name"), NULL },
-+        {"uid", 'u', POPT_ARG_INT, &user->uid, 0, _("Override uid (non-zero value)"), NULL },
-+        {"gid", 'g', POPT_ARG_INT, &user->gid, 0, _("Override gid (non-zero value)"), NULL },
-+        {"home", 'h', POPT_ARG_STRING, &user->home, 0, _("Override home directory"), NULL },
-+        {"shell", 's', POPT_ARG_STRING, &user->shell, 0, _("Override shell"), NULL },
-+        {"gecos", 'c', POPT_ARG_STRING, &user->gecos, 0, _("Override gecos"), NULL },
-+        POPT_TABLEEND
-+    };
-+
-+    return parse_cmdline(cmdline, tool_ctx, options, &user->input_name,
-+                         &user->orig_name, &user->domain);
-+}
-+
-+static int parse_cmdline_user_del(struct sss_cmdline *cmdline,
-+                                  struct sss_tool_ctx *tool_ctx,
-+                                  struct override_user *user)
-+{
-+    return parse_cmdline(cmdline, tool_ctx, NULL, &user->input_name,
-+                         &user->orig_name, &user->domain);
-+}
-+
-+static int parse_cmdline_group_add(struct sss_cmdline *cmdline,
-+                                   struct sss_tool_ctx *tool_ctx,
-+                                   struct override_group *group)
-+{
-+    struct poptOption options[] = {
-+        POPT_AUTOHELP
-+        {"name", 'n', POPT_ARG_STRING, &group->name, 0, _("Override name"), NULL },
-+        {"gid", 'g', POPT_ARG_INT, &group->gid, 0, _("Override gid"), NULL },
-+        POPT_TABLEEND
-+    };
-+
-+    return parse_cmdline(cmdline, tool_ctx, options, &group->input_name,
-+                         &group->orig_name, &group->domain);
-+}
-+
-+static int parse_cmdline_group_del(struct sss_cmdline *cmdline,
-+                                   struct sss_tool_ctx *tool_ctx,
-+                                   struct override_group *group)
-+{
-+    return parse_cmdline(cmdline, tool_ctx, NULL, &group->input_name,
-+                         &group->orig_name, &group->domain);
-+}
-+
-+static errno_t prepare_view(struct sss_domain_info *domain)
-+{
-+    char *viewname = NULL;
-+    errno_t ret;
-+
-+    ret = sysdb_get_view_name(NULL, domain->sysdb, &viewname);
-+    if (ret != EOK && ret != ENOENT) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name() failed.\n");
-+        return ret;
-+    }
-+
-+    if (ret == EOK) {
-+        if (is_local_view(viewname)) {
-+            DEBUG(SSSDBG_TRACE_FUNC, "%s view is already present.\n", viewname);
-+            ret = EOK;
-+            goto done;
-+        } else if (viewname != NULL) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, "There already exists view %s. "
-+                  "Only one view is supported. Nothing to do.\n", viewname);
-+            ret = EEXIST;
-+            goto done;
-+        }
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Creating %s view.\n", LOCALVIEW);
-+
-+    ret = sysdb_update_view_name(domain->sysdb, LOCALVIEW);
-+    if (ret == EOK) {
-+        printf("SSSD needs to be restarted for the changes to take effect.\n");
-+    }
-+
-+done:
-+    talloc_free(viewname);
-+    return ret;
-+}
-+
-+static char *build_anchor(TALLOC_CTX *mem_ctx, const char *obj_dn)
-+{
-+    char *anchor;
-+    char *safe_dn;
-+    errno_t ret;
-+
-+    ret = sysdb_dn_sanitize(mem_ctx, obj_dn, &safe_dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_dn_sanitize() failed\n");
-+        return NULL;
-+    }
-+
-+    anchor = talloc_asprintf(mem_ctx, ":%s:%s", LOCALVIEW, safe_dn);
-+
-+    talloc_free(safe_dn);
-+
-+    return anchor;
-+}
-+
-+static struct sysdb_attrs *build_attrs(TALLOC_CTX *mem_ctx,
-+                                       const char *name,
-+                                       uid_t uid,
-+                                       gid_t gid,
-+                                       const char *home,
-+                                       const char *shell,
-+                                       const char *gecos)
-+{
-+    struct sysdb_attrs *attrs;
-+    errno_t ret;
-+
-+    attrs = sysdb_new_attrs(mem_ctx);
-+    if (attrs == NULL) {
-+        return NULL;
-+    }
-+
-+    if (name != NULL) {
-+        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    if (uid != 0) {
-+        ret = sysdb_attrs_add_uint32(attrs, SYSDB_UIDNUM, uid);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    if (gid != 0) {
-+        ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    if (home != NULL) {
-+        ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, home);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    if (shell != NULL) {
-+        ret = sysdb_attrs_add_string(attrs, SYSDB_SHELL, shell);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    if (gecos != NULL) {
-+        ret = sysdb_attrs_add_string(attrs, SYSDB_GECOS, gecos);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(attrs);
-+        return NULL;
-+    }
-+
-+    return attrs;
-+}
-+
-+static struct sysdb_attrs *build_user_attrs(TALLOC_CTX *mem_ctx,
-+                                            struct override_user *user)
-+{
-+    return build_attrs(mem_ctx, user->name, user->uid, user->gid, user->home,
-+                       user->shell, user->gecos);
-+}
-+
-+static struct sysdb_attrs *build_group_attrs(TALLOC_CTX *mem_ctx,
-+                                             struct override_group *group)
-+{
-+    return build_attrs(mem_ctx, group->name, 0, group->gid, 0, NULL, NULL);
-+}
-+
-+static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx,
-+                                         enum sysdb_member_type type,
-+                                         const char *name,
-+                                         struct sss_domain_info *domain,
-+                                         struct sss_domain_info *domains,
-+                                         struct sss_domain_info **_new_domain)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct sss_domain_info *dom;
-+    struct ldb_result *res;
-+    const char *dn;
-+    const char *strtype;
-+    bool check_next;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return NULL;
-+    }
-+
-+    /* Ensure that the object is in cache. */
-+    switch (type) {
-+    case SYSDB_MEMBER_USER:
-+        if (getpwnam(name) == NULL) {
-+            ret = ENOENT;
-+            goto done;
-+        }
-+        break;
-+    case SYSDB_MEMBER_GROUP:
-+        if (getgrnam(name) == NULL) {
-+            ret = ENOENT;
-+            goto done;
-+        }
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported member type %d\n", type);
-+        ret = ERR_INTERNAL;
-+        goto done;
-+    }
-+
-+    /* Find domain if it is unknown. */
-+    if (domain == NULL) {
-+        check_next = true;
-+        dom = domains;
-+    } else {
-+        check_next = false;
-+        dom = domain;
-+    }
-+
-+    do {
-+        switch (type) {
-+        case SYSDB_MEMBER_USER:
-+            DEBUG(SSSDBG_TRACE_FUNC, "Trying to find user %s@%s\n",
-+                  name, dom->name);
-+            ret = sysdb_getpwnam(tmp_ctx, dom, name, &res);
-+            strtype = "user";
-+            break;
-+        case SYSDB_MEMBER_GROUP:
-+            DEBUG(SSSDBG_TRACE_FUNC, "Trying to find group %s@%s\n",
-+                  name, dom->name);
-+            ret = sysdb_getgrnam(tmp_ctx, dom, name, &res);
-+            strtype = "group";
-+            break;
-+        default:
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported member type %d\n", type);
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-+
-+        if (ret == EOK && res->count == 0) {
-+            ret = ENOENT;
-+
-+            if (check_next) {
-+                dom = dom->next;
-+                continue;
-+            }
-+        }
-+
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find %s %s@%s [%d]: %s\n",
-+                  strtype, name, dom->name, ret, sss_strerror(ret));
-+            goto done;
-+        } else if (res->count != 1) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "More than one %s found?\n", strtype);
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-+
-+        check_next = false;
-+    } while (check_next && dom != NULL);
-+
-+    if (dom == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "No domain match for %s\n", name);
-+        ret = ENOENT;
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Domain of %s %s is %s\n",
-+          strtype, name, dom->name);
-+
-+    dn = ldb_dn_get_linearized(res->msgs[0]->dn);
-+    if (dn == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "ldb_dn_get_linearized() failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    talloc_steal(mem_ctx, dn);
-+    *_new_domain = dom;
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    if (ret != EOK) {
-+        return NULL;
-+    }
-+
-+    return dn;
-+}
-+
-+static const char * get_user_dn_and_domain(TALLOC_CTX *mem_ctx,
-+                                           struct sss_domain_info *domains,
-+                                           struct override_user *user)
-+{
-+    return get_object_dn_and_domain(mem_ctx, SYSDB_MEMBER_USER,
-+                         user->orig_name, user->domain, domains,
-+                         &user->domain);
-+}
-+
-+static const char * get_group_dn_and_domain(TALLOC_CTX *mem_ctx,
-+                                            struct sss_domain_info *domains,
-+                                            struct override_group *group)
-+{
-+    return get_object_dn_and_domain(mem_ctx, SYSDB_MEMBER_GROUP,
-+                         group->orig_name, group->domain, domains,
-+                         &group->domain);
-+}
-+
-+static errno_t override_object_add(struct sss_domain_info *domain,
-+                                   enum sysdb_member_type type,
-+                                   struct sysdb_attrs *attrs,
-+                                   const char *obj_dn)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    const char *anchor;
-+    struct ldb_dn *ldb_dn;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ldb_dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb), obj_dn);
-+    if (ldb_dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    anchor = build_anchor(tmp_ctx, obj_dn);
-+    if (anchor == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Creating override for %s\n", obj_dn);
-+
-+    ret = sysdb_store_override(domain, LOCALVIEW, type, attrs, ldb_dn);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t override_object_del(struct sss_domain_info *domain,
-+                                   const char *obj_dn)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    const char *anchor;
-+    struct ldb_dn *override_dn;
-+    struct ldb_message *msg;
-+    errno_t ret;
-+    int sret;
-+    bool in_transaction = false;
-+    struct ldb_context *ldb = sysdb_ctx_get_ldb(domain->sysdb);
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    anchor = build_anchor(tmp_ctx, obj_dn);
-+    if (anchor == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    override_dn = ldb_dn_new_fmt(tmp_ctx, ldb,
-+                        SYSDB_TMPL_OVERRIDE, anchor, LOCALVIEW);
-+    if (override_dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Removing override for %s\n", obj_dn);
-+
-+    ret = sysdb_transaction_start(domain->sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start() failed.\n");
-+        goto done;
-+    }
-+    in_transaction = true;
-+
-+    ret = sysdb_delete_entry(domain->sysdb, override_dn, true);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_entry() failed.\n");
-+        goto done;
-+    }
-+
-+    msg = ldb_msg_new(tmp_ctx);
-+    if (msg == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    msg->dn = ldb_dn_new(msg, ldb, obj_dn);
-+    if (msg->dn == NULL) {
-+        ret = ENOMEM;
-+        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 = ldb_modify(ldb, msg);
-+    if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "ldb_modify() failed: [%s](%d)[%s]\n",
-+              ldb_strerror(ret), ret, ldb_errstring(ldb));
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    ret = sysdb_transaction_commit(domain->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(domain->sysdb);
-+        if (sret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
-+        }
-+    }
-+
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static int override_user_add(struct sss_cmdline *cmdline,
-+                             struct sss_tool_ctx *tool_ctx,
-+                             void *pvt)
-+{
-+    struct override_user user = {NULL};
-+    struct sysdb_attrs *attrs;
-+    const char *dn;
-+    int ret;
-+
-+    ret = parse_cmdline_user_add(cmdline, tool_ctx, &user);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    dn = get_user_dn_and_domain(tool_ctx, tool_ctx->domains, &user);
-+    if (dn == NULL) {
-+        fprintf(stderr, _("Unable to find user %s@%s.\n"),
-+                user.orig_name,
-+                user.domain == NULL ? "[unknown]" : user.domain->name);
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = prepare_view(user.domain);
-+    if (ret == EEXIST) {
-+        fprintf(stderr, _("Other than LOCAL view already exist in "
-+                "domain %s.\n"), user.domain->name);
-+        return EXIT_FAILURE;
-+    } else if (ret != EOK) {
-+        fprintf(stderr, _("Unable to prepare view [%d]: %s.\n"),
-+                ret, sss_strerror(ret));
-+        return EXIT_FAILURE;
-+    }
-+
-+    attrs = build_user_attrs(tool_ctx, &user);
-+    if (attrs == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = override_object_add(user.domain, SYSDB_MEMBER_USER, attrs, dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    return EXIT_SUCCESS;
-+}
-+
-+static int override_user_del(struct sss_cmdline *cmdline,
-+                             struct sss_tool_ctx *tool_ctx,
-+                             void *pvt)
-+{
-+    struct override_user user = {NULL};
-+    const char *dn;
-+    int ret;
-+
-+    ret = parse_cmdline_user_del(cmdline, tool_ctx, &user);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    dn = get_user_dn_and_domain(tool_ctx, tool_ctx->domains, &user);
-+    if (dn == NULL) {
-+        fprintf(stderr, _("Unable to find user %s@%s.\n"),
-+                user.orig_name, user.domain->name);
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = override_object_del(user.domain, dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    return EXIT_SUCCESS;
-+}
-+
-+static int override_group_add(struct sss_cmdline *cmdline,
-+                              struct sss_tool_ctx *tool_ctx,
-+                              void *pvt)
-+{
-+    struct override_group group = {NULL};
-+    struct sysdb_attrs *attrs;
-+    const char *dn;
-+    int ret;
-+
-+    ret = parse_cmdline_group_add(cmdline, tool_ctx, &group);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    dn = get_group_dn_and_domain(tool_ctx, tool_ctx->domains, &group);
-+    if (dn == NULL) {
-+        fprintf(stderr, _("Unable to find group %s@%s.\n"),
-+                group.orig_name, group.domain->name);
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = prepare_view(group.domain);
-+    if (ret == EEXIST) {
-+        fprintf(stderr, _("Other than LOCAL view already exist in "
-+                "domain %s.\n"), group.domain->name);
-+        return EXIT_FAILURE;
-+    } else if (ret != EOK) {
-+        fprintf(stderr, _("Unable to prepare view [%d]: %s.\n"),
-+                ret, sss_strerror(ret));
-+        return EXIT_FAILURE;
-+    }
-+
-+    attrs = build_group_attrs(tool_ctx, &group);
-+    if (attrs == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = override_object_add(group.domain, SYSDB_MEMBER_GROUP, attrs, dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    return EXIT_SUCCESS;
-+}
-+
-+static int override_group_del(struct sss_cmdline *cmdline,
-+                              struct sss_tool_ctx *tool_ctx,
-+                              void *pvt)
-+{
-+    struct override_group group = {NULL};
-+    const char *dn;
-+    int ret;
-+
-+    ret = parse_cmdline_group_del(cmdline, tool_ctx, &group);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    dn = get_group_dn_and_domain(tool_ctx, tool_ctx->domains, &group);
-+    if (dn == NULL) {
-+        fprintf(stderr, _("Unable to find group %s@%s.\n"),
-+                group.orig_name, group.domain->name);
-+        return EXIT_FAILURE;
-+    }
-+
-+    ret = override_object_del(group.domain, dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    return EXIT_SUCCESS;
-+}
-+
-+int main(int argc, const char **argv)
-+{
-+    struct sss_route_cmd commands[] = {
-+        {"user-add", override_user_add},
-+        {"user-del", override_user_del},
-+        {"group-add", override_group_add},
-+        {"group-del", override_group_del},
-+        {NULL, NULL}
-+    };
-+
-+    return sss_tool_main(argc, argv, commands, NULL);
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch b/SOURCES/0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch
new file mode 100644
index 0000000..f58a855
--- /dev/null
+++ b/SOURCES/0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch
@@ -0,0 +1,277 @@
+From 2ffd083501491a8ac3880dc834d01f7ee00fddfc Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 30 Jun 2016 13:48:58 +0200
+Subject: [PATCH 23/27] sysdb: add UPN suffix support for the master domain
+
+sysdb_master_domain_update() and sysdb_master_domain_add_info() are now
+aware of the UPN suffix attribute.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 132b31fd5fb74a7627896cdceaf29c7601ed4795)
+---
+ src/confdb/confdb.h                      |  1 +
+ src/db/sysdb.h                           |  4 ++-
+ src/db/sysdb_subdomains.c                | 49 ++++++++++++++++++++++++++++++--
+ src/providers/ad/ad_id.c                 |  2 +-
+ src/providers/ad/ad_subdomains.c         |  2 +-
+ src/providers/ipa/ipa_subdomains.c       | 10 ++++++-
+ src/tests/cmocka/test_sysdb_subdomains.c | 18 ++++++++----
+ 7 files changed, 74 insertions(+), 12 deletions(-)
+
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index cc8f66f02eb5ac10ced826326f80bbf5eda82ee1..0265ccac5ee2e7b8baa05bf6b09df39ea5b4059a 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -315,6 +315,7 @@ struct sss_domain_info {
+      */
+     char *forest;
+     struct sss_domain_info *forest_root;
++    char **upn_suffixes;
+ };
+ 
+ /**
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 609921fbb0f29561d7e52e8d1404a929af3c5b26..a8dcaa4a9ac5715150487f7efc9c35b778fa0163 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -147,6 +147,7 @@
+ #define SYSDB_SUBDOMAIN_ENUM "enumerate"
+ #define SYSDB_SUBDOMAIN_FOREST "memberOfForest"
+ #define SYSDB_SUBDOMAIN_TRUST_DIRECTION "trustDirection"
++#define SYSDB_UPN_SUFFIXES "upnSuffixes"
+ 
+ #define SYSDB_BASE_ID "baseID"
+ #define SYSDB_ID_RANGE_SIZE "idRangeSize"
+@@ -475,7 +476,8 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
+                                      const char *realm,
+                                      const char *flat,
+                                      const char *id,
+-                                     const char* forest);
++                                     const char *forest,
++                                     struct ldb_message_element *alt_dom_suf);
+ 
+ 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 456e6621b3434a9dbf2e611ad880facbc171c174..c0a190f36d886325a5be1e5d1145b6aef6860ffc 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -448,6 +448,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
+     errno_t ret;
+     TALLOC_CTX *tmp_ctx;
+     const char *tmp_str;
++    struct ldb_message_element **tmp_el;
+     struct ldb_dn *basedn;
+     struct ldb_result *res;
+     const char *attrs[] = {"cn",
+@@ -455,6 +456,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
+                            SYSDB_SUBDOMAIN_FLAT,
+                            SYSDB_SUBDOMAIN_ID,
+                            SYSDB_SUBDOMAIN_FOREST,
++                           SYSDB_UPN_SUFFIXES,
+                            NULL};
+     char *view_name = NULL;
+ 
+@@ -539,6 +541,19 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
+         }
+     }
+ 
++    tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES);
++    if (tmp_el != NULL) {
++        talloc_free(domain->upn_suffixes);
++        domain->upn_suffixes = sss_ldb_el_to_string_list(domain, tmp_el);
++        if (domain->upn_suffixes == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "sss_ldb_el_to_string_list failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    } else {
++        talloc_zfree(domain->upn_suffixes);
++    }
++
+     ret = sysdb_get_view_name(tmp_ctx, domain->sysdb, &view_name);
+     if (ret != EOK && ret != ENOENT) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
+@@ -633,7 +648,8 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
+                                      const char *realm,
+                                      const char *flat,
+                                      const char *id,
+-                                     const char* forest)
++                                     const char *forest,
++                                     struct ldb_message_element *upn_suffixes)
+ {
+     TALLOC_CTX *tmp_ctx;
+     struct ldb_message *msg;
+@@ -720,7 +736,6 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
+             ret = sysdb_error_to_errno(ret);
+             goto done;
+         }
+-
+         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_REALM, realm);
+         if (ret != LDB_SUCCESS) {
+             ret = sysdb_error_to_errno(ret);
+@@ -730,6 +745,36 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
+         do_update = true;
+     }
+ 
++    if (upn_suffixes != NULL) {
++        talloc_free(discard_const(upn_suffixes->name));
++        upn_suffixes->name = talloc_strdup(upn_suffixes, SYSDB_UPN_SUFFIXES);
++        if (upn_suffixes->name == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        ret = ldb_msg_add(msg, upn_suffixes, LDB_FLAG_MOD_REPLACE);
++        if (ret != LDB_SUCCESS) {
++            ret = sysdb_error_to_errno(ret);
++            goto done;
++        }
++
++        do_update = true;
++    } else {
++        /* Remove alternative_domain_suffixes from the cache */
++        if (domain->upn_suffixes != NULL) {
++            ret = ldb_msg_add_empty(msg, SYSDB_UPN_SUFFIXES,
++                                    LDB_FLAG_MOD_DELETE, NULL);
++            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_id.c b/src/providers/ad/ad_id.c
+index 92ac4ab6a13d7094f7a663b4a070feea3be09571..98915b4b966e2665dbd34257e4002d72b95d76b2 100644
+--- a/src/providers/ad/ad_id.c
++++ b/src/providers/ad/ad_id.c
+@@ -631,7 +631,7 @@ ad_enumeration_master_done(struct tevent_req *subreq)
+     }
+ 
+     ret = sysdb_master_domain_add_info(state->sdom->dom, state->realm,
+-                                       flat_name, master_sid, forest);
++                                       flat_name, master_sid, forest, NULL);
+     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 05dfc3085fb14a87b5703518d784056b71bf5de0..0a8d1f53cb005507abe4ac55d0fa1ccc9e32b173 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -1131,7 +1131,7 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+     }
+ 
+     ret = sysdb_master_domain_add_info(state->be_ctx->domain, realm,
+-                                       flat_name, master_sid, forest);
++                                       flat_name, master_sid, forest, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info [%d]: %s\n",
+               ret, sss_strerror(ret));
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 263d6207960c232d08114bd0163b3fd03a690685..62b8f65e5d29a4850f90ea7c19abd297becc96f5 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -855,6 +855,7 @@ static void ipa_subdomains_master_done(struct tevent_req *subreq)
+     const char *flat = NULL;
+     const char *id = NULL;
+     const char *realm = NULL;
++    struct ldb_message_element *alternative_domain_suffixes = NULL;
+     errno_t ret;
+ 
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+@@ -879,6 +880,12 @@ static void ipa_subdomains_master_done(struct tevent_req *subreq)
+         if (ret != EOK) {
+             goto done;
+         }
++
++        ret = sysdb_attrs_get_el_ext(reply[0], IPA_ADDITIONAL_SUFFIXES, false,
++                                     &alternative_domain_suffixes);
++        if (ret != EOK && ret != ENOENT) {
++            goto done;
++        }
+     } else {
+         /* All search paths are searched and no master domain record was
+          * found.
+@@ -896,7 +903,8 @@ static void ipa_subdomains_master_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
+-    ret = sysdb_master_domain_add_info(state->domain, realm, flat, id, NULL);
++    ret = sysdb_master_domain_add_info(state->domain, realm, flat, id, NULL,
++                                       alternative_domain_suffixes);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add master domain info "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
+index f55c2918015900351483e3471bf946ea60872dae..6d1ec884284487a12bcbfad77c00cd6c30f67707 100644
+--- a/src/tests/cmocka/test_sysdb_subdomains.c
++++ b/src/tests/cmocka/test_sysdb_subdomains.c
+@@ -165,7 +165,8 @@ static void test_sysdb_master_domain_ops(void **state)
+         talloc_get_type(*state, struct subdom_test_ctx);
+ 
+     ret = sysdb_master_domain_add_info(test_ctx->tctx->dom,
+-                                       "realm1", "flat1", "id1", "forest1");
++                                       "realm1", "flat1", "id1", "forest1",
++                                       NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_master_domain_update(test_ctx->tctx->dom);
+@@ -177,7 +178,8 @@ static void test_sysdb_master_domain_ops(void **state)
+     assert_string_equal(test_ctx->tctx->dom->forest, "forest1");
+ 
+     ret = sysdb_master_domain_add_info(test_ctx->tctx->dom,
+-                                       "realm2", "flat2", "id2", "forest2");
++                                       "realm2", "flat2", "id2", "forest2",
++                                       NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_master_domain_update(test_ctx->tctx->dom);
+@@ -298,7 +300,8 @@ static void test_sysdb_link_forest_root_ad(void **state)
+                                        TEST_REALM,
+                                        TEST_FLAT_NAME,
+                                        TEST_SID,
+-                                       TEST_FOREST);
++                                       TEST_FOREST,
++                                       NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+@@ -374,7 +377,8 @@ static void test_sysdb_link_forest_member_ad(void **state)
+                                        child_dom[1],
+                                        child_dom[2],
+                                        child_dom[3],
+-                                       TEST_FOREST);
++                                       TEST_FOREST,
++                                       NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+@@ -457,7 +461,8 @@ static void test_sysdb_link_ad_multidom(void **state)
+                                        TEST_REALM,
+                                        TEST_FLAT_NAME,
+                                        TEST_SID,
+-                                       TEST_FOREST);
++                                       TEST_FOREST,
++                                       NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(main_dom1->sysdb,
+@@ -477,7 +482,8 @@ static void test_sysdb_link_ad_multidom(void **state)
+                                        TEST_REALM2,
+                                        TEST_FLAT_NAME2,
+                                        TEST_SID2,
+-                                       TEST_FOREST2);
++                                       TEST_FOREST2,
++                                       NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(main_dom2->sysdb,
+-- 
+2.4.11
+
diff --git a/SOURCES/0024-IPA-Better-debugging.patch b/SOURCES/0024-IPA-Better-debugging.patch
deleted file mode 100644
index d589ad3..0000000
--- a/SOURCES/0024-IPA-Better-debugging.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From a42ad73cc1aca7b923c3a7ebd01580378888f002 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 22 Jul 2015 15:17:57 +0200
-Subject: [PATCH 24/27] IPA: Better debugging
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
----
- src/providers/ipa/ipa_subdomains_server.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index cd8c6301c4e4fbbf194ca98ce7a7bfe6215b381c..a9e2c1f700ef47716be868bad68590b8d5d0d42a 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -623,6 +623,9 @@ ipa_server_trust_add_send(TALLOC_CTX *mem_ctx,
- 
- immediate:
-     if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not add trusted subdomain %s from forest %s\n",
-+              subdom->name, state->forest);
-         tevent_req_error(req, ret);
-     } else {
-         tevent_req_done(req);
--- 
-2.4.3
-
diff --git a/SOURCES/0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch b/SOURCES/0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch
new file mode 100644
index 0000000..4b900cf
--- /dev/null
+++ b/SOURCES/0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch
@@ -0,0 +1,428 @@
+From f3be4b46d39c1a0106b60d561bbdeee4c80961aa Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 1 Jul 2016 12:54:39 +0200
+Subject: [PATCH 24/27] sysdb: make subdomain calls aware of upn_suffixes
+
+sysdb_subdomain_store() and sysdb_update_subdomains() can now update
+upn_suffixes as well.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 20348a30feb4be619b3b691c24c9be8131507c46)
+---
+ src/confdb/confdb.h                           |  2 +-
+ src/db/sysdb.h                                |  3 +-
+ src/db/sysdb_subdomains.c                     | 56 +++++++++++++++++++++++++--
+ src/providers/ad/ad_subdomains.c              |  2 +-
+ src/providers/ipa/ipa_subdomains.c            |  9 ++++-
+ src/tests/cmocka/test_ipa_subdomains_server.c |  4 +-
+ src/tests/cmocka/test_nss_srv.c               |  2 +-
+ src/tests/cmocka/test_sysdb_subdomains.c      | 28 +++++++-------
+ src/tests/sysdb-tests.c                       |  6 +--
+ 9 files changed, 85 insertions(+), 27 deletions(-)
+
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index 0265ccac5ee2e7b8baa05bf6b09df39ea5b4059a..72adbd80ea534eb0becd3e517c00b0c26d00444c 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -315,7 +315,7 @@ struct sss_domain_info {
+      */
+     char *forest;
+     struct sss_domain_info *forest_root;
+-    char **upn_suffixes;
++    const char **upn_suffixes;
+ };
+ 
+ /**
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index a8dcaa4a9ac5715150487f7efc9c35b778fa0163..407ce3c18a7077e8fe45c3c9c7576ae626105122 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -466,7 +466,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+                               const char *name, const char *realm,
+                               const char *flat_name, const char *domain_id,
+                               bool mpg, bool enumerate, const char *forest,
+-                              uint32_t trust_direction);
++                              uint32_t trust_direction,
++                              struct ldb_message_element *upn_suffixes);
+ 
+ errno_t sysdb_update_subdomains(struct sss_domain_info *domain);
+ 
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index c0a190f36d886325a5be1e5d1145b6aef6860ffc..02206e470e8e035cc05848137df6a1eb04806869 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -237,6 +237,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
+                            SYSDB_SUBDOMAIN_ENUM,
+                            SYSDB_SUBDOMAIN_FOREST,
+                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
++                           SYSDB_UPN_SUFFIXES,
+                            NULL};
+     struct sss_domain_info *dom;
+     struct ldb_dn *basedn;
+@@ -248,6 +249,8 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
+     bool mpg;
+     bool enumerate;
+     uint32_t trust_direction;
++    struct ldb_message_element *tmp_el;
++    const char **upn_suffixes;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -308,6 +311,17 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
+         forest = ldb_msg_find_attr_as_string(res->msgs[i],
+                                              SYSDB_SUBDOMAIN_FOREST, NULL);
+ 
++        upn_suffixes = NULL;
++        tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES);
++        if (tmp_el != NULL) {
++            upn_suffixes = sss_ldb_el_to_string_list(tmp_ctx, tmp_el);
++            if (upn_suffixes == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "sss_ldb_el_to_string_list failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++        }
++
+         trust_direction = ldb_msg_find_attr_as_int(res->msgs[i],
+                                              SYSDB_SUBDOMAIN_TRUST_DIRECTION,
+                                              0);
+@@ -382,6 +396,9 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
+                     }
+                 }
+ 
++                talloc_zfree(dom->upn_suffixes);
++                dom->upn_suffixes = talloc_steal(dom, upn_suffixes);
++
+                 if (!dom->has_views && dom->view_name == NULL) {
+                     /* maybe views are not initialized, copy from parent */
+                     dom->has_views = dom->parent->has_views;
+@@ -448,7 +465,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
+     errno_t ret;
+     TALLOC_CTX *tmp_ctx;
+     const char *tmp_str;
+-    struct ldb_message_element **tmp_el;
++    struct ldb_message_element *tmp_el;
+     struct ldb_dn *basedn;
+     struct ldb_result *res;
+     const char *attrs[] = {"cn",
+@@ -806,7 +823,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+                               const char *name, const char *realm,
+                               const char *flat_name, const char *domain_id,
+                               bool mpg, bool enumerate, const char *forest,
+-                              uint32_t trust_direction)
++                              uint32_t trust_direction,
++                              struct ldb_message_element *upn_suffixes)
+ {
+     TALLOC_CTX *tmp_ctx;
+     struct ldb_message *msg;
+@@ -820,8 +838,10 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+                            SYSDB_SUBDOMAIN_ENUM,
+                            SYSDB_SUBDOMAIN_FOREST,
+                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
++                           SYSDB_UPN_SUFFIXES,
+                            NULL};
+     const char *tmp_str;
++    struct ldb_message_element *tmp_el;
+     bool tmp_bool;
+     bool store = false;
+     int realm_flags = 0;
+@@ -831,6 +851,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+     int enum_flags = 0;
+     int forest_flags = 0;
+     int td_flags = 0;
++    int upn_flags = 0;
+     uint32_t tmp_td;
+     int ret;
+ 
+@@ -864,6 +885,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+         enum_flags = LDB_FLAG_MOD_ADD;
+         if (forest) forest_flags = LDB_FLAG_MOD_ADD;
+         if (trust_direction) td_flags = LDB_FLAG_MOD_ADD;
++        if (upn_suffixes) upn_flags = LDB_FLAG_MOD_ADD;
+     } else if (res->count != 1) {
+         ret = EINVAL;
+         goto done;
+@@ -915,11 +937,21 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+         if (tmp_td != trust_direction) {
+             td_flags = LDB_FLAG_MOD_REPLACE;
+         }
++
++        if (upn_suffixes) {
++            tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES);
++            /* Luckily ldb_msg_element_compare() only compares the values and
++             * not the name. */
++            if (tmp_el == NULL
++                    || ldb_msg_element_compare(upn_suffixes, tmp_el) != 0) {
++                upn_flags = LDB_FLAG_MOD_REPLACE;
++            }
++        }
+     }
+ 
+     if (!store && realm_flags == 0 && flat_flags == 0 && id_flags == 0
+             && mpg_flags == 0 && enum_flags == 0 && forest_flags == 0
+-            && td_flags == 0) {
++            && td_flags == 0 && upn_flags == 0) {
+         ret = EOK;
+         goto done;
+     }
+@@ -1048,6 +1080,24 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+         }
+     }
+ 
++    if (upn_flags) {
++        tmp_el = talloc_zero(tmp_ctx, struct ldb_message_element);
++        if (tmp_el == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        tmp_el->name = SYSDB_UPN_SUFFIXES;
++        tmp_el->num_values = upn_suffixes->num_values;
++        tmp_el->values = upn_suffixes->values;
++        ret = ldb_msg_add(msg, tmp_el, upn_flags);
++        if (ret != LDB_SUCCESS) {
++            ret = sysdb_error_to_errno(ret);
++            goto done;
++        }
++    }
++
+     ret = ldb_modify(sysdb->ldb, msg);
+     if (ret != LDB_SUCCESS) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to "
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 0a8d1f53cb005507abe4ac55d0fa1ccc9e32b173..928c4fe93cc6afa5c3f69c14503896db820a4c0a 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -252,7 +252,7 @@ ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
+     mpg = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, name, sid_str);
+ 
+     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
+-                                mpg, enumerate, domain->forest, 0);
++                                mpg, enumerate, domain->forest, 0, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n");
+         goto done;
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 62b8f65e5d29a4850f90ea7c19abd297becc96f5..925b1d8b133eb56724ee4f9133a2487090982a8b 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -375,6 +375,7 @@ static errno_t ipa_subdom_store(struct sss_domain_info *parent,
+     bool mpg;
+     bool enumerate;
+     uint32_t direction;
++    struct ldb_message_element *alternative_domain_suffixes = NULL;
+ 
+     tmp_ctx = talloc_new(parent);
+     if (tmp_ctx == NULL) {
+@@ -405,6 +406,12 @@ static errno_t ipa_subdom_store(struct sss_domain_info *parent,
+         goto done;
+     }
+ 
++    ret = sysdb_attrs_get_el_ext(attrs, IPA_ADDITIONAL_SUFFIXES, false,
++                                 &alternative_domain_suffixes);
++    if (ret != EOK && ret != ENOENT) {
++        goto done;
++    }
++
+     mpg = sdap_idmap_domain_has_algorithmic_mapping(sdap_idmap_ctx, name, id);
+ 
+     ret = ipa_subdom_get_forest(tmp_ctx, sysdb_ctx_get_ldb(parent->sysdb),
+@@ -431,7 +438,7 @@ static errno_t ipa_subdom_store(struct sss_domain_info *parent,
+           "Trust direction of %s is %s\n", name, ipa_trust_dir2str(direction));
+     ret = sysdb_subdomain_store(parent->sysdb, name, realm, flat,
+                                 id, mpg, enumerate, forest,
+-                                direction);
++                                direction, alternative_domain_suffixes);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n");
+         goto done;
+diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c
+index 0fddc951894dee45658497851473b9bddbba0ef7..123cf11c01ef4687eecad31a9d73120a87c643e1 100644
+--- a/src/tests/cmocka/test_ipa_subdomains_server.c
++++ b/src/tests/cmocka/test_ipa_subdomains_server.c
+@@ -253,14 +253,14 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx,
+                                 SUBDOM_NAME, SUBDOM_REALM,
+                                 NULL, SUBDOM_SID,
+                                 true, false, SUBDOM_REALM,
+-                                direction);
++                                direction, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 CHILD_NAME, CHILD_REALM,
+                                 CHILD_FLAT, CHILD_SID,
+                                 true, false, SUBDOM_REALM,
+-                                direction);
++                                direction, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index 4137e9151be561a57a8f2e674f385ecb37119255..82a304feed864b09168d0f3e06a4e1bb120df7e4 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -3089,7 +3089,7 @@ static int nss_subdom_test_setup(void **state)
+ 
+     ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+-                                false, false, NULL, 0);
++                                false, false, NULL, 0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom);
+diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
+index 6d1ec884284487a12bcbfad77c00cd6c30f67707..c9db56841e841472c81d00a79f475dbbd975ccb0 100644
+--- a/src/tests/cmocka/test_sysdb_subdomains.c
++++ b/src/tests/cmocka/test_sysdb_subdomains.c
+@@ -103,7 +103,7 @@ static void test_sysdb_subdomain_create(void **state)
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 dom1[0], dom1[1], dom1[2], dom1[3],
+-                                false, false, NULL, 0);
++                                false, false, NULL, 0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+@@ -115,7 +115,7 @@ static void test_sysdb_subdomain_create(void **state)
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 dom2[0], dom2[1], dom2[2], dom2[3],
+-                                false, false, NULL, 1);
++                                false, false, NULL, 1, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+@@ -128,12 +128,12 @@ static void test_sysdb_subdomain_create(void **state)
+     /* Reverse the trust directions */
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 dom1[0], dom1[1], dom1[2], dom1[3],
+-                                false, false, NULL, 1);
++                                false, false, NULL, 1, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 dom2[0], dom2[1], dom2[2], dom2[3],
+-                                false, false, NULL, 0);
++                                false, false, NULL, 0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+@@ -215,27 +215,27 @@ static void test_sysdb_link_forest_root_ipa(void **state)
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 dom1[0], dom1[1], dom1[2], dom1[3],
+-                                false, false, dom1[4], 0);
++                                false, false, dom1[4], 0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 child_dom1[0], child_dom1[1],
+                                 child_dom1[2], child_dom1[3],
+                                 false, false, child_dom1[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 dom2[0], dom2[1], dom2[2], dom2[3],
+                                 false, false, dom2[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 child_dom2[0], child_dom2[1],
+                                 child_dom2[2], child_dom2[3],
+                                 false, false, child_dom2[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+@@ -308,14 +308,14 @@ static void test_sysdb_link_forest_root_ad(void **state)
+                                 child_dom[0], child_dom[1],
+                                 child_dom[2], child_dom[3],
+                                 false, false, child_dom[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 sub_dom[0], sub_dom[1],
+                                 sub_dom[2], sub_dom[3],
+                                 false, false, sub_dom[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+@@ -385,14 +385,14 @@ static void test_sysdb_link_forest_member_ad(void **state)
+                                 sub_dom[0], sub_dom[1],
+                                 sub_dom[2], sub_dom[3],
+                                 false, false, sub_dom[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+                                 forest_root[0], forest_root[1],
+                                 forest_root[2], forest_root[3],
+                                 false, false, forest_root[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_master_domain_update(test_ctx->tctx->dom);
+@@ -469,7 +469,7 @@ static void test_sysdb_link_ad_multidom(void **state)
+                                 child_dom[0], child_dom[1],
+                                 child_dom[2], child_dom[3],
+                                 false, false, child_dom[4],
+-                                0);
++                                0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_master_domain_update(main_dom1);
+@@ -489,7 +489,7 @@ static void test_sysdb_link_ad_multidom(void **state)
+     ret = sysdb_subdomain_store(main_dom2->sysdb,
+                                 dom2_forest_root[0], dom2_forest_root[1],
+                                 dom2_forest_root[2], dom2_forest_root[3],
+-                                false, false, dom2_forest_root[4], 0);
++                                false, false, dom2_forest_root[4], 0, NULL);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sysdb_master_domain_update(main_dom2);
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index bac8a8788b4fde0d6039121efead6fc20fa046f9..d1450015cb0f0b073045e7b6031423e3f5494d78 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -5472,7 +5472,7 @@ START_TEST(test_sysdb_subdomain_store_user)
+     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
+     ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+-                                false, false, NULL, 0);
++                                false, false, NULL, 0, NULL);
+     fail_if(ret != EOK, "Could not set up the test (test subdom)");
+ 
+     ret = sysdb_update_subdomains(test_ctx->domain);
+@@ -5551,7 +5551,7 @@ START_TEST(test_sysdb_subdomain_user_ops)
+     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
+     ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+-                                false, false, NULL, 0);
++                                false, false, NULL, 0, NULL);
+     fail_if(ret != EOK, "Could not set up the test (test subdom)");
+ 
+     ret = sysdb_update_subdomains(test_ctx->domain);
+@@ -5624,7 +5624,7 @@ START_TEST(test_sysdb_subdomain_group_ops)
+     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
+     ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+-                                false, false, NULL, 0);
++                                false, false, NULL, 0, NULL);
+     fail_if(ret != EOK, "Could not set up the test (test subdom)");
+ 
+     ret = sysdb_update_subdomains(test_ctx->domain);
+-- 
+2.4.11
+
diff --git a/SOURCES/0025-DP-add-dp_get_module_data.patch b/SOURCES/0025-DP-add-dp_get_module_data.patch
new file mode 100644
index 0000000..bd41853
--- /dev/null
+++ b/SOURCES/0025-DP-add-dp_get_module_data.patch
@@ -0,0 +1,44 @@
+From 5ce7c218a7bd34672bd19359dcbeed51cc237474 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 1 Jul 2016 17:57:31 +0200
+Subject: [PATCH 25/27] DP: add dp_get_module_data()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 35fa5a83ce8badf6bc868937047f44c3f32b7c28)
+---
+ src/providers/data_provider/dp.h         | 2 ++
+ src/providers/data_provider/dp_targets.c | 5 +++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
+index 8cdbd7768a0b3f7f234b6bce6abab02419b3b9d1..5b36baf3489be4cce463dfb42c65a0b7f7ece9ef 100644
+--- a/src/providers/data_provider/dp.h
++++ b/src/providers/data_provider/dp.h
+@@ -118,6 +118,8 @@ bool _dp_target_enabled(struct data_provider *provider,
+ struct dp_module *dp_target_module(struct data_provider *provider,
+                                    enum dp_targets target);
+ 
++void *dp_get_module_data(struct dp_module *dp_module);
++
+ void _dp_set_method(struct dp_method *methods,
+                     enum dp_methods method,
+                     dp_req_send_fn send_fn,
+diff --git a/src/providers/data_provider/dp_targets.c b/src/providers/data_provider/dp_targets.c
+index e19cf93a3693dede98567d2105021488380b5408..87ecfe55daa805eec0265795ef76751a1568c474 100644
+--- a/src/providers/data_provider/dp_targets.c
++++ b/src/providers/data_provider/dp_targets.c
+@@ -88,6 +88,11 @@ struct dp_module *dp_target_module(struct data_provider *provider,
+     return provider->targets[target]->module;
+ }
+ 
++void *dp_get_module_data(struct dp_module *dp_module)
++{
++    return dp_module == NULL ? NULL : dp_module->module_data;
++}
++
+ const char *dp_target_to_string(enum dp_targets target)
+ {
+     switch (target) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0025-UTIL-Lower-debug-level-in-perform_checks.patch b/SOURCES/0025-UTIL-Lower-debug-level-in-perform_checks.patch
deleted file mode 100644
index c0b93de..0000000
--- a/SOURCES/0025-UTIL-Lower-debug-level-in-perform_checks.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From ce03dffa77053f837ff4d7e0fbb3208118f2d768 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 22 Jul 2015 16:29:09 +0200
-Subject: [PATCH 25/27] UTIL: Lower debug level in perform_checks()
-
-Failures in perform_checks() don't have to be fatal, therefore the debug
-messages shouldn't be either.
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
----
- src/util/check_and_open.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/src/util/check_and_open.c b/src/util/check_and_open.c
-index 59b90bf4b96731e385fcf92ed8bc251cb94abfda..b40ae2003e3de22ce9e4ca07cecc68e18a7abab4 100644
---- a/src/util/check_and_open.c
-+++ b/src/util/check_and_open.c
-@@ -99,12 +99,12 @@ static errno_t perform_checks(struct stat *stat_buf,
-     }
- 
-     if ((mode & S_IFMT) != (st_mode & S_IFMT)) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "File is not the right type.\n");
-+        DEBUG(SSSDBG_TRACE_LIBS, "File is not the right type.\n");
-         return EINVAL;
-     }
- 
-     if ((st_mode & ALLPERMS) != (mode & ALLPERMS)) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
-+        DEBUG(SSSDBG_TRACE_LIBS,
-               "File has the wrong (bit masked) mode [%.7o], "
-               "expected [%.7o].\n",
-               (st_mode & ALLPERMS), (mode & ALLPERMS));
-@@ -112,12 +112,12 @@ static errno_t perform_checks(struct stat *stat_buf,
-     }
- 
-     if (uid != (uid_t)(-1) && stat_buf->st_uid != uid) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "File must be owned by uid [%d].\n", uid);
-+        DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by uid [%d].\n", uid);
-         return EINVAL;
-     }
- 
-     if (gid != (gid_t)(-1) && stat_buf->st_gid != gid) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "File must be owned by gid [%d].\n", gid);
-+        DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by gid [%d].\n", gid);
-         return EINVAL;
-     }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0026-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch b/SOURCES/0026-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch
deleted file mode 100644
index fceec58..0000000
--- a/SOURCES/0026-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch
+++ /dev/null
@@ -1,116 +0,0 @@
-From dba7ccc7594be1881967aa274090d61a97aec5fa Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 22 Jul 2015 17:20:11 +0200
-Subject: [PATCH 26/27] IPA: Handle sssd-owned keytabs when running as root
-
-https://fedorahosted.org/sssd/ticket/2718
-
-This patch handles the case where the keytab is created with sssd:sssd
-ownership (perhaps by the IPA oddjob script) but SSSD runs as root,
-which is the default in many distributions.
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
----
- src/providers/ipa/ipa_subdomains.h        |  3 ++
- src/providers/ipa/ipa_subdomains_server.c | 46 +++++++++++++++++++++++++------
- 2 files changed, 41 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h
-index 5bc63a173a1a8967eb5de30a2da84a81377d3900..2302c5f03e80de2ea1efad424769e777cd6dd8d5 100644
---- a/src/providers/ipa/ipa_subdomains.h
-+++ b/src/providers/ipa/ipa_subdomains.h
-@@ -94,6 +94,9 @@ struct ipa_server_mode_ctx {
- 
-     struct ipa_ad_server_ctx *trusts;
-     struct ipa_ext_groups *ext_groups;
-+
-+    uid_t kt_owner_uid;
-+    uid_t kt_owner_gid;
- };
- 
- int ipa_ad_subdom_init(struct be_ctx *be_ctx,
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index a9e2c1f700ef47716be868bad68590b8d5d0d42a..4bfea61e6dd0a02f6b723a39f7ba236c914009b0 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -520,16 +520,28 @@ static errno_t ipa_getkeytab_recv(struct tevent_req *req, int *child_status)
-     return EOK;
- }
- 
--static errno_t ipa_check_keytab(const char *keytab)
-+static errno_t ipa_check_keytab(const char *keytab,
-+                                uid_t kt_owner_uid,
-+                                gid_t kt_owner_gid)
- {
-     errno_t ret;
- 
-     ret = check_file(keytab, getuid(), getgid(), S_IFREG|0600, 0, NULL, false);
--    if (ret != EOK) {
--        if (ret != ENOENT) {
--            DEBUG(SSSDBG_OP_FAILURE, "Failed to check for %s\n", keytab);
--        } else {
--            DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab);
-+    if (ret == ENOENT) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab);
-+        goto done;
-+    } else if (ret != EOK) {
-+        if (kt_owner_uid) {
-+            ret = check_file(keytab, kt_owner_uid, kt_owner_gid,
-+                             S_IFREG|0600, 0, NULL, false);
-+        }
-+
-+        if (ret != EOK) {
-+            if (ret != ENOENT) {
-+                DEBUG(SSSDBG_OP_FAILURE, "Failed to check for %s\n", keytab);
-+            } else {
-+                DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab);
-+            }
-         }
-         goto done;
-     }
-@@ -648,7 +660,9 @@ static errno_t ipa_server_trust_add_1way(struct tevent_req *req)
-         return EIO;
-     }
- 
--    ret = ipa_check_keytab(state->keytab);
-+    ret = ipa_check_keytab(state->keytab,
-+                           state->id_ctx->server_mode->kt_owner_uid,
-+                           state->id_ctx->server_mode->kt_owner_gid);
-     if (ret == EOK) {
-         DEBUG(SSSDBG_TRACE_FUNC,
-               "Keytab already present, can add the trust\n");
-@@ -704,7 +718,9 @@ static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq)
-     DEBUG(SSSDBG_TRACE_FUNC,
-           "Keytab successfully retrieved to %s\n", state->keytab);
- 
--    ret = ipa_check_keytab(state->keytab);
-+    ret = ipa_check_keytab(state->keytab,
-+                           state->id_ctx->server_mode->kt_owner_uid,
-+                           state->id_ctx->server_mode->kt_owner_gid);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "ipa_check_keytab failed: %d\n", ret);
-         tevent_req_error(req, ret);
-@@ -1029,6 +1045,20 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx,
-     id_ctx->server_mode->hostname = hostname;
-     id_ctx->server_mode->trusts = NULL;
-     id_ctx->server_mode->ext_groups = NULL;
-+    id_ctx->server_mode->kt_owner_uid = 0;
-+    id_ctx->server_mode->kt_owner_gid = 0;
-+
-+    if (getuid() == 0) {
-+        /* We need to handle keytabs created by IPA oddjob script gracefully
-+         * even if we're running as root and IPA creates them as the SSSD user
-+         */
-+        ret = sss_user_by_name_or_uid(SSSD_USER,
-+                                      &id_ctx->server_mode->kt_owner_uid,
-+                                      &id_ctx->server_mode->kt_owner_gid);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get ID of %s\n", SSSD_USER);
-+        }
-+    }
- 
-     ret = ipa_ad_subdom_reinit(be_ctx, be_ctx->ev,
-                                be_ctx, id_ctx, be_ctx->domain);
--- 
-2.4.3
-
diff --git a/SOURCES/0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch b/SOURCES/0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch
new file mode 100644
index 0000000..878d78e
--- /dev/null
+++ b/SOURCES/0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch
@@ -0,0 +1,60 @@
+From ec460578800d850e5a4f9d522920db1d79147dd6 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 1 Jul 2016 17:58:02 +0200
+Subject: [PATCH 26/27] IPA: add ipa_init_get_krb5_auth_ctx()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 17dccc24e4490dfda2820d46b62a029b14ba2359)
+---
+ src/providers/ipa/ipa_common.h |  5 +++++
+ src/providers/ipa/ipa_init.c   | 13 +++++++++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
+index 939c898e1a690806abd37493aabfb7bdec3e87a9..add9df87692c732b3567eee5584e7698991c66ca 100644
+--- a/src/providers/ipa/ipa_common.h
++++ b/src/providers/ipa/ipa_common.h
+@@ -34,6 +34,8 @@ struct ipa_service {
+     struct krb5_service *krb5_service;
+ };
+ 
++struct ipa_init_ctx;
++
+ enum ipa_basic_opt {
+     IPA_DOMAIN = 0,
+     IPA_SERVER,
+@@ -287,4 +289,7 @@ errno_t ipa_idmap_get_ranges_from_sysdb(struct sdap_idmap_ctx *idmap_ctx,
+ errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx,
+                        struct sdap_id_ctx *id_ctx,
+                        struct sdap_idmap_ctx **_idmap_ctx);
++
++
++struct krb5_ctx *ipa_init_get_krb5_auth_ctx(void *data);
+ #endif /* _IPA_COMMON_H_ */
+diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
+index d3093b3b5d269e6acd29f35560cf8299017c72b5..959cdb4a7c40c1be03dd1e7c66dee6e65ca76607 100644
+--- a/src/providers/ipa/ipa_init.c
++++ b/src/providers/ipa/ipa_init.c
+@@ -58,6 +58,19 @@ struct ipa_init_ctx {
+     struct ipa_auth_ctx *auth_ctx;
+ };
+ 
++
++struct krb5_ctx *ipa_init_get_krb5_auth_ctx(void *data)
++{
++    struct ipa_init_ctx *ipa_init_ctx;
++
++    ipa_init_ctx = talloc_get_type(data, struct ipa_init_ctx);
++    if (ipa_init_ctx == NULL || ipa_init_ctx->auth_ctx == NULL) {
++        return NULL;
++    }
++
++    return ipa_init_ctx->auth_ctx->krb5_auth_ctx;
++}
++
+ static bool srv_in_server_list(const char *servers)
+ {
+     TALLOC_CTX *tmp_ctx;
+-- 
+2.4.11
+
diff --git a/SOURCES/0027-IPA-enable-enterprise-principals-if-server-supports-.patch b/SOURCES/0027-IPA-enable-enterprise-principals-if-server-supports-.patch
new file mode 100644
index 0000000..8589359
--- /dev/null
+++ b/SOURCES/0027-IPA-enable-enterprise-principals-if-server-supports-.patch
@@ -0,0 +1,149 @@
+From 6b5b0732b7f4fab195a6205e1046a8402f5d3040 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 1 Jul 2016 18:18:14 +0200
+Subject: [PATCH 27/27] IPA: enable enterprise principals if server supports
+ them
+
+If there are alternative UPN suffixes found on the server we can safely
+assume that the IPA server supports enterprise principals.
+
+Resolves https://fedorahosted.org/sssd/ticket/3018
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 70673115c03c37ddc64c951b53d92df9d3310762)
+---
+ src/man/sssd-krb5.5.xml            |  6 +++
+ src/providers/ipa/ipa_subdomains.c | 86 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 92 insertions(+)
+
+diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml
+index e7fdd19e07db99314a9491faff9974d7d5e617e6..60b7dfb508c0d054a421fd46957574f52e0333d7 100644
+--- a/src/man/sssd-krb5.5.xml
++++ b/src/man/sssd-krb5.5.xml
+@@ -513,6 +513,12 @@
+                         <para>
+                             Default: false (AD provider: true)
+                         </para>
++                        <para>
++                            The IPA provider will set to option to 'true' if it
++                            detects that the server is capable of handling
++                            enterprise principals and the option is not set
++                            explicitly in the config file.
++                        </para>
+                     </listitem>
+                 </varlistentry>
+ 
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 925b1d8b133eb56724ee4f9133a2487090982a8b..4e5bceb8c761bf4476928168d620baf2beb62ad5 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -28,6 +28,7 @@
+ #include "providers/ipa/ipa_subdomains.h"
+ #include "providers/ipa/ipa_common.h"
+ #include "providers/ipa/ipa_id.h"
++#include "providers/ipa/ipa_opts.h"
+ 
+ #include <ctype.h>
+ 
+@@ -999,6 +1000,84 @@ immediately:
+     return req;
+ }
+ 
++static errno_t ipa_enable_enterprise_principals(struct be_ctx *be_ctx)
++{
++    int ret;
++    struct sss_domain_info *d;
++    TALLOC_CTX *tmp_ctx;
++    char **vals = NULL;
++    struct dp_module *auth;
++    struct krb5_ctx *krb5_auth_ctx;
++
++    d = get_domains_head(be_ctx->domain);
++
++    while (d != NULL) {
++        DEBUG(SSSDBG_TRACE_ALL, "checking [%s].\n", d->name);
++        if (d->upn_suffixes != NULL) {
++            break;
++        }
++        d = get_next_domain(d, SSS_GND_DESCEND);
++    }
++
++    if (d == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL,
++              "No UPN suffixes found, "
++              "no need to enable enterprise principals.\n");
++        return EOK;
++    }
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    ret = confdb_get_param(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
++                     ipa_def_krb5_opts[KRB5_USE_ENTERPRISE_PRINCIPAL].opt_name,
++                     &vals);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "confdb_get_param failed.\n");
++        goto done;
++    }
++
++    if (vals[0]) {
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "Parameter [%s] set in config file and will not be changed.\n",
++              ipa_def_krb5_opts[KRB5_USE_ENTERPRISE_PRINCIPAL].opt_name);
++        return EOK;
++    }
++
++    auth = dp_target_module(be_ctx->provider, DPT_AUTH);
++    if (auth == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "Unable to find auth proivder.\n");
++        ret = EINVAL;
++        goto done;
++    }
++
++    krb5_auth_ctx = ipa_init_get_krb5_auth_ctx(dp_get_module_data(auth));
++    if (krb5_auth_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "Unable to find auth proivder data.\n");
++        ret = EINVAL;
++        goto done;
++    }
++
++    ret = dp_opt_set_bool(krb5_auth_ctx->opts,
++                          KRB5_USE_ENTERPRISE_PRINCIPAL, true);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "dp_opt_set_bool failed.\n");
++        goto done;
++    }
++
++    DEBUG(SSSDBG_CONF_SETTINGS, "Enterprise principals enabled.\n");
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
+ static void ipa_subdomains_slave_search_done(struct tevent_req *subreq)
+ {
+     struct ipa_subdomains_slave_state *state;
+@@ -1037,6 +1116,13 @@ static void ipa_subdomains_slave_search_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
++    ret = ipa_enable_enterprise_principals(state->sd_ctx->be_ctx);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_enable_enterprise_principals failed. "
++                                 "Enterprise principals might not work as "
++                                 "expected.\n");
++    }
++
+     if (state->sd_ctx->ipa_id_ctx->server_mode == NULL) {
+         ret = EOK;
+         goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0027-TESTS-fix-compiler-warnings.patch b/SOURCES/0027-TESTS-fix-compiler-warnings.patch
deleted file mode 100644
index 92545e5..0000000
--- a/SOURCES/0027-TESTS-fix-compiler-warnings.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From b211247a005257a4e2dec0d43b719600c51a14d4 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Tue, 28 Jul 2015 04:12:48 -0400
-Subject: [PATCH 27/27] TESTS: fix compiler warnings
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
----
- src/confdb/confdb.h                 | 2 +-
- src/tests/cmocka/test_sysdb_views.c | 2 --
- 2 files changed, 1 insertion(+), 3 deletions(-)
-
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 36df6aea268cc5c82696f20b1a65963350d5e100..0b0ae0dcf2cd26462a9b0c895d833faf5c85b4e5 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -266,7 +266,7 @@ struct sss_domain_info {
-     struct timeval subdomains_last_checked;
- 
-     bool has_views;
--    char *view_name;
-+    const char *view_name;
- 
-     struct sss_domain_info *prev;
-     struct sss_domain_info *next;
-diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
-index 83007b76a625edef67109850648b2d71645e22bb..c53d8187b181a5937f642eec32af28e8207b292b 100644
---- a/src/tests/cmocka/test_sysdb_views.c
-+++ b/src/tests/cmocka/test_sysdb_views.c
-@@ -285,7 +285,6 @@ void test_sysdb_add_overrides_to_object_local(void **state)
- {
-     int ret;
-     struct ldb_message *orig;
--    struct ldb_message_element *el;
-     char *tmp_str;
-     struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-                                                          struct sysdb_test_ctx);
-@@ -314,7 +313,6 @@ void test_sysdb_add_overrides_to_object_missing_overridedn(void **state)
- {
-     int ret;
-     struct ldb_message *orig;
--    struct ldb_message_element *el;
-     char *tmp_str;
-     struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
-                                                          struct sysdb_test_ctx);
--- 
-2.4.3
-
diff --git a/SOURCES/0028-intg-Invalidate-memory-cache-before-removing-files.patch b/SOURCES/0028-intg-Invalidate-memory-cache-before-removing-files.patch
deleted file mode 100644
index 80cc677..0000000
--- a/SOURCES/0028-intg-Invalidate-memory-cache-before-removing-files.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From daf44387652fe46a2c8e694720f6b14436a6f31f Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 24 Jul 2015 12:31:42 +0200
-Subject: [PATCH 28/37] intg: Invalidate memory cache before removing files
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Workaround for:
-https://fedorahosted.org/sssd/ticket/2726
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/tests/intg/ldap_test.py | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/tests/intg/ldap_test.py b/src/tests/intg/ldap_test.py
-index afc77d7023ea31757def84f21e5d15997ba72013..bfe4e65ee54e232cd37d91f8ca5b6e9edf42b49d 100644
---- a/src/tests/intg/ldap_test.py
-+++ b/src/tests/intg/ldap_test.py
-@@ -90,6 +90,7 @@ def create_sssd_fixture(request):
-                 time.sleep(1)
-         except:
-             pass
-+        subprocess.call(["sss_cache", "-E"])
-         for path in os.listdir(config.DB_PATH):
-             os.unlink(config.DB_PATH + "/" + path)
-         for path in os.listdir(config.MCACHE_PATH):
--- 
-2.4.3
-
diff --git a/SOURCES/0028-views-allow-override-added-for-non-default-views-at-.patch b/SOURCES/0028-views-allow-override-added-for-non-default-views-at-.patch
new file mode 100644
index 0000000..fb5707c
--- /dev/null
+++ b/SOURCES/0028-views-allow-override-added-for-non-default-views-at-.patch
@@ -0,0 +1,74 @@
+From 845e3a3acea6f83b15ed3d887fcc4ed42cb3eb5a Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 11 Jul 2016 15:04:32 +0200
+Subject: [PATCH 28/31] views: allow override added for non-default views at
+ runtime
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Currently a new override for a non-default view cannot be displayed at
+run-time. It even does not only require a restart but the view must be
+un-applied and applied again to make the changes visible.
+
+This patch fixes this and makes non-default view behave like the default
+view where the data from a newly added override are displayed after the
+cached entry of the related object is expired.
+
+Resolves https://fedorahosted.org/sssd/ticket/3092
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 26a3d4f2ef35a088e4c5fc928290052c89a2ff43)
+---
+ src/db/sysdb_views.c | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 7adc1523050243b8936cb98be3c71ce4364a03db..2b89e5ca41f719e1217ef3b9e0fd683656e05d42 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -454,15 +454,23 @@ errno_t sysdb_store_override(struct sss_domain_info *domain,
+     obj_override_dn = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OVERRIDE_DN,
+                                                   NULL);
+     if (obj_override_dn != NULL) {
++        /* obj_override_dn can either point to the object itself, i.e there is
++         * no override, or to a overide object. This means it can change from
++         * the object DN to a override DN and back but not from one override
++         * DN to a different override DN. If the new and the old DN are the
++         * same we do not need to update the original object.  */
+         if (strcmp(obj_override_dn, override_dn_str) != 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Existing [%s] and new [%s] override DN do not match.\n",
+-                   obj_override_dn, override_dn_str);
+-            ret = EINVAL;
+-            goto done;
++            if (strcmp(obj_override_dn, obj_dn_str) != 0
++                    && strcmp(override_dn_str, obj_dn_str) != 0) {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Existing [%s] and new [%s] override DN do not match.\n",
++                       obj_override_dn, override_dn_str);
++                ret = EINVAL;
++                goto done;
++            }
++        } else {
++            add_ref = false;
+         }
+-
+-        add_ref = false;
+     }
+ 
+     ret = ldb_transaction_start(domain->sysdb->ldb);
+@@ -580,7 +588,9 @@ errno_t sysdb_store_override(struct sss_domain_info *domain,
+ 
+         msg->dn = obj_dn;
+ 
+-        ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_ADD,
++        ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN,
++                                obj_override_dn == NULL ? LDB_FLAG_MOD_ADD
++                                                        : LDB_FLAG_MOD_REPLACE,
+                                 NULL);
+         if (ret != LDB_SUCCESS) {
+             DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+-- 
+2.4.11
+
diff --git a/SOURCES/0029-krb5-do-not-send-SSS_OTP-if-two-factors-were-used.patch b/SOURCES/0029-krb5-do-not-send-SSS_OTP-if-two-factors-were-used.patch
deleted file mode 100644
index 1399bd5..0000000
--- a/SOURCES/0029-krb5-do-not-send-SSS_OTP-if-two-factors-were-used.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 8ffbe4698421aaafa59f0813232883c4fc41514d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 23 Jul 2015 15:56:44 +0200
-Subject: [PATCH 29/37] krb5: do not send SSS_OTP if two factors were used
-
-Resolves https://fedorahosted.org/sssd/ticket/2729
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_auth.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
-index 8886456c00c86914da364fd08efc25a488b0e686..d1bf4025b052d82413d1f370a36b0b99720d6f05 100644
---- a/src/providers/krb5/krb5_auth.c
-+++ b/src/providers/krb5/krb5_auth.c
-@@ -1091,7 +1091,12 @@ 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) {
-+    /* The SSS_OTP message will prevent pam_sss from putting the entered
-+     * password on the PAM stack for other modules to use. This is not needed
-+     * when both factors were entered separately because here the first factor
-+     * (long term password) can be passed to the other modules. */
-+    if (res->otp == true && pd->cmd == SSS_PAM_AUTHENTICATE
-+            && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_2FA) {
-         uint32_t otp_flag = 1;
-         ret = pam_add_response(pd, SSS_OTP, sizeof(uint32_t),
-                                (const uint8_t *) &otp_flag);
--- 
-2.4.3
-
diff --git a/SOURCES/0029-sssctl-move-filter-creation-to-separate-function.patch b/SOURCES/0029-sssctl-move-filter-creation-to-separate-function.patch
new file mode 100644
index 0000000..6abaf60
--- /dev/null
+++ b/SOURCES/0029-sssctl-move-filter-creation-to-separate-function.patch
@@ -0,0 +1,129 @@
+From 634311d9250903599a61b2f5e205e2568ae92497 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 12 Jul 2016 12:59:48 +0200
+Subject: [PATCH 29/31] sssctl: move filter creation to separate function
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+(cherry picked from commit 3c6e15e8aa38d9dfa02a7255fad56149bdfb35a6)
+---
+ src/tools/sssctl/sssctl_cache.c | 81 +++++++++++++++++++++++------------------
+ 1 file changed, 46 insertions(+), 35 deletions(-)
+
+diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
+index e23bb89db95217e66a441b7e4d6d32e668486cc8..3e7644e327eb3e5a0e33023e7a3f5f0f15e03cf6 100644
+--- a/src/tools/sssctl/sssctl_cache.c
++++ b/src/tools/sssctl/sssctl_cache.c
+@@ -285,27 +285,16 @@ done:
+     return ret;
+ }
+ 
+-static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx,
+-                                  struct sss_domain_info *domains,
+-                                  struct sss_domain_info *domain,
+-                                  sssctl_basedn_fn basedn_fn,
+-                                  enum cache_object obj_type,
+-                                  const char *attr_name,
+-                                  const char *attr_value,
+-                                  const char **attrs,
+-                                  struct sysdb_attrs **_entry,
+-                                  struct sss_domain_info **_dom)
++static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx,
++                                        struct sss_domain_info *dom,
++                                        enum cache_object obj_type,
++                                        const char *attr_name,
++                                        const char *attr_value)
+ {
+-    TALLOC_CTX *tmp_ctx;
+-    struct sss_domain_info *dom;
+-    struct sysdb_attrs *entry;
+-    struct ldb_dn *base_dn;
+-    bool fqn_provided;
+-    bool qualify_attr = false;
+-    char *filter;
+-    errno_t ret;
+     const char *class;
++    const char *filter;
+     char *filter_value;
++    bool qualify_attr = false;
+ 
+     if (strcmp(attr_name, SYSDB_NAME) == 0 &&
+             (obj_type == CACHED_USER ||
+@@ -326,9 +315,44 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx,
+     default:
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "sssctl doesn't handle this object type (type=%d)\n", obj_type);
+-        return EINVAL;
++        return NULL;
+     }
+ 
++    if (qualify_attr) {
++        filter_value = sss_create_internal_fqname(NULL, attr_value, dom->name);
++    } else {
++        filter_value = talloc_strdup(NULL, attr_value);
++    }
++    if (filter_value == NULL) {
++        return NULL;
++    }
++
++    filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))",
++                             class, attr_name, filter_value);
++    talloc_free(filter_value);
++
++    return filter;
++}
++
++static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx,
++                                  struct sss_domain_info *domains,
++                                  struct sss_domain_info *domain,
++                                  sssctl_basedn_fn basedn_fn,
++                                  enum cache_object obj_type,
++                                  const char *attr_name,
++                                  const char *attr_value,
++                                  const char **attrs,
++                                  struct sysdb_attrs **_entry,
++                                  struct sss_domain_info **_dom)
++{
++    TALLOC_CTX *tmp_ctx;
++    struct sss_domain_info *dom;
++    struct sysdb_attrs *entry;
++    struct ldb_dn *base_dn;
++    bool fqn_provided;
++    const char *filter;
++    errno_t ret;
++
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+@@ -349,23 +373,10 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+ 
+-        if (qualify_attr) {
+-            filter_value = sss_create_internal_fqname(tmp_ctx,
+-                                                      attr_value,
+-                                                      dom->name);
+-        } else {
+-            filter_value = talloc_strdup(tmp_ctx, attr_value);
+-        }
+-        if (filter_value == NULL) {
+-            ret = ENOMEM;
+-            goto done;
+-        }
+-
+-        filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(%s=%s))",
+-                                 class, attr_name, filter_value);
+-        talloc_free(filter_value);
++        filter = sssctl_create_filter(tmp_ctx, dom, obj_type,
++                                      attr_name, attr_value);
+         if (filter == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
++            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create filter\n");
+             ret = ENOMEM;
+             goto done;
+         }
+-- 
+2.4.11
+
diff --git a/SOURCES/0030-sssctl-improve-readability-of-a-condition.patch b/SOURCES/0030-sssctl-improve-readability-of-a-condition.patch
new file mode 100644
index 0000000..88e259d
--- /dev/null
+++ b/SOURCES/0030-sssctl-improve-readability-of-a-condition.patch
@@ -0,0 +1,36 @@
+From 5ff189fbc8135d5900ac97120c587128a35f56eb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 13 Jul 2016 10:41:00 +0200
+Subject: [PATCH 30/31] sssctl: improve readability of a condition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+(cherry picked from commit aa691837a2fa2fe2e38a55d576644074e0f45bd8)
+---
+ src/tools/sssctl/sssctl_cache.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
+index 3e7644e327eb3e5a0e33023e7a3f5f0f15e03cf6..22e3fad89e3c1bbfce48439b43acd2346da3e56f 100644
+--- a/src/tools/sssctl/sssctl_cache.c
++++ b/src/tools/sssctl/sssctl_cache.c
+@@ -296,10 +296,10 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx,
+     char *filter_value;
+     bool qualify_attr = false;
+ 
+-    if (strcmp(attr_name, SYSDB_NAME) == 0 &&
+-            (obj_type == CACHED_USER ||
+-             obj_type == CACHED_GROUP)) {
+-        qualify_attr = true;
++    if (strcmp(attr_name, SYSDB_NAME) == 0) {
++        if (obj_type == CACHED_USER || obj_type == CACHED_GROUP) {
++            qualify_attr = true;
++        }
+     }
+ 
+     switch (obj_type) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0030-utils-add-NSS-version-of-cert-utils.patch b/SOURCES/0030-utils-add-NSS-version-of-cert-utils.patch
deleted file mode 100644
index d66d074..0000000
--- a/SOURCES/0030-utils-add-NSS-version-of-cert-utils.patch
+++ /dev/null
@@ -1,345 +0,0 @@
-From cbbdb6250744154bf9b5d0718ec68f2b63dfaff0 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 22 Jun 2015 16:36:36 +0200
-Subject: [PATCH 30/37] utils: add NSS version of cert utils
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                        |  29 ++++-
- configure.ac                       |   4 +-
- contrib/sssd.spec.in               |   1 -
- src/tests/cmocka/test_cert_utils.c |   4 +
- src/util/cert/nss/cert.c           | 212 +++++++++++++++++++++++++++++++++++++
- 5 files changed, 244 insertions(+), 6 deletions(-)
- create mode 100644 src/util/cert/nss/cert.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 912bfc6641465ef5cd2ff2cce9975b4027c3218d..277166ec66b3d67101e628990e68704c886b0c59 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -709,6 +709,17 @@ if HAVE_NSS
-                         src/util/crypto/nss/nss_util.c
-     SSS_CRYPT_CFLAGS = $(NSS_CFLAGS)
-     SSS_CRYPT_LIBS = $(NSS_LIBS)
-+
-+    SSS_CERT_SOURCES = \
-+        src/util/cert/cert_common.c \
-+        src/util/cert/nss/cert.c \
-+        $(NULL)
-+    SSS_CERT_CFLAGS = \
-+        $(NSS_CFLAGS) \
-+        $(NULL)
-+    SSS_CERT_LIBS = \
-+        $(NSS_LIBS) \
-+        $(NULL)
- else
-     SSS_CRYPT_SOURCES = src/util/crypto/libcrypto/crypto_base64.c \
-                         src/util/crypto/libcrypto/crypto_hmac_sha1.c \
-@@ -716,6 +727,17 @@ else
-                         src/util/crypto/libcrypto/crypto_obfuscate.c
-     SSS_CRYPT_CFLAGS = $(CRYPTO_CFLAGS)
-     SSS_CRYPT_LIBS = $(CRYPTO_LIBS)
-+
-+    SSS_CERT_SOURCES = \
-+        src/util/cert/cert_common.c \
-+        src/util/cert/libcrypto/cert.c \
-+        $(NULL)
-+    SSS_CERT_CFLAGS = \
-+        $(CRYPTO_CFLAGS) \
-+        $(NULL)
-+    SSS_CERT_LIBS = \
-+        $(CRYPTO_LIBS) \
-+        $(NULL)
- endif
- 
- libsss_crypt_la_SOURCES = \
-@@ -735,14 +757,13 @@ libsss_crypt_la_LDFLAGS = \
- pkglib_LTLIBRARIES += libsss_cert.la
- 
- libsss_cert_la_SOURCES = \
--    src/util/cert/cert_common.c \
--    src/util/cert/libcrypto/cert.c \
-+    $(SSS_CERT_SOURCES) \
-     $(NULL)
- libsss_cert_la_CFLAGS = \
--    $(CRYPTO_CFLAGS) \
-+    $(SSS_CERT_CFLAGS) \
-     $(NULL)
- libsss_cert_la_LIBADD = \
--    $(CRYPTO_LIBS) \
-+    $(SSS_CERT_LIBS) \
-     $(TALLOC_LIBS) \
-     libsss_crypt.la \
-     libsss_debug.la \
-diff --git a/configure.ac b/configure.ac
-index 29bedf74db6594b5788d51570514a07e082d5e42..4b4f8f3228bf13c594c86e1e39474a1d02ffd984 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -341,7 +341,9 @@ if test x$cryptolib = xnss; then
-     AM_CHECK_NSS
- fi
- 
--AM_CHECK_LIBCRYPTO
-+if test x$cryptolib = xlibcrypto; then
-+    AM_CHECK_LIBCRYPTO
-+fi
- 
- AM_CHECK_INOTIFY
- 
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index f050501ff9d0711a0da7f094ee968cae87a3f49b..54260e32e24ece372ed7130ab29d766bb1923f77 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -106,7 +106,6 @@ BuildRequires: dbus-libs
- BuildRequires: openldap-devel
- BuildRequires: pam-devel
- BuildRequires: nss-devel
--BuildRequires: openssl-devel
- BuildRequires: nspr-devel
- BuildRequires: pcre-devel
- BuildRequires: libxslt
-diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
-index 5bcbafb27dbdff596c07b8aad10ca15a35ff4ef5..8063b1a65e8692142cbb3cf82fe41afa6567bc91 100644
---- a/src/tests/cmocka/test_cert_utils.c
-+++ b/src/tests/cmocka/test_cert_utils.c
-@@ -23,7 +23,9 @@
- */
- 
- #include <popt.h>
-+#ifdef HAVE_LIBCRYPTO
- #include <openssl/objects.h>
-+#endif
- 
- #include "util/cert.h"
- #include "tests/cmocka/common_mock.h"
-@@ -349,7 +351,9 @@ int main(int argc, const char *argv[])
- 
-     ret = cmocka_run_group_tests(tests, NULL, NULL);
- 
-+#ifdef HAVE_LIBCRYPTO
-     CRYPTO_cleanup_all_ex_data(); /* to make valgrind happy */
-+#endif
- 
- #ifdef HAVE_NSS
-     /* Cleanup NSS and NSPR to make valgrind happy. */
-diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..a20abf63a10de9a5e9810f1c7d56686d063d60c7
---- /dev/null
-+++ b/src/util/cert/nss/cert.c
-@@ -0,0 +1,212 @@
-+
-+/*
-+   SSSD - certificate handling utils - NSS version
-+
-+   Copyright (C) Sumit Bose <sbose@redhat.com> 2015
-+
-+   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 <cert.h>
-+#include <base64.h>
-+
-+#include "util/crypto/nss/nss_util.h"
-+
-+#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
-+#define NS_CERT_TRAILER "-----END CERTIFICATE-----"
-+#define NS_CERT_HEADER_LEN  ((sizeof NS_CERT_HEADER) - 1)
-+#define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1)
-+
-+errno_t sss_cert_der_to_pem(TALLOC_CTX *mem_ctx, const uint8_t *der_blob,
-+                            size_t der_size, char **pem, size_t *pem_size)
-+{
-+
-+    CERTCertDBHandle *handle;
-+    CERTCertificate *cert = NULL;
-+    SECItem der_item;
-+    char *ascii_crlf = NULL;
-+    size_t ascii_crlf_len;
-+    char *ascii_lf = NULL;
-+    char *pem_cert_str = NULL;
-+    int ret;
-+    size_t c;
-+    size_t d;
-+
-+    /* initialize NSS if needed */
-+    ret = nspr_nss_init();
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n");
-+        return ret;
-+    }
-+
-+    handle = CERT_GetDefaultCertDB();
-+
-+    der_item.len = der_size;
-+    der_item.data = discard_const(der_blob);
-+
-+    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
-+    if (cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
-+        return EINVAL;
-+    }
-+
-+    ascii_crlf = BTOA_DataToAscii(cert->derCert.data, cert->derCert.len);
-+    if (ascii_crlf == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "BTOA_DataToAscii failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    ascii_crlf_len = strlen(ascii_crlf) + 1;
-+    ascii_lf = talloc_size(mem_ctx, ascii_crlf_len * sizeof(char));
-+    if (ascii_lf == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "malloc failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    d = 0;
-+    for (c = 0; c < ascii_crlf_len; c++) {
-+        if (ascii_crlf[c] != '\r') {
-+            ascii_lf[d++] = ascii_crlf[c];
-+        }
-+    }
-+
-+    pem_cert_str = talloc_asprintf(mem_ctx, "%s\n%s\n%s\n", NS_CERT_HEADER,
-+                                                            ascii_lf,
-+                                                            NS_CERT_TRAILER);
-+    if (pem_cert_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    if (pem_size != NULL) {
-+        *pem_size = strlen(pem_cert_str);
-+    }
-+
-+    if (pem != NULL) {
-+        *pem = pem_cert_str;
-+        pem_cert_str = NULL;
-+    }
-+
-+    ret = EOK;
-+done:
-+    talloc_free(pem_cert_str);
-+    talloc_free(ascii_lf);
-+    PORT_Free(ascii_crlf);
-+    CERT_DestroyCertificate(cert);
-+
-+    return ret;
-+}
-+
-+errno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem,
-+                            uint8_t **_der_blob, size_t *_der_size)
-+{
-+    const char *ps;
-+    const char *pe;
-+    size_t pem_len;
-+    uint8_t *der_blob = NULL;
-+    unsigned int der_size; /* unsigned int to match 2nd parameter of
-+                              ATOB_AsciiToData */
-+    CERTCertDBHandle *handle;
-+    CERTCertificate *cert = NULL;
-+    SECItem der_item;
-+    int ret;
-+    char *b64 = NULL;
-+
-+    /* initialize NSS if needed */
-+    ret = nspr_nss_init();
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n");
-+        return ret;
-+    }
-+
-+    if (pem == NULL || *pem == '\0') {
-+        return EINVAL;
-+    }
-+
-+    pem_len = strlen(pem);
-+    if (pem_len <= NS_CERT_HEADER_LEN + NS_CERT_TRAILER_LEN) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "PEM data too short.\n");
-+        return EINVAL;
-+    }
-+
-+    if (strncmp(pem, NS_CERT_HEADER, NS_CERT_HEADER_LEN) != 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM header.\n");
-+        return EINVAL;
-+    }
-+    if (pem[NS_CERT_HEADER_LEN] != '\n') {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing newline in PEM data.\n");
-+        return EINVAL;
-+    }
-+
-+    pe = pem + pem_len - NS_CERT_TRAILER_LEN;
-+    if (pem[pem_len - 1] == '\n') {
-+        pe--;
-+    }
-+    if (strncmp(pe, NS_CERT_TRAILER, NS_CERT_TRAILER_LEN) != 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM trailer.\n");
-+        return EINVAL;
-+    }
-+
-+    ps = pem + NS_CERT_HEADER_LEN + 1;
-+
-+    b64 = talloc_strndup(mem_ctx, ps, pe - ps);
-+    if(b64 == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    der_blob = ATOB_AsciiToData(b64, &der_size);
-+    if (der_blob == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ATOB_AsciiToData failed.\n");
-+        return EIO;
-+    }
-+
-+    handle = CERT_GetDefaultCertDB();
-+
-+    der_item.len = der_size;
-+    der_item.data = der_blob;
-+
-+    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
-+    if (cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    if (_der_blob != NULL) {
-+        *_der_blob = talloc_memdup(mem_ctx, cert->derCert.data,
-+                                   cert->derCert.len);
-+        if (*_der_blob == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    if (_der_size != NULL) {
-+        *_der_size = cert->derCert.len;
-+    }
-+done:
-+    PORT_Free(der_blob);
-+    talloc_free(b64);
-+    CERT_DestroyCertificate(cert);
-+
-+    return ret;
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0031-Add-NSS-version-of-p11_child.patch b/SOURCES/0031-Add-NSS-version-of-p11_child.patch
deleted file mode 100644
index 81896fc..0000000
--- a/SOURCES/0031-Add-NSS-version-of-p11_child.patch
+++ /dev/null
@@ -1,720 +0,0 @@
-From 95bea503429c3f44654265486a07f1696b017e84 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 10 Jul 2015 12:10:53 +0200
-Subject: [PATCH 31/37] Add NSS version of p11_child
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                   |  25 +-
- contrib/sssd.spec.in          |   1 +
- src/p11_child/p11_child_nss.c | 636 ++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 661 insertions(+), 1 deletion(-)
- create mode 100644 src/p11_child/p11_child_nss.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 277166ec66b3d67101e628990e68704c886b0c59..e4add9757058773915f1971786b8a9ad584ec51f 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -148,7 +148,9 @@ endif
- if BUILD_SEMANAGE
- sssdlibexec_PROGRAMS += selinux_child
- endif
--
-+if HAVE_NSS
-+sssdlibexec_PROGRAMS += p11_child
-+endif
- 
- if BUILD_PAC_RESPONDER
-     sssdlibexec_PROGRAMS += sssd_pac
-@@ -3146,6 +3148,23 @@ proxy_child_LDADD = \
-     $(SSSD_LIBS) \
-     $(SSSD_INTERNAL_LTLIBS)
- 
-+p11_child_SOURCES = \
-+    src/p11_child/p11_child_nss.c \
-+    src/util/atomic_io.c \
-+    $(NULL)
-+p11_child_CFLAGS = \
-+    $(AM_CFLAGS) \
-+    $(POPT_CFLAGS) \
-+    $(NSS_CFLAGS) \
-+    $(NULL)
-+p11_child_LDADD = \
-+    libsss_debug.la \
-+    $(TALLOC_LIBS) \
-+    $(POPT_LIBS) \
-+    $(NSS_LIBS) \
-+    libsss_crypt.la \
-+    $(NULL)
-+
- memberof_la_SOURCES = \
-     src/ldb_modules/memberof.c \
-     src/util/util.c
-@@ -3541,6 +3560,10 @@ if BUILD_SEMANAGE
- 	-chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/selinux_child
- 	chmod 4750 $(DESTDIR)$(sssdlibexecdir)/selinux_child
- endif
-+if HAVE_NSS
-+	-chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/p11_child
-+	chmod 4750 $(DESTDIR)$(sssdlibexecdir)/p11_child
-+endif
- endif
- 
- install-data-hook:
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index 54260e32e24ece372ed7130ab29d766bb1923f77..9ca9a8b4dce5c5d70fb4df268270bcfb0c9b17bb 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -684,6 +684,7 @@ rm -rf $RPM_BUILD_ROOT
- %{_libexecdir}/%{servicename}/sssd_autofs
- %{_libexecdir}/%{servicename}/sssd_ssh
- %{_libexecdir}/%{servicename}/sssd_sudo
-+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/p11_child
- 
- %dir %{_libdir}/%{name}
- %{_libdir}/%{name}/libsss_simple.so
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..6948c142aa7843cda5ff6d18f5853b10c387c224
---- /dev/null
-+++ b/src/p11_child/p11_child_nss.c
-@@ -0,0 +1,636 @@
-+/*
-+    SSSD
-+
-+    Helper child to commmunicate with SmartCard via NSS
-+
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2015 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 <unistd.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <popt.h>
-+
-+#include "util/util.h"
-+
-+#include <nss.h>
-+#include <base64.h>
-+#include <cryptohi.h>
-+#include <secmod.h>
-+#include <cert.h>
-+#include <keyhi.h>
-+#include <pk11pub.h>
-+#include <prerror.h>
-+
-+#include "util/child_common.h"
-+#include "providers/dp_backend.h"
-+#include "util/crypto/sss_crypto.h"
-+
-+enum op_mode {
-+    OP_NONE,
-+    OP_AUTH,
-+    OP_PREAUTH
-+};
-+
-+enum pin_mode {
-+    PIN_NONE,
-+    PIN_STDIN,
-+    PIN_KEYPAD
-+};
-+
-+static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg)
-+{
-+  /* give up if 1) no password was supplied, or 2) the password has already
-+   * been rejected once by this token. */
-+  if (retry || (arg == NULL)) {
-+    return NULL;
-+  }
-+  return PL_strdup((char *)arg);
-+}
-+
-+
-+
-+int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-+            enum op_mode mode, const char *pin, char **cert,
-+            char **token_name_out)
-+{
-+    int ret;
-+    SECStatus rv;
-+    NSSInitContext *nss_ctx;
-+    SECMODModuleList *mod_list;
-+    SECMODModuleList *mod_list_item;
-+    const char *slot_name;
-+    const char *token_name;
-+    uint32_t flags = NSS_INIT_READONLY
-+                                   | NSS_INIT_FORCEOPEN
-+                                   | NSS_INIT_NOROOTINIT
-+                                   | NSS_INIT_OPTIMIZESPACE
-+                                   | NSS_INIT_PK11RELOAD;
-+    NSSInitParameters parameters = { 0 };
-+    parameters.length =  sizeof (parameters);
-+    PK11SlotInfo *slot = NULL;
-+    CK_SLOT_ID slot_id;
-+    SECMODModuleID module_id;
-+    CERTCertList *cert_list = NULL;
-+    CERTCertListNode *cert_list_node;
-+    const PK11DefaultArrayEntry friendly_attr = { "Publicly-readable certs",
-+                                                  SECMOD_FRIENDLY_FLAG,
-+                                                  CKM_INVALID_MECHANISM };
-+    CERTCertDBHandle *handle;
-+    unsigned char random_value[128];
-+    SECKEYPrivateKey *priv_key;
-+    SECOidTag algtag;
-+    SECItem signed_random_value = {0};
-+    SECKEYPublicKey *pub_key;
-+    CERTCertificate *found_cert = NULL;
-+    PK11SlotList *list = NULL;
-+    PK11SlotListElement *le;
-+
-+
-+    nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
-+    if (nss_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n",
-+                                 PR_GetError());
-+        return EIO;
-+    }
-+
-+    PK11_SetPasswordFunc(password_passthrough);
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "Default Module List:\n");
-+    mod_list = SECMOD_GetDefaultModuleList();
-+    for (mod_list_item = mod_list; mod_list_item != NULL;
-+                                   mod_list_item = mod_list_item->next) {
-+        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n",
-+                                mod_list_item->module->commonName);
-+        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n",
-+                                mod_list_item->module->dllName);
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "Dead Module List:\n");
-+    mod_list = SECMOD_GetDeadModuleList();
-+    for (mod_list_item = mod_list; mod_list_item != NULL;
-+                                   mod_list_item = mod_list_item->next) {
-+        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n",
-+                                mod_list_item->module->commonName);
-+        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n",
-+                                mod_list_item->module->dllName);
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "DB Module List:\n");
-+    mod_list = SECMOD_GetDBModuleList();
-+    for (mod_list_item = mod_list; mod_list_item != NULL;
-+                                   mod_list_item = mod_list_item->next) {
-+        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n",
-+                                mod_list_item->module->commonName);
-+        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n",
-+                                mod_list_item->module->dllName);
-+    }
-+
-+    if (slot_name_in != NULL) {
-+        slot = PK11_FindSlotByName(slot_name_in);
-+        if (slot == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "PK11_FindSlotByName failed for [%s]: [%d].\n",
-+                                     slot_name_in, PR_GetError());
-+            return EIO;
-+        }
-+    } else {
-+
-+        list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE,
-+                                 NULL);
-+        if (list == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n");
-+            return EIO;
-+        }
-+
-+        for (le = list->head; le; le = le->next) {
-+            CK_SLOT_INFO slInfo;
-+
-+            slInfo.flags = 0;
-+            rv = PK11_GetSlotInfo(le->slot, &slInfo);
-+            DEBUG(SSSDBG_TRACE_ALL,
-+                  "Description [%s] Manufacturer [%s] flags [%lu].\n",
-+                  slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags);
-+            if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
-+                slot = PK11_ReferenceSlot(le->slot);
-+                break;
-+           }
-+        }
-+        PK11_FreeSlotList(list);
-+        if (slot == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n");
-+            return EIO;
-+        }
-+    }
-+
-+
-+    slot_id = PK11_GetSlotID(slot);
-+    module_id = PK11_GetModuleID(slot);
-+    slot_name = PK11_GetSlotName(slot);
-+    token_name = PK11_GetTokenName(slot);
-+    DEBUG(SSSDBG_TRACE_ALL, "Found [%s] in slot [%s][%d] of module [%d].\n",
-+          token_name, slot_name, (int) slot_id, (int) module_id);
-+
-+    if (PK11_IsFriendly(slot)) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Token is friendly.\n");
-+    } else {
-+        DEBUG(SSSDBG_TRACE_ALL,
-+              "Token is NOT friendly.\n");
-+        if (mode == OP_PREAUTH) {
-+            DEBUG(SSSDBG_TRACE_ALL, "Trying to switch to friendly to read certificate.\n");
-+            rv = PK11_UpdateSlotAttribute(slot, &friendly_attr, PR_TRUE);
-+            if (rv != SECSuccess) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "PK11_UpdateSlotAttribute failed, continue.\n");
-+            }
-+        }
-+    }
-+
-+    /* TODO: check  PK11_ProtectedAuthenticationPath() and return the result */
-+    if (mode == OP_AUTH || PK11_NeedLogin(slot)) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Login required.\n");
-+        if (pin != NULL) {
-+            rv = PK11_Authenticate(slot, PR_FALSE, discard_const(pin));
-+            if (rv !=  SECSuccess) {
-+                DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d].\n",
-+                                         PR_GetError());
-+                return EIO;
-+            }
-+        } else {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Login required but no pin available, continue.\n");
-+        }
-+    } else {
-+        DEBUG(SSSDBG_TRACE_ALL, "Login NOT required.\n");
-+    }
-+
-+    cert_list = PK11_ListCertsInSlot(slot);
-+    if (cert_list == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d].\n",
-+                                 PR_GetError());
-+        return EIO;
-+    }
-+
-+    for (cert_list_node = CERT_LIST_HEAD(cert_list);
-+                !CERT_LIST_END(cert_list_node, cert_list);
-+                cert_list_node = CERT_LIST_NEXT(cert_list_node)) {
-+        if (cert_list_node->cert) {
-+            DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n",
-+                             cert_list_node->cert->nickname,
-+                             cert_list_node->cert->subjectName);
-+        } else {
-+            DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n");
-+        }
-+    }
-+
-+    rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d].\n",
-+                                 PR_GetError());
-+        return EIO;
-+    }
-+
-+    rv = CERT_FilterCertListForUserCerts(cert_list);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListForUserCerts failed: [%d].\n",
-+                                 PR_GetError());
-+        return EIO;
-+    }
-+
-+
-+    handle = CERT_GetDefaultCertDB();
-+    if (handle == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d].\n",
-+                                 PR_GetError());
-+        return EIO;
-+    }
-+
-+
-+    found_cert = NULL;
-+    DEBUG(SSSDBG_TRACE_ALL, "Filtered certificates:\n");
-+    for (cert_list_node = CERT_LIST_HEAD(cert_list);
-+                !CERT_LIST_END(cert_list_node, cert_list);
-+                cert_list_node = CERT_LIST_NEXT(cert_list_node)) {
-+        if (cert_list_node->cert) {
-+            DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n",
-+                             cert_list_node->cert->nickname,
-+                             cert_list_node->cert->subjectName);
-+
-+            if (found_cert == NULL) {
-+                found_cert = cert_list_node->cert;
-+            } else {
-+                DEBUG(SSSDBG_TRACE_ALL, "More than one certificate found, " \
-+                                        "using just the first one.\n");
-+            }
-+        } else {
-+            DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n");
-+        }
-+    }
-+
-+    if (found_cert == NULL) {
-+        DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n");
-+        *cert = NULL;
-+        *token_name_out = NULL;
-+        ret = EOK;
-+        goto done;
-+    }
-+
-+    rv = CERT_VerifyCertificateNow(handle, found_cert, PR_TRUE,
-+                                   certificateUsageSSLClient, NULL, NULL);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "CERT_VerifyCertificateNow failed [%d].\n",
-+              PR_GetError());
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    if (mode == OP_AUTH) {
-+        rv = PK11_GenerateRandom(random_value, sizeof(random_value));
-+        if (rv != SECSuccess) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "PK11_GenerateRandom failed [%d].\n", PR_GetError());
-+            return EIO;
-+        }
-+
-+        priv_key = PK11_FindPrivateKeyFromCert(slot, found_cert, NULL);
-+        if (priv_key == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "PK11_FindPrivateKeyFromCert failed [%d]." \
-+                  "Maybe pin is missing.\n", PR_GetError());
-+            ret = EIO;
-+            goto done;
-+        }
-+
-+        algtag = SEC_GetSignatureAlgorithmOidTag(priv_key->keyType,
-+                                                  SEC_OID_SHA1);
-+        if (algtag == SEC_OID_UNKNOWN) {
-+            SECKEY_DestroyPrivateKey(priv_key);
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "SEC_GetSignatureAlgorithmOidTag failed [%d].",
-+                  PR_GetError());
-+            ret = EIO;
-+            goto done;
-+        }
-+
-+        rv = SEC_SignData(&signed_random_value,
-+                          random_value, sizeof(random_value),
-+                          priv_key, algtag);
-+        SECKEY_DestroyPrivateKey(priv_key);
-+        if (rv != SECSuccess) {
-+            DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d].",
-+                                     PR_GetError());
-+            ret = EIO;
-+            goto done;
-+        }
-+
-+        pub_key = CERT_ExtractPublicKey(found_cert);
-+        if (pub_key == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "CERT_ExtractPublicKey failed [%d].", PR_GetError());
-+            ret = EIO;
-+            goto done;
-+        }
-+
-+        rv = VFY_VerifyData(random_value, sizeof(random_value),
-+                            pub_key, &signed_random_value, algtag,
-+                            NULL);
-+        SECKEY_DestroyPublicKey(pub_key);
-+        if (rv != SECSuccess) {
-+            DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d].",
-+                                     PR_GetError());
-+            ret = EACCES;
-+            goto done;
-+        }
-+
-+        DEBUG(SSSDBG_TRACE_ALL,
-+              "Certificate verified and validated.\n");
-+    }
-+
-+    *cert = sss_base64_encode(mem_ctx, found_cert->derCert.data,
-+                                       found_cert->derCert.len);
-+    if (*cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    *token_name_out = talloc_strdup(mem_ctx, token_name);
-+    if (*token_name_out == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy slot name.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    if (slot != NULL) {
-+        PK11_FreeSlot(slot);
-+    }
-+
-+    if (cert_list != NULL) {
-+        CERT_DestroyCertList(cert_list);
-+    }
-+
-+    PORT_Free(signed_random_value.data);
-+
-+    rv = NSS_ShutdownContext(nss_ctx);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n",
-+                                 PR_GetError());
-+    }
-+
-+    return ret;
-+}
-+
-+static errno_t p11c_recv_data(TALLOC_CTX *mem_ctx, int fd, char **pin)
-+{
-+    uint8_t buf[IN_BUF_SIZE];
-+    ssize_t len;
-+    errno_t ret;
-+    char *str;
-+
-+    errno = 0;
-+    len = sss_atomic_read_s(fd, buf, IN_BUF_SIZE);
-+    if (len == -1) {
-+        ret = errno;
-+        ret = (ret == 0) ? EINVAL: ret;
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "read failed [%d][%s].\n", ret, strerror(ret));
-+        return ret;
-+    }
-+
-+    if (len == 0 || *buf == '\0') {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n");
-+        return EINVAL;
-+    }
-+
-+    str = talloc_strndup(mem_ctx, (char *) buf, len);
-+    if (str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    if (strlen(str) != len) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Input contains additional data, only PIN expected.\n");
-+        talloc_free(str);
-+        return EINVAL;
-+    }
-+
-+    *pin = str;
-+
-+    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;
-+    char *cert;
-+    enum op_mode mode = OP_NONE;
-+    enum pin_mode pin_mode = PIN_NONE;
-+    char *pin = NULL;
-+    char *slot_name_in = NULL;
-+    char *token_name_out = NULL;
-+    char *nss_db = NULL;
-+
-+    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 },
-+        {"auth", 0, POPT_ARG_NONE, NULL, 'a', _("Run in auth mode"), NULL},
-+        {"pre", 0, POPT_ARG_NONE, NULL, 'p', _("Run in pre-auth mode"), NULL},
-+        {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL},
-+        {"keypad", 0, POPT_ARG_NONE, NULL, 'k', _("Expect PIN on keypad"),
-+         NULL},
-+        {"nssdb", 0, POPT_ARG_STRING, &nss_db, 0, _("NSS DB to use"),
-+         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) {
-+        case 'a':
-+            if (mode != OP_NONE) {
-+                fprintf(stderr,
-+                        "\n--auth and --pre are mutually exclusive and " \
-+                        "should be only used once.\n\n");
-+                poptPrintUsage(pc, stderr, 0);
-+                _exit(-1);
-+            }
-+            mode = OP_AUTH;
-+            break;
-+        case 'p':
-+            if (mode != OP_NONE) {
-+                fprintf(stderr,
-+                        "\n--auth and --pre are mutually exclusive and " \
-+                        "should be only used once.\n\n");
-+                poptPrintUsage(pc, stderr, 0);
-+                _exit(-1);
-+            }
-+            mode = OP_PREAUTH;
-+            break;
-+        case 'i':
-+            if (pin_mode != PIN_NONE) {
-+                fprintf(stderr, "\n--pin and --keypad are mutually exclusive " \
-+                                "and should be only used once.\n\n");
-+                poptPrintUsage(pc, stderr, 0);
-+                _exit(-1);
-+            }
-+            pin_mode = PIN_STDIN;
-+            break;
-+        case 'k':
-+            if (pin_mode != PIN_NONE) {
-+                fprintf(stderr, "\n--pin and --keypad are mutually exclusive " \
-+                                "and should be only used once.\n\n");
-+                poptPrintUsage(pc, stderr, 0);
-+                _exit(-1);
-+            }
-+            pin_mode = PIN_KEYPAD;
-+            break;
-+        default:
-+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
-+                  poptBadOption(pc, 0), poptStrerror(opt));
-+            poptPrintUsage(pc, stderr, 0);
-+            _exit(-1);
-+        }
-+    }
-+
-+    if (nss_db == NULL) {
-+        fprintf(stderr, "\nMissing NSS DB --nssdb must be specified.\n\n");
-+        poptPrintUsage(pc, stderr, 0);
-+        _exit(-1);
-+    }
-+
-+    if (mode == OP_NONE) {
-+        fprintf(stderr, "\nMissing operation mode, " \
-+                        "either --auth or --pre must be specified.\n\n");
-+        poptPrintUsage(pc, stderr, 0);
-+        _exit(-1);
-+    } else if (mode == OP_AUTH && pin_mode == PIN_NONE) {
-+        fprintf(stderr, "\nMissing pin mode for authentication, " \
-+                        "either --pin or --keypad must be specified.\n");
-+        poptPrintUsage(pc, stderr, 0);
-+        _exit(-1);
-+    }
-+
-+    poptFreeContext(pc);
-+
-+    DEBUG_INIT(debug_level);
-+
-+    debug_prg_name = talloc_asprintf(NULL, "[sssd[p11_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, "p11_child started.\n");
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL, "Running in [%s] mode.\n",
-+          mode == OP_AUTH ? "auth"
-+                          : (mode == OP_PREAUTH ? "pre-auth" : "unknown"));
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL,
-+          "Running with effective IDs: [%"SPRIuid"][%"SPRIgid"].\n",
-+          geteuid(), getegid());
-+
-+    if (getuid() != 0) {
-+        ret = setuid(0);
-+        if (ret == -1) {
-+            ret = errno;
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "setuid failed: %d, p11_child might not work!\n", ret);
-+        }
-+    }
-+
-+    if (getgid() != 0) {
-+        ret = setgid(0);
-+        if (ret == -1) {
-+            ret = errno;
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "setgid failed: %d, p11_child might not work!\n", ret);
-+        }
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL,
-+          "Running with real IDs [%"SPRIuid"][%"SPRIgid"].\n",
-+          getuid(), getgid());
-+
-+    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);
-+
-+
-+    if (mode == OP_AUTH && pin_mode == PIN_STDIN) {
-+        ret = p11c_recv_data(main_ctx, STDIN_FILENO, &pin);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read pin.\n");
-+            goto fail;
-+        }
-+    }
-+
-+    ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, &cert,
-+                  &token_name_out);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n");
-+        goto fail;
-+    }
-+
-+    if (cert != NULL) {
-+        fprintf(stdout, "%s\n", token_name_out);
-+        fprintf(stdout, "%s\n", cert);
-+    }
-+
-+    talloc_free(main_ctx);
-+    return EXIT_SUCCESS;
-+fail:
-+    DEBUG(SSSDBG_CRIT_FAILURE, "p11_child failed!\n");
-+    close(STDOUT_FILENO);
-+    talloc_free(main_ctx);
-+    return EXIT_FAILURE;
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0031-sssctl-Use-localtime-for-time-stamps.patch b/SOURCES/0031-sssctl-Use-localtime-for-time-stamps.patch
new file mode 100644
index 0000000..d94a0eb
--- /dev/null
+++ b/SOURCES/0031-sssctl-Use-localtime-for-time-stamps.patch
@@ -0,0 +1,34 @@
+From e6cfc113e6f3f7cc1c941d12e0ac7032f19affb9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Thu, 14 Jul 2016 15:33:19 +0200
+Subject: [PATCH 31/31] sssctl: Use localtime for time stamps
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3096
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit f316e5446313bbf61c96b6763badc21604bff4a3)
+---
+ src/tools/sssctl/sssctl_cache.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
+index 22e3fad89e3c1bbfce48439b43acd2346da3e56f..4a1f3558ed7064ca40ccf9313d99fbab36e6e4c9 100644
+--- a/src/tools/sssctl/sssctl_cache.c
++++ b/src/tools/sssctl/sssctl_cache.c
+@@ -67,7 +67,7 @@ static errno_t time_to_string(TALLOC_CTX *mem_ctx,
+     char str[255];
+     size_t ret;
+ 
+-    tm = gmtime(&timestamp);
++    tm = localtime(&timestamp);
+     if (tm == NULL) {
+         return ENOMEM;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0032-SECRETS-Log-message-for-failures-with-removing-file.patch b/SOURCES/0032-SECRETS-Log-message-for-failures-with-removing-file.patch
new file mode 100644
index 0000000..10627ef
--- /dev/null
+++ b/SOURCES/0032-SECRETS-Log-message-for-failures-with-removing-file.patch
@@ -0,0 +1,38 @@
+From 38b3bd9bde495d44283de2b837ab0239140edb3d Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 22 Jul 2016 09:53:40 +0200
+Subject: [PATCH 32/44] SECRETS: Log message for failures with removing file
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Type: Unchecked return value
+Reported by coverity
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+---
+ src/responder/secrets/local.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
+index 620134ea6b45629114ba795d0e232f414f6e5009..2a85ac06945322265fbd1012c9697728c37b77a0 100644
+--- a/src/responder/secrets/local.c
++++ b/src/responder/secrets/local.c
+@@ -624,7 +624,13 @@ int generate_master_key(const char *filename, size_t size)
+     rsize = sss_atomic_io_s(fd, buf, size, false);
+     close(fd);
+     if (rsize != size) {
+-        unlink(filename);
++        ret = unlink(filename);
++        /* non-fatal failure */
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Failed to remove file: %s - %d [%s]!\n",
++                  filename, ret, sss_strerror(ret));
++        }
+         return EFAULT;
+     }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0032-pack_message_v3-allow-empty-name.patch b/SOURCES/0032-pack_message_v3-allow-empty-name.patch
deleted file mode 100644
index 695df0f..0000000
--- a/SOURCES/0032-pack_message_v3-allow-empty-name.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 1b9a3d516341560ccf8b5f9fab0886f3d05defce Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 26 Jun 2015 14:45:21 +0200
-Subject: [PATCH 32/37] pack_message_v3: allow empty name
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/sss_client/pam_message.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/src/sss_client/pam_message.c b/src/sss_client/pam_message.c
-index b8104c680d0e733b713c665e6206dc4b0d379237..b239f6f53da54054c52e484bdd076193709cb003 100644
---- a/src/sss_client/pam_message.c
-+++ b/src/sss_client/pam_message.c
-@@ -107,9 +107,10 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
-     uint8_t *buf;
-     size_t rp;
- 
--    len = sizeof(uint32_t) +
--          2*sizeof(uint32_t) + pi->pam_user_size +
--          sizeof(uint32_t);
-+    len = sizeof(uint32_t) + sizeof(uint32_t);
-+
-+    len +=  *pi->pam_user != '\0' ?
-+                2*sizeof(uint32_t) + pi->pam_user_size : 0;
-     len += *pi->pam_service != '\0' ?
-                 2*sizeof(uint32_t) + pi->pam_service_size : 0;
-     len += *pi->pam_tty != '\0' ?
--- 
-2.4.3
-
diff --git a/SOURCES/0033-IPA-fix-capaths-output.patch b/SOURCES/0033-IPA-fix-capaths-output.patch
new file mode 100644
index 0000000..f5b2f92
--- /dev/null
+++ b/SOURCES/0033-IPA-fix-capaths-output.patch
@@ -0,0 +1,67 @@
+From cf161fe0317fd37e1c5ad826cb783905aaf1f048 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 18 Jul 2016 17:19:36 +0200
+Subject: [PATCH 33/44] IPA: fix [capaths] output
+
+the capaths for a single domain should be collected in a single
+sub-section in the MIT Kerberos configuration not spread over multiple
+one. See the capaths section of the krb5.conf man page for details.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3103
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/util/domain_info_utils.c | 29 ++++++++++++++++++++++++++---
+ 1 file changed, 26 insertions(+), 3 deletions(-)
+
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 360f70376c472466168d93d45b6c547d51dd18c6..8cdd50d8d521d734e9ffd9b4e81cd6fbd7d158c7 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -280,6 +280,7 @@ sss_write_domain_mappings(struct sss_domain_info *domain)
+     bool capaths_started = false;
+     char *uc_forest;
+     char *uc_parent;
++    char *parent_capaths = NULL;
+ 
+     if (domain == NULL || domain->name == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "No domain name provided\n");
+@@ -399,9 +400,31 @@ sss_write_domain_mappings(struct sss_domain_info *domain)
+             capaths_started = true;
+         }
+ 
+-        ret = fprintf(fstream, "%s = {\n  %s = %s\n}\n%s = {\n  %s = %s\n}\n",
+-                                dom->realm, uc_parent, uc_forest,
+-                                uc_parent, dom->realm, uc_forest);
++        ret = fprintf(fstream, "%s = {\n  %s = %s\n}\n",
++                                dom->realm, uc_parent, uc_forest);
++        if (ret < 0) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n");
++            goto done;
++        }
++
++        if (parent_capaths == NULL) {
++            parent_capaths = talloc_asprintf(tmp_ctx, "  %s = %s\n", dom->realm,
++                                                                     uc_forest);
++        } else {
++            parent_capaths = talloc_asprintf_append(parent_capaths,
++                                                    "  %s = %s\n", dom->realm,
++                                                    uc_forest);
++        }
++        if (parent_capaths == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "talloc_asprintf/talloc_asprintf_append failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    if (parent_capaths != NULL) {
++        ret = fprintf(fstream, "%s = {\n%s}\n", uc_parent, parent_capaths);
+         if (ret < 0) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n");
+             goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0033-authok-add-support-for-Smart-Card-related-authtokens.patch b/SOURCES/0033-authok-add-support-for-Smart-Card-related-authtokens.patch
deleted file mode 100644
index 891e411..0000000
--- a/SOURCES/0033-authok-add-support-for-Smart-Card-related-authtokens.patch
+++ /dev/null
@@ -1,287 +0,0 @@
-From f9a027877ecdd697a052f6135963fb3726692310 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 26 Jun 2015 17:55:23 +0200
-Subject: [PATCH 33/37] authok: add support for Smart Card related authtokens
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/sss_client/sss_cli.h        |  7 ++++
- src/tests/cmocka/test_authtok.c | 75 +++++++++++++++++++++++++++++++++++++++++
- src/util/authtok.c              | 64 +++++++++++++++++++++++++++++++++++
- src/util/authtok.h              | 41 ++++++++++++++++++++++
- 4 files changed, 187 insertions(+)
-
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index 0dfb525bacba5f6928e8ece76e05f60d7f2eebd5..3c4e938ae37c042879b1ae26fe389fa37cef682c 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -308,6 +308,13 @@ enum sss_authtok_type {
-     SSS_AUTHTOK_TYPE_2FA =       0x0003, /**< Authentication token has two
-                                           * factors, they may or may no contain
-                                           * a trailing \\0 */
-+    SSS_AUTHTOK_TYPE_SC_PIN =    0x0004, /**< Authentication token is a Smart
-+                                          * Card pin, it may or may no contain
-+                                          * a trailing \\0 */
-+    SSS_AUTHTOK_TYPE_SC_KEYPAD = 0x0005, /**< Authentication token indicates
-+                                          * Smart Card authentication is used
-+                                          * and that the pin will be entered
-+                                          * at the card reader. */
- };
- 
- /**
-diff --git a/src/tests/cmocka/test_authtok.c b/src/tests/cmocka/test_authtok.c
-index 5aa47c7b6b8c955666a9c73d5f9627d6378d13e0..30dcc9c8401103a275bd592fe8afd2c2f396ffb1 100644
---- a/src/tests/cmocka/test_authtok.c
-+++ b/src/tests/cmocka/test_authtok.c
-@@ -488,6 +488,77 @@ void test_sss_authtok_2fa_blobs_missing_null(void **state)
-     MISSING_NULL_CHECK;
- }
- 
-+void test_sss_authtok_sc_keypad(void **state)
-+{
-+    struct test_state *ts;
-+
-+    ts = talloc_get_type_abort(*state, struct test_state);
-+
-+    sss_authtok_set_sc_keypad(NULL);
-+
-+    sss_authtok_set_sc_keypad(ts->authtoken);
-+    assert_int_equal(sss_authtok_get_type(ts->authtoken),
-+                     SSS_AUTHTOK_TYPE_SC_KEYPAD);
-+    assert_int_equal(sss_authtok_get_size(ts->authtoken), 0);
-+    assert_null(sss_authtok_get_data(ts->authtoken));
-+}
-+
-+void test_sss_authtok_sc_pin(void **state)
-+{
-+    struct test_state *ts;
-+    int ret;
-+    size_t size;
-+    const char *pin;
-+    size_t len;
-+
-+    ts = talloc_get_type_abort(*state, struct test_state);
-+
-+    ret = sss_authtok_set_sc_pin(NULL, NULL, 0);
-+    assert_int_equal(ret, EFAULT);
-+
-+    ret = sss_authtok_set_sc_pin(ts->authtoken, NULL, 0);
-+    assert_int_equal(ret, EINVAL);
-+
-+    ret = sss_authtok_set_sc_pin(ts->authtoken, "12345678", 0);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(sss_authtok_get_type(ts->authtoken),
-+                     SSS_AUTHTOK_TYPE_SC_PIN);
-+    size = sss_authtok_get_size(ts->authtoken);
-+    assert_int_equal(size, 9);
-+    assert_memory_equal(sss_authtok_get_data(ts->authtoken), "12345678\0",
-+                                             size);
-+
-+    ret = sss_authtok_set_sc_pin(ts->authtoken, "12345678", 5);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(sss_authtok_get_type(ts->authtoken),
-+                     SSS_AUTHTOK_TYPE_SC_PIN);
-+    size = sss_authtok_get_size(ts->authtoken);
-+    assert_int_equal(size, 6);
-+    assert_memory_equal(sss_authtok_get_data(ts->authtoken), "12345\0",
-+                                             size);
-+
-+    ret = sss_authtok_get_sc_pin(ts->authtoken, &pin, &len);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(len, 5);
-+    assert_string_equal(pin, "12345");
-+
-+    sss_authtok_set_empty(ts->authtoken);
-+
-+    ret = sss_authtok_get_sc_pin(ts->authtoken, &pin, &len);
-+    assert_int_equal(ret, ENOENT);
-+
-+    ret = sss_authtok_set_password(ts->authtoken, "12345", 0);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sss_authtok_get_sc_pin(ts->authtoken, &pin, &len);
-+    assert_int_equal(ret, EACCES);
-+
-+    sss_authtok_set_empty(ts->authtoken);
-+
-+    ret = sss_authtok_get_sc_pin(NULL, &pin, &len);
-+    assert_int_equal(ret, EFAULT);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -517,6 +588,10 @@ int main(int argc, const char *argv[])
-                                         setup, teardown),
-         cmocka_unit_test_setup_teardown(test_sss_authtok_2fa_blobs_missing_null,
-                                         setup, teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_authtok_sc_keypad,
-+                                        setup, teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_authtok_sc_pin,
-+                                        setup, teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-diff --git a/src/util/authtok.c b/src/util/authtok.c
-index 45761df80175fded8a6c6e5dac8a90180b11d225..6062cd875ce2c6b541ef237e7f7bdddac80366c5 100644
---- a/src/util/authtok.c
-+++ b/src/util/authtok.c
-@@ -39,6 +39,8 @@ size_t sss_authtok_get_size(struct sss_auth_token *tok)
-     case SSS_AUTHTOK_TYPE_PASSWORD:
-     case SSS_AUTHTOK_TYPE_CCFILE:
-     case SSS_AUTHTOK_TYPE_2FA:
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-         return tok->length;
-     case SSS_AUTHTOK_TYPE_EMPTY:
-         return 0;
-@@ -72,6 +74,8 @@ errno_t sss_authtok_get_password(struct sss_auth_token *tok,
-         return EOK;
-     case SSS_AUTHTOK_TYPE_CCFILE:
-     case SSS_AUTHTOK_TYPE_2FA:
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-         return EACCES;
-     }
- 
-@@ -95,6 +99,8 @@ errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok,
-         return EOK;
-     case SSS_AUTHTOK_TYPE_PASSWORD:
-     case SSS_AUTHTOK_TYPE_2FA:
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-         return EACCES;
-     }
- 
-@@ -144,9 +150,11 @@ void sss_authtok_set_empty(struct sss_auth_token *tok)
-         return;
-     case SSS_AUTHTOK_TYPE_PASSWORD:
-     case SSS_AUTHTOK_TYPE_2FA:
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-         safezero(tok->data, tok->length);
-         break;
-     case SSS_AUTHTOK_TYPE_CCFILE:
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-         break;
-     }
- 
-@@ -187,6 +195,11 @@ errno_t sss_authtok_set(struct sss_auth_token *tok,
-         return sss_authtok_set_ccfile(tok, (const char *)data, len);
-     case SSS_AUTHTOK_TYPE_2FA:
-         return sss_authtok_set_2fa_from_blob(tok, data, len);
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+        return sss_authtok_set_sc_pin(tok, (const char*)data, len);
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-+        sss_authtok_set_sc_keypad(tok);
-+        return EOK;
-     case SSS_AUTHTOK_TYPE_EMPTY:
-         sss_authtok_set_empty(tok);
-         return EOK;
-@@ -411,3 +424,54 @@ errno_t sss_authtok_set_2fa(struct sss_auth_token *tok,
- 
-     return EOK;
- }
-+
-+errno_t sss_authtok_set_sc_pin(struct sss_auth_token *tok, const char *pin,
-+                               size_t len)
-+{
-+    if (tok == NULL) {
-+        return EFAULT;
-+    }
-+    if (pin == NULL) {
-+        return EINVAL;
-+    }
-+
-+    sss_authtok_set_empty(tok);
-+
-+    return sss_authtok_set_string(tok, SSS_AUTHTOK_TYPE_SC_PIN,
-+                                  "sc_pin", pin, len);
-+}
-+
-+errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **pin,
-+                               size_t *len)
-+{
-+    if (!tok) {
-+        return EFAULT;
-+    }
-+    switch (tok->type) {
-+    case SSS_AUTHTOK_TYPE_EMPTY:
-+        return ENOENT;
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+        *pin = (const char *)tok->data;
-+        if (len) {
-+            *len = tok->length - 1;
-+        }
-+        return EOK;
-+    case SSS_AUTHTOK_TYPE_PASSWORD:
-+    case SSS_AUTHTOK_TYPE_CCFILE:
-+    case SSS_AUTHTOK_TYPE_2FA:
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-+        return EACCES;
-+    }
-+
-+    return EINVAL;
-+}
-+
-+void sss_authtok_set_sc_keypad(struct sss_auth_token *tok)
-+{
-+    if (!tok) {
-+        return;
-+    }
-+    sss_authtok_set_empty(tok);
-+
-+    tok->type = SSS_AUTHTOK_TYPE_SC_KEYPAD;
-+}
-diff --git a/src/util/authtok.h b/src/util/authtok.h
-index cb366270832852281a222018f8e27feb1500ff01..f1a01a42306a720fc39e701078550a071835e980 100644
---- a/src/util/authtok.h
-+++ b/src/util/authtok.h
-@@ -223,4 +223,45 @@ errno_t sss_authtok_set_2fa(struct sss_auth_token *tok,
- errno_t sss_authtok_get_2fa(struct sss_auth_token *tok,
-                             const char **fa1, size_t *fa1_len,
-                             const char **fa2, size_t *fa2_len);
-+
-+/**
-+ * @brief Set a Smart Card pin into a an auth token, replacing any previous data
-+ *
-+ * @param tok        A pointer to a sss_auth_token structure to change, also
-+ *                   used as a memory context to allocate the internal data.
-+ * @param pin        A string
-+ * @param len        The length of the string or, if 0 is passed,
-+ *                   then strlen(password) will be used internally.
-+ *
-+ * @return       EOK on success
-+ *               ENOMEM on error
-+ */
-+errno_t sss_authtok_set_sc_pin(struct sss_auth_token *tok, const char *pin,
-+                               size_t len);
-+
-+/**
-+ * @brief Returns a Smart Card pin as const string if the auth token is of
-+ *        type SSS_AUTHTOK_TYPE_SC_PIN, otherwise it returns an error
-+ *
-+ * @param tok    A pointer to an sss_auth_token
-+ * @param pin    A pointer to a const char *, that will point to a null
-+ *               terminated string
-+ * @param len    The length of the pin string
-+ *
-+ * @return       EOK on success
-+ *               ENOENT if the token is empty
-+ *               EACCESS if the token is not a Smart Card pin token
-+ */
-+errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **pin,
-+                               size_t *len);
-+
-+/**
-+ * @brief Sets an auth token to type SSS_AUTHTOK_TYPE_SC_KEYPAD, replacing any
-+ *        previous data
-+ *
-+ * @param tok        A pointer to a sss_auth_token structure to change, also
-+ *                   used as a memory context to allocate the internal data.
-+ */
-+void sss_authtok_set_sc_keypad(struct sss_auth_token *tok);
-+
- #endif /*  __AUTHTOK_H__ */
--- 
-2.4.3
-
diff --git a/SOURCES/0034-PAM-add-certificate-support-to-PAM-pre-auth-NOTEST.patch b/SOURCES/0034-PAM-add-certificate-support-to-PAM-pre-auth-NOTEST.patch
deleted file mode 100644
index 8f70539..0000000
--- a/SOURCES/0034-PAM-add-certificate-support-to-PAM-pre-auth-NOTEST.patch
+++ /dev/null
@@ -1,1732 +0,0 @@
-unchanged:
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -115,6 +115,8 @@
- #define CONFDB_PAM_TRUSTED_USERS "pam_trusted_users"
- #define CONFDB_PAM_PUBLIC_DOMAINS "pam_public_domains"
- #define CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE "pam_account_expired_message"
-+#define CONFDB_PAM_CERT_AUTH "pam_cert_auth"
-+#define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path"
- 
- /* SUDO */
- #define CONFDB_SUDO_CONF_ENTRY "config/sudo"
-unchanged:
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -382,6 +382,8 @@ dist_noinst_DATA = \
-     contrib/ci/distro.sh \
-     contrib/ci/misc.sh \
-     contrib/ci/sssd.supp \
-+    src/tests/cmocka/p11_nssdb/cert9.db \
-+    src/tests/cmocka/p11_nssdb/key4.db \
-     $(NULL)
- 
- ###############################
-@@ -1086,6 +1088,7 @@ sssd_pam_SOURCES = \
-     src/responder/pam/pam_LOCAL_domain.c \
-     src/responder/pam/pamsrv.c \
-     src/responder/pam/pamsrv_cmd.c \
-+    src/responder/pam/pamsrv_p11.c \
-     src/responder/pam/pamsrv_dp.c \
-     src/responder/pam/pam_helpers.c \
-     $(SSSD_RESPONDER_OBJ)
-@@ -1877,11 +1880,13 @@ pam_srv_tests_SOURCES = \
-     src/tests/cmocka/test_pam_srv.c \
-     src/sss_client/pam_message.c \
-     src/responder/pam/pamsrv_cmd.c \
-+    src/responder/pam/pamsrv_p11.c \
-     src/responder/pam/pam_helpers.c \
-     src/responder/pam/pamsrv_dp.c \
-     src/responder/pam/pam_LOCAL_domain.c \
-     $(NULL)
- pam_srv_tests_CFLAGS = \
-+    -U SSSD_LIBEXEC_PATH -DSSSD_LIBEXEC_PATH=\"$(abs_builddir)\" \
-     $(AM_CFLAGS) \
-     $(NULL)
- pam_srv_tests_LDFLAGS = \
-unchanged:
---- a/configure.ac
-+++ b/configure.ac
-@@ -400,6 +400,9 @@ abs_build_dir=`pwd`
- AC_DEFINE_UNQUOTED([ABS_BUILD_DIR], ["$abs_build_dir"], [Absolute path to the build directory])
- AC_SUBST([abs_builddir], $abs_build_dir)
- 
-+my_srcdir=`readlink -f $srcdir`
-+AC_DEFINE_UNQUOTED([ABS_SRC_DIR], ["$my_srcdir"], [Absolute path to the source directory])
-+
- AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
-                  src/sysv/sssd src/sysv/gentoo/sssd src/sysv/SUSE/sssd
-                  po/Makefile.in src/man/Makefile src/tests/cwrap/Makefile
-unchanged:
---- a/src/responder/pam/pamsrv.c
-+++ b/src/responder/pam/pamsrv.c
-@@ -50,6 +50,8 @@
- #define ALL_DOMAIMS_ARE_PUBLIC "all"
- #define NO_DOMAIMS_ARE_PUBLIC "none"
- #define DEFAULT_ALLOWED_UIDS ALL_UIDS_ALLOWED
-+#define DEFAULT_PAM_CERT_AUTH false
-+#define DEFAULT_PAM_CERT_DB_PATH SYSCONFDIR"/pki/nssdb"
- 
- struct mon_cli_iface monitor_pam_methods = {
-     { &mon_cli_iface_meta, 0 },
-@@ -302,6 +304,38 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
-+    /* Check if certificate based authentication is enabled */
-+    ret = confdb_get_bool(pctx->rctx->cdb,
-+                          CONFDB_PAM_CONF_ENTRY,
-+                          CONFDB_PAM_CERT_AUTH,
-+                          DEFAULT_PAM_CERT_AUTH,
-+                          &pctx->cert_auth);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to determine get cert db path.\n");
-+        goto done;
-+    }
-+
-+    pctx->p11_child_debug_fd = -1;
-+    if (pctx->cert_auth) {
-+        ret = p11_child_init(pctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_FATAL_FAILURE, "p11_child_init failed.\n");
-+            goto done;
-+        }
-+
-+        ret = confdb_get_string(pctx->rctx->cdb, pctx,
-+                                CONFDB_PAM_CONF_ENTRY,
-+                                CONFDB_PAM_CERT_DB_PATH,
-+                                DEFAULT_PAM_CERT_DB_PATH,
-+                                &pctx->nss_db);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "Failed to determine if certificate based authentication is " \
-+                  "enabled or not.\n");
-+            goto done;
-+        }
-+    }
-+
-     ret = EOK;
- 
- done:
-unchanged:
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -43,6 +43,10 @@ struct pam_ctx {
-     /* List of domains that are accessible even for untrusted users. */
-     char **public_domains;
-     int public_domains_count;
-+
-+    bool cert_auth;
-+    int p11_child_debug_fd;
-+    char *nss_db;
- };
- 
- struct pam_auth_dp_req {
-@@ -65,6 +69,9 @@ struct pam_auth_req {
-     bool cached_auth_failed;
- 
-     struct pam_auth_dp_req *dpreq_spy;
-+
-+    struct ldb_message *cert_user_obj;
-+    char *token_name;
- };
- 
- struct sss_cmd_table *get_pam_cmds(void);
-@@ -73,4 +80,19 @@ int pam_dp_send_req(struct pam_auth_req *preq, int timeout);
- 
- int LOCAL_pam_handler(struct pam_auth_req *preq);
- 
-+errno_t p11_child_init(struct pam_ctx *pctx);
-+
-+struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_context *ev,
-+                                       int child_debug_fd,
-+                                       const char *nss_db,
-+                                       time_t timeout,
-+                                       struct pam_data *pd);
-+errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-+                            char **cert, char **token_name);
-+
-+errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
-+                              const char *token_name);
-+
-+bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd);
- #endif /* __PAMSRV_H__ */
-unchanged:
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -31,6 +31,7 @@
- #include "providers/data_provider.h"
- #include "responder/pam/pamsrv.h"
- #include "responder/pam/pam_helpers.h"
-+#include "responder/common/responder_cache_req.h"
- #include "db/sysdb.h"
- 
- enum pam_verbosity {
-@@ -49,6 +50,7 @@ static errno_t
- pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
-                                          const char *name,
-                                          uint64_t *_value);
-+
- static void pam_reply(struct pam_auth_req *preq);
- 
- static errno_t pack_user_info_account_expired(TALLOC_CTX *mem_ctx,
-@@ -154,6 +156,13 @@ static int extract_authtok_v2(struct sss_auth_token *tok,
-         ret = sss_authtok_set(tok, SSS_AUTHTOK_TYPE_2FA,
-                               auth_token_data, auth_token_length);
-         break;
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+        ret = sss_authtok_set_sc_pin(tok, (const char *) auth_token_data,
-+                                     auth_token_length);
-+        break;
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-+        sss_authtok_set_sc_keypad(tok);
-+        break;
-     default:
-         return EINVAL;
-     }
-@@ -892,6 +901,7 @@ static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
- }
- 
- static void pam_forwarder_cb(struct tevent_req *req);
-+static void pam_forwarder_cert_cb(struct tevent_req *req);
- static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
-                                        const char *err_msg, void *ptr);
- static int pam_check_user_search(struct pam_auth_req *preq);
-@@ -939,9 +949,22 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p
-         goto done;
-     }
- 
--    ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
--                                     cctx->rctx->default_domain, pd->logon_name,
--                                     &pd->domain, &pd->user);
-+    if (pd->logon_name != NULL) {
-+        ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
-+                                         cctx->rctx->default_domain,
-+                                         pd->logon_name,
-+                                         &pd->domain, &pd->user);
-+    } else {
-+        /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
-+         * name is determined with the help of a certificate */
-+        if (pd->cmd == SSS_PAM_PREAUTH) {
-+            ret = EOK;
-+        } else {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+    }
- 
-     DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
- 
-@@ -1052,49 +1075,66 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
-         goto done;
-     }
- 
--    /* now check user is valid */
--    if (pd->domain) {
--        preq->domain = responder_get_domain(cctx->rctx, pd->domain);
--        if (!preq->domain) {
--            ret = ENOENT;
--            goto done;
--        }
--
--        ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
--                                      preq->domain, pd->user);
--        if (ncret == EEXIST) {
--            /* User found in the negative cache */
--            ret = ENOENT;
--            goto done;
--        }
--    } else {
--        for (dom = preq->cctx->rctx->domains;
--             dom;
--             dom = get_next_domain(dom, false)) {
--            if (dom->fqnames) continue;
-+    if (pd->user != NULL) {
-+        /* now check user is valid */
-+        if (pd->domain) {
-+            preq->domain = responder_get_domain(cctx->rctx, pd->domain);
-+            if (!preq->domain) {
-+                ret = ENOENT;
-+                goto done;
-+            }
- 
-             ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
--                                          dom, pd->user);
--            if (ncret == ENOENT) {
--                /* User not found in the negative cache
--                 * Proceed with PAM actions
--                 */
--                break;
-+                                          preq->domain, pd->user);
-+            if (ncret == EEXIST) {
-+                /* User found in the negative cache */
-+                ret = ENOENT;
-+                goto done;
-             }
-+        } else {
-+            for (dom = preq->cctx->rctx->domains;
-+                 dom;
-+                 dom = get_next_domain(dom, false)) {
-+                if (dom->fqnames) continue;
- 
--            /* Try the next domain */
--            DEBUG(SSSDBG_TRACE_FUNC,
--                  "User [%s@%s] filtered out (negative cache). "
--                   "Trying next domain.\n", pd->user, dom->name);
-+                ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
-+                                              dom, pd->user);
-+                if (ncret == ENOENT) {
-+                    /* User not found in the negative cache
-+                     * Proceed with PAM actions
-+                     */
-+                    break;
-+                }
-+
-+                /* Try the next domain */
-+                DEBUG(SSSDBG_TRACE_FUNC,
-+                      "User [%s@%s] filtered out (negative cache). "
-+                       "Trying next domain.\n", pd->user, dom->name);
-+            }
-+
-+            if (!dom) {
-+                ret = ENOENT;
-+                goto done;
-+            }
-+            preq->domain = dom;
-         }
-+    }
- 
--        if (!dom) {
--            ret = ENOENT;
--            goto done;
-+    if (may_do_cert_auth(pctx, pd)) {
-+        req = pam_check_cert_send(cctx, cctx->ev, pctx->p11_child_debug_fd,
-+                                  pctx->nss_db, 10, pd);
-+        if (req == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
-+            ret = ENOMEM;
-+        } else {
-+            tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
-+            ret = EAGAIN;
-         }
--        preq->domain = dom;
-+
-+        goto done;
-     }
- 
-+
-     if (preq->domain->provider == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "Domain [%s] has no auth provider.\n", preq->domain->name);
-@@ -1113,6 +1153,142 @@ done:
-     return pam_check_user_done(preq, ret);
- }
- 
-+static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req);
-+static void pam_forwarder_cert_cb(struct tevent_req *req)
-+{
-+    struct pam_auth_req *preq = tevent_req_callback_data(req,
-+                                                         struct pam_auth_req);
-+    struct cli_ctx *cctx = preq->cctx;
-+    struct pam_data *pd;
-+    errno_t ret = EOK;
-+    char *cert;
-+    struct pam_ctx *pctx =
-+            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
-+
-+    ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name);
-+    talloc_free(req);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n");
-+        goto done;
-+    }
-+
-+    pd = preq->pd;
-+
-+    if (cert == NULL) {
-+        if (pd->logon_name == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "No certificate found and no logon name given, " \
-+                  "authentication not possible.\n");;
-+            ret = ENOENT;
-+        } else {
-+            if (pd->cmd == SSS_PAM_AUTHENTICATE) {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "No certificate returned, authentication failed.\n");
-+                ret = ENOENT;
-+            } else {
-+                ret = pam_check_user_search(preq);
-+                if (ret == EOK) {
-+                    pam_dom_forwarder(preq);
-+                }
-+            }
-+
-+        }
-+        goto done;
-+    }
-+
-+
-+    req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
-+                                      pctx->ncache, pctx->neg_timeout,
-+                                      0, NULL, cert);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq);
-+    return;
-+
-+done:
-+    pam_check_user_done(preq, ret);
-+}
-+
-+static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-+{
-+    int ret;
-+    struct ldb_result *res;
-+    struct sss_domain_info *domain;
-+    struct pam_auth_req *preq = tevent_req_callback_data(req,
-+                                                         struct pam_auth_req);
-+    const char *cert_user;
-+
-+
-+    ret = cache_req_user_by_cert_recv(preq, req, &res, &domain, NULL);
-+    talloc_zfree(req);
-+    if (ret != EOK && ret != ENOENT) {
-+        DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n");
-+        goto done;
-+    }
-+
-+    if (ret == EOK && res->count > 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Search by certificate returned more than one result.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    if (ret == EOK) {
-+        if (preq->domain == NULL) {
-+            preq->domain = domain;
-+        }
-+
-+        preq->cert_user_obj = talloc_steal(preq, res->msgs[0]);
-+
-+        if (preq->pd->logon_name == NULL) {
-+            cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj,
-+                                                    SYSDB_NAME, NULL);
-+            if (cert_user == NULL) {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "Certificate user object has not name.\n");
-+                ret = ENOENT;
-+                goto done;
-+            }
-+
-+            DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n",
-+                                    cert_user);
-+
-+            ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
-+            }
-+
-+            preq->pd->domain = talloc_strdup(preq->pd, domain->name);
-+            if (preq->pd->domain == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+                ret = ENOMEM;
-+                goto done;
-+            }
-+            preq->pd->pam_status = PAM_SUCCESS;
-+            pam_reply(preq);
-+            return;
-+        }
-+    } else {
-+        if (preq->pd->logon_name == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Missing logon name and no certificate user found.\n");
-+            ret = ENOENT;
-+            goto done;
-+        }
-+    }
-+
-+    ret = pam_check_user_search(preq);
-+    if (ret == EOK) {
-+        pam_dom_forwarder(preq);
-+    }
-+
-+done:
-+    pam_check_user_done(preq, ret);
-+}
-+
- static void pam_forwarder_cb(struct tevent_req *req)
- {
-     struct pam_auth_req *preq = tevent_req_callback_data(req,
-@@ -1120,6 +1296,8 @@ static void pam_forwarder_cb(struct tevent_req *req)
-     struct cli_ctx *cctx = preq->cctx;
-     struct pam_data *pd;
-     errno_t ret = EOK;
-+    struct pam_ctx *pctx =
-+            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
- 
-     ret = sss_dp_get_domains_recv(req);
-     talloc_free(req);
-@@ -1158,6 +1336,20 @@ static void pam_forwarder_cb(struct tevent_req *req)
-         }
-     }
- 
-+    if (may_do_cert_auth(pctx, pd)) {
-+        req = pam_check_cert_send(cctx, cctx->ev, pctx->p11_child_debug_fd,
-+                                  pctx->nss_db, 10, pd);
-+        if (req == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
-+            ret = ENOMEM;
-+        } else {
-+            tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
-+            ret = EAGAIN;
-+        }
-+
-+        goto done;
-+    }
-+
-     ret = pam_check_user_search(preq);
-     if (ret == EOK) {
-         pam_dom_forwarder(preq);
-@@ -1542,6 +1734,7 @@ 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);
-+    const char *cert_user;
- 
-     if (!preq->pd->domain) {
-         preq->pd->domain = preq->domain->name;
-@@ -1579,6 +1772,51 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
-         return;
-     }
- 
-+    if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_obj != NULL) {
-+        /* Check if user matches certificate user */
-+        cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj, SYSDB_NAME,
-+                                                NULL);
-+        if (cert_user == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Certificate user object has not name.\n");
-+            preq->pd->pam_status = PAM_USER_UNKNOWN;
-+            pam_reply(preq);
-+            return;
-+        }
-+
-+        /* pam_check_user_search() calls pd_set_primary_name() is the search
-+         * was successful, so pd->user contains the canonical name as well */
-+        if (strcmp(cert_user, preq->pd->user) == 0) {
-+
-+            preq->pd->pam_status = PAM_SUCCESS;
-+
-+            if (preq->pd->cmd == SSS_PAM_PREAUTH) {
-+                ret = add_pam_cert_response(preq->pd, cert_user,
-+                                            preq->token_name);
-+                if (ret != EOK) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
-+                    preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
-+                }
-+            }
-+
-+            preq->callback = pam_reply;
-+            pam_reply(preq);
-+            return;
-+        } else {
-+            if (preq->pd->cmd == SSS_PAM_PREAUTH) {
-+                DEBUG(SSSDBG_TRACE_FUNC,
-+                      "User and certificate user do not match, " \
-+                      "continue with other authentication methods.\n");
-+            } else {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "User and certificate user do not match.\n");
-+                preq->pd->pam_status = PAM_AUTH_ERR;
-+                pam_reply(preq);
-+                return;
-+            }
-+        }
-+    }
-+
-     if (!NEED_CHECK_PROVIDER(preq->domain->provider) ) {
-         preq->callback = pam_reply;
-         ret = LOCAL_pam_handler(preq);
-unchanged:
---- /dev/null
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -0,0 +1,527 @@
-+/*
-+   SSSD
-+
-+   PAM Responder - certificate realted requests
-+
-+   Copyright (C) Sumit Bose <sbose@redhat.com> 2015
-+
-+   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 <time.h>
-+
-+#include "util/util.h"
-+#include "providers/data_provider.h"
-+#include "util/child_common.h"
-+#include "util/strtonum.h"
-+#include "responder/pam/pamsrv.h"
-+
-+
-+#ifndef SSSD_LIBEXEC_PATH
-+#error "SSSD_LIBEXEC_PATH not defined"
-+#endif  /* SSSD_LIBEXEC_PATH */
-+
-+#define P11_CHILD_LOG_FILE "p11_child"
-+#define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
-+
-+errno_t p11_child_init(struct pam_ctx *pctx)
-+{
-+    return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
-+}
-+
-+bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd)
-+{
-+    size_t c;
-+    const char *sc_services[] = { "login", "su", "su-l", "gdm-smartcard",
-+                                  "gdm-password", "kdm", "sudo", "sudo-i",
-+                                  NULL };
-+    if (!pctx->cert_auth) {
-+        return false;
-+    }
-+
-+    if (pd->cmd != SSS_PAM_PREAUTH && pd->cmd != SSS_PAM_AUTHENTICATE) {
-+        return false;
-+    }
-+
-+    if (pd->cmd == SSS_PAM_AUTHENTICATE
-+           && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
-+           && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
-+        return false;
-+    }
-+
-+    /* TODO: make services configurable */
-+    if (pd->service == NULL || *pd->service == '\0') {
-+        return false;
-+    }
-+    for (c = 0; sc_services[c] != NULL; c++) {
-+        if (strcmp(pd->service, sc_services[c]) == 0) {
-+            break;
-+        }
-+    }
-+    if  (sc_services[c] == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Smartcard authentication for service [%s] not supported.\n",
-+              pd->service);
-+        return false;
-+    }
-+
-+    return true;
-+}
-+
-+static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
-+                                          struct pam_data *pd,
-+                                          uint8_t **_buf, size_t *_len)
-+{
-+    int ret;
-+    uint8_t *buf;
-+    size_t len;
-+    const char *pin = NULL;
-+
-+    if (pd == NULL || pd->authtok == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing authtok.\n");
-+        return EINVAL;
-+    }
-+
-+    switch (sss_authtok_get_type(pd->authtok)) {
-+    case SSS_AUTHTOK_TYPE_SC_PIN:
-+        ret = sss_authtok_get_sc_pin(pd->authtok, &pin, &len);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc_pin failed.\n");
-+            return ret;
-+        }
-+        if (pin == NULL || len == 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n");
-+            return EINVAL;
-+        }
-+
-+        buf = talloc_size(mem_ctx, len);
-+        if (buf == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+            return ENOMEM;
-+        }
-+
-+        safealign_memcpy(buf, pin, len, NULL);
-+
-+        break;
-+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-+        /* Nothing to send */
-+        len = 0;
-+        buf = NULL;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported authtok type [%d].\n",
-+                                   sss_authtok_get_type(pd->authtok));
-+        return EINVAL;
-+    }
-+
-+    *_len = len;
-+    *_buf = buf;
-+
-+    return EOK;
-+}
-+
-+static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
-+                                        ssize_t buf_len, char **_cert,
-+                                        char **_token_name)
-+{
-+    int ret;
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    uint8_t *p;
-+    uint8_t *pn;
-+    char *cert = NULL;
-+    char *token_name = NULL;
-+
-+    if (buf_len < 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Error occured while reading data from p11_child.\n");
-+        return EIO;
-+    }
-+
-+    if (buf_len == 0) {
-+        DEBUG(SSSDBG_TRACE_LIBS, "No certificate found.\n");
-+        ret = EOK;
-+        goto done;
-+    }
-+
-+    p = memchr(buf, '\n', buf_len);
-+    if (p == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n");
-+        return EINVAL;
-+    }
-+    if (p == buf) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n");
-+        return EINVAL;
-+    }
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf));
-+    if (token_name == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    p++;
-+    pn = memchr(p, '\n', buf_len - (p - buf));
-+    if (pn == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Missing new-line in p11_child response.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    if (pn == p) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
-+    if(cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert);
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret == EOK) {
-+        *_token_name = talloc_steal(mem_ctx, token_name);
-+        *_cert = talloc_steal(mem_ctx, cert);
-+    }
-+
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-+
-+struct pam_check_cert_state {
-+    int child_status;
-+    struct sss_child_ctx_old *child_ctx;
-+    struct tevent_timer *timeout_handler;
-+    struct tevent_context *ev;
-+
-+    int write_to_child_fd;
-+    int read_from_child_fd;
-+    char *cert;
-+    char *token_name;
-+};
-+
-+static void p11_child_write_done(struct tevent_req *subreq);
-+static void p11_child_done(struct tevent_req *subreq);
-+static void p11_child_timeout(struct tevent_context *ev,
-+                              struct tevent_timer *te,
-+                              struct timeval tv, void *pvt);
-+
-+struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_context *ev,
-+                                       int child_debug_fd,
-+                                       const char *nss_db,
-+                                       time_t timeout,
-+                                       struct pam_data *pd)
-+{
-+    errno_t ret;
-+    struct tevent_req *req;
-+    struct tevent_req *subreq;
-+    struct pam_check_cert_state *state;
-+    pid_t child_pid;
-+    struct timeval tv;
-+    int pipefd_to_child[2];
-+    int pipefd_from_child[2];
-+    const char *extra_args[5] = {NULL, NULL, NULL, NULL, NULL};
-+    uint8_t *write_buf = NULL;
-+    size_t write_buf_len = 0;
-+
-+    req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state);
-+    if (req == NULL) {
-+        return NULL;
-+    }
-+
-+    if (nss_db == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing NSS DB.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    /* extra_args are added in revers order */
-+    extra_args[1] = "--nssdb";
-+    extra_args[0] = nss_db;
-+    if (pd->cmd == SSS_PAM_AUTHENTICATE) {
-+        extra_args[2] = "--auth";
-+        switch (sss_authtok_get_type(pd->authtok)) {
-+        case SSS_AUTHTOK_TYPE_SC_PIN:
-+            extra_args[3] = "--pin";
-+            break;
-+        case SSS_AUTHTOK_TYPE_SC_KEYPAD:
-+            extra_args[3] = "--keypad";
-+            break;
-+        default:
-+            DEBUG(SSSDBG_OP_FAILURE, "Unsupported authtok type.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+    } else if (pd->cmd == SSS_PAM_PREAUTH) {
-+        extra_args[2] = "--pre";
-+    } else {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d}.\n", pd->cmd);
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    state->ev = ev;
-+    state->child_status = EFAULT;
-+    state->read_from_child_fd = -1;
-+    state->write_to_child_fd = -1;
-+    state->cert = NULL;
-+    state->token_name = NULL;
-+
-+    ret = pipe(pipefd_from_child);
-+    if (ret == -1) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "pipe failed [%d][%s].\n", ret, strerror(ret));
-+        goto done;
-+    }
-+    ret = pipe(pipefd_to_child);
-+    if (ret == -1) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "pipe failed [%d][%s].\n", ret, strerror(ret));
-+        goto done;
-+    }
-+
-+    if (child_debug_fd == -1) {
-+        child_debug_fd = STDERR_FILENO;
-+    }
-+
-+    child_pid = fork();
-+    if (child_pid == 0) { /* child */
-+        ret = exec_child_ex(state, pipefd_to_child, pipefd_from_child,
-+                            P11_CHILD_PATH, child_debug_fd, extra_args,
-+                            STDIN_FILENO, STDOUT_FILENO);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec p11 child: [%d][%s].\n",
-+                                       ret, strerror(ret));
-+            goto done;
-+        }
-+    } else if (child_pid > 0) { /* parent */
-+
-+        state->read_from_child_fd = pipefd_from_child[0];
-+        close(pipefd_from_child[1]);
-+        sss_fd_nonblocking(state->read_from_child_fd);
-+
-+        state->write_to_child_fd = pipefd_to_child[1];
-+        close(pipefd_to_child[0]);
-+        sss_fd_nonblocking(state->write_to_child_fd);
-+
-+        /* Set up SIGCHLD handler */
-+        ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
-+                ret, sss_strerror(ret));
-+            ret = ERR_P11_CHILD;
-+            goto done;
-+        }
-+
-+        /* Set up timeout handler */
-+        tv = tevent_timeval_current_ofs(timeout, 0);
-+        state->timeout_handler = tevent_add_timer(ev, req, tv,
-+                                                  p11_child_timeout, req);
-+        if(state->timeout_handler == NULL) {
-+            ret = ERR_P11_CHILD;
-+            goto done;
-+        }
-+
-+        if (pd->cmd == SSS_PAM_AUTHENTICATE) {
-+            ret = get_p11_child_write_buffer(state, pd, &write_buf,
-+                                             &write_buf_len);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "get_p11_child_write_buffer failed.\n");
-+                goto done;
-+            }
-+        }
-+
-+        if (write_buf_len != 0) {
-+            subreq = write_pipe_send(state, ev, write_buf, write_buf_len,
-+                                     state->write_to_child_fd);
-+            if (subreq == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE, "write_pipe_send failed.\n");
-+                ret = ERR_P11_CHILD;
-+                goto done;
-+            }
-+            tevent_req_set_callback(subreq, p11_child_write_done, req);
-+        } else {
-+            subreq = read_pipe_send(state, ev, state->read_from_child_fd);
-+            if (subreq == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
-+                ret = ERR_P11_CHILD;
-+                goto done;
-+            }
-+            tevent_req_set_callback(subreq, p11_child_done, req);
-+        }
-+
-+        /* Now either wait for the timeout to fire or the child
-+         * to finish
-+         */
-+    } else { /* error */
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n",
-+                                   ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        tevent_req_post(req, ev);
-+    }
-+    return req;
-+}
-+
-+static void p11_child_write_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct pam_check_cert_state *state = tevent_req_data(req,
-+                                                   struct pam_check_cert_state);
-+    int ret;
-+
-+    ret = write_pipe_recv(subreq);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    close(state->write_to_child_fd);
-+    state->write_to_child_fd = -1;
-+
-+    subreq = read_pipe_send(state, state->ev, state->read_from_child_fd);
-+    if (subreq == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    }
-+    tevent_req_set_callback(subreq, p11_child_done, req);
-+}
-+
-+static void p11_child_done(struct tevent_req *subreq)
-+{
-+    uint8_t *buf;
-+    ssize_t buf_len;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct pam_check_cert_state *state = tevent_req_data(req,
-+                                                   struct pam_check_cert_state);
-+    int ret;
-+
-+    talloc_zfree(state->timeout_handler);
-+
-+    ret = read_pipe_recv(subreq, state, &buf, &buf_len);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    close(state->read_from_child_fd);
-+    state->read_from_child_fd = -1;
-+
-+    ret = parse_p11_child_response(state, buf, buf_len, &state->cert,
-+                                   &state->token_name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n");
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+    return;
-+}
-+
-+static void p11_child_timeout(struct tevent_context *ev,
-+                              struct tevent_timer *te,
-+                              struct timeval tv, void *pvt)
-+{
-+    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
-+    struct pam_check_cert_state *state =
-+                              tevent_req_data(req, struct pam_check_cert_state);
-+
-+    DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for p11_child.\n");
-+    child_handler_destroy(state->child_ctx);
-+    state->child_ctx = NULL;
-+    state->child_status = ETIMEDOUT;
-+    tevent_req_error(req, ERR_P11_CHILD);
-+}
-+
-+errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-+                            char **cert, char **token_name)
-+{
-+    struct pam_check_cert_state *state =
-+                              tevent_req_data(req, struct pam_check_cert_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    if (cert != NULL) {
-+        *cert = talloc_steal(mem_ctx, state->cert);
-+    }
-+
-+    if (token_name != NULL) {
-+        *token_name = talloc_steal(mem_ctx, state->token_name);
-+    }
-+
-+    return EOK;
-+}
-+
-+errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
-+                              const char *token_name)
-+{
-+    uint8_t *msg = NULL;
-+    size_t user_len;
-+    size_t msg_len;
-+    size_t slot_len;
-+    int ret;
-+
-+    if (user == NULL || token_name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n");
-+        return EINVAL;
-+    }
-+
-+    user_len = strlen(user) + 1;
-+    slot_len = strlen(token_name) + 1;
-+    msg_len = user_len + slot_len;
-+
-+    msg = talloc_zero_size(pd, msg_len);
-+    if (msg == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    memcpy(msg, user, user_len);
-+    memcpy(msg + user_len, token_name, slot_len);
-+
-+    ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg);
-+    talloc_free(msg);
-+
-+    return ret;
-+}
-unchanged:
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -417,6 +417,7 @@ enum response_type {
-                           * @param Three zero terminated strings, if one of the
-                           * strings is missing the message will contain only
-                           * an empty string (\0) for that component. */
-+    SSS_PAM_CERT_INFO,
-     SSS_OTP,             /**< Indicates that the autotok was a OTP, so don't
-                           * cache it. There is no message.
-                           * @param None. */
-unchanged:
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -32,7 +32,10 @@
- #include "sss_client/pam_message.h"
- #include "sss_client/sss_cli.h"
- 
-+#include "util/crypto/sss_crypto.h"
-+#ifdef HAVE_NSS
- #include "util/crypto/nss/nss_util.h"
-+#endif
- 
- #define TESTS_PATH "tests_pam"
- #define TEST_CONF_DB "test_pam_conf.ldb"
-@@ -40,6 +43,34 @@
- #define TEST_SUBDOM_NAME "test.subdomain"
- #define TEST_ID_PROVIDER "ldap"
- 
-+#define NSS_DB_PATH "./sssd_test_nssdb"
-+#define NSS_DB "sql:"NSS_DB_PATH
-+
-+#define TEST_TOKEN_NAME "SSSD Test Token"
-+#define TEST_TOKEN_CERT \
-+"MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
-+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \
-+"NjMyMDdaFw0xNzA2MjMxNjMyMDdaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \
-+"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \
-+"ADCCAQoCggEBALXUq56VlY+Z0aWLLpFAjFfbElPBXGQsbZb85J3cGyPjaMHC9wS+" \
-+"wjB6Ve4HmQyPLx8hbINdDmbawMHYQvTScLYfsqLtj0Lqw20sUUmedk+Es5Oh9VHo" \
-+"nd8MavYx25Du2u+T0iSgNIDikXguiwCmtAj8VC49ebbgITcjJGzMmiiuJkV3o93Y" \
-+"vvYF0VjLGDQbQWOy7IxzYJeNVJnZWKo67CHdok6qOrm9rxQt81rzwV/mGLbCMUbr" \
-+"+N4M8URtd7EmzaYZQmNm//s2owFrCYMxpLiURPj+URZVuB72504/Ix7X0HCbA/AV" \
-+"26J27fPY5nc8DMwfhUDCbTqPH/JEjd3mvY8CAwEAAaOCASYwggEiMB8GA1UdIwQY" \
-+"MBaAFJOq+KAQmPEnNp8Wok23eGTdE7aDMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \
-+"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \
-+"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \
-+"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \
-+"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \
-+"IEF1dGhvcml0eTAdBgNVHQ4EFgQUFaDNd5a53QGpaw5m63hnwXicMQ8wDQYJKoZI" \
-+"hvcNAQELBQADggEBADH7Nj00qqGhGJeXJQAsepqSskz/wooqXh8vgVyb8SS4N0/c" \
-+"0aQtVmY81xamlXE12ZFpwDX43d+EufBkwCUKFX/+8JFDd2doAyeJxv1xM22kKRpc" \
-+"AqITPgMsa9ToGMWxjbVpc/X/5YfZixWPF0/eZUTotBj9oaR039UrhGfyN7OguF/G" \
-+"rzmxtB5y4ZrMpcD/Oe90mkd9HY7sA/fB8OWOUgeRfQoh97HNS0UiDWsPtfxmjQG5" \
-+"zotpoBIZmdH+ipYsu58HohHVlM9Wi5H4QmiiXl+Soldkq7eXYlafcmT7wv8+cKwz" \
-+"Nz0Tm3+eYpFqRo3skr6QzXi525Jkg3r6r+kkhxU=" \
-+
- struct pam_test_ctx {
-     struct sss_test_ctx *tctx;
-     struct sss_domain_info *subdom;
-@@ -56,6 +87,84 @@ struct pam_test_ctx {
- /* Must be global because it is needed in some wrappers */
- struct pam_test_ctx *pam_test_ctx;
- 
-+static errno_t setup_nss_db(void)
-+{
-+    int ret;
-+    FILE *fp;
-+    int status;
-+    pid_t child_pid;
-+
-+    ret = mkdir(NSS_DB_PATH, 0775);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to create " NSS_DB_PATH ".\n");
-+        return ret;
-+    }
-+
-+    child_pid = fork();
-+    if (child_pid == 0) { /* child */
-+        ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d",
-+                     NSS_DB, NULL);
-+        if (ret == -1) {
-+            DEBUG(SSSDBG_FATAL_FAILURE, "execl() failed.\n");
-+            exit(-1);
-+        }
-+    } else if (child_pid > 0) {
-+        wait(&status);
-+    } else {
-+        ret = errno;
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fork() failed\n");
-+        return ret;
-+    }
-+
-+    fp = fopen(NSS_DB_PATH"/pkcs11.txt", "w");
-+    if (fp == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n");
-+        return ret;
-+    }
-+    ret = fprintf(fp, "library=libsoftokn3.so\nname=soft\n");
-+    if (ret < 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
-+        return ret;
-+    }
-+    ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR);
-+    if (ret < 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
-+        return ret;
-+    }
-+    ret = fclose(fp);
-+    if (ret != 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fclose() failed.\n");
-+        return ret;
-+    }
-+
-+    return EOK;
-+}
-+
-+static void cleanup_nss_db(void)
-+{
-+    int ret;
-+
-+    ret = unlink(NSS_DB_PATH"/cert9.db");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove cert9.db.\n");
-+    }
-+
-+    ret = unlink(NSS_DB_PATH"/key4.db");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove key4.db.\n");
-+    }
-+
-+    ret = unlink(NSS_DB_PATH"/pkcs11.txt");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove pkcs11.db.\n");
-+    }
-+
-+    ret = rmdir(NSS_DB_PATH);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n");
-+    }
-+}
-+
- struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
- {
-     struct pam_ctx *pctx;
-@@ -113,6 +222,7 @@ void test_pam_setup(struct sss_test_conf_param params[],
-     assert_non_null(pam_test_ctx->cctx);
- 
-     pam_test_ctx->cctx->cli_protocol_version = register_cli_protocol_version();
-+    pam_test_ctx->cctx->ev = pam_test_ctx->tctx->ev;
- }
- 
- static int pam_test_setup(void **state)
-@@ -141,6 +251,22 @@ static int pam_test_setup(void **state)
-                                discard_const("pamuser"),
-                                pam_test_ctx->pctx->id_timeout);
-     assert_int_equal(ret, EOK);
-+
-+    /* Prime the cache with a user for wrong matches */
-+    ret = sysdb_add_user(pam_test_ctx->tctx->dom,
-+                         "wronguser", 321, 654, "wrong user",
-+                         "/home/wringuser", "/bin/sh", NULL,
-+                         NULL, 300, 0);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Add entry to the initgr cache to make sure no initgr request is sent to
-+     * the backend */
-+    ret = pam_initgr_cache_set(pam_test_ctx->pctx->rctx->ev,
-+                               pam_test_ctx->pctx->id_table,
-+                               discard_const("wronguser"),
-+                               pam_test_ctx->pctx->id_timeout);
-+    assert_int_equal(ret, EOK);
-+
-     return 0;
- }
- 
-@@ -151,12 +277,19 @@ static int pam_test_teardown(void **state)
-     ret = sysdb_delete_user(pam_test_ctx->tctx->dom, "pamuser", 0);
-     assert_int_equal(ret, EOK);
- 
-+    ret = sysdb_delete_user(pam_test_ctx->tctx->dom, "wronguser", 0);
-+    assert_int_equal(ret, EOK);
-+
-     talloc_free(pam_test_ctx);
-     return 0;
- }
- 
- typedef int (*cmd_cb_fn_t)(uint32_t, uint8_t *, size_t);
- 
-+
-+int __real_read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-+                          uint8_t **buf, ssize_t *len);
-+
- void __real_sss_packet_get_body(struct sss_packet *packet,
-                                 uint8_t **body, size_t *blen);
- 
-@@ -239,8 +372,13 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
-     size_t needed_size;
-     uint8_t *authtok;
- 
--    pi.pam_user = name;
--    pi.pam_user_size = strlen(pi.pam_user) + 1;
-+    if (name != NULL) {
-+        pi.pam_user = name;
-+        pi.pam_user_size = strlen(pi.pam_user) + 1;
-+    } else {
-+        pi.pam_user = "";
-+        pi.pam_user_size = 0;
-+    }
- 
-     if (pwd != NULL) {
-         if (fa2 != NULL) {
-@@ -287,6 +425,52 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
-     will_return(__wrap_sss_packet_get_body, buf_size);
- }
- 
-+static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
-+                                const char *pin)
-+{
-+    size_t buf_size;
-+    uint8_t *m_buf;
-+    uint8_t *buf;
-+    struct pam_items pi = { 0 };
-+    int ret;
-+
-+    if (name != NULL) {
-+        pi.pam_user = name;
-+        pi.pam_user_size = strlen(pi.pam_user) + 1;
-+    } else {
-+        pi.pam_user = "";
-+        pi.pam_user_size = 0;
-+    }
-+
-+    if (pin != NULL) {
-+        pi.pam_authtok = discard_const(pin);
-+        pi.pam_authtok_size = strlen(pi.pam_authtok) + 1;
-+        pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN;
-+    }
-+
-+    pi.pam_service = "login";
-+    pi.pam_service_size = strlen(pi.pam_service) + 1;
-+    pi.pam_tty = "/dev/tty";
-+    pi.pam_tty_size = strlen(pi.pam_tty) + 1;
-+    pi.pam_ruser = "remuser";
-+    pi.pam_ruser_size = strlen(pi.pam_ruser) + 1;
-+    pi.pam_rhost = "remhost";
-+    pi.pam_rhost_size = strlen(pi.pam_rhost) + 1;
-+    pi.requested_domains = "";
-+    pi.cli_pid = 12345;
-+
-+    ret = pack_message_v3(&pi, &buf_size, &m_buf);
-+    assert_int_equal(ret, 0);
-+
-+    buf = talloc_memdup(mem_ctx, m_buf, buf_size);
-+    free(m_buf);
-+    assert_non_null(buf);
-+
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+    will_return(__wrap_sss_packet_get_body, buf);
-+    will_return(__wrap_sss_packet_get_body, buf_size);
-+}
-+
- static int test_pam_simple_check(uint32_t status, uint8_t *body, size_t blen)
- {
-     size_t rp = 0;
-@@ -312,6 +496,46 @@ static int test_pam_simple_check(uint32_t status, uint8_t *body, size_t blen)
-     return EOK;
- }
- 
-+static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
-+{
-+    size_t rp = 0;
-+    uint32_t val;
-+
-+    assert_int_equal(status, 0);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, pam_test_ctx->exp_pam_status);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, 2);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, SSS_PAM_DOMAIN_NAME);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, 9);
-+
-+    assert_int_equal(*(body + rp + val - 1), 0);
-+    assert_string_equal(body + rp, TEST_DOM_NAME);
-+    rp += val;
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, SSS_PAM_CERT_INFO);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME)));
-+
-+    assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0);
-+    assert_string_equal(body + rp, "pamuser");
-+    rp += sizeof("pamuser");
-+
-+    assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0);
-+    assert_string_equal(body + rp, TEST_TOKEN_NAME);
-+
-+    return EOK;
-+}
-+
-+
- static int test_pam_offline_chauthtok_check(uint32_t status,
-                                             uint8_t *body, size_t blen)
- {
-@@ -372,6 +596,23 @@ static int test_pam_wrong_pw_offline_auth_check(uint32_t status,
-     return test_pam_simple_check(status, body, blen);
- }
- 
-+static int test_pam_user_unknown_check(uint32_t status,
-+                                       uint8_t *body, size_t blen)
-+{
-+    size_t rp = 0;
-+    uint32_t val;
-+
-+    assert_int_equal(status, 0);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, PAM_USER_UNKNOWN);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, 0);
-+
-+    return EOK;
-+}
-+
- void test_pam_authenticate(void **state)
- {
-     int ret;
-@@ -859,6 +1100,245 @@ void test_pam_offline_chauthtok(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+static void set_cert_auth_param(struct pam_ctx *pctx, const char *dbpath)
-+{
-+    pam_test_ctx->pctx->cert_auth = true;
-+    pam_test_ctx->pctx->nss_db = discard_const(dbpath);
-+}
-+
-+void test_pam_preauth_cert_nocert(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_pam_simple_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+static int test_lookup_by_cert_cb(void *pvt)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    unsigned char *der = NULL;
-+    size_t der_size;
-+
-+    if (pvt != NULL) {
-+
-+        attrs = sysdb_new_attrs(pam_test_ctx);
-+        assert_non_null(attrs);
-+
-+        der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
-+        assert_non_null(der);
-+
-+        ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
-+        talloc_free(der);
-+        assert_int_equal(ret, EOK);
-+
-+        ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, "pamuser", attrs,
-+                                  LDB_FLAG_MOD_ADD);
-+        assert_int_equal(ret, EOK);
-+    }
-+
-+    return EOK;
-+}
-+
-+static int test_lookup_by_cert_wrong_user_cb(void *pvt)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    unsigned char *der = NULL;
-+    size_t der_size;
-+
-+    if (pvt != NULL) {
-+        attrs = sysdb_new_attrs(pam_test_ctx);
-+        assert_non_null(attrs);
-+
-+        der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
-+        assert_non_null(der);
-+
-+        ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
-+        talloc_free(der);
-+        assert_int_equal(ret, EOK);
-+
-+        ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, "wronguser", attrs,
-+                                  LDB_FLAG_MOD_ADD);
-+        assert_int_equal(ret, EOK);
-+    }
-+
-+    return EOK;
-+}
-+
-+
-+void test_pam_preauth_cert_nomatch(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb, NULL);
-+
-+    set_cmd_cb(test_pam_simple_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_pam_preauth_cert_match(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
-+                      discard_const(TEST_TOKEN_CERT));
-+
-+    set_cmd_cb(test_pam_cert_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_pam_preauth_cert_match_wrong_user(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv(0, 0, NULL, test_lookup_by_cert_wrong_user_cb,
-+                      discard_const(TEST_TOKEN_CERT));
-+
-+    set_cmd_cb(test_pam_simple_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+
-+void test_pam_preauth_cert_no_logon_name(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-+
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
-+                      discard_const(TEST_TOKEN_CERT));
-+
-+    set_cmd_cb(test_pam_cert_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_pam_preauth_no_cert_no_logon_name(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
-+
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_pam_user_unknown_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_pam_preauth_cert_no_logon_name_no_match(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-+
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb, NULL);
-+
-+    set_cmd_cb(test_pam_user_unknown_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_pam_cert_auth(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456");
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
-+                      discard_const(TEST_TOKEN_CERT));
-+
-+    set_cmd_cb(test_pam_simple_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     int rv;
-@@ -925,6 +1405,23 @@ int main(int argc, const char *argv[])
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_offline_chauthtok,
-                                         pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nocert,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nomatch,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match_wrong_user,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_cert_no_logon_name,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_no_cert_no_logon_name,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(
-+                                   test_pam_preauth_cert_no_logon_name_no_match,
-+                                   pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_cert_auth,
-+                                        pam_test_setup, pam_test_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-@@ -950,8 +1447,16 @@ int main(int argc, const char *argv[])
-     test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
-     test_dom_suite_setup(TESTS_PATH);
- 
-+    cleanup_nss_db();
-+    rv = setup_nss_db();
-+    if (rv != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "setup_nss_db failed.\n");
-+        exit(-1);
-+    }
-+
-     rv = cmocka_run_group_tests(tests, NULL, NULL);
-     if (rv == 0 && !no_cleanup) {
-+        cleanup_nss_db();
-         test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
-     }
- 
-unchanged:
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -78,6 +78,7 @@ struct err_string error_to_str[] = {
-     { "Unsupported trust direction" }, /* ERR_TRUST_NOT_SUPPORTED */
-     { "Retrieving keytab failed" }, /* ERR_IPA_GETKEYTAB_FAILED */
-     { "Trusted forest root unknown" }, /* ERR_TRUST_FOREST_UNKNOWN */
-+    { "p11_child failed" }, /* ERR_P11_CHILD */
-     { "ERR_LAST" } /* ERR_LAST */
- };
- 
-only in patch2:
-unchanged:
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -100,6 +100,7 @@ enum sssd_errors {
-     ERR_TRUST_NOT_SUPPORTED,
-     ERR_IPA_GETKEYTAB_FAILED,
-     ERR_TRUST_FOREST_UNKNOWN,
-+    ERR_P11_CHILD,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
diff --git a/SOURCES/0034-UTIL-make-domain-mapping-content-testable.patch b/SOURCES/0034-UTIL-make-domain-mapping-content-testable.patch
new file mode 100644
index 0000000..c3dcc69
--- /dev/null
+++ b/SOURCES/0034-UTIL-make-domain-mapping-content-testable.patch
@@ -0,0 +1,286 @@
+From 9d02728f8d64742e28f32fdf5bfdf083dc15a5c8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 18 Jul 2016 17:37:49 +0200
+Subject: [PATCH 34/44] UTIL: make domain mapping content testable
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/util/domain_info_utils.c | 216 +++++++++++++++++++++++++++----------------
+ src/util/util.h              |   4 +
+ 2 files changed, 138 insertions(+), 82 deletions(-)
+
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 8cdd50d8d521d734e9ffd9b4e81cd6fbd7d158c7..587a6b993d2bd70662df8e0b0d5963fa00c84cf8 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -262,11 +262,135 @@ sss_krb5_touch_config(void)
+     return EOK;
+ }
+ 
++errno_t sss_get_domain_mappings_content(TALLOC_CTX *mem_ctx,
++                                        struct sss_domain_info *domain,
++                                        char **content)
++{
++    int ret;
++    char *o = NULL;
++    struct sss_domain_info *dom;
++    struct sss_domain_info *parent_dom;
++    char *uc_parent = NULL;
++    char *uc_forest = NULL;
++    char *parent_capaths = NULL;
++    bool capaths_started = false;
++
++    if (domain == NULL || content == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Missing parameter.\n");
++        return EINVAL;
++    }
++
++    o = talloc_strdup(mem_ctx, "[domain_realm]\n");
++    if (o == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    /* This loops skips the starting parent and start rigth with the first
++     * subdomain. Although in all the interesting cases (AD and IPA) the
++     * default is that realm and DNS domain are the same strings (expect case)
++     * and no domain_realm mapping is needed we might consider to add this
++     * domain here as well to cover corner cases? */
++    for (dom = get_next_domain(domain, SSS_GND_DESCEND);
++                dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
++                dom = get_next_domain(dom, 0)) {
++        o = talloc_asprintf_append(o, ".%s = %s\n%s = %s\n",
++                               dom->name, dom->realm, dom->name, dom->realm);
++        if (o == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    parent_dom = domain;
++    uc_parent = get_uppercase_realm(mem_ctx, parent_dom->name);
++    if (uc_parent == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    for (dom = get_next_domain(domain, SSS_GND_DESCEND);
++            dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
++            dom = get_next_domain(dom, 0)) {
++
++        if (dom->forest == NULL) {
++            continue;
++        }
++
++        talloc_free(uc_forest);
++        uc_forest = get_uppercase_realm(mem_ctx, dom->forest);
++        if (uc_forest == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        if (!capaths_started) {
++            o = talloc_asprintf_append(o, "[capaths]\n");
++            if (o == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++            capaths_started = true;
++        }
++
++        o = talloc_asprintf_append(o, "%s = {\n  %s = %s\n}\n",
++                                   dom->realm, uc_parent, uc_forest);
++        if (o == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++
++        if (parent_capaths == NULL) {
++            parent_capaths = talloc_asprintf(mem_ctx, "  %s = %s\n", dom->realm,
++                                                                     uc_forest);
++        } else {
++            parent_capaths = talloc_asprintf_append(parent_capaths,
++                                                    "  %s = %s\n", dom->realm,
++                                                    uc_forest);
++        }
++        if (parent_capaths == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "talloc_asprintf/talloc_asprintf_append failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    if (parent_capaths != NULL) {
++        o = talloc_asprintf_append(o, "%s = {\n%s}\n", uc_parent,
++                                                       parent_capaths);
++        if (o == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n");
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(parent_capaths);
++    talloc_free(uc_parent);
++    talloc_free(uc_forest);
++
++    if (ret == EOK) {
++        *content = o;
++    } else {
++        talloc_free(o);
++    }
++
++    return ret;
++}
++
+ errno_t
+ sss_write_domain_mappings(struct sss_domain_info *domain)
+ {
+-    struct sss_domain_info *dom;
+-    struct sss_domain_info *parent_dom;
+     errno_t ret;
+     errno_t err;
+     TALLOC_CTX *tmp_ctx;
+@@ -277,10 +401,7 @@ sss_write_domain_mappings(struct sss_domain_info *domain)
+     mode_t old_mode;
+     FILE *fstream = NULL;
+     int i;
+-    bool capaths_started = false;
+-    char *uc_forest;
+-    char *uc_parent;
+-    char *parent_capaths = NULL;
++    char *content = NULL;
+ 
+     if (domain == NULL || domain->name == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "No domain name provided\n");
+@@ -290,6 +411,12 @@ sss_write_domain_mappings(struct sss_domain_info *domain)
+     tmp_ctx = talloc_new(NULL);
+     if (!tmp_ctx) return ENOMEM;
+ 
++    ret = sss_get_domain_mappings_content(tmp_ctx, domain, &content);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sss_get_domain_mappings_content failed.\n");
++        goto done;
++    }
++
+     sanitized_domain = talloc_strdup(tmp_ctx, domain->name);
+     if (sanitized_domain == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+@@ -349,88 +476,13 @@ sss_write_domain_mappings(struct sss_domain_info *domain)
+         goto done;
+     }
+ 
+-    ret = fprintf(fstream, "[domain_realm]\n");
++    ret = fprintf(fstream, "%s", content);
+     if (ret < 0) {
+         DEBUG(SSSDBG_OP_FAILURE, "fprintf failed\n");
+         ret = EIO;
+         goto done;
+     }
+ 
+-    for (dom = get_next_domain(domain, SSS_GND_DESCEND);
+-         dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
+-         dom = get_next_domain(dom, 0)) {
+-        ret = fprintf(fstream, ".%s = %s\n%s = %s\n",
+-                               dom->name, dom->realm, dom->name, dom->realm);
+-        if (ret < 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n");
+-            goto done;
+-        }
+-    }
+-
+-    parent_dom = domain;
+-    uc_parent = get_uppercase_realm(tmp_ctx, parent_dom->name);
+-    if (uc_parent == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    for (dom = get_next_domain(domain, SSS_GND_DESCEND);
+-            dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
+-            dom = get_next_domain(dom, 0)) {
+-
+-        if (dom->forest == NULL) {
+-            continue;
+-        }
+-
+-        uc_forest = get_uppercase_realm(tmp_ctx, dom->forest);
+-        if (uc_forest == NULL) {
+-            DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n");
+-            ret = ENOMEM;
+-            goto done;
+-        }
+-
+-        if (!capaths_started) {
+-            ret = fprintf(fstream, "[capaths]\n");
+-            if (ret < 0) {
+-                DEBUG(SSSDBG_OP_FAILURE, "fprintf failed\n");
+-                ret = EIO;
+-                goto done;
+-            }
+-            capaths_started = true;
+-        }
+-
+-        ret = fprintf(fstream, "%s = {\n  %s = %s\n}\n",
+-                                dom->realm, uc_parent, uc_forest);
+-        if (ret < 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n");
+-            goto done;
+-        }
+-
+-        if (parent_capaths == NULL) {
+-            parent_capaths = talloc_asprintf(tmp_ctx, "  %s = %s\n", dom->realm,
+-                                                                     uc_forest);
+-        } else {
+-            parent_capaths = talloc_asprintf_append(parent_capaths,
+-                                                    "  %s = %s\n", dom->realm,
+-                                                    uc_forest);
+-        }
+-        if (parent_capaths == NULL) {
+-            DEBUG(SSSDBG_OP_FAILURE,
+-                  "talloc_asprintf/talloc_asprintf_append failed.\n");
+-            ret = ENOMEM;
+-            goto done;
+-        }
+-    }
+-
+-    if (parent_capaths != NULL) {
+-        ret = fprintf(fstream, "%s = {\n%s}\n", uc_parent, parent_capaths);
+-        if (ret < 0) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n");
+-            goto done;
+-        }
+-    }
+-
+     ret = fclose(fstream);
+     fstream = NULL;
+     if (ret != 0) {
+diff --git a/src/util/util.h b/src/util/util.h
+index 8a5caa52c2dc5243c3ae51c5a38fd65a949f4ac4..122be90b967fb7793adaff95f3754d7a199fcf48 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -540,6 +540,10 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
+  * written to */
+ #define KRB5_MAPPING_DIR PUBCONF_PATH"/krb5.include.d"
+ 
++errno_t sss_get_domain_mappings_content(TALLOC_CTX *mem_ctx,
++                                        struct sss_domain_info *domain,
++                                        char **content);
++
+ errno_t sss_write_domain_mappings(struct sss_domain_info *domain);
+ 
+ errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize);
+-- 
+2.4.11
+
diff --git a/SOURCES/0035-pam_sss-add-sc-support.patch b/SOURCES/0035-pam_sss-add-sc-support.patch
deleted file mode 100644
index d5a550d..0000000
--- a/SOURCES/0035-pam_sss-add-sc-support.patch
+++ /dev/null
@@ -1,168 +0,0 @@
-From 98be4f0858e7c38f18b73fda6949edf7790bcad6 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 3 Jul 2015 14:05:11 +0200
-Subject: [PATCH 35/37] pam_sss: add sc support
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/sss_client/pam_message.h |  3 ++
- src/sss_client/pam_sss.c     | 94 +++++++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 96 insertions(+), 1 deletion(-)
-
-diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
-index 3b3841a2c66b46d78855164099684ef2ac98ed77..f0a7a076cf38a4efc8befcc2fb835ae26e9415a4 100644
---- a/src/sss_client/pam_message.h
-+++ b/src/sss_client/pam_message.h
-@@ -56,6 +56,9 @@ struct pam_items {
-     char *otp_token_id;
-     char *otp_challenge;
-     char *first_factor;
-+
-+    char *cert_user;
-+    char *token_name;
- };
- 
- int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer);
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index e4fa83e12c71bb05dd329686cf2d2df6323ff3bd..431f5dc62655dd1e6901f16f72dcad9703f037ac 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -155,6 +155,12 @@ static void overwrite_and_free_pam_items(struct pam_items *pi)
- 
-     free(pi->otp_challenge);
-     pi->otp_challenge = NULL;
-+
-+    free(pi->cert_user);
-+    pi->cert_user = NULL;
-+
-+    free(pi->token_name);
-+    pi->token_name = NULL;
- }
- 
- static int null_strcmp(const char *s1, const char *s2) {
-@@ -922,7 +928,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
-                 break;
-             case SSS_PAM_OTP_INFO:
-                 if (buf[p + (len - 1)] != '\0') {
--                    D(("system info does not end with \\0."));
-+                    D(("otp info does not end with \\0."));
-                     break;
-                 }
- 
-@@ -959,6 +965,33 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
-                 }
- 
-                 break;
-+            case SSS_PAM_CERT_INFO:
-+                if (buf[p + (len - 1)] != '\0') {
-+                    D(("cert info does not end with \\0."));
-+                    break;
-+                }
-+
-+                pi->cert_user = strdup((char *) &buf[p]);
-+                if (pi->cert_user == NULL) {
-+                    D(("strdup failed"));
-+                    break;
-+                }
-+
-+                offset = strlen(pi->cert_user) + 1;
-+                if (offset >= len) {
-+                    D(("Cert message size mismatch"));
-+                    free(pi->cert_user);
-+                    pi->cert_user = NULL;
-+                    break;
-+                }
-+                pi->token_name = strdup((char *) &buf[p + offset]);
-+                if (pi->token_name == NULL) {
-+                    D(("strdup failed"));
-+                    break;
-+                }
-+                D(("cert user: [%s] token name: [%s]", pi->cert_user,
-+                                                       pi->token_name));
-+                break;
-             default:
-                 D(("Unknown response type [%d]", type));
-         }
-@@ -1039,6 +1072,9 @@ static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi)
-     pi->otp_token_id = NULL;
-     pi->otp_challenge = NULL;
- 
-+    pi->cert_user = NULL;
-+    pi->token_name = NULL;
-+
-     return PAM_SUCCESS;
- }
- 
-@@ -1345,6 +1381,60 @@ done:
-     return ret;
- }
- 
-+#define SC_PROMPT_FMT "PIN for %s for user %s"
-+static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
-+{
-+    int ret;
-+    char *answer = NULL;
-+    char *prompt;
-+    size_t size;
-+
-+    if (pi->token_name == NULL || *pi->token_name == '\0'
-+            || pi->cert_user == NULL || *pi->cert_user == '\0') {
-+        return EINVAL;
-+    }
-+
-+    size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name) +
-+           strlen(pi->cert_user);
-+    prompt = malloc(size);
-+    if (prompt == NULL) {
-+        D(("malloc failed."));
-+        return ENOMEM;
-+    }
-+
-+    ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name, pi->cert_user);
-+    if (ret < 0 || ret >= size) {
-+        D(("snprintf failed."));
-+        free(prompt);
-+        return EFAULT;
-+    }
-+
-+    ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
-+    free(prompt);
-+    if (ret != PAM_SUCCESS) {
-+        D(("do_pam_conversation failed."));
-+        return ret;
-+    }
-+
-+    if (answer == NULL) {
-+        pi->pam_authtok = NULL;
-+        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
-+        pi->pam_authtok_size=0;
-+    } else {
-+        pi->pam_authtok = strdup(answer);
-+        _pam_overwrite((void *)answer);
-+        free(answer);
-+        answer=NULL;
-+        if (pi->pam_authtok == NULL) {
-+            return PAM_BUF_ERR;
-+        }
-+        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN;
-+        pi->pam_authtok_size=strlen(pi->pam_authtok);
-+    }
-+
-+    return PAM_SUCCESS;
-+}
-+
- static int prompt_new_password(pam_handle_t *pamh, struct pam_items *pi)
- {
-     int ret;
-@@ -1458,6 +1548,8 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
-                         && pi->otp_challenge != NULL)) {
-             ret = prompt_2fa(pamh, pi, _("First Factor: "),
-                              _("Second Factor: "));
-+        } else if (pi->cert_user != NULL) {
-+            ret = prompt_sc_pin(pamh, pi);
-         } else {
-             ret = prompt_password(pamh, pi, _("Password: "));
-         }
--- 
-2.4.3
-
diff --git a/SOURCES/0035-tests-add-tests-for-sss_get_domain_mappings_content.patch b/SOURCES/0035-tests-add-tests-for-sss_get_domain_mappings_content.patch
new file mode 100644
index 0000000..d2d75a0
--- /dev/null
+++ b/SOURCES/0035-tests-add-tests-for-sss_get_domain_mappings_content.patch
@@ -0,0 +1,201 @@
+From 16495f6aca6fb1a3f0cdb30b4a50493453e8ca0f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 20 Jul 2016 12:03:48 +0200
+Subject: [PATCH 35/44] tests: add tests for sss_get_domain_mappings_content()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/tests/cmocka/test_utils.c | 163 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 163 insertions(+)
+
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index b08b19708bb59a076a79805fa37a15924152b8e2..4c72a59437105e683cec2d39c36951aeff63767b 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -55,6 +55,95 @@ struct dom_list_test_ctx {
+     struct sss_domain_info *dom_list;
+ };
+ 
++static int setup_dom_list_with_subdomains(void **state)
++{
++    struct dom_list_test_ctx *test_ctx;
++    struct sss_domain_info *dom = NULL;
++    struct sss_domain_info *c = NULL;
++
++    assert_true(leak_check_setup());
++
++    test_ctx = talloc_zero(global_talloc_context, struct dom_list_test_ctx);
++    assert_non_null(test_ctx);
++
++    dom = talloc_zero(test_ctx, struct sss_domain_info);
++    assert_non_null(dom);
++
++    dom->name = talloc_asprintf(dom, "configured.dom");
++    assert_non_null(dom->name);
++
++    dom->realm = talloc_asprintf(dom, "CONFIGURED.DOM");
++    assert_non_null(dom->realm);
++
++    dom->flat_name = talloc_asprintf(dom, "CONFIGURED");
++    assert_non_null(dom->flat_name);
++
++    dom->domain_id = talloc_asprintf(dom, "S-1-5-21-1-2-1");
++    assert_non_null(dom->domain_id);
++
++    DLIST_ADD(test_ctx->dom_list, dom);
++
++    c = talloc_zero(test_ctx, struct sss_domain_info);
++    assert_non_null(c);
++
++    c->name = talloc_asprintf(c, "subdom1.dom");
++    assert_non_null(c->name);
++
++    c->realm = talloc_asprintf(c, "SUBDOM1.DOM");
++    assert_non_null(c->realm);
++
++    c->flat_name = talloc_asprintf(c, "subdom1");
++    assert_non_null(c->flat_name);
++
++    c->domain_id = talloc_asprintf(c, "S-1-5-21-1-2-2");
++    assert_non_null(c->domain_id);
++
++    c->parent = dom;
++
++    DLIST_ADD_END(test_ctx->dom_list, c, struct sss_domain_info *);
++
++    c = talloc_zero(test_ctx, struct sss_domain_info);
++    assert_non_null(c);
++
++    c->name = talloc_asprintf(c, "subdom2.dom");
++    assert_non_null(c->name);
++
++    c->realm = talloc_asprintf(c, "SUBDOM2.DOM");
++    assert_non_null(c->realm);
++
++    c->flat_name = talloc_asprintf(c, "subdom2");
++    assert_non_null(c->flat_name);
++
++    c->domain_id = talloc_asprintf(c, "S-1-5-21-1-2-3");
++    assert_non_null(c->domain_id);
++
++    c->parent = dom;
++
++    DLIST_ADD_END(test_ctx->dom_list, c, struct sss_domain_info *);
++
++    c = talloc_zero(test_ctx, struct sss_domain_info);
++    assert_non_null(c);
++
++    c->name = talloc_asprintf(c, "subdom3.dom");
++    assert_non_null(c->name);
++
++    c->realm = talloc_asprintf(c, "SUBDOM3.DOM");
++    assert_non_null(c->realm);
++
++    c->flat_name = talloc_asprintf(c, "subdom3");
++    assert_non_null(c->flat_name);
++
++    c->domain_id = talloc_asprintf(c, "S-1-5-21-1-2-4");
++    assert_non_null(c->domain_id);
++
++    c->parent = dom;
++
++    DLIST_ADD_END(test_ctx->dom_list, c, struct sss_domain_info *);
++
++    check_leaks_push(test_ctx);
++    *state = test_ctx;
++    return 0;
++}
+ 
+ static int setup_dom_list(void **state)
+ {
+@@ -1682,6 +1771,77 @@ static void test_sss_output_name(void **state)
+     assert_true(check_leaks_pop(global_talloc_context) == true);
+ }
+ 
++static void test_sss_get_domain_mappings_content(void **state)
++{
++    struct dom_list_test_ctx *test_ctx;
++    int ret;
++    struct sss_domain_info *dom;
++    char *content;
++    struct sss_domain_info *c;
++
++    ret = sss_get_domain_mappings_content(NULL, NULL, NULL);
++    assert_int_equal(ret, EINVAL);
++
++    test_ctx = talloc_get_type(*state, struct dom_list_test_ctx);
++    assert_non_null(test_ctx);
++
++    dom = get_domains_head(test_ctx->dom_list);
++    assert_non_null(dom);
++
++    /* no forest */
++    ret = sss_get_domain_mappings_content(test_ctx, dom, &content);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(content,
++                        "[domain_realm]\n"
++                        ".subdom1.dom = SUBDOM1.DOM\n"
++                        "subdom1.dom = SUBDOM1.DOM\n"
++                        ".subdom2.dom = SUBDOM2.DOM\n"
++                        "subdom2.dom = SUBDOM2.DOM\n"
++                        ".subdom3.dom = SUBDOM3.DOM\n"
++                        "subdom3.dom = SUBDOM3.DOM\n");
++    talloc_free(content);
++
++    /* IPA with forest */
++    c = find_domain_by_name(dom, "subdom2.dom", true);
++    assert_non_null(c);
++    c->forest_root = find_domain_by_name(dom, "subdom1.dom", true);
++    assert_non_null(c->forest_root);
++    c->forest = "subdom1.dom";
++
++    c = find_domain_by_name(dom, "subdom3.dom", true);
++    assert_non_null(c);
++    c->forest_root = find_domain_by_name(dom, "subdom1.dom", true);
++    assert_non_null(c->forest_root);
++    c->forest = "subdom1.dom";
++
++    ret = sss_get_domain_mappings_content(test_ctx, dom, &content);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(content,
++                        "[domain_realm]\n"
++                        ".subdom1.dom = SUBDOM1.DOM\n"
++                        "subdom1.dom = SUBDOM1.DOM\n"
++                        ".subdom2.dom = SUBDOM2.DOM\n"
++                        "subdom2.dom = SUBDOM2.DOM\n"
++                        ".subdom3.dom = SUBDOM3.DOM\n"
++                        "subdom3.dom = SUBDOM3.DOM\n"
++                        "[capaths]\n"
++                        "SUBDOM2.DOM = {\n"
++                        "  CONFIGURED.DOM = SUBDOM1.DOM\n"
++                        "}\n"
++                        "SUBDOM3.DOM = {\n"
++                        "  CONFIGURED.DOM = SUBDOM1.DOM\n"
++                        "}\n"
++                        "CONFIGURED.DOM = {\n"
++                        "  SUBDOM2.DOM = SUBDOM1.DOM\n"
++                        "  SUBDOM3.DOM = SUBDOM1.DOM\n"
++                        "}\n");
++    talloc_free(content);
++
++    /* Next steps, test AD domain setup. If we join a child domain we have a
++     * similar case as with IPA but if we join the forest root the generate
++     * capaths might not be as expected. */
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -1773,6 +1933,9 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(test_sss_output_name,
+                                         setup_leak_tests,
+                                         teardown_leak_tests),
++        cmocka_unit_test_setup_teardown(test_sss_get_domain_mappings_content,
++                                        setup_dom_list_with_subdomains,
++                                        teardown_dom_list),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.4.11
+
diff --git a/SOURCES/0036-Amend-debug-messages-after-failure-of-unlink.patch b/SOURCES/0036-Amend-debug-messages-after-failure-of-unlink.patch
new file mode 100644
index 0000000..5a2a303
--- /dev/null
+++ b/SOURCES/0036-Amend-debug-messages-after-failure-of-unlink.patch
@@ -0,0 +1,151 @@
+From ce5063550ef45f7abb3ec2ec3cb52a190bb38af5 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 25 Jul 2016 09:11:08 +0200
+Subject: [PATCH 36/44] Amend debug messages after failure of unlink
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some messages did not have errno or name of problematic file.
+There was also improper use of negative value.
+The function strerror was called with -1 instead of errno
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+---
+ src/providers/ipa/ipa_init.c            | 5 +++--
+ src/responder/common/responder_common.c | 3 ++-
+ src/responder/secrets/local.c           | 1 +
+ src/sbus/sssd_dbus_server.c             | 9 +++++----
+ src/tools/files.c                       | 3 ++-
+ src/tools/tools_mc_util.c               | 7 ++++---
+ src/util/util.c                         | 6 ++++--
+ 7 files changed, 21 insertions(+), 13 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
+index 959cdb4a7c40c1be03dd1e7c66dee6e65ca76607..c31e195f48b2f369de1b78b38a0f3522d73d8dce 100644
+--- a/src/providers/ipa/ipa_init.c
++++ b/src/providers/ipa/ipa_init.c
+@@ -440,9 +440,10 @@ static void cleanup_ipa_preauth_indicator(void)
+ 
+     ret = unlink(PAM_PREAUTH_INDICATOR);
+     if (ret != EOK) {
++        ret = errno;
+         DEBUG(SSSDBG_OP_FAILURE,
+-              "Failed to remove preauth indicator file [%s].\n",
+-              PAM_PREAUTH_INDICATOR);
++              "Failed to remove preauth indicator file [%s] %d [%s].\n",
++              PAM_PREAUTH_INDICATOR, ret, sss_strerror(ret));
+     }
+ }
+ 
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index 02a64368cad60990436497865aa0c772a39cde5a..7f6264ae70e5073063b5cfcd73098eefad2ce653 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -629,7 +629,8 @@ int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
+     if (ret != 0 && errno != ENOENT) {
+         ret = errno;
+         DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Cannot remove old socket (errno=%d), bind might fail!\n", ret);
++              "Cannot remove old socket (errno=%d [%s]), bind might fail!\n",
++              ret, sss_strerror(ret));
+     }
+ 
+     if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
+index 2a85ac06945322265fbd1012c9697728c37b77a0..470aec0e195a54dd2af2b929ff1b7a304331a214 100644
+--- a/src/responder/secrets/local.c
++++ b/src/responder/secrets/local.c
+@@ -627,6 +627,7 @@ int generate_master_key(const char *filename, size_t size)
+         ret = unlink(filename);
+         /* non-fatal failure */
+         if (ret != EOK) {
++            ret = errno;
+             DEBUG(SSSDBG_MINOR_FAILURE,
+                   "Failed to remove file: %s - %d [%s]!\n",
+                   filename, ret, sss_strerror(ret));
+diff --git a/src/sbus/sssd_dbus_server.c b/src/sbus/sssd_dbus_server.c
+index 0a1cace415b3514a6904e92a2d879538ce51a593..6cc4172a07118ff99bb6f122c3a1de25cee18c8c 100644
+--- a/src/sbus/sssd_dbus_server.c
++++ b/src/sbus/sssd_dbus_server.c
+@@ -103,8 +103,9 @@ create_socket_symlink(const char *filename, const char *symlink_filename)
+         ret = unlink(symlink_filename);
+         if (ret != 0) {
+             ret = errno;
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot remove old symlink: [%d][%s].\n",
+-                      ret, strerror(ret));
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Cannot remove old symlink '%s': [%d][%s].\n",
++                  symlink_filename, ret, strerror(ret));
+             return EIO;
+         }
+         errno = 0;
+@@ -351,8 +352,8 @@ done:
+         if (tmp_ret != EOK) {
+             tmp_ret = errno;
+             DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Failed to remove symbolic link: %d [%s]!\n",
+-                  tmp_ret, sss_strerror(tmp_ret));
++                  "Failed to remove symbolic link '%s': %d [%s]!\n",
++                  symlink_filename, tmp_ret, sss_strerror(tmp_ret));
+         }
+     }
+     talloc_free(tmp_ctx);
+diff --git a/src/tools/files.c b/src/tools/files.c
+index 5364f5c0dd53aad71452e18b8d7f1f04532132a4..8f1aa68beeb2676b56733f49550de170b404c789 100644
+--- a/src/tools/files.c
++++ b/src/tools/files.c
+@@ -225,7 +225,8 @@ static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx,
+             if (ret != 0) {
+                 ret = errno;
+                 DEBUG(SSSDBG_CRIT_FAILURE,
+-                        "Removing file failed: [%d][%s]\n", ret, strerror(ret));
++                      "Removing file failed '%s': [%d][%s]\n",
++                      result->d_name, ret, strerror(ret));
+                 goto fail;
+             }
+         }
+diff --git a/src/tools/tools_mc_util.c b/src/tools/tools_mc_util.c
+index ce899eb3c674afe8271be526dc83aa909cbecf89..2516a1981ddd965d4cae8c469ed79aaef8fa7193 100644
+--- a/src/tools/tools_mc_util.c
++++ b/src/tools/tools_mc_util.c
+@@ -117,10 +117,11 @@ done:
+         if (ret == EOK) {
+             pret = unlink(mc_filename);
+             if (pret == -1) {
++                pret = errno;
+                 DEBUG(SSSDBG_MINOR_FAILURE,
+-                      "Failed to unlink file %s. "
+-                       "Will be unlinked later by sssd_nss.\n",
+-                       mc_filename);
++                      "Failed to unlink file %s, %d [%s]. "
++                      "Will be unlinked later by sssd_nss.\n",
++                      mc_filename, pret, strerror(pret));
+             }
+         }
+     }
+diff --git a/src/util/util.c b/src/util/util.c
+index 89abfe734873161008dc9a7a42e7a87364f8074a..d4878bfaf4f0e92672756f12137d79ec65ef48f6 100644
+--- a/src/util/util.c
++++ b/src/util/util.c
+@@ -990,13 +990,15 @@ static int unlink_dbg(const char *filename)
+ 
+     ret = unlink(filename);
+     if (ret != 0) {
+-        if (errno == 2) {
++        ret = errno;
++        if (ret == ENOENT) {
+             DEBUG(SSSDBG_TRACE_INTERNAL,
+                   "File already removed: [%s]\n", filename);
+             return 0;
+         } else {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Cannot remove temporary file [%s]\n", filename);
++                  "Cannot remove temporary file [%s] %d [%s]\n",
++                  filename, ret, strerror(ret));
+             return -1;
+         }
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0036-ssh-generate-public-keys-from-certificate.patch b/SOURCES/0036-ssh-generate-public-keys-from-certificate.patch
deleted file mode 100644
index d01d9e7..0000000
--- a/SOURCES/0036-ssh-generate-public-keys-from-certificate.patch
+++ /dev/null
@@ -1,618 +0,0 @@
-From ace8a2f80fe5bb755512e4a7281146ce4fe311a6 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 15 Jul 2015 09:40:00 +0200
-Subject: [PATCH 36/37] ssh: generate public keys from certificate
-
-Resolves: https://fedorahosted.org/sssd/ticket/2711
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                          |   7 +-
- src/confdb/confdb.h                  |   2 +
- src/config/SSSDConfig/__init__.py.in |   1 +
- src/config/etc/sssd.api.conf         |   1 +
- src/man/sssd.conf.5.xml              |  13 ++++
- src/responder/ssh/sshsrv.c           |   9 +++
- src/responder/ssh/sshsrv_cmd.c       |  54 ++++++++++++---
- src/responder/ssh/sshsrv_private.h   |   1 +
- src/tests/cmocka/test_cert_utils.c   |  62 +++++++++++++++++
- src/util/cert.h                      |   4 ++
- src/util/cert/libcrypto/cert.c       |  93 +++++++++++++++++++++++++
- src/util/cert/nss/cert.c             | 130 +++++++++++++++++++++++++++++++++++
- 12 files changed, 364 insertions(+), 13 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index fd78c1bb770b98adee9a6c1ead3b0d6f4345fb9b..5345d90d22cd285a5268ac50a6b527645acdb351 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1129,10 +1129,13 @@ sssd_ssh_SOURCES = \
-     src/responder/ssh/sshsrv.c \
-     src/responder/ssh/sshsrv_dp.c \
-     src/responder/ssh/sshsrv_cmd.c \
--    $(SSSD_RESPONDER_OBJ)
-+    $(SSSD_RESPONDER_OBJ) \
-+    $(NULL)
- sssd_ssh_LDADD = \
-     $(SSSD_LIBS) \
--    $(SSSD_INTERNAL_LTLIBS)
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    libsss_cert.la \
-+    $(NULL)
- endif
- 
- sssd_pac_SOURCES = \
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index c3cdf49e08d10367e9e98c093a4aa2569b985170..df454337ab4d89c5857e73ee0e5392c2b4bba8b4 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -135,6 +135,8 @@
- #define CONFDB_DEFAULT_SSH_HASH_KNOWN_HOSTS true
- #define CONFDB_SSH_KNOWN_HOSTS_TIMEOUT "ssh_known_hosts_timeout"
- #define CONFDB_DEFAULT_SSH_KNOWN_HOSTS_TIMEOUT 180
-+#define CONFDB_SSH_CA_DB "ca_db"
-+#define CONFDB_DEFAULT_SSH_CA_DB SYSCONFDIR"/pki/nssdb"
- 
- /* PAC */
- #define CONFDB_PAC_CONF_ENTRY "config/pac"
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index 4b519eddd04cde83c209f5a1940832cc7f41c736..7d361026c09ce8fd8d6a69f6bb3f3817bc3d68ba 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -99,6 +99,7 @@ option_strings = {
-     # [ssh]
-     'ssh_hash_known_hosts': _('Whether to hash host names and addresses in the known_hosts file'),
-     'ssh_known_hosts_timeout': _('How many seconds to keep a host in the known_hosts file after its host keys were requested'),
-+    'ca_db': _('Path to storage of trusted CA certificates'),
- 
-     # [pac]
-     'allowed_uids': _('List of UIDs or user names allowed to access the PAC responder'),
-diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
-index 29fd896ccd7a3aa5ff81e15b771746a80ffc01af..cf6ce63012176d49f757afbc8a343b24aef869e8 100644
---- a/src/config/etc/sssd.api.conf
-+++ b/src/config/etc/sssd.api.conf
-@@ -72,6 +72,7 @@ autofs_negative_timeout = int, None, false
- # ssh service
- ssh_hash_known_hosts = bool, None, false
- ssh_known_hosts_timeout = int, None, false
-+ca_db = str, None, false
- 
- [pac]
- # PAC responder
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 7d3a57b0eadec48d64cc9ddcb226b89a1600b432..37e73515fbfcae0da492533de72ad3208c870e9b 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -1082,6 +1082,19 @@ pam_account_expired_message = Account expired, please call help desk.
-                         </para>
-                     </listitem>
-                 </varlistentry>
-+                <varlistentry>
-+                    <term>ca_db (string)</term>
-+                    <listitem>
-+                        <para>
-+                            Path to a storage of trusted CA certificates. The
-+                            option is used to validate user certificates before
-+                            deriving public ssh keys from them.
-+                        </para>
-+                        <para>
-+                            Default: /etc/pki/nssdb
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-             </variablelist>
-         </refsect2>
- 
-diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
-index 9439b9d89ae47dc66d392f0c434f4de1c1c0b4ea..d4e202d87f520f1bdcd521733592027773a821d6 100644
---- a/src/responder/ssh/sshsrv.c
-+++ b/src/responder/ssh/sshsrv.c
-@@ -163,6 +163,15 @@ int ssh_process_init(TALLOC_CTX *mem_ctx,
-         goto fail;
-     }
- 
-+    ret = confdb_get_string(ssh_ctx->rctx->cdb, ssh_ctx,
-+                            CONFDB_SSH_CONF_ENTRY, CONFDB_SSH_CA_DB,
-+                            CONFDB_DEFAULT_SSH_CA_DB, &ssh_ctx->ca_db);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Error reading CA DB from confdb (%d) [%s]\n",
-+              ret, strerror(ret));
-+        goto fail;
-+    }
-+
-     ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
-diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
-index 4833587910cade32ecb0b5f65b417d58a498b01e..f630e5f0311dadc69bee59afb672720f7018169d 100644
---- a/src/responder/ssh/sshsrv_cmd.c
-+++ b/src/responder/ssh/sshsrv_cmd.c
-@@ -27,6 +27,7 @@
- #include "util/util.h"
- #include "util/crypto/sss_crypto.h"
- #include "util/sss_ssh.h"
-+#include "util/cert.h"
- #include "db/sysdb.h"
- #include "db/sysdb_ssh.h"
- #include "providers/data_provider.h"
-@@ -219,7 +220,8 @@ static errno_t
- ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
- {
-     errno_t ret;
--    const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, NULL };
-+    const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, SYSDB_USER_CERT,
-+                            NULL };
-     struct ldb_result *res;
- 
-     DEBUG(SSSDBG_TRACE_FUNC,
-@@ -794,6 +796,8 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
- 
- static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx,
-                                           struct ldb_message_element *el,
-+                                          bool cert_data,
-+                                          struct ssh_ctx *ssh_ctx,
-                                           size_t fqname_len,
-                                           const char *fqname,
-                                           size_t *c)
-@@ -819,12 +823,22 @@ static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx,
-     }
- 
-     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;
-+        if (cert_data) {
-+            ret = cert_to_ssh_key(tmp_ctx, ssh_ctx->ca_db,
-+                                  el->values[d].data, el->values[d].length,
-+                                  &key, &key_len);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, "cert_to_ssh_key failed.\n");
-+                return ret;
-+            }
-+        } else  {
-+            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,
-@@ -862,10 +876,13 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
-     struct ldb_message_element *el = NULL;
-     struct ldb_message_element *el_override = NULL;
-     struct ldb_message_element *el_orig = NULL;
-+    struct ldb_message_element *el_user_cert = NULL;
-     uint32_t count = 0;
-     const char *name;
-     char *fqname;
-     uint32_t fqname_len;
-+    struct ssh_ctx *ssh_ctx = talloc_get_type(cctx->rctx->pvt_ctx,
-+                                              struct ssh_ctx);
- 
-     ret = sss_packet_new(cctx->creq, 0,
-                          sss_packet_get_cmd(cctx->creq->in),
-@@ -893,6 +910,12 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
-         }
-     }
- 
-+    el_user_cert = ldb_msg_find_element(cmd_ctx->result, SYSDB_USER_CERT);
-+    if (el_user_cert) {
-+        /* TODO check if cert is valid */
-+        count += el_user_cert->num_values;
-+    }
-+
-     ret = sss_packet_grow(cctx->creq->out, 2*sizeof(uint32_t));
-     if (ret != EOK) {
-         return ret;
-@@ -922,20 +945,29 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
- 
-     fqname_len = strlen(fqname)+1;
- 
--    ret = decode_and_add_base64_data(cmd_ctx, el, fqname_len, fqname, &c);
-+    ret = decode_and_add_base64_data(cmd_ctx, el, false, ssh_ctx,
-+                                     fqname_len, fqname, &c);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
-         return ret;
-     }
- 
--    ret = decode_and_add_base64_data(cmd_ctx, el_orig, fqname_len, fqname, &c);
-+    ret = decode_and_add_base64_data(cmd_ctx, el_orig, false, ssh_ctx,
-+                                     fqname_len, fqname, &c);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
-         return ret;
-     }
- 
--    ret = decode_and_add_base64_data(cmd_ctx, el_override, fqname_len, fqname,
--                                     &c);
-+    ret = decode_and_add_base64_data(cmd_ctx, el_override, false, ssh_ctx,
-+                                     fqname_len, fqname, &c);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
-+        return ret;
-+    }
-+
-+    ret = decode_and_add_base64_data(cmd_ctx, el_user_cert, true, ssh_ctx,
-+                                     fqname_len, fqname, &c);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
-         return ret;
-diff --git a/src/responder/ssh/sshsrv_private.h b/src/responder/ssh/sshsrv_private.h
-index ebb30ce7cbc982bb29b73592d5873e7d3652228a..beb8e18db77d8224e49df141748484ce61b11dac 100644
---- a/src/responder/ssh/sshsrv_private.h
-+++ b/src/responder/ssh/sshsrv_private.h
-@@ -32,6 +32,7 @@ struct ssh_ctx {
- 
-     bool hash_known_hosts;
-     int known_hosts_timeout;
-+    char *ca_db;
- };
- 
- struct ssh_cmd_ctx {
-diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
-index 8063b1a65e8692142cbb3cf82fe41afa6567bc91..7bd8cf2344003421e9ec84dc5e1b2305a861ab38 100644
---- a/src/tests/cmocka/test_cert_utils.c
-+++ b/src/tests/cmocka/test_cert_utils.c
-@@ -21,15 +21,18 @@
-     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 "config.h"
- 
- #include <popt.h>
- #ifdef HAVE_LIBCRYPTO
- #include <openssl/objects.h>
-+#include <openssl/crypto.h>
- #endif
- 
- #include "util/cert.h"
- #include "tests/cmocka/common_mock.h"
- #include "util/crypto/nss/nss_util.h"
-+#include "util/crypto/sss_crypto.h"
- 
- 
- /* TODO: create a certificate for this test */
-@@ -306,6 +309,63 @@ void test_sss_cert_derb64_to_ldap_filter(void **state)
-     talloc_free(filter);
- }
- 
-+
-+#define SSH_TEST_CERT \
-+"MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
-+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \
-+"NjMyMDdaFw0xNzA2MjMxNjMyMDdaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \
-+"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \
-+"ADCCAQoCggEBALXUq56VlY+Z0aWLLpFAjFfbElPBXGQsbZb85J3cGyPjaMHC9wS+" \
-+"wjB6Ve4HmQyPLx8hbINdDmbawMHYQvTScLYfsqLtj0Lqw20sUUmedk+Es5Oh9VHo" \
-+"nd8MavYx25Du2u+T0iSgNIDikXguiwCmtAj8VC49ebbgITcjJGzMmiiuJkV3o93Y" \
-+"vvYF0VjLGDQbQWOy7IxzYJeNVJnZWKo67CHdok6qOrm9rxQt81rzwV/mGLbCMUbr" \
-+"+N4M8URtd7EmzaYZQmNm//s2owFrCYMxpLiURPj+URZVuB72504/Ix7X0HCbA/AV" \
-+"26J27fPY5nc8DMwfhUDCbTqPH/JEjd3mvY8CAwEAAaOCASYwggEiMB8GA1UdIwQY" \
-+"MBaAFJOq+KAQmPEnNp8Wok23eGTdE7aDMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \
-+"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \
-+"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \
-+"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \
-+"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \
-+"IEF1dGhvcml0eTAdBgNVHQ4EFgQUFaDNd5a53QGpaw5m63hnwXicMQ8wDQYJKoZI" \
-+"hvcNAQELBQADggEBADH7Nj00qqGhGJeXJQAsepqSskz/wooqXh8vgVyb8SS4N0/c" \
-+"0aQtVmY81xamlXE12ZFpwDX43d+EufBkwCUKFX/+8JFDd2doAyeJxv1xM22kKRpc" \
-+"AqITPgMsa9ToGMWxjbVpc/X/5YfZixWPF0/eZUTotBj9oaR039UrhGfyN7OguF/G" \
-+"rzmxtB5y4ZrMpcD/Oe90mkd9HY7sA/fB8OWOUgeRfQoh97HNS0UiDWsPtfxmjQG5" \
-+"zotpoBIZmdH+ipYsu58HohHVlM9Wi5H4QmiiXl+Soldkq7eXYlafcmT7wv8+cKwz" \
-+"Nz0Tm3+eYpFqRo3skr6QzXi525Jkg3r6r+kkhxU="
-+
-+#define SSH_PUB_KEY "AAAAB3NzaC1yc2EAAAADAQABAAABAQC11KuelZWPmdGliy6RQIxX2xJTwVxkLG2W/OSd3Bsj42jBwvcEvsIwelXuB5kMjy8fIWyDXQ5m2sDB2EL00nC2H7Ki7Y9C6sNtLFFJnnZPhLOTofVR6J3fDGr2MduQ7trvk9IkoDSA4pF4LosAprQI/FQuPXm24CE3IyRszJooriZFd6Pd2L72BdFYyxg0G0FjsuyMc2CXjVSZ2ViqOuwh3aJOqjq5va8ULfNa88Ff5hi2wjFG6/jeDPFEbXexJs2mGUJjZv/7NqMBawmDMaS4lET4/lEWVbge9udOPyMe19BwmwPwFduidu3z2OZ3PAzMH4VAwm06jx/yRI3d5r2P"
-+
-+void test_cert_to_ssh_key(void **state)
-+{
-+    int ret;
-+    uint8_t *key;
-+    size_t key_size;
-+    uint8_t *exp_key;
-+    size_t exp_key_size;
-+    uint8_t *der;
-+    size_t der_size;
-+
-+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
-+    assert_non_null(ts);
-+
-+    der = sss_base64_decode(ts, SSH_TEST_CERT, &der_size);
-+    assert_non_null(der);
-+
-+    exp_key = sss_base64_decode(ts, SSH_PUB_KEY, &exp_key_size);
-+    assert_non_null(exp_key);
-+
-+    ret = cert_to_ssh_key(ts, "sql:" ABS_SRC_DIR "/src/tests/cmocka/p11_nssdb",
-+                          der, der_size, &key, &key_size);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(key_size, exp_key_size);
-+    assert_memory_equal(key, exp_key, exp_key_size);
-+
-+    talloc_free(der);
-+    talloc_free(key);
-+    talloc_free(exp_key);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -330,6 +390,8 @@ int main(int argc, const char *argv[])
-                                         setup, teardown),
-         cmocka_unit_test_setup_teardown(test_sss_cert_derb64_to_ldap_filter,
-                                         setup, teardown),
-+        cmocka_unit_test_setup_teardown(test_cert_to_ssh_key,
-+                                        setup, teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-diff --git a/src/util/cert.h b/src/util/cert.h
-index 79ea1a4ab58149a312bece265798ab3a3f459114..edbafc492a1ed42ad616d0bf2fae882046711746 100644
---- a/src/util/cert.h
-+++ b/src/util/cert.h
-@@ -44,4 +44,8 @@ errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64,
- errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx,
-                                  const uint8_t *blob, size_t blob_size,
-                                  char **_str);
-+
-+errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db,
-+                        const uint8_t *der_blob, size_t der_size,
-+                        uint8_t **key, size_t *key_size);
- #endif /* __CERT_H__ */
-diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c
-index 1a250f60d1a7dfd5c883ec7e9b1f9491fb74c9b0..01f9554b990d6a139bb9a1d8d558c1c3f6bb745c 100644
---- a/src/util/cert/libcrypto/cert.c
-+++ b/src/util/cert/libcrypto/cert.c
-@@ -166,3 +166,96 @@ done:
-     return ret;
- 
- }
-+
-+#define SSH_RSA_HEADER "ssh-rsa"
-+#define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
-+
-+errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db,
-+                        const uint8_t *der_blob, size_t der_size,
-+                        uint8_t **key, size_t *key_size)
-+{
-+    int ret;
-+    size_t size;
-+    const unsigned char *d;
-+    uint8_t *buf = NULL;
-+    size_t c;
-+    X509 *cert = NULL;
-+    EVP_PKEY *cert_pub_key = NULL;
-+    int modulus_len;
-+    unsigned char modulus[OPENSSL_RSA_MAX_MODULUS_BITS/8];
-+    int exponent_len;
-+    unsigned char exponent[OPENSSL_RSA_MAX_PUBEXP_BITS/8];
-+
-+    if (der_blob == NULL || der_size == 0) {
-+        return EINVAL;
-+    }
-+
-+    d = (const unsigned char *) der_blob;
-+
-+    cert = d2i_X509(NULL, &d, (int) der_size);
-+    if (cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "d2i_X509 failed.\n");
-+        return EINVAL;
-+    }
-+
-+    /* TODO: verify certificate !!!!! */
-+
-+    cert_pub_key = X509_get_pubkey(cert);
-+    if (cert_pub_key == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "X509_get_pubkey failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    if (cert_pub_key->type != EVP_PKEY_RSA) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Expected RSA public key, found unsupported [%d].\n",
-+              cert_pub_key->type);
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    modulus_len = BN_bn2bin(cert_pub_key->pkey.rsa->n, modulus);
-+    exponent_len = BN_bn2bin(cert_pub_key->pkey.rsa->e, exponent);
-+
-+    size = SSH_RSA_HEADER_LEN + 3 * sizeof(uint32_t)
-+                + modulus_len
-+                + exponent_len
-+                + 1; /* see comment about missing 00 below */
-+
-+    buf = talloc_size(mem_ctx, size);
-+    if (buf == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    c = 0;
-+
-+    SAFEALIGN_SET_UINT32(buf, htobe32(SSH_RSA_HEADER_LEN), &c);
-+    safealign_memcpy(&buf[c], SSH_RSA_HEADER, SSH_RSA_HEADER_LEN, &c);
-+    SAFEALIGN_SET_UINT32(&buf[c], htobe32(exponent_len), &c);
-+    safealign_memcpy(&buf[c], exponent, exponent_len, &c);
-+
-+    /* Adding missing 00 which afaik is added to make sure
-+     * the bigint is handled as positive number */
-+    /* TODO: make a better check if 00 must be added or not, e.g. ... & 0x80)
-+     */
-+    SAFEALIGN_SET_UINT32(&buf[c], htobe32(modulus_len + 1), &c);
-+    SAFEALIGN_SETMEM_VALUE(&buf[c], '\0', unsigned char, &c);
-+    safealign_memcpy(&buf[c], modulus, modulus_len, &c);
-+
-+    *key = buf;
-+    *key_size = size;
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK)  {
-+        talloc_free(buf);
-+    }
-+    EVP_PKEY_free(cert_pub_key);
-+    X509_free(cert);
-+
-+    return ret;
-+}
-diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c
-index a20abf63a10de9a5e9810f1c7d56686d063d60c7..1ada35b6321b9e0f3daf87b3412cf7a124cbf2c7 100644
---- a/src/util/cert/nss/cert.c
-+++ b/src/util/cert/nss/cert.c
-@@ -20,9 +20,13 @@
- 
- #include "util/util.h"
- 
-+#include <nss.h>
- #include <cert.h>
- #include <base64.h>
-+#include <key.h>
-+#include <prerror.h>
- 
-+#include "util/crypto/sss_crypto.h"
- #include "util/crypto/nss/nss_util.h"
- 
- #define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
-@@ -210,3 +214,129 @@ done:
- 
-     return ret;
- }
-+
-+#define SSH_RSA_HEADER "ssh-rsa"
-+#define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
-+
-+errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db,
-+                        const uint8_t *der_blob, size_t der_size,
-+                        uint8_t **key, size_t *key_size)
-+{
-+    CERTCertDBHandle *handle;
-+    CERTCertificate *cert = NULL;
-+    SECItem der_item;
-+    SECKEYPublicKey *cert_pub_key = NULL;
-+    int ret;
-+    size_t size;
-+    uint8_t *buf = NULL;
-+    size_t c;
-+    NSSInitContext *nss_ctx;
-+    NSSInitParameters parameters = { 0 };
-+    parameters.length =  sizeof (parameters);
-+    SECStatus rv;
-+
-+    if (der_blob == NULL || der_size == 0) {
-+        return EINVAL;
-+    }
-+
-+    /* initialize NSS with context, we might have already called
-+     * NSS_NoDB_Init() but for validation we need to have access to a DB with
-+     * the trusted issuer cert. Only NSS_InitContext will really open the DB
-+     * in this case. I'm not sure about how long validation might need e.g. if
-+     * CRLs or OSCP is enabled, maybe it would be better to run validation in
-+     * p11_child ? */
-+    nss_ctx = NSS_InitContext(ca_db, "", "", SECMOD_DB, &parameters,
-+                              NSS_INIT_READONLY);
-+    if (nss_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n",
-+                                 PR_GetError());
-+        return EIO;
-+    }
-+
-+    handle = CERT_GetDefaultCertDB();
-+
-+    der_item.len = der_size;
-+    der_item.data = discard_const(der_blob);
-+
-+    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
-+    if (cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    rv = CERT_VerifyCertificateNow(handle, cert, PR_TRUE,
-+                                   certificateUsageSSLClient, NULL, NULL);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "CERT_VerifyCertificateNow failed [%d].\n",
-+                                   PR_GetError());
-+        ret = EACCES;
-+        goto done;
-+    }
-+
-+    cert_pub_key = CERT_ExtractPublicKey(cert);
-+    if (cert_pub_key == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_ExtractPublicKey failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    if (cert_pub_key->keyType != rsaKey) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Expected RSA public key, found unsupported [%d].\n",
-+              cert_pub_key->keyType);
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    size = SSH_RSA_HEADER_LEN + 3 * sizeof(uint32_t)
-+                + cert_pub_key->u.rsa.modulus.len
-+                + cert_pub_key->u.rsa.publicExponent.len
-+                + 1; /* see comment about missing 00 below */
-+
-+    buf = talloc_size(mem_ctx, size);
-+    if (buf == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    c = 0;
-+
-+    SAFEALIGN_SET_UINT32(buf, htobe32(SSH_RSA_HEADER_LEN), &c);
-+    safealign_memcpy(&buf[c], SSH_RSA_HEADER, SSH_RSA_HEADER_LEN, &c);
-+    SAFEALIGN_SET_UINT32(&buf[c],
-+                         htobe32(cert_pub_key->u.rsa.publicExponent.len), &c);
-+    safealign_memcpy(&buf[c], cert_pub_key->u.rsa.publicExponent.data,
-+                     cert_pub_key->u.rsa.publicExponent.len, &c);
-+
-+    /* Looks like nss drops the leading 00 which afaik is added to make sure
-+     * the bigint is handled as positive number */
-+    /* TODO: make a better check if 00 must be added or not, e.g. ... & 0x80)
-+     */
-+    SAFEALIGN_SET_UINT32(&buf[c],
-+                         htobe32(cert_pub_key->u.rsa.modulus.len + 1 ), &c);
-+    SAFEALIGN_SETMEM_VALUE(&buf[c], '\0', unsigned char, &c);
-+    safealign_memcpy(&buf[c], cert_pub_key->u.rsa.modulus.data,
-+                     cert_pub_key->u.rsa.modulus.len, &c);
-+
-+    *key = buf;
-+    *key_size = size;
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK)  {
-+        talloc_free(buf);
-+    }
-+    SECKEY_DestroyPublicKey(cert_pub_key);
-+    CERT_DestroyCertificate(cert);
-+
-+    rv = NSS_ShutdownContext(nss_ctx);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n",
-+                                 PR_GetError());
-+    }
-+
-+    return ret;
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0037-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch b/SOURCES/0037-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch
deleted file mode 100644
index 222e9e3..0000000
--- a/SOURCES/0037-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From e10bcf99c6105b733b043a50ea96223a46784581 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 21 Jul 2015 11:44:03 +0200
-Subject: [PATCH 37/37] IPA: Remove MPG groups if getgrgid was called before
- getpw()
-
-https://fedorahosted.org/sssd/ticket/2724
-
-This bug only affects IPA clients that are connected to IPA servers with
-AD trust and ID mapping in effect.
-
-If an IPA client calls getgrgid() for an ID that matches a user, the
-user's private group would be returned and stored as a group entry.
-
-Subsequent queries for that user would fail, because MPG domains impose
-uniqueness restriction for both the ID and name space across groups and
-users.
-
-To work around that, we remove the UPG groups in MPG domains during a
-group lookup.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/providers/ipa/ipa_s2n_exop.c | 41 ++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 39 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index 812a4bbd707faf5c184594b562c148d1e704fd58..1e6368dc7ef1a6f60b541409f7f6740d602f0d43 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -1764,6 +1764,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-     int tret;
-     struct sysdb_attrs *gid_override_attrs = NULL;
-     char ** exop_grouplist;
-+    struct ldb_message *msg;
- 
-     tmp_ctx = talloc_new(NULL);
-     if (tmp_ctx == NULL) {
-@@ -2005,8 +2006,44 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-                                    attrs->a.user.pw_dir, attrs->a.user.pw_shell,
-                                    NULL, attrs->sysdb_attrs, NULL,
-                                    timeout, now);
--            if (ret != EOK) {
--                DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_user failed.\n");
-+            if (ret == EEXIST && dom->mpg == true) {
-+                /* This handles the case where getgrgid() was called for
-+                 * this user, so a group was created in the cache
-+                 */
-+                ret = sysdb_search_group_by_name(tmp_ctx, dom, name, NULL, &msg);
-+                if (ret != EOK) {
-+                    /* Fail even on ENOENT, the group must be around */
-+                    DEBUG(SSSDBG_OP_FAILURE,
-+                          "Could not delete MPG group [%d]: %s\n",
-+                          ret, sss_strerror(ret));
-+                    goto done;
-+                }
-+
-+                ret = sysdb_delete_group(dom, NULL, attrs->a.user.pw_uid);
-+                if (ret != EOK) {
-+                    DEBUG(SSSDBG_OP_FAILURE,
-+                          "sysdb_delete_group failed for MPG group [%d]: %s\n",
-+                          ret, sss_strerror(ret));
-+                    goto done;
-+                }
-+
-+                ret = sysdb_store_user(dom, name, NULL,
-+                                       attrs->a.user.pw_uid,
-+                                       gid, attrs->a.user.pw_gecos,
-+                                       attrs->a.user.pw_dir,
-+                                       attrs->a.user.pw_shell,
-+                                       NULL, attrs->sysdb_attrs, NULL,
-+                                       timeout, now);
-+                if (ret != EOK) {
-+                    DEBUG(SSSDBG_OP_FAILURE,
-+                          "sysdb_store_user failed for MPG user [%d]: %s\n",
-+                          ret, sss_strerror(ret));
-+                    goto done;
-+                }
-+            } else if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "sysdb_store_user failed [%d]: %s\n",
-+                      ret, sss_strerror(ret));
-                 goto done;
-             }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch b/SOURCES/0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch
new file mode 100644
index 0000000..ca36fa7
--- /dev/null
+++ b/SOURCES/0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch
@@ -0,0 +1,40 @@
+From af7accb9071ca5f73632e2b47c13f2ce7d26995e Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 25 Jul 2016 08:31:17 +0200
+Subject: [PATCH 37/44] SYSDB: Do not try to modify ts cache for unsupported
+ DNs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Only users and groups have timestamp data in separate cache.
+It caused false positive warnings for autofs, netgroup ...
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+---
+ src/db/sysdb_ops.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 4755ea3427b99a51d73b7b9134e357cf2b987613..19d6be03ede1bcec3bc7a4ed777e326460d80591 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -1198,9 +1198,14 @@ int sysdb_set_entry_attr(struct sysdb_ctx *sysdb,
+     sysdb_write = sysdb_entry_attrs_diff(sysdb, entry_dn, attrs, mod_op);
+     if (sysdb_write == true) {
+         ret = sysdb_set_cache_entry_attr(sysdb->ldb, entry_dn, attrs, mod_op);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Cannot set attrs for %s, %d [%s]\n",
++                  ldb_dn_get_linearized(entry_dn), ret, sss_strerror(ret));
++        }
+     }
+ 
+-    if (ret == EOK) {
++    if (ret == EOK && is_ts_ldb_dn(entry_dn)) {
+         tret = sysdb_set_ts_entry_attr(sysdb, entry_dn, attrs, mod_op);
+         if (tret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+-- 
+2.4.11
+
diff --git a/SOURCES/0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch b/SOURCES/0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch
new file mode 100644
index 0000000..d92dc85
--- /dev/null
+++ b/SOURCES/0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch
@@ -0,0 +1,96 @@
+From 83f4fbf2cb3f9318aedfa03e526671e3c444c40b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 12 Jul 2016 13:16:43 +0200
+Subject: [PATCH 38/44] AD: avoid memory leak in netlogon_get_domain_info() and
+ make it public
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ad/ad_common.h      |  6 ++++++
+ src/providers/ad/ad_domain_info.c | 29 ++++++++++++++++++++---------
+ 2 files changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index ce363c5a4122aa5e48ca83b0b2bdf63ff4372d91..f4a90e4f0a3fe5910071d5fe690d0a356e2a0bd1 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -185,4 +185,10 @@ errno_t ad_autofs_init(TALLOC_CTX *mem_ctx,
+ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
+                                                  struct ad_options *ad_opts);
+ 
++errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
++                                 struct sysdb_attrs *reply,
++                                 char **_flat_name,
++                                 char **_site,
++                                 char **_forest);
++
+ #endif /* AD_COMMON_H_ */
+diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c
+index 5f17ae5427b1206af3ad03dccce9452aefc2e6e2..a06379c263878aa95741055636d0a12764f3ad8c 100644
+--- a/src/providers/ad/ad_domain_info.c
++++ b/src/providers/ad/ad_domain_info.c
+@@ -35,12 +35,11 @@
+ #include "providers/ad/ad_common.h"
+ #include "util/util.h"
+ 
+-static errno_t
+-netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+-                         struct sysdb_attrs *reply,
+-                         char **_flat_name,
+-                         char **_site,
+-                         char **_forest)
++errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
++                                 struct sysdb_attrs *reply,
++                                 char **_flat_name,
++                                 char **_site,
++                                 char **_forest)
+ {
+     errno_t ret;
+     struct ldb_message_element *el;
+@@ -51,6 +50,7 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+     const char *flat_name;
+     const char *site;
+     const char *forest;
++    TALLOC_CTX *tmp_ctx;
+ 
+     ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el);
+     if (ret != EOK) {
+@@ -66,13 +66,24 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+         return EIO;
+     }
+ 
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
+     blob.data = el->values[0].data;
+     blob.length = el->values[0].length;
+ 
+-    ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
++    /* The ndr_pull_* calls do not use ndr_pull as a talloc context to
++     * allocate memory but the second argument of ndr_pull_init_blob(). To
++     * make sure no memory is leaked here a temporary talloc context is
++     * needed. */
++    ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx);
+     if (ndr_pull == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
+-        return ENOMEM;
++        ret = ENOMEM;
++        goto done;
+     }
+ 
+     ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
+@@ -146,7 +157,7 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+ 
+     ret = EOK;
+ done:
+-    talloc_free(ndr_pull);
++    talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0038-mmap_cache-Rename-variables.patch b/SOURCES/0038-mmap_cache-Rename-variables.patch
deleted file mode 100644
index 3b5f30a..0000000
--- a/SOURCES/0038-mmap_cache-Rename-variables.patch
+++ /dev/null
@@ -1,122 +0,0 @@
-From fca34746951f740c544e62a5b60929c41a198fd1 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Thu, 16 Jul 2015 16:54:00 +0200
-Subject: [PATCH 38/47] mmap_cache: Rename variables
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit 39b31427e2d11ca318df11fd48db33a7cc610aa7)
----
- src/responder/nss/nsssrv_mmap_cache.c | 16 ++++++++--------
- src/responder/nss/nsssrv_mmap_cache.h |  4 ++--
- src/sss_client/nss_mc_initgr.c        | 10 +++++-----
- src/util/mmap_cache.h                 |  2 +-
- 4 files changed, 16 insertions(+), 16 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
-index ebda8ac6fab3dd87f5a1d8e43717bf7a5b5a9878..16bc926f3ba4f5ab096bd0fb43895edef2b57c50 100644
---- a/src/responder/nss/nsssrv_mmap_cache.c
-+++ b/src/responder/nss/nsssrv_mmap_cache.c
-@@ -959,8 +959,8 @@ done:
- 
- errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-                                     struct sized_string *name,
--                                    uint32_t memnum,
--                                    uint8_t *membuf)
-+                                    uint32_t num_groups,
-+                                    uint8_t *gids_buf)
- {
-     struct sss_mc_ctx *mcc = *_mcc;
-     struct sss_mc_rec *rec;
-@@ -974,8 +974,8 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-         return EINVAL;
-     }
- 
--    /* memnum + reserved + array of members + name*/
--    data_len = (2 + memnum) * sizeof(uint32_t) + name->len;
-+    /* num_groups + reserved + array of gids + name*/
-+    data_len = (2 + num_groups) * sizeof(uint32_t) + name->len;
-     rec_len = sizeof(struct sss_mc_rec) + sizeof(struct sss_mc_initgr_data)
-               + data_len;
-     if (rec_len > mcc->dt_size) {
-@@ -998,10 +998,10 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-                             name->str, name->len, name->str, name->len);
- 
-     /* initgroups struct */
--    data->members = memnum;
--    memcpy(data->gids, membuf, memnum * sizeof(uint32_t));
--    memcpy(&data->gids[memnum], name->str, name->len);
--    data->name = MC_PTR_DIFF(&data->gids[memnum], data);
-+    data->num_groups = num_groups;
-+    memcpy(data->gids, gids_buf, num_groups * sizeof(uint32_t));
-+    memcpy(&data->gids[num_groups], name->str, name->len);
-+    data->name = MC_PTR_DIFF(&data->gids[num_groups], data);
- 
-     MC_LOWER_BARRIER(rec);
- 
-diff --git a/src/responder/nss/nsssrv_mmap_cache.h b/src/responder/nss/nsssrv_mmap_cache.h
-index 3a6764dd36bf3346d789bb287b3a94df120f36ee..b09e4a6f8efa364ae7a6407bab9d8a2a2143c812 100644
---- a/src/responder/nss/nsssrv_mmap_cache.h
-+++ b/src/responder/nss/nsssrv_mmap_cache.h
-@@ -53,8 +53,8 @@ errno_t sss_mmap_cache_gr_store(struct sss_mc_ctx **_mcc,
- 
- errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-                                     struct sized_string *name,
--                                    uint32_t memnum,
--                                    uint8_t *membuf);
-+                                    uint32_t num_groups,
-+                                    uint8_t *gids_buf);
- 
- errno_t sss_mmap_cache_pw_invalidate(struct sss_mc_ctx *mcc,
-                                      struct sized_string *name);
-diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c
-index bfb09d6550c310fbab254dc9b3ab7b306b7d3f06..e21b9f40aba00f9cc2385a561fc2bcc163c5791a 100644
---- a/src/sss_client/nss_mc_initgr.c
-+++ b/src/sss_client/nss_mc_initgr.c
-@@ -42,7 +42,7 @@ static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
-     struct sss_mc_initgr_data *data;
-     time_t expire;
-     long int i;
--    uint32_t gid_count;
-+    uint32_t num_groups;
-     long int max_ret;
- 
-     /* additional checks before filling result*/
-@@ -53,15 +53,15 @@ static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
-     }
- 
-     data = (struct sss_mc_initgr_data *)rec->data;
--    gid_count = data->members;
--    max_ret = gid_count;
-+    num_groups = data->num_groups;
-+    max_ret = num_groups;
- 
-     /* check we have enough space in the buffer */
--    if ((*size - *start) < gid_count) {
-+    if ((*size - *start) < num_groups) {
-         long int newsize;
-         gid_t *newgroups;
- 
--        newsize = *size + gid_count;
-+        newsize = *size + num_groups;
-         if ((limit > 0) && (newsize > limit)) {
-             newsize = limit;
-             max_ret = newsize - *start;
-diff --git a/src/util/mmap_cache.h b/src/util/mmap_cache.h
-index 438e28a3d217041278fc1bb60aa553d098516035..a8703d5da4022e11c4bc2f3e2f8710e7f9d982bf 100644
---- a/src/util/mmap_cache.h
-+++ b/src/util/mmap_cache.h
-@@ -139,7 +139,7 @@ struct sss_mc_grp_data {
- 
- struct sss_mc_initgr_data {
-     rel_ptr_t name;         /* ptr to name string, rel. to struct base addr */
--    uint32_t members;       /* number of members in groups */
-+    uint32_t num_groups;    /* number of groups */
-     uint32_t gids[0];       /* array of all groups
-                              * string with name is stored after gids */
- };
--- 
-2.4.3
-
diff --git a/SOURCES/0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch b/SOURCES/0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch
new file mode 100644
index 0000000..f81ee20
--- /dev/null
+++ b/SOURCES/0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch
@@ -0,0 +1,217 @@
+From df00f0d33874381fc36ee59eaf28a4918ae5dc56 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 12 Jul 2016 13:29:33 +0200
+Subject: [PATCH 39/44] AD: netlogon_get_domain_info() allow missing arguments
+ and empty results
+
+netlogon_get_domain_info() should not fail if not all parameters can be
+retrieved. It should be the responsibility of the caller to see if the
+needed data is available and act accordingly.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3104
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ad/ad_common.h      |   1 +
+ src/providers/ad/ad_domain_info.c | 108 +++++++++++++++++++++-----------------
+ src/providers/ad/ad_gpo.c         |   2 +-
+ src/providers/ad/ad_subdomains.c  |   3 +-
+ 4 files changed, 64 insertions(+), 50 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index f4a90e4f0a3fe5910071d5fe690d0a356e2a0bd1..7e86faf1142d7be49eef01e1ddd7bfafea2fcedc 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -187,6 +187,7 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
+ 
+ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+                                  struct sysdb_attrs *reply,
++                                 bool check_next_nearest_site_as_well,
+                                  char **_flat_name,
+                                  char **_site,
+                                  char **_forest);
+diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c
+index a06379c263878aa95741055636d0a12764f3ad8c..5302c8083bd832d0772829d9f3a4b8e9537d34b9 100644
+--- a/src/providers/ad/ad_domain_info.c
++++ b/src/providers/ad/ad_domain_info.c
+@@ -37,6 +37,7 @@
+ 
+ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+                                  struct sysdb_attrs *reply,
++                                 bool check_next_nearest_site_as_well,
+                                  char **_flat_name,
+                                  char **_site,
+                                  char **_forest)
+@@ -47,9 +48,6 @@ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+     struct ndr_pull *ndr_pull = NULL;
+     enum ndr_err_code ndr_err;
+     struct netlogon_samlogon_response response;
+-    const char *flat_name;
+-    const char *site;
+-    const char *forest;
+     TALLOC_CTX *tmp_ctx;
+ 
+     ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el);
+@@ -102,57 +100,73 @@ errno_t netlogon_get_domain_info(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 domain name data available\n");
+-        ret = ENOENT;
+-        goto done;
++    /* get flat domain name */
++    if (_flat_name != NULL) {
++        if (response.data.nt5_ex.domain_name != NULL &&
++            *response.data.nt5_ex.domain_name != '\0') {
++            *_flat_name = talloc_strdup(mem_ctx,
++                                        response.data.nt5_ex.domain_name);
++            if (*_flat_name == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++        } else {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "No netlogon flat domain name data available.\n");
++            *_flat_name = NULL;
++        }
+     }
+ 
+-    *_flat_name = talloc_strdup(mem_ctx, flat_name);
+-    if (*_flat_name == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+-        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;
++    if (_forest != NULL) {
++        if (response.data.nt5_ex.forest != NULL &&
++            *response.data.nt5_ex.forest != '\0') {
++            *_forest = talloc_strdup(mem_ctx, response.data.nt5_ex.forest);
++            if (*_forest == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++        } else {
++            DEBUG(SSSDBG_MINOR_FAILURE, "No netlogon forest data available.\n");
++            *_forest = NULL;
++        }
+     }
+ 
+     /* get site name */
+-    if (response.data.nt5_ex.client_site != NULL
+-        && response.data.nt5_ex.client_site[0] != '\0') {
+-        site = response.data.nt5_ex.client_site;
+-    } else {
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "No netlogon site name data available\n");
+-        ret = ENOENT;
+-        goto done;
+-    }
++    if (_site != NULL) {
++        if (response.data.nt5_ex.client_site != NULL
++            && response.data.nt5_ex.client_site[0] != '\0') {
++            *_site = talloc_strdup(mem_ctx, response.data.nt5_ex.client_site);
++            if (*_site == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
++        } else {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "No netlogon site name data available.\n");
++            *_site = NULL;
+ 
+-    *_site = talloc_strdup(mem_ctx, site);
+-    if (*_site == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+-        ret = ENOMEM;
+-        goto done;
++            if (check_next_nearest_site_as_well) {
++                if (response.data.nt5_ex.next_closest_site != NULL
++                        && response.data.nt5_ex.next_closest_site[0] != '\0') {
++                    *_site = talloc_strdup(mem_ctx,
++                                        response.data.nt5_ex.next_closest_site);
++                    if (*_site == NULL) {
++                        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                        ret = ENOMEM;
++                        goto done;
++                    }
++                } else {
++                    DEBUG(SSSDBG_MINOR_FAILURE,
++                          "No netlogon next closest site name data "
++                          "available.\n");
++                }
++            }
++        }
+     }
+ 
+     ret = EOK;
+@@ -388,7 +402,7 @@ ad_master_domain_netlogon_done(struct tevent_req *subreq)
+ 
+     /* Exactly one flat name. Carry on */
+ 
+-    ret = netlogon_get_domain_info(state, reply[0], &state->flat,
++    ret = netlogon_get_domain_info(state, reply[0], false, &state->flat,
+                                    &state->site, &state->forest);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 3e54fd8b5932a97779e178c7d3c5b9f6d3b3277c..f609d28136918adfe6a8d5e95319b27ffcab79c0 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -2801,7 +2801,7 @@ ad_gpo_site_name_retrieval_done(struct tevent_req *subreq)
+     ret = ad_master_domain_recv(subreq, state, NULL, NULL, &site, NULL);
+     talloc_zfree(subreq);
+ 
+-    if (ret != EOK) {
++    if (ret != EOK || site == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
+         tevent_req_error(req, ENOENT);
+         return;
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 928c4fe93cc6afa5c3f69c14503896db820a4c0a..e9da04e384e598927f9c8c203a751bcccd29e895 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -1108,14 +1108,13 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+     char *master_sid;
+     char *flat_name;
+     char *forest;
+-    char *site;
+     errno_t ret;
+ 
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+ 
+     ret = ad_master_domain_recv(subreq, state, &flat_name, &master_sid,
+-                                &site, &forest);
++                                NULL, &forest);
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain information "
+-- 
+2.4.11
+
diff --git a/SOURCES/0039-mmap_cache-Override-functions-for-initgr-mmap-cache.patch b/SOURCES/0039-mmap_cache-Override-functions-for-initgr-mmap-cache.patch
deleted file mode 100644
index 209ff16..0000000
--- a/SOURCES/0039-mmap_cache-Override-functions-for-initgr-mmap-cache.patch
+++ /dev/null
@@ -1,146 +0,0 @@
-From 8ca168c6f459d77cdf8f46d27a392d0847343703 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Thu, 16 Jul 2015 17:00:12 +0200
-Subject: [PATCH 39/47] mmap_cache: "Override" functions for initgr mmap cache
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Functions sss_mc_get_strs_offset and sss_mc_get_strs_len provides
-data about strings for individual memory caches (passwd, ...)
-Their are used in generic responder mmap cache code to find a record
-in mmap cache (sss_mc_find_record). Data provided from functions sss_mc_get_*
-are used for checking the validity of record. So in case of corrupted record
-the whole mmap cache can be invalidated.
-
-Functions sss_mc_get_strs_offset and sss_mc_get_strs_len did not provide
-data for initgroups mmap cache and therefore particular record could not be
-invalidated.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2716
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit 225dc6914cdc8920b02a129b98ece1ed97b99c03)
----
- src/responder/nss/nsssrv_mmap_cache.c | 15 ++++++++++++---
- src/sss_client/nss_mc_initgr.c        | 16 +++++++++++-----
- src/util/mmap_cache.h                 |  6 +++++-
- 3 files changed, 28 insertions(+), 9 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
-index 16bc926f3ba4f5ab096bd0fb43895edef2b57c50..ab9e769b1f4d5d17a8c41429afce292298239bc5 100644
---- a/src/responder/nss/nsssrv_mmap_cache.c
-+++ b/src/responder/nss/nsssrv_mmap_cache.c
-@@ -475,6 +475,9 @@ static errno_t sss_mc_get_strs_offset(struct sss_mc_ctx *mcc,
-     case SSS_MC_GROUP:
-         *_offset = offsetof(struct sss_mc_grp_data, strs);
-         return EOK;
-+    case SSS_MC_INITGROUPS:
-+        *_offset = offsetof(struct sss_mc_initgr_data, gids);
-+        return EOK;
-     default:
-         DEBUG(SSSDBG_FATAL_FAILURE, "Unknown memory cache type.\n");
-         return EINVAL;
-@@ -492,6 +495,9 @@ static errno_t sss_mc_get_strs_len(struct sss_mc_ctx *mcc,
-     case SSS_MC_GROUP:
-         *_len = ((struct sss_mc_grp_data *)&rec->data)->strs_len;
-         return EOK;
-+    case SSS_MC_INITGROUPS:
-+        *_len = ((struct sss_mc_initgr_data *)&rec->data)->data_len;
-+        return EOK;
-     default:
-         DEBUG(SSSDBG_FATAL_FAILURE, "Unknown memory cache type.\n");
-         return EINVAL;
-@@ -974,8 +980,8 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-         return EINVAL;
-     }
- 
--    /* num_groups + reserved + array of gids + name*/
--    data_len = (2 + num_groups) * sizeof(uint32_t) + name->len;
-+    /* array of gids + name */
-+    data_len = num_groups * sizeof(uint32_t) + name->len;
-     rec_len = sizeof(struct sss_mc_rec) + sizeof(struct sss_mc_initgr_data)
-               + data_len;
-     if (rec_len > mcc->dt_size) {
-@@ -998,10 +1004,13 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-                             name->str, name->len, name->str, name->len);
- 
-     /* initgroups struct */
-+    data->strs_len = name->len;
-+    data->data_len = data_len;
-+    data->reserved = MC_INVALID_VAL32;
-     data->num_groups = num_groups;
-     memcpy(data->gids, gids_buf, num_groups * sizeof(uint32_t));
-     memcpy(&data->gids[num_groups], name->str, name->len);
--    data->name = MC_PTR_DIFF(&data->gids[num_groups], data);
-+    data->strs = data->name = MC_PTR_DIFF(&data->gids[num_groups], data);
- 
-     MC_LOWER_BARRIER(rec);
- 
-diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c
-index e21b9f40aba00f9cc2385a561fc2bcc163c5791a..153617ea9c6489b7439b9676904b42b042f6697c 100644
---- a/src/sss_client/nss_mc_initgr.c
-+++ b/src/sss_client/nss_mc_initgr.c
-@@ -93,6 +93,7 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-     uint32_t hash;
-     uint32_t slot;
-     int ret;
-+    const size_t data_offset = offsetof(struct sss_mc_initgr_data, gids);
-     uint8_t *max_addr;
- 
-     ret = sss_nss_mc_get_ctx("initgroups", &initgr_mc_ctx);
-@@ -128,16 +129,21 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-         }
- 
-         data = (struct sss_mc_initgr_data *)rec->data;
-+        rec_name = (char *)data + data->name;
-         /* Integrity check
--         * - array with gids must be within data_table
--         * - string must be within data_table */
--        if ((uint8_t *)data->gids > max_addr
--                || (uint8_t *)data + data->name + name_len > max_addr) {
-+         * - name_len cannot be longer than all strings or data
-+         * - data->name cannot point outside strings
-+         * - all data must be within data_table
-+         * - name must be within data_table */
-+        if (name_len > data->data_len
-+            || name_len > data->strs_len
-+            || (data->strs + name_len) > (data_offset + data->data_len)
-+            || (uint8_t *)data->gids + data->data_len > max_addr
-+            || (uint8_t *)rec_name + name_len > max_addr) {
-             ret = ENOENT;
-             goto done;
-         }
- 
--        rec_name = (char *)data + data->name;
-         if (strcmp(name, rec_name) == 0) {
-             break;
-         }
-diff --git a/src/util/mmap_cache.h b/src/util/mmap_cache.h
-index a8703d5da4022e11c4bc2f3e2f8710e7f9d982bf..b5917b3c0973276e43e9fe160cec7528b1224f8f 100644
---- a/src/util/mmap_cache.h
-+++ b/src/util/mmap_cache.h
-@@ -79,7 +79,7 @@ typedef uint32_t rel_ptr_t;
- 
- 
- #define SSS_MC_MAJOR_VNO    1
--#define SSS_MC_MINOR_VNO    0
-+#define SSS_MC_MINOR_VNO    1
- 
- #define SSS_MC_HEADER_UNINIT    0   /* after ftruncate or before reset */
- #define SSS_MC_HEADER_ALIVE     1   /* current and in use */
-@@ -139,6 +139,10 @@ struct sss_mc_grp_data {
- 
- struct sss_mc_initgr_data {
-     rel_ptr_t name;         /* ptr to name string, rel. to struct base addr */
-+    rel_ptr_t strs;         /* ptr to concatenation of all strings */
-+    uint32_t reserved;
-+    uint32_t strs_len;      /* length of strs */
-+    uint32_t data_len;      /* all initgroups data len */
-     uint32_t num_groups;    /* number of groups */
-     uint32_t gids[0];       /* array of all groups
-                              * string with name is stored after gids */
--- 
-2.4.3
-
diff --git a/SOURCES/0040-mmap-Invalidate-initgroups-memory-cache-after-any-ch.patch b/SOURCES/0040-mmap-Invalidate-initgroups-memory-cache-after-any-ch.patch
deleted file mode 100644
index 579937b..0000000
--- a/SOURCES/0040-mmap-Invalidate-initgroups-memory-cache-after-any-ch.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 999edf37f10c90f8a2e87c16183bac2d0c6fe833 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 3 Aug 2015 12:58:03 +0200
-Subject: [PATCH 40/47] mmap: Invalidate initgroups memory cache after any
- change
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Initgroups memory cache was invalidated only in case on removed user.
-it should be invalidated also after changes in group membership.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2716
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit ea7839cec593b4a7c678fab52ab864518db6699b)
----
- src/responder/nss/nsssrv_cmd.c | 17 +++++++++--------
- 1 file changed, 9 insertions(+), 8 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index b3998015fa621cad8e06a126a674f94d26158dda..0bfbf0eab115826ebde53b4cfcf6661f2f6328c7 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -3903,14 +3903,6 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
-                   ret, strerror(ret));
-         }
- 
--        ret = sss_mmap_cache_initgr_invalidate(nctx->initgr_mc_ctx,
--                                               &delete_name);
--        if (ret != EOK && ret != ENOENT) {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Internal failure in memory cache code: %d [%s]\n",
--                  ret, strerror(ret));
--        }
--
-         /* Also invalidate his groups */
-         changed = true;
-     } else {
-@@ -3958,6 +3950,15 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
-                        ret, strerror(ret));
-             }
-         }
-+
-+        to_sized_string(&delete_name, name);
-+        ret = sss_mmap_cache_initgr_invalidate(nctx->initgr_mc_ctx,
-+                                               &delete_name);
-+        if (ret != EOK && ret != ENOENT) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Internal failure in memory cache code: %d [%s]\n",
-+                  ret, strerror(ret));
-+        }
-     }
- 
- done:
--- 
-2.4.3
-
diff --git a/SOURCES/0040-tests-add-tests-for-netlogon_get_domain_info.patch b/SOURCES/0040-tests-add-tests-for-netlogon_get_domain_info.patch
new file mode 100644
index 0000000..b429a27
--- /dev/null
+++ b/SOURCES/0040-tests-add-tests-for-netlogon_get_domain_info.patch
@@ -0,0 +1,125 @@
+From 4319dabb39ea91d1c1cd9fe5294e17706045bd48 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 11 Jul 2016 17:05:29 +0200
+Subject: [PATCH 40/44] tests: add tests for netlogon_get_domain_info
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                       |  1 +
+ src/tests/cmocka/test_ad_common.c | 81 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 82 insertions(+)
+
+diff --git a/Makefile.am b/Makefile.am
+index d05919705910fa565ff954224ce40feb5d7ff39f..cefd9a43442fc19933f1e373d4f2ed4bb3ba3201 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2470,6 +2470,7 @@ ad_common_tests_SOURCES = \
+     src/providers/ad/ad_opts.c \
+     src/providers/ad/ad_pac.c \
+     src/providers/ad/ad_pac_common.c \
++    src/providers/ad/ad_domain_info.c \
+     src/providers/ldap/sdap_async_initgroups_ad.c \
+     $(NULL)
+ ad_common_tests_CFLAGS = \
+diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
+index b7a5838de04e1a788bb9a61e84df00fc9bcc784b..7987330e2d0f5df93b62e4a68f34bc4ae23bd79b 100644
+--- a/src/tests/cmocka/test_ad_common.c
++++ b/src/tests/cmocka/test_ad_common.c
+@@ -802,6 +802,84 @@ void test_user_conn_list(void **state)
+     talloc_free(conn_list);
+ }
+ 
++void test_netlogon_get_domain_info(void **state)
++{
++    int ret;
++    struct sysdb_attrs *attrs;
++    struct ldb_val val = { 0 };
++    char *flat_name;
++    char *site;
++    char *forest;
++
++    struct ad_common_test_ctx *test_ctx = talloc_get_type(*state,
++                                                     struct ad_common_test_ctx);
++    assert_non_null(test_ctx);
++
++    attrs = sysdb_new_attrs(test_ctx);
++    assert_non_null(attrs);
++
++    ret = netlogon_get_domain_info(test_ctx, attrs, false, NULL, NULL, NULL);
++    assert_int_equal(ret, ENOENT);
++
++    ret = sysdb_attrs_add_val(attrs, AD_AT_NETLOGON, &val);
++    assert_int_equal(ret, EOK);
++
++    ret = netlogon_get_domain_info(test_ctx, attrs, false, NULL, NULL, NULL);
++    assert_int_equal(ret, EBADMSG);
++
++    talloc_free(attrs);
++    attrs = sysdb_new_attrs(test_ctx);
++    assert_non_null(attrs);
++
++    val.data = sss_base64_decode(test_ctx, "FwAAAP0zAABsGcIYI7j2TL97Rd+TvpATAmFkBWRldmVsAMAYCWFkLXNlcnZlcsAYAkFEAAlBRC1TRVJWRVIAABdEZWZhdWx0LUZpcnN0LVNpdGUtTmFtZQDAQAUAAAD/////", &val.length);
++    assert_non_null(val.data);
++
++    ret = sysdb_attrs_add_val(attrs, AD_AT_NETLOGON, &val);
++    assert_int_equal(ret, EOK);
++
++    ret = netlogon_get_domain_info(test_ctx, attrs, false, &flat_name, &site, &forest);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(flat_name, "AD");
++    assert_string_equal(site, "Default-First-Site-Name");
++    assert_string_equal(forest, "ad.devel");
++
++    /* missing site */
++    talloc_free(flat_name);
++    talloc_free(site);
++    talloc_free(forest);
++    talloc_free(val.data);
++    talloc_free(attrs);
++    attrs = sysdb_new_attrs(test_ctx);
++    assert_non_null(attrs);
++
++    val.data = sss_base64_decode(test_ctx, "FwAAAH0zAABsGcIYI7j2TL97Rd+TvpATAmFkBWRldmVsAMAYCWFkLXNlcnZlcsAYAkFEAAlBRC1TRVJWRVIAABdEZWZhdWx0LUZpcnN0LVNpdGUtTmFtZQAABQAAAP////8=", &val.length);
++    assert_non_null(val.data);
++
++    ret = sysdb_attrs_add_val(attrs, AD_AT_NETLOGON, &val);
++    assert_int_equal(ret, EOK);
++
++    ret = netlogon_get_domain_info(test_ctx, attrs, false, &flat_name, &site, &forest);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(flat_name, "AD");
++    assert_null(site);
++    assert_string_equal(forest, "ad.devel");
++
++    talloc_free(flat_name);
++    talloc_free(site);
++    talloc_free(forest);
++    ret = netlogon_get_domain_info(test_ctx, attrs, true, &flat_name, &site, &forest);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(flat_name, "AD");
++    assert_null(site);
++    assert_string_equal(forest, "ad.devel");
++
++    talloc_free(flat_name);
++    talloc_free(site);
++    talloc_free(forest);
++    talloc_free(val.data);
++    talloc_free(attrs);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -845,6 +923,9 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(test_ad_get_pac_data_from_user_entry,
+                                         test_ad_common_setup,
+                                         test_ad_common_teardown),
++        cmocka_unit_test_setup_teardown(test_netlogon_get_domain_info,
++                                        test_ad_common_setup,
++                                        test_ad_common_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.4.11
+
diff --git a/SOURCES/0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch b/SOURCES/0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch
new file mode 100644
index 0000000..28bfa38
--- /dev/null
+++ b/SOURCES/0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch
@@ -0,0 +1,217 @@
+From b0873f4a99f44eabae11e1cc62f6ec49c07466f0 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 18 Jul 2016 11:25:47 +0200
+Subject: [PATCH 41/44] AD: replace ad_get_client_site_parse_ndr() with
+ netlogon_get_domain_info()
+
+netlogon_get_domain_info() does not fail if only the site is missing in
+the CLDAP ping respond. If the site is not available a Global Catalog
+can still be looked up with the forest name. Only if the forest name is
+missing as well we fall back to the configured domain name.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3104
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ad/ad_srv.c | 153 ++++++++++------------------------------------
+ 1 file changed, 33 insertions(+), 120 deletions(-)
+
+diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
+index 9602945e66aa0529938bdd63067f00971dbcbe89..ff01ee95c4d2c6875a989394489f1a0495cc3003 100644
+--- a/src/providers/ad/ad_srv.c
++++ b/src/providers/ad/ad_srv.c
+@@ -405,93 +405,10 @@ done:
+     return;
+ }
+ 
+-static errno_t ad_get_client_site_parse_ndr(TALLOC_CTX *mem_ctx,
+-                                            uint8_t *data,
+-                                            size_t length,
+-                                            char **_site_name,
+-                                            char **_forest_name)
+-{
+-    TALLOC_CTX *tmp_ctx = NULL;
+-    struct ndr_pull *ndr_pull = NULL;
+-    struct netlogon_samlogon_response response;
+-    enum ndr_err_code ndr_err;
+-    char *site = NULL;
+-    char *forest = NULL;
+-    DATA_BLOB blob;
+-    errno_t ret;
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+-        return ENOMEM;
+-    }
+-
+-    blob.data = data;
+-    blob.length = length;
+-
+-    ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
+-    if (ndr_pull == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
+-                                                  &response);
+-    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+-        DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_netlogon_samlogon_response() "
+-                                  "failed [%d]\n", ndr_err);
+-        ret = EBADMSG;
+-        goto done;
+-    }
+-
+-    if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) {
+-        DEBUG(SSSDBG_OP_FAILURE, "This NT version does not provide site "
+-                                  "information [%x]\n", response.ntver);
+-        ret = EBADMSG;
+-        goto done;
+-    }
+-
+-    if (response.data.nt5_ex.client_site != NULL
+-        && response.data.nt5_ex.client_site[0] != '\0') {
+-        site = talloc_strdup(tmp_ctx, response.data.nt5_ex.client_site);
+-    } else if (response.data.nt5_ex.next_closest_site != NULL
+-               && response.data.nt5_ex.next_closest_site[0] != '\0') {
+-        site = talloc_strdup(tmp_ctx, response.data.nt5_ex.next_closest_site);
+-    } else {
+-        ret = ENOENT;
+-        goto done;
+-    }
+-
+-    if (response.data.nt5_ex.forest != NULL
+-            && response.data.nt5_ex.forest[0] != '\0') {
+-        forest = talloc_strdup(tmp_ctx, response.data.nt5_ex.forest);
+-    } else {
+-        ret = ENOENT;
+-        goto done;
+-    }
+-
+-
+-    if (site == NULL || forest == NULL) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    *_site_name = talloc_steal(mem_ctx, site);
+-    *_forest_name = talloc_steal(mem_ctx, forest);
+-
+-    ret = EOK;
+-
+-done:
+-    talloc_free(tmp_ctx);
+-    return ret;
+-}
+-
+ static void ad_get_client_site_done(struct tevent_req *subreq)
+ {
+     struct ad_get_client_site_state *state = NULL;
+     struct tevent_req *req = NULL;
+-    struct ldb_message_element *el = NULL;
+     struct sysdb_attrs **reply = NULL;
+     size_t reply_count;
+     errno_t ret;
+@@ -520,25 +437,8 @@ static void ad_get_client_site_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
+-    ret = sysdb_attrs_get_el(reply[0], AD_AT_NETLOGON, &el);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
+-        goto done;
+-    }
+-
+-    if (el->num_values == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE, "netlogon has no value\n");
+-        ret = ENOENT;
+-        goto done;
+-    } else if (el->num_values > 1) {
+-        DEBUG(SSSDBG_OP_FAILURE, "More than one netlogon value?\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = ad_get_client_site_parse_ndr(state, el->values[0].data,
+-                                       el->values[0].length, &state->site,
+-                                       &state->forest);
++    ret = netlogon_get_domain_info(state, reply[0], true, NULL, &state->site,
++                                   &state->forest);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve site name [%d]: %s\n",
+                                   ret, strerror(ret));
+@@ -547,6 +447,7 @@ static void ad_get_client_site_done(struct tevent_req *subreq)
+     }
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
++    DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest);
+ 
+ done:
+     if (ret != EOK) {
+@@ -803,30 +704,42 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq)
+ 
+         ret = EOK;
+     }
++
++    primary_domain = state->discovery_domain;
++    backup_domain = NULL;
++
+     if (ret == EOK) {
+         if (strcmp(state->service, "gc") == 0) {
+-            primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
+-                                             state->site, state->forest);
+-            if (primary_domain == NULL) {
+-                ret = ENOMEM;
+-                goto done;
+-            }
++            if (state->forest != NULL) {
++                if (state->site != NULL) {
++                    primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
++                                                     state->site,
++                                                     state->forest);
++                    if (primary_domain == NULL) {
++                        ret = ENOMEM;
++                        goto done;
++                    }
+ 
+-            backup_domain = state->forest;
++                    backup_domain = state->forest;
++                } else {
++                    primary_domain = state->forest;
++                    backup_domain = NULL;
++                }
++            }
+         } else {
+-            primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
+-                                             state->site, state->discovery_domain);
+-            if (primary_domain == NULL) {
+-                ret = ENOMEM;
+-                goto done;
+-            }
++            if (state->site != NULL) {
++                primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
++                                                 state->site,
++                                                 state->discovery_domain);
++                if (primary_domain == NULL) {
++                    ret = ENOMEM;
++                    goto done;
++                }
+ 
+-            backup_domain = state->discovery_domain;
++                backup_domain = state->discovery_domain;
++            }
+         }
+-    } else if (ret == ENOENT) {
+-        primary_domain = state->discovery_domain;
+-        backup_domain = NULL;
+-    } else {
++    } else if (ret != ENOENT && ret != EOK) {
+         goto done;
+     }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0041-sss_client-Update-integrity-check-of-records-in-mmap.patch b/SOURCES/0041-sss_client-Update-integrity-check-of-records-in-mmap.patch
deleted file mode 100644
index c59a460..0000000
--- a/SOURCES/0041-sss_client-Update-integrity-check-of-records-in-mmap.patch
+++ /dev/null
@@ -1,227 +0,0 @@
-From e115f70d717ab8232172b358739ba7a0e1102caa Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Thu, 30 Jul 2015 10:50:47 +0200
-Subject: [PATCH 41/47] sss_client: Update integrity check of records in mmap
- cache
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The function sss_nss_mc_get_record return copy of record from memory
-cache in last argument. Because we should not access data directly
-to avoid problems with consistency of record.
-The function sss_nss_mc_get_record also check whether length of record
-is within data area (with macro MC_CHECK_RECORD_LENGTH)
-
-However we also tried to do the same check in functions sss_nss_mc_get{gr, pw}*
-Pointer to end of strings in record was compared to pointer to the end
-of data table. But these two pointers are not within the same allocated area
-and does not make sense to compare them. Sometimes record can be allocated
-before mmaped area and sometime after. Sometimes it will return cached data
-and other time will fall back to responder.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2743
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit ba847347cade817ee927397d82c952b51b0dcb2b)
----
- src/sss_client/nss_mc_group.c  | 19 ++++++++++---------
- src/sss_client/nss_mc_initgr.c | 26 +++++++++++++-------------
- src/sss_client/nss_mc_passwd.c | 20 ++++++++++----------
- 3 files changed, 33 insertions(+), 32 deletions(-)
-
-diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c
-index e0fdb97f628ac19741409be29566e4af5a391f74..aacf59d9fd8b81ea895f4660de08f3e44f0ce645 100644
---- a/src/sss_client/nss_mc_group.c
-+++ b/src/sss_client/nss_mc_group.c
-@@ -112,16 +112,16 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
-     uint32_t hash;
-     uint32_t slot;
-     int ret;
--    size_t strs_offset;
--    uint8_t *max_addr;
-+    const size_t strs_offset = offsetof(struct sss_mc_grp_data, strs);
-+    size_t data_size;
- 
-     ret = sss_nss_mc_get_ctx("group", &gr_mc_ctx);
-     if (ret) {
-         return ret;
-     }
- 
--    /* Get max address of data table. */
--    max_addr = gr_mc_ctx.data_table + gr_mc_ctx.dt_size;
-+    /* Get max size of data table. */
-+    data_size = gr_mc_ctx.dt_size;
- 
-     /* hashes are calculated including the NULL terminator */
-     hash = sss_nss_mc_hash(&gr_mc_ctx, name, name_len + 1);
-@@ -130,7 +130,7 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
-     /* If slot is not within the bounds of mmaped region and
-      * it's value is not MC_INVALID_VAL, then the cache is
-      * probbably corrupted. */
--    while (MC_SLOT_WITHIN_BOUNDS(slot, gr_mc_ctx.dt_size)) {
-+    while (MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
-         /* free record from previous iteration */
-         free(rec);
-         rec = NULL;
-@@ -147,15 +147,16 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
-             continue;
-         }
- 
--        strs_offset = offsetof(struct sss_mc_grp_data, strs);
-         data = (struct sss_mc_grp_data *)rec->data;
-         /* Integrity check
-          * - name_len cannot be longer than all strings
-          * - data->name cannot point outside strings
--         * - all strings must be within data_table */
-+         * - all strings must be within copy of record
-+         * - size of record must be lower that data table size */
-         if (name_len > data->strs_len
-             || (data->name + name_len) > (strs_offset + data->strs_len)
--            || (uint8_t *)data->strs + data->strs_len > max_addr) {
-+            || data->strs_len > rec->len
-+            || rec->len > data_size) {
-             ret = ENOENT;
-             goto done;
-         }
-@@ -168,7 +169,7 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
-         slot = sss_nss_mc_next_slot_with_hash(rec, hash);
-     }
- 
--    if (!MC_SLOT_WITHIN_BOUNDS(slot, gr_mc_ctx.dt_size)) {
-+    if (!MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
-         ret = ENOENT;
-         goto done;
-     }
-diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c
-index 153617ea9c6489b7439b9676904b42b042f6697c..74143d9fb3c674c3116d7f4cf0b4c03d993743a2 100644
---- a/src/sss_client/nss_mc_initgr.c
-+++ b/src/sss_client/nss_mc_initgr.c
-@@ -94,15 +94,15 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-     uint32_t slot;
-     int ret;
-     const size_t data_offset = offsetof(struct sss_mc_initgr_data, gids);
--    uint8_t *max_addr;
-+    size_t data_size;
- 
-     ret = sss_nss_mc_get_ctx("initgroups", &initgr_mc_ctx);
-     if (ret) {
-         return ret;
-     }
- 
--    /* Get max address of data table. */
--    max_addr = initgr_mc_ctx.data_table + initgr_mc_ctx.dt_size;
-+    /* Get max size of data table. */
-+    data_size = initgr_mc_ctx.dt_size;
- 
-     /* hashes are calculated including the NULL terminator */
-     hash = sss_nss_mc_hash(&initgr_mc_ctx, name, name_len + 1);
-@@ -111,7 +111,7 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-     /* If slot is not within the bounds of mmaped region and
-      * it's value is not MC_INVALID_VAL, then the cache is
-      * probbably corrupted. */
--    while (MC_SLOT_WITHIN_BOUNDS(slot, initgr_mc_ctx.dt_size)) {
-+    while (MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
-         /* free record from previous iteration */
-         free(rec);
-         rec = NULL;
-@@ -132,14 +132,14 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-         rec_name = (char *)data + data->name;
-         /* Integrity check
-          * - name_len cannot be longer than all strings or data
--         * - data->name cannot point outside strings
--         * - all data must be within data_table
--         * - name must be within data_table */
--        if (name_len > data->data_len
--            || name_len > data->strs_len
--            || (data->strs + name_len) > (data_offset + data->data_len)
--            || (uint8_t *)data->gids + data->data_len > max_addr
--            || (uint8_t *)rec_name + name_len > max_addr) {
-+         * - all data must be within copy of record
-+         * - size of record must be lower that data table size
-+         * - data->strs cannot point outside strings */
-+        if (name_len > data->strs_len
-+            || data->strs_len > data->data_len
-+            || data->data_len > rec->len
-+            || rec->len > data_size
-+            || (data->strs + name_len) > (data_offset + data->data_len)) {
-             ret = ENOENT;
-             goto done;
-         }
-@@ -151,7 +151,7 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-         slot = sss_nss_mc_next_slot_with_hash(rec, hash);
-     }
- 
--    if (!MC_SLOT_WITHIN_BOUNDS(slot, initgr_mc_ctx.dt_size)) {
-+    if (!MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
-         ret = ENOENT;
-         goto done;
-     }
-diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c
-index 10e43e2af43c5e7f1738e281b3ed260d89f3a004..0da7ad0aeece7d38ca34bb3fde64adc898eaf0ae 100644
---- a/src/sss_client/nss_mc_passwd.c
-+++ b/src/sss_client/nss_mc_passwd.c
-@@ -105,16 +105,16 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
-     uint32_t hash;
-     uint32_t slot;
-     int ret;
--    size_t strs_offset;
--    uint8_t *max_addr;
-+    const size_t strs_offset = offsetof(struct sss_mc_pwd_data, strs);
-+    size_t data_size;
- 
-     ret = sss_nss_mc_get_ctx("passwd", &pw_mc_ctx);
-     if (ret) {
-         return ret;
-     }
- 
--    /* Get max address of data table. */
--    max_addr = pw_mc_ctx.data_table + pw_mc_ctx.dt_size;
-+    /* Get max size of data table. */
-+    data_size = pw_mc_ctx.dt_size;
- 
-     /* hashes are calculated including the NULL terminator */
-     hash = sss_nss_mc_hash(&pw_mc_ctx, name, name_len + 1);
-@@ -123,7 +123,7 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
-     /* If slot is not within the bounds of mmaped region and
-      * it's value is not MC_INVALID_VAL, then the cache is
-      * probbably corrupted. */
--    while (MC_SLOT_WITHIN_BOUNDS(slot, pw_mc_ctx.dt_size)) {
-+    while (MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
-         /* free record from previous iteration */
-         free(rec);
-         rec = NULL;
-@@ -140,16 +140,16 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
-             continue;
-         }
- 
--        strs_offset = offsetof(struct sss_mc_pwd_data, strs);
--
-         data = (struct sss_mc_pwd_data *)rec->data;
-         /* Integrity check
-          * - name_len cannot be longer than all strings
-          * - data->name cannot point outside strings
--         * - all strings must be within data_table */
-+         * - all strings must be within copy of record
-+         * - size of record must be lower that data table size */
-         if (name_len > data->strs_len
-             || (data->name + name_len) > (strs_offset + data->strs_len)
--            || (uint8_t *)data->strs + data->strs_len > max_addr) {
-+            || data->strs_len > rec->len
-+            || rec->len > data_size) {
-             ret = ENOENT;
-             goto done;
-         }
-@@ -162,7 +162,7 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
-         slot = sss_nss_mc_next_slot_with_hash(rec, hash);
-     }
- 
--    if (!MC_SLOT_WITHIN_BOUNDS(slot, pw_mc_ctx.dt_size)) {
-+    if (!MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
-         ret = ENOENT;
-         goto done;
-     }
--- 
-2.4.3
-
diff --git a/SOURCES/0042-intg_test-Add-module-for-simulation-of-utility-id.patch b/SOURCES/0042-intg_test-Add-module-for-simulation-of-utility-id.patch
deleted file mode 100644
index 71ff852..0000000
--- a/SOURCES/0042-intg_test-Add-module-for-simulation-of-utility-id.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From b47156c92867daaa2c30a7f4ad884a27273e54ff Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 29 Jul 2015 14:35:52 +0200
-Subject: [PATCH 42/47] intg_test: Add module for simulation of utility id
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit 38b07019861240cf5107f5d51fc0027519e21619)
----
- src/tests/intg/Makefile.am |   1 +
- src/tests/intg/sssd_id.py  | 119 +++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 120 insertions(+)
- create mode 100644 src/tests/intg/sssd_id.py
-
-diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
-index 9383e112002baa7b0d200a3dc205aa2856089c97..7488022ed59dd894ba7b6808c5573706412098c7 100644
---- a/src/tests/intg/Makefile.am
-+++ b/src/tests/intg/Makefile.am
-@@ -1,5 +1,6 @@
- dist_noinst_DATA = \
-     config.py.m4 \
-+    sssd_id.py \
-     ds.py \
-     ds_openldap.py \
-     ent.py \
-diff --git a/src/tests/intg/sssd_id.py b/src/tests/intg/sssd_id.py
-new file mode 100644
-index 0000000000000000000000000000000000000000..45f2822b5b33d99b6a7cbbbba0450c774e05ff11
---- /dev/null
-+++ b/src/tests/intg/sssd_id.py
-@@ -0,0 +1,119 @@
-+#
-+# Module for simulation of utility "id" from coreutils
-+#
-+# Copyright (c) 2015 Red Hat, Inc.
-+# Author: Lukas Slebodnik <lslebodn@redhat.com>
-+#
-+# This 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; version 2 only
-+#
-+# 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/>.
-+#
-+import config
-+import pwd
-+import grp
-+from ctypes import (cdll, c_int, c_char, c_uint32, c_long, c_char_p,
-+                    POINTER, pointer)
-+
-+
-+class NssReturnCode(object):
-+    """ 'enum' class for name service switch retrn code """
-+    TRYAGAIN = -2,
-+    UNAVAIL = -1
-+    NOTFOUND = 0
-+    SUCCESS = 1
-+    RETURN = 2
-+
-+
-+def call_sssd_initgroups(user, gid):
-+    """
-+    Function will initialize the supplementary group access list
-+    for given user. It will gather groups only provided by sssd.
-+
-+    Arguments are the same as for C function initgroups
-+    @param string user name of user
-+    @param int gid the additional gid will be also added to the list.
-+
-+    @return (int, int, List[int]) (err, errno, gids)
-+        gids shoudl contain user group IDs if err is NssReturnCode.SUCCESS
-+        otherwise errno will contain non-zero vlaue.
-+    """
-+    libnss_sss_path = config.PREFIX + "/lib/libnss_sss.so.2"
-+    libnss_sss = cdll.LoadLibrary(libnss_sss_path)
-+
-+    func = libnss_sss._nss_sss_initgroups_dyn
-+    func.restype = c_int
-+    func.argtypes = [POINTER(c_char), c_uint32, POINTER(c_long),
-+                     POINTER(c_long), POINTER(POINTER(c_uint32)), c_long,
-+                     POINTER(c_int)]
-+
-+    start = POINTER(c_long)(c_long(0))
-+    size = POINTER(c_long)(c_long(0))
-+    groups = POINTER(c_uint32)()
-+    p_groups = pointer(groups)
-+    limit = c_long(-1)
-+    errno = POINTER(c_int)(c_int(0))
-+
-+    res = func(c_char_p(user), c_uint32(gid), start, size, p_groups, limit,
-+               errno)
-+
-+    gids = []
-+    if res == NssReturnCode.SUCCESS:
-+        gids_count = size[0]
-+        assert gids_count > 0, "_nss_sss_initgroups_dyn shoulld return " \
-+                               "one gid"
-+
-+        for i in range(0, gids_count):
-+            gids.append(int(p_groups.contents[i]))
-+
-+    return (int(res), errno[0], gids)
-+
-+
-+def get_user_gids(user):
-+    """
-+    Function will initialize the supplementary group access list
-+    for given user. It will gather groups only provided by sssd.
-+
-+    Arguments are the same as for C function initgroups
-+    @param string user name of user
-+
-+    @return (int, int, List[int]) (err, errno, gids)
-+        gids shoudl contain user group IDs if err is NssReturnCode.SUCCESS
-+        otherwise errno will contain non-zero vlaue.
-+    """
-+    pwd_user = pwd.getpwnam(user)
-+    uid = pwd_user.pw_uid
-+    gid = pwd_user.pw_gid
-+
-+    user = pwd.getpwuid(uid).pw_name
-+
-+    return call_sssd_initgroups(user, gid)
-+
-+
-+def get_user_groups(user):
-+    """
-+    Function will initialize the supplementary group access list
-+    for given user. It will gather groups only provided by sssd.
-+
-+    Arguments are the same as for C function initgroups
-+    @param string user name of user
-+
-+    @return (int, int, List[string]) (err, errno, groups)
-+        roups shoudl contain names of user groups
-+        if err is NssReturnCode.SUCCESS
-+        otherwise errno will contain non-zero vlaue.
-+    """
-+    (res, errno, gids) = get_user_gids(user)
-+    groups = []
-+
-+    if res == NssReturnCode.SUCCESS:
-+        groups = [grp.getgrgid(gid).gr_name for gid in gids]
-+
-+    return (res, errno, groups)
--- 
-2.4.3
-
diff --git a/SOURCES/0042-sysdb_master_domain_add_info-properly-set-do_update.patch b/SOURCES/0042-sysdb_master_domain_add_info-properly-set-do_update.patch
new file mode 100644
index 0000000..15f9cbc
--- /dev/null
+++ b/SOURCES/0042-sysdb_master_domain_add_info-properly-set-do_update.patch
@@ -0,0 +1,35 @@
+From 9899507b2da55a374baef13c4dc3914fe853cf87 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 25 Jul 2016 17:37:51 +0200
+Subject: [PATCH 42/44] sysdb_master_domain_add_info: properly set do_update
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+do_update should be only set if there is a change, i.e if something was
+added to the ldb_message.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/db/sysdb_subdomains.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index 02206e470e8e035cc05848137df6a1eb04806869..ff83f914f31d566e050c74a3ef5f5745f8c93add 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -787,9 +787,9 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
+                 ret = sysdb_error_to_errno(ret);
+                 goto done;
+             }
+-        }
+ 
+-        do_update = true;
++            do_update = true;
++        }
+     }
+ 
+     if (do_update == false) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch b/SOURCES/0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch
new file mode 100644
index 0000000..20883fd
--- /dev/null
+++ b/SOURCES/0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch
@@ -0,0 +1,30 @@
+From bfbafa51da5e407659c924eed5970f17510ae913 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 19 Jul 2016 14:28:35 +0200
+Subject: [PATCH 43/44] SYSDB: Removing of duplication of sysdb_ts_cache_attrs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+---
+ src/db/sysdb.h | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 407ce3c18a7077e8fe45c3c9c7576ae626105122..0cc550a4c389b4a1a2b78aff760f4b5cbf94e17f 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -315,9 +315,6 @@ struct range_info {
+ /* These attributes are stored in the timestamp cache */
+ extern const char *sysdb_ts_cache_attrs[];
+ 
+-/* These attributes are stored in the timestamp cache */
+-extern const char *sysdb_ts_cache_attrs[];
+-
+ /* values are copied in the structure, allocated on "attrs" */
+ int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
+                         const char *name, const struct ldb_val *val);
+-- 
+2.4.11
+
diff --git a/SOURCES/0043-intg_test-Add-integration-test-for-memory-cache.patch b/SOURCES/0043-intg_test-Add-integration-test-for-memory-cache.patch
deleted file mode 100644
index 67012ce..0000000
--- a/SOURCES/0043-intg_test-Add-integration-test-for-memory-cache.patch
+++ /dev/null
@@ -1,384 +0,0 @@
-From a45f9034e912b6242459a8d576f60ff829508bc3 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 21 Jul 2015 08:55:14 +0200
-Subject: [PATCH 43/47] intg_test: Add integration test for memory cache
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit a2c10cf31d14bac598f5cd008973375c3f9575a6)
----
- src/tests/intg/Makefile.am          |   1 +
- src/tests/intg/test_memory_cache.py | 347 ++++++++++++++++++++++++++++++++++++
- 2 files changed, 348 insertions(+)
- create mode 100644 src/tests/intg/test_memory_cache.py
-
-diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
-index 7488022ed59dd894ba7b6808c5573706412098c7..6819c2f2cea137c7544e94b0b29391611533b20c 100644
---- a/src/tests/intg/Makefile.am
-+++ b/src/tests/intg/Makefile.am
-@@ -8,6 +8,7 @@ dist_noinst_DATA = \
-     ldap_ent.py \
-     ldap_test.py \
-     util.py \
-+    test_memory_cache.py \
-     $(NULL)
- 
- config.py: config.py.m4
-diff --git a/src/tests/intg/test_memory_cache.py b/src/tests/intg/test_memory_cache.py
-new file mode 100644
-index 0000000000000000000000000000000000000000..5a1f07651b70a5bf1fbacceeae6825ea4341e3b5
---- /dev/null
-+++ b/src/tests/intg/test_memory_cache.py
-@@ -0,0 +1,347 @@
-+#
-+# LDAP integration test
-+#
-+# Copyright (c) 2015 Red Hat, Inc.
-+# Author: Lukas Slebodnik <lslebodn@redhat.com>
-+#
-+# This 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; version 2 only
-+#
-+# 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/>.
-+#
-+import os
-+import stat
-+import ent
-+import config
-+import signal
-+import subprocess
-+import time
-+import pytest
-+import ds_openldap
-+import ldap_ent
-+import sssd_id
-+from util import unindent
-+
-+LDAP_BASE_DN = "dc=example,dc=com"
-+
-+
-+@pytest.fixture(scope="module")
-+def ds_inst(request):
-+    """LDAP server instance fixture"""
-+    ds_inst = ds_openldap.DSOpenLDAP(
-+        config.PREFIX, 10389, LDAP_BASE_DN,
-+        "cn=admin", "Secret123")
-+    try:
-+        ds_inst.setup()
-+    except:
-+        ds_inst.teardown()
-+        raise
-+    request.addfinalizer(lambda: ds_inst.teardown())
-+    return ds_inst
-+
-+
-+@pytest.fixture(scope="module")
-+def ldap_conn(request, ds_inst):
-+    """LDAP server connection fixture"""
-+    ldap_conn = ds_inst.bind()
-+    ldap_conn.ds_inst = ds_inst
-+    request.addfinalizer(lambda: ldap_conn.unbind_s())
-+    return ldap_conn
-+
-+
-+def create_ldap_fixture(request, ldap_conn, ent_list):
-+    """Add LDAP entries and add teardown for removing them"""
-+    for entry in ent_list:
-+        ldap_conn.add_s(entry[0], entry[1])
-+
-+    def teardown():
-+        for entry in ent_list:
-+            ldap_conn.delete_s(entry[0])
-+    request.addfinalizer(teardown)
-+
-+
-+def create_conf_fixture(request, contents):
-+    """Generate sssd.conf and add teardown for removing it"""
-+    conf = open(config.CONF_PATH, "w")
-+    conf.write(contents)
-+    conf.close()
-+    os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
-+    request.addfinalizer(lambda: os.unlink(config.CONF_PATH))
-+
-+
-+def stop_sssd():
-+    pid_file = open(config.PIDFILE_PATH, "r")
-+    pid = int(pid_file.read())
-+    os.kill(pid, signal.SIGTERM)
-+    while True:
-+        try:
-+            os.kill(pid, signal.SIGCONT)
-+        except:
-+            break
-+        time.sleep(1)
-+
-+
-+def create_sssd_fixture(request):
-+    """Start sssd and add teardown for stopping it and removing state"""
-+    if subprocess.call(["sssd", "-D", "-f"]) != 0:
-+        raise Exception("sssd start failed")
-+
-+    def teardown():
-+        try:
-+            stop_sssd()
-+        except:
-+            pass
-+        subprocess.call(["sss_cache", "-E"])
-+        for path in os.listdir(config.DB_PATH):
-+            os.unlink(config.DB_PATH + "/" + path)
-+        for path in os.listdir(config.MCACHE_PATH):
-+            os.unlink(config.MCACHE_PATH + "/" + path)
-+    request.addfinalizer(teardown)
-+
-+
-+@pytest.fixture
-+def sanity_rfc2307(request, ldap_conn):
-+    ent_list = ldap_ent.List(LDAP_BASE_DN)
-+    ent_list.add_user("user1", 1001, 2001)
-+    ent_list.add_user("user2", 1002, 2002)
-+    ent_list.add_user("user3", 1003, 2003)
-+    ent_list.add_user("user11", 1011, 2001)
-+    ent_list.add_user("user12", 1012, 2002)
-+    ent_list.add_user("user13", 1013, 2003)
-+    ent_list.add_user("user21", 1021, 2001)
-+    ent_list.add_user("user22", 1022, 2002)
-+    ent_list.add_user("user23", 1023, 2003)
-+
-+    ent_list.add_group("group1", 2001, ["user1", "user11", "user21"])
-+    ent_list.add_group("group2", 2002, ["user2", "user12", "user22"])
-+    ent_list.add_group("group3", 2003, ["user3", "user13", "user23"])
-+
-+    ent_list.add_group("group0x", 2000, ["user1", "user2", "user3"])
-+    ent_list.add_group("group1x", 2010, ["user11", "user12", "user13"])
-+    ent_list.add_group("group2x", 2020, ["user21", "user22", "user23"])
-+    create_ldap_fixture(request, ldap_conn, ent_list)
-+
-+    conf = unindent("""\
-+        [sssd]
-+        config_file_version = 2
-+        domains             = LDAP
-+        services            = nss
-+
-+        [nss]
-+
-+        [domain/LDAP]
-+        ldap_auth_disable_tls_never_use_in_production = true
-+        ldap_schema         = rfc2307
-+        id_provider         = ldap
-+        auth_provider       = ldap
-+        sudo_provider       = ldap
-+        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
-+        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
-+    """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_getpwnam(ldap_conn, sanity_rfc2307):
-+    ent.assert_passwd_by_name(
-+        'user1',
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1001,
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user2',
-+        dict(name='user2', passwd='*', uid=1002, gid=2002,
-+             gecos='1002', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1002,
-+        dict(name='user2', passwd='*', uid=1002, gid=2002,
-+             gecos='1002', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user3',
-+        dict(name='user3', passwd='*', uid=1003, gid=2003,
-+             gecos='1003', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1003,
-+        dict(name='user3', passwd='*', uid=1003, gid=2003,
-+             gecos='1003', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user11',
-+        dict(name='user11', passwd='*', uid=1011, gid=2001,
-+             gecos='1011', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1011,
-+        dict(name='user11', passwd='*', uid=1011, gid=2001,
-+             gecos='1011', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user12',
-+        dict(name='user12', passwd='*', uid=1012, gid=2002,
-+             gecos='1012', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1012,
-+        dict(name='user12', passwd='*', uid=1012, gid=2002,
-+             gecos='1012', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user13',
-+        dict(name='user13', passwd='*', uid=1013, gid=2003,
-+             gecos='1013', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1013,
-+        dict(name='user13', passwd='*', uid=1013, gid=2003,
-+             gecos='1013', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user21',
-+        dict(name='user21', passwd='*', uid=1021, gid=2001,
-+             gecos='1021', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1021,
-+        dict(name='user21', passwd='*', uid=1021, gid=2001,
-+             gecos='1021', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user22',
-+        dict(name='user22', passwd='*', uid=1022, gid=2002,
-+             gecos='1022', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1022,
-+        dict(name='user22', passwd='*', uid=1022, gid=2002,
-+             gecos='1022', shell='/bin/bash'))
-+
-+    ent.assert_passwd_by_name(
-+        'user23',
-+        dict(name='user23', passwd='*', uid=1023, gid=2003,
-+             gecos='1023', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1023,
-+        dict(name='user23', passwd='*', uid=1023, gid=2003,
-+             gecos='1023', shell='/bin/bash'))
-+
-+
-+def test_getpwnam_with_mc(ldap_conn, sanity_rfc2307):
-+    test_getpwnam(ldap_conn, sanity_rfc2307)
-+    stop_sssd()
-+    test_getpwnam(ldap_conn, sanity_rfc2307)
-+
-+
-+def test_getgrnam_simple(ldap_conn, sanity_rfc2307):
-+    ent.assert_group_by_name("group1", dict(name="group1", gid=2001))
-+    ent.assert_group_by_gid(2001, dict(name="group1", gid=2001))
-+
-+    ent.assert_group_by_name("group2", dict(name="group2", gid=2002))
-+    ent.assert_group_by_gid(2002, dict(name="group2", gid=2002))
-+
-+    ent.assert_group_by_name("group3", dict(name="group3", gid=2003))
-+    ent.assert_group_by_gid(2003, dict(name="group3", gid=2003))
-+
-+    ent.assert_group_by_name("group0x", dict(name="group0x", gid=2000))
-+    ent.assert_group_by_gid(2000, dict(name="group0x", gid=2000))
-+
-+    ent.assert_group_by_name("group1x", dict(name="group1x", gid=2010))
-+    ent.assert_group_by_gid(2010, dict(name="group1x", gid=2010))
-+
-+    ent.assert_group_by_name("group2x", dict(name="group2x", gid=2020))
-+    ent.assert_group_by_gid(2020, dict(name="group2x", gid=2020))
-+
-+
-+def test_getgrnam_simple_with_mc(ldap_conn, sanity_rfc2307):
-+    test_getgrnam_simple(ldap_conn, sanity_rfc2307)
-+    stop_sssd()
-+    test_getgrnam_simple(ldap_conn, sanity_rfc2307)
-+
-+
-+def test_getgrnam_membership(ldap_conn, sanity_rfc2307):
-+    ent.assert_group_by_name(
-+        "group1",
-+        dict(mem=ent.contains_only("user1", "user11", "user21")))
-+    ent.assert_group_by_gid(
-+        2001,
-+        dict(mem=ent.contains_only("user1", "user11", "user21")))
-+
-+    ent.assert_group_by_name(
-+        "group2",
-+        dict(mem=ent.contains_only("user2", "user12", "user22")))
-+    ent.assert_group_by_gid(
-+        2002,
-+        dict(mem=ent.contains_only("user2", "user12", "user22")))
-+
-+    ent.assert_group_by_name(
-+        "group3",
-+        dict(mem=ent.contains_only("user3", "user13", "user23")))
-+    ent.assert_group_by_gid(
-+        2003,
-+        dict(mem=ent.contains_only("user3", "user13", "user23")))
-+
-+    ent.assert_group_by_name(
-+        "group0x",
-+        dict(mem=ent.contains_only("user1", "user2", "user3")))
-+    ent.assert_group_by_gid(
-+        2000,
-+        dict(mem=ent.contains_only("user1", "user2", "user3")))
-+
-+    ent.assert_group_by_name(
-+        "group1x",
-+        dict(mem=ent.contains_only("user11", "user12", "user13")))
-+    ent.assert_group_by_gid(
-+        2010,
-+        dict(mem=ent.contains_only("user11", "user12", "user13")))
-+
-+    ent.assert_group_by_name(
-+        "group2x",
-+        dict(mem=ent.contains_only("user21", "user22", "user23")))
-+    ent.assert_group_by_gid(
-+        2020,
-+        dict(mem=ent.contains_only("user21", "user22", "user23")))
-+
-+
-+def test_getgrnam_membership_with_mc(ldap_conn, sanity_rfc2307):
-+    test_getgrnam_membership(ldap_conn, sanity_rfc2307)
-+    stop_sssd()
-+    test_getgrnam_membership(ldap_conn, sanity_rfc2307)
-+
-+
-+def assert_user_gids_equal(user, expected_gids):
-+    (res, errno, gids) = sssd_id.get_user_gids(user)
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user %s, %d" % (user, errno)
-+
-+    assert sorted(gids) == sorted(expected_gids), \
-+        "result: %s\n expected %s" % (
-+            ", ".join(["%s" % s for s in sorted(gids)]),
-+            ", ".join(["%s" % s for s in sorted(expected_gids)])
-+        )
-+
-+
-+def test_initgroups(ldap_conn, sanity_rfc2307):
-+    assert_user_gids_equal('user1', [2000, 2001])
-+    assert_user_gids_equal('user2', [2000, 2002])
-+    assert_user_gids_equal('user3', [2000, 2003])
-+
-+    assert_user_gids_equal('user11', [2010, 2001])
-+    assert_user_gids_equal('user12', [2010, 2002])
-+    assert_user_gids_equal('user13', [2010, 2003])
-+
-+    assert_user_gids_equal('user21', [2020, 2001])
-+    assert_user_gids_equal('user22', [2020, 2002])
-+    assert_user_gids_equal('user23', [2020, 2003])
-+
-+
-+def test_initgroups_with_mc(ldap_conn, sanity_rfc2307):
-+    test_initgroups(ldap_conn, sanity_rfc2307)
-+    stop_sssd()
-+    test_initgroups(ldap_conn, sanity_rfc2307)
--- 
-2.4.3
-
diff --git a/SOURCES/0044-NSS-Initgr-memory-cache-should-work-with-fq-names.patch b/SOURCES/0044-NSS-Initgr-memory-cache-should-work-with-fq-names.patch
deleted file mode 100644
index ce3e241..0000000
--- a/SOURCES/0044-NSS-Initgr-memory-cache-should-work-with-fq-names.patch
+++ /dev/null
@@ -1,257 +0,0 @@
-From 5c5a094438ac6c81d99066ec58778cab23e0a939 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 13 Jul 2015 10:40:06 +0200
-Subject: [PATCH 44/47] NSS: Initgr memory cache should work with fq names
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-We need to stored two versions of name to the initgroups memory cache.
-Otherwise it could be stored many times if sssd is configured with
-case_sensitive = false. It would be impossible to invalidate all
-version of names after user login. As a result of this wrong user
-groups could be returned from initgroups memory cache.
-
-Therefore we store raw name provided by glibc function
-and internal sanitized fully qualified name,
-which is unique for particular user.
-
-This patch also increase average space for initgroups
-because there are also stored two quite long names in case of
-fq names.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2712
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit dda0258705de7255e6ec54b7f9adbde83a220996)
----
- src/responder/nss/nsssrv_cmd.c        | 30 +++++++++++++++++++++++++-----
- src/responder/nss/nsssrv_mmap_cache.c | 32 +++++++++++++++++++++-----------
- src/responder/nss/nsssrv_mmap_cache.h |  1 +
- src/responder/nss/nsssrv_private.h    |  2 ++
- src/util/mmap_cache.h                 |  7 ++++---
- 5 files changed, 53 insertions(+), 19 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index 0bfbf0eab115826ebde53b4cfcf6661f2f6328c7..aa64432d51f15ed17212b8c40eebf5c9322bc784 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -1354,6 +1354,7 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx)
-     }
- 
-     rawname = (const char *)body;
-+    dctx->mc_name = rawname;
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "Running command [%d] with input [%s].\n",
-                                dctx->cmdctx->cmd, rawname);
-@@ -3940,6 +3941,13 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
-     }
- 
-     if (changed) {
-+        char *fq_name = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
-+        if (!fq_name) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Could not create fq name\n");
-+            goto done;
-+        }
-+
-         for (i = 0; i < gnum; i++) {
-             id = groups[i];
- 
-@@ -3951,7 +3959,7 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
-             }
-         }
- 
--        to_sized_string(&delete_name, name);
-+        to_sized_string(&delete_name, fq_name);
-         ret = sss_mmap_cache_initgr_invalidate(nctx->initgr_mc_ctx,
-                                                &delete_name);
-         if (ret != EOK && ret != ENOENT) {
-@@ -3971,6 +3979,7 @@ static int fill_initgr(struct sss_packet *packet,
-                        struct sss_domain_info *dom,
-                        struct ldb_result *res,
-                        struct nss_ctx *nctx,
-+                       const char *mc_name,
-                        const char *name)
- {
-     uint8_t *body;
-@@ -4059,9 +4068,18 @@ static int fill_initgr(struct sss_packet *packet,
-     }
- 
-     if (nctx->initgr_mc_ctx) {
--        to_sized_string(&rawname, name);
-+        struct sized_string unique_name;
-+        char *fq_name = sss_tc_fqname(packet, dom->names, dom, name);
-+        if (!fq_name) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Could not create fq name\n");
-+            return ENOMEM;
-+        }
-+
-+        to_sized_string(&rawname, mc_name);
-+        to_sized_string(&unique_name, fq_name);
-         ret = sss_mmap_cache_initgr_store(&nctx->initgr_mc_ctx, &rawname,
--                                          num - skipped, gids);
-+                                          &unique_name, num - skipped, gids);
-         if (ret != EOK && ret != ENOMEM) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Failed to store user %s(%s) in mmap cache!\n",
-@@ -4089,7 +4107,7 @@ static int nss_cmd_initgr_send_reply(struct nss_dom_ctx *dctx)
-     }
- 
-     ret = fill_initgr(cctx->creq->out, dctx->domain, dctx->res, nctx,
--                      dctx->rawname);
-+                      dctx->mc_name, cmdctx->name);
-     if (ret) {
-         return ret;
-     }
-@@ -4137,8 +4155,10 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
-         name = sss_get_cased_name(dctx, cmdctx->name, dom->case_sensitive);
-         if (!name) return ENOMEM;
- 
--        name = sss_reverse_replace_space(dctx, name,
-+        name = sss_reverse_replace_space(cmdctx, name,
-                                          nctx->rctx->override_space);
-+        /* save name so it can be used in initgr reply */
-+        cmdctx->name = name;
-         if (name == NULL) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "sss_reverse_replace_space failed\n");
-diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
-index ab9e769b1f4d5d17a8c41429afce292298239bc5..62f4c543c628712810b6dfbc669c586c39ca609d 100644
---- a/src/responder/nss/nsssrv_mmap_cache.c
-+++ b/src/responder/nss/nsssrv_mmap_cache.c
-@@ -31,8 +31,8 @@
- #define SSS_AVG_PASSWD_PAYLOAD (MC_SLOT_SIZE * 4)
- /* short group name and no gids (private user group */
- #define SSS_AVG_GROUP_PAYLOAD (MC_SLOT_SIZE * 3)
--/* average place for 40 supplementary groups */
--#define SSS_AVG_INITGROUP_PAYLOAD (MC_SLOT_SIZE * 4)
-+/* average place for 40 supplementary groups + 2 names */
-+#define SSS_AVG_INITGROUP_PAYLOAD (MC_SLOT_SIZE * 5)
- 
- #define MC_NEXT_BARRIER(val) ((((val) + 1) & 0x00ffffff) | 0xf0000000)
- 
-@@ -965,6 +965,7 @@ done:
- 
- errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-                                     struct sized_string *name,
-+                                    struct sized_string *unique_name,
-                                     uint32_t num_groups,
-                                     uint8_t *gids_buf)
- {
-@@ -973,6 +974,7 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-     struct sss_mc_initgr_data *data;
-     size_t data_len;
-     size_t rec_len;
-+    size_t pos;
-     int ret;
- 
-     if (mcc == NULL) {
-@@ -980,20 +982,22 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-         return EINVAL;
-     }
- 
--    /* array of gids + name */
--    data_len = num_groups * sizeof(uint32_t) + name->len;
-+    /* array of gids + name + unique_name */
-+    data_len = num_groups * sizeof(uint32_t) + name->len + unique_name->len;
-     rec_len = sizeof(struct sss_mc_rec) + sizeof(struct sss_mc_initgr_data)
-               + data_len;
-     if (rec_len > mcc->dt_size) {
-         return ENOMEM;
-     }
- 
--    ret = sss_mc_get_record(_mcc, rec_len, name, &rec);
-+    /* use unique name for searching potential old records */
-+    ret = sss_mc_get_record(_mcc, rec_len, unique_name, &rec);
-     if (ret != EOK) {
-         return ret;
-     }
- 
-     data = (struct sss_mc_initgr_data *)rec->data;
-+    pos = 0;
- 
-     MC_RAISE_BARRIER(rec);
- 
-@@ -1001,16 +1005,22 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-      * Use the first key twice.
-      */
-     sss_mmap_set_rec_header(mcc, rec, rec_len, mcc->valid_time_slot,
--                            name->str, name->len, name->str, name->len);
-+                            name->str, name->len,
-+                            unique_name->str, unique_name->len);
- 
-     /* initgroups struct */
--    data->strs_len = name->len;
-+    data->strs_len = name->len + unique_name->len;
-     data->data_len = data_len;
--    data->reserved = MC_INVALID_VAL32;
-     data->num_groups = num_groups;
--    memcpy(data->gids, gids_buf, num_groups * sizeof(uint32_t));
--    memcpy(&data->gids[num_groups], name->str, name->len);
--    data->strs = data->name = MC_PTR_DIFF(&data->gids[num_groups], data);
-+    memcpy((char *)data->gids + pos, gids_buf, num_groups * sizeof(uint32_t));
-+    pos += num_groups * sizeof(uint32_t);
-+
-+    memcpy((char *)data->gids + pos, unique_name->str, unique_name->len);
-+    data->strs = data->unique_name = MC_PTR_DIFF((char *)data->gids + pos, data);
-+    pos += unique_name->len;
-+
-+    memcpy((char *)data->gids + pos, name->str, name->len);
-+    data->name = MC_PTR_DIFF((char *)data->gids + pos, data);
- 
-     MC_LOWER_BARRIER(rec);
- 
-diff --git a/src/responder/nss/nsssrv_mmap_cache.h b/src/responder/nss/nsssrv_mmap_cache.h
-index b09e4a6f8efa364ae7a6407bab9d8a2a2143c812..b84fbc8edef69db96c17a48a4862d63942297c66 100644
---- a/src/responder/nss/nsssrv_mmap_cache.h
-+++ b/src/responder/nss/nsssrv_mmap_cache.h
-@@ -53,6 +53,7 @@ errno_t sss_mmap_cache_gr_store(struct sss_mc_ctx **_mcc,
- 
- errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
-                                     struct sized_string *name,
-+                                    struct sized_string *unique_name,
-                                     uint32_t num_groups,
-                                     uint8_t *gids_buf);
- 
-diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h
-index e9f00b114975ef760aaaac45e6e91f6e40c52b9a..e5a2486f1fb9a8de39ec90f802f596b2c2f6af7f 100644
---- a/src/responder/nss/nsssrv_private.h
-+++ b/src/responder/nss/nsssrv_private.h
-@@ -79,6 +79,8 @@ struct nss_dom_ctx {
- 
-     /* Service-specific */
-     const char *protocol;
-+
-+    const char *mc_name;
- };
- 
- struct setent_step_ctx {
-diff --git a/src/util/mmap_cache.h b/src/util/mmap_cache.h
-index b5917b3c0973276e43e9fe160cec7528b1224f8f..22c1ae62d1ff0c816c23bd8b26140990d692134c 100644
---- a/src/util/mmap_cache.h
-+++ b/src/util/mmap_cache.h
-@@ -138,14 +138,15 @@ struct sss_mc_grp_data {
- };
- 
- struct sss_mc_initgr_data {
--    rel_ptr_t name;         /* ptr to name string, rel. to struct base addr */
-+    rel_ptr_t unique_name;  /* ptr to unique name string, rel. to struct base addr */
-+    rel_ptr_t name;         /* ptr to raw name string, rel. to struct base addr */
-     rel_ptr_t strs;         /* ptr to concatenation of all strings */
--    uint32_t reserved;
-     uint32_t strs_len;      /* length of strs */
-     uint32_t data_len;      /* all initgroups data len */
-     uint32_t num_groups;    /* number of groups */
-     uint32_t gids[0];       /* array of all groups
--                             * string with name is stored after gids */
-+                             * string with name and unique_name is stored
-+                             * after gids */
- };
- 
- #pragma pack()
--- 
-2.4.3
-
diff --git a/SOURCES/0044-test_utils-Fixing-assignment-discards-const-qualifie.patch b/SOURCES/0044-test_utils-Fixing-assignment-discards-const-qualifie.patch
new file mode 100644
index 0000000..053dc43
--- /dev/null
+++ b/SOURCES/0044-test_utils-Fixing-assignment-discards-const-qualifie.patch
@@ -0,0 +1,37 @@
+From 2af91b3728470b9831a748d51d081b117648ae91 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 26 Jul 2016 10:37:19 +0200
+Subject: [PATCH 44/44] test_utils: Fixing assignment discards 'const'
+ qualifier
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/cmocka/test_utils.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index 4c72a59437105e683cec2d39c36951aeff63767b..5349accc5c6b55f7d725bfdeaf318b90289880dd 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -1806,13 +1806,13 @@ static void test_sss_get_domain_mappings_content(void **state)
+     assert_non_null(c);
+     c->forest_root = find_domain_by_name(dom, "subdom1.dom", true);
+     assert_non_null(c->forest_root);
+-    c->forest = "subdom1.dom";
++    c->forest = discard_const_p(char, "subdom1.dom");
+ 
+     c = find_domain_by_name(dom, "subdom3.dom", true);
+     assert_non_null(c);
+     c->forest_root = find_domain_by_name(dom, "subdom1.dom", true);
+     assert_non_null(c->forest_root);
+-    c->forest = "subdom1.dom";
++    c->forest = discard_const_p(char, "subdom1.dom");
+ 
+     ret = sss_get_domain_mappings_content(test_ctx, dom, &content);
+     assert_int_equal(ret, EOK);
+-- 
+2.4.11
+
diff --git a/SOURCES/0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch b/SOURCES/0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch
new file mode 100644
index 0000000..bd9f1d8
--- /dev/null
+++ b/SOURCES/0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch
@@ -0,0 +1,85 @@
+From 9812095cc83c7258584235528d355c301c492b92 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 12 Jul 2016 17:09:00 +0200
+Subject: [PATCH 45/62] IPA: make ipa_resolve_user_list_{send|recv} public and
+ allow AD users
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit f2e8a7c3230fac11175c0bd17c14c66a8e9b25ad)
+---
+ src/providers/ipa/ipa_id.c | 20 ++++++++++++++++----
+ src/providers/ipa/ipa_id.h |  8 ++++++++
+ 2 files changed, 24 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index e092cd2f80d3c102f88a9bc48a352e1a140b14e8..7cc79f92b5dcd481706353d403125c46d587e7f6 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -71,7 +71,7 @@ struct ipa_resolve_user_list_state {
+ 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 *
++struct tevent_req *
+ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+                            struct ipa_id_ctx *ipa_ctx,
+                            const char *domain_name,
+@@ -132,7 +132,14 @@ 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 = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx, ar);
++    if (strcasecmp(state->domain_name,
++                   state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) {
++        subreq = ipa_subdomain_account_send(state, state->ev, state->ipa_ctx,
++                                            ar);
++    } else {
++        subreq = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx,
++                                              ar);
++    }
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct_req_send failed.\n");
+         return ENOMEM;
+@@ -151,7 +158,12 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq)
+                                             struct ipa_resolve_user_list_state);
+     int ret;
+ 
+-    ret = ipa_id_get_account_info_recv(subreq, &state->dp_error);
++    if (strcasecmp(state->domain_name,
++                   state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) {
++        ret = ipa_subdomain_account_recv(subreq, &state->dp_error);
++    } else {
++        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);
+@@ -182,7 +194,7 @@ done:
+     return;
+ }
+ 
+-static int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error)
++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);
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index 17db5226a29a54485f7b26eb9853ef2380426bdf..485fa3f8e6af48ddcf1178c3486456753035c948 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -135,4 +135,12 @@ struct tevent_req *ipa_get_subdom_acct_process_pac_send(TALLOC_CTX *mem_ctx,
+                                                    struct ldb_message *user_msg);
+ 
+ errno_t ipa_get_subdom_acct_process_pac_recv(struct tevent_req *req);
++
++struct tevent_req *
++ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
++                           struct ipa_id_ctx *ipa_ctx,
++                           const char *domain_name,
++                           struct ldb_message_element *users);
++int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error);
++
+ #endif
+-- 
+2.4.11
+
diff --git a/SOURCES/0045-test_memory_cache-Add-test-for-initgroups-mc-with-fq.patch b/SOURCES/0045-test_memory_cache-Add-test-for-initgroups-mc-with-fq.patch
deleted file mode 100644
index af7a5dd..0000000
--- a/SOURCES/0045-test_memory_cache-Add-test-for-initgroups-mc-with-fq.patch
+++ /dev/null
@@ -1,187 +0,0 @@
-From b54fa4dacbb9cb225159d21976b637a78e461060 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 24 Jul 2015 15:13:01 +0200
-Subject: [PATCH 45/47] test_memory_cache: Add test for initgroups mc with fq
- names
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit cb8c24707275c5bda7310d67e7f46c75d3ac36ea)
----
- src/tests/intg/test_memory_cache.py | 140 +++++++++++++++++++++++++++++++++++-
- 1 file changed, 138 insertions(+), 2 deletions(-)
-
-diff --git a/src/tests/intg/test_memory_cache.py b/src/tests/intg/test_memory_cache.py
-index 5a1f07651b70a5bf1fbacceeae6825ea4341e3b5..12ce3c5054fe76560e31137d88043baf20641d3a 100644
---- a/src/tests/intg/test_memory_cache.py
-+++ b/src/tests/intg/test_memory_cache.py
-@@ -106,8 +106,7 @@ def create_sssd_fixture(request):
-     request.addfinalizer(teardown)
- 
- 
--@pytest.fixture
--def sanity_rfc2307(request, ldap_conn):
-+def load_data_to_ldap(request, ldap_conn):
-     ent_list = ldap_ent.List(LDAP_BASE_DN)
-     ent_list.add_user("user1", 1001, 2001)
-     ent_list.add_user("user2", 1002, 2002)
-@@ -128,6 +127,64 @@ def sanity_rfc2307(request, ldap_conn):
-     ent_list.add_group("group2x", 2020, ["user21", "user22", "user23"])
-     create_ldap_fixture(request, ldap_conn, ent_list)
- 
-+
-+@pytest.fixture
-+def sanity_rfc2307(request, ldap_conn):
-+    load_data_to_ldap(request, ldap_conn)
-+
-+    conf = unindent("""\
-+        [sssd]
-+        config_file_version = 2
-+        domains             = LDAP
-+        services            = nss
-+
-+        [nss]
-+
-+        [domain/LDAP]
-+        ldap_auth_disable_tls_never_use_in_production = true
-+        ldap_schema         = rfc2307
-+        id_provider         = ldap
-+        auth_provider       = ldap
-+        sudo_provider       = ldap
-+        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
-+        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
-+    """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+@pytest.fixture
-+def fqname_rfc2307(request, ldap_conn):
-+    load_data_to_ldap(request, ldap_conn)
-+
-+    conf = unindent("""\
-+        [sssd]
-+        config_file_version = 2
-+        domains             = LDAP
-+        services            = nss
-+
-+        [nss]
-+
-+        [domain/LDAP]
-+        ldap_auth_disable_tls_never_use_in_production = true
-+        ldap_schema         = rfc2307
-+        id_provider         = ldap
-+        auth_provider       = ldap
-+        sudo_provider       = ldap
-+        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
-+        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
-+        use_fully_qualified_names = true
-+    """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+@pytest.fixture
-+def fqname_case_insensitive_rfc2307(request, ldap_conn):
-+    load_data_to_ldap(request, ldap_conn)
-+
-     conf = unindent("""\
-         [sssd]
-         config_file_version = 2
-@@ -144,6 +201,8 @@ def sanity_rfc2307(request, ldap_conn):
-         sudo_provider       = ldap
-         ldap_uri            = {ldap_conn.ds_inst.ldap_url}
-         ldap_search_base    = {ldap_conn.ds_inst.base_dn}
-+        use_fully_qualified_names = true
-+        case_sensitive = false
-     """).format(**locals())
-     create_conf_fixture(request, conf)
-     create_sssd_fixture(request)
-@@ -345,3 +404,80 @@ def test_initgroups_with_mc(ldap_conn, sanity_rfc2307):
-     test_initgroups(ldap_conn, sanity_rfc2307)
-     stop_sssd()
-     test_initgroups(ldap_conn, sanity_rfc2307)
-+
-+
-+def test_initgroups_fqname_with_mc(ldap_conn, fqname_rfc2307):
-+    assert_user_gids_equal('user1@LDAP', [2000, 2001])
-+    stop_sssd()
-+    assert_user_gids_equal('user1@LDAP', [2000, 2001])
-+
-+
-+def assert_initgroups_equal(user, primary_gid, expected_gids):
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups(user, primary_gid)
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user %s, %d" % (user, errno)
-+
-+    assert sorted(gids) == sorted(expected_gids), \
-+        "result: %s\n expected %s" % (
-+            ", ".join(["%s" % s for s in sorted(gids)]),
-+            ", ".join(["%s" % s for s in sorted(expected_gids)])
-+        )
-+
-+
-+def assert_stored_last_initgroups(user1_case1, user1_case2, user1_case_last,
-+                                  primary_gid, expected_gids):
-+
-+    assert_initgroups_equal(user1_case1, primary_gid, expected_gids)
-+    assert_initgroups_equal(user1_case2, primary_gid, expected_gids)
-+    assert_initgroups_equal(user1_case_last, primary_gid, expected_gids)
-+    stop_sssd()
-+
-+    user = user1_case1
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups(user, primary_gid)
-+    assert res == sssd_id.NssReturnCode.UNAVAIL, \
-+        "Initgroups for user shoudl fail user %s, %d" % (user, res)
-+
-+    user = user1_case2
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups(user, primary_gid)
-+    assert res == sssd_id.NssReturnCode.UNAVAIL, \
-+        "Initgroups for user shoudl fail user %s, %d" % (user, res)
-+
-+    # Just last invocation of initgroups shoudl PASS
-+    # Otherwise, we would not be able to invalidate it
-+    assert_initgroups_equal(user1_case_last, primary_gid, expected_gids)
-+
-+
-+def test_initgroups_case_insensitive_with_mc1(ldap_conn,
-+                                              fqname_case_insensitive_rfc2307):
-+    user1_case1 = 'User1@LDAP'
-+    user1_case2 = 'uSer1@LDAP'
-+    user1_case_last = 'usEr1@LDAP'
-+    primary_gid = 2001
-+    expected_gids = [2000, 2001]
-+
-+    assert_stored_last_initgroups(user1_case1, user1_case2, user1_case_last,
-+                                  primary_gid, expected_gids)
-+
-+
-+def test_initgroups_case_insensitive_with_mc2(ldap_conn,
-+                                              fqname_case_insensitive_rfc2307):
-+    user1_case1 = 'usEr1@LDAP'
-+    user1_case2 = 'User1@LDAP'
-+    user1_case_last = 'uSer1@LDAP'
-+    primary_gid = 2001
-+    expected_gids = [2000, 2001]
-+
-+    assert_stored_last_initgroups(user1_case1, user1_case2, user1_case_last,
-+                                  primary_gid, expected_gids)
-+
-+
-+def test_initgroups_case_insensitive_with_mc3(ldap_conn,
-+                                              fqname_case_insensitive_rfc2307):
-+    user1_case1 = 'uSer1@LDAP'
-+    user1_case2 = 'usEr1@LDAP'
-+    user1_case_last = 'User1@LDAP'
-+    primary_gid = 2001
-+    expected_gids = [2000, 2001]
-+
-+    assert_stored_last_initgroups(user1_case1, user1_case2, user1_case_last,
-+                                  primary_gid, expected_gids)
--- 
-2.4.3
-
diff --git a/SOURCES/0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch b/SOURCES/0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch
new file mode 100644
index 0000000..9b41801
--- /dev/null
+++ b/SOURCES/0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch
@@ -0,0 +1,115 @@
+From c17e7bc80adf9741054e53dc6e8d8f6afa273e18 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 12 Jul 2016 17:09:40 +0200
+Subject: [PATCH 46/62] IPA: expand ghost members of AD groups in server-mode
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 160ba891ec483c5b7d2a3fcca5bd992fc790efe0)
+---
+ src/providers/ipa/ipa_subdomains_id.c | 79 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 78 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 65bfd33765d5799037075e599049761f18466bb2..542c596a983bcb48f4eac699f78eb956326cefa2 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -1201,6 +1201,67 @@ fail:
+     return;
+ }
+ 
++static void ipa_check_ghost_members_done(struct tevent_req *subreq);
++static errno_t ipa_check_ghost_members(struct tevent_req *req)
++{
++    struct ipa_get_ad_acct_state *state = tevent_req_data(req,
++                                                struct ipa_get_ad_acct_state);
++    errno_t ret;
++    struct tevent_req *subreq;
++    struct ldb_message_element *ghosts = NULL;
++
++
++    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");
++            return EOK;
++        } else if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n");
++            return ret;
++        }
++    }
++
++    ghosts = ldb_msg_find_element(state->obj_msg, SYSDB_GHOST);
++
++    if (ghosts != NULL) {
++        /* Resolve ghost members */
++        subreq = ipa_resolve_user_list_send(state, state->ev,
++                                            state->ipa_ctx,
++                                            state->obj_dom->name,
++                                            ghosts);
++        if (subreq == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list_send failed.\n");
++            return ENOMEM;
++        }
++        tevent_req_set_callback(subreq, ipa_check_ghost_members_done, req);
++        return EAGAIN;
++    }
++
++    return EOK;
++}
++
++static void ipa_check_ghost_members_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                struct tevent_req);
++    int ret;
++
++    ret = ipa_resolve_user_list_recv(subreq, NULL);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list request failed [%d]\n",
++                                  ret);
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++    return;
++}
++
+ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+ {
+     struct ipa_get_ad_acct_state *state = tevent_req_data(req,
+@@ -1228,11 +1289,27 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+     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) {
++            && entry_type != BE_REQ_BY_SECID
++            && entry_type != BE_REQ_GROUP) {
+         tevent_req_done(req);
+         return EOK;
+     }
+ 
++    /* expand ghost members, if any, to get group members with overrides
++     * right. */
++    if (entry_type == BE_REQ_GROUP) {
++        ret = ipa_check_ghost_members(req);
++        if (ret == EOK) {
++            tevent_req_done(req);
++            return EOK;
++        } else if (ret == EAGAIN) {
++            return EOK;
++        } else {
++            DEBUG(SSSDBG_OP_FAILURE, "ipa_check_ghost_members failed.\n");
++            return ret;
++        }
++    }
++
+     /* Replace ID with name in search filter */
+     if ((entry_type == BE_REQ_USER && state->ar->filter_type == BE_FILTER_IDNUM)
+             || (entry_type == BE_REQ_INITGROUPS
+-- 
+2.4.11
+
diff --git a/SOURCES/0046-test_memory_cache-Test-mmap-cache-after-initgroups.patch b/SOURCES/0046-test_memory_cache-Test-mmap-cache-after-initgroups.patch
deleted file mode 100644
index e258a2f..0000000
--- a/SOURCES/0046-test_memory_cache-Test-mmap-cache-after-initgroups.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-From 2d4478e11739f3934d788a9c47c8d990e41afd67 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 4 Aug 2015 11:59:35 +0200
-Subject: [PATCH 46/47] test_memory_cache: Test mmap cache after initgroups
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/tests/intg/test_memory_cache.py | 89 +++++++++++++++++++++++++++++++++++++
- 1 file changed, 89 insertions(+)
-
-diff --git a/src/tests/intg/test_memory_cache.py b/src/tests/intg/test_memory_cache.py
-index 12ce3c5054fe76560e31137d88043baf20641d3a..c809a4b6daacfd04834db46d21bfb97ad025ada6 100644
---- a/src/tests/intg/test_memory_cache.py
-+++ b/src/tests/intg/test_memory_cache.py
-@@ -19,6 +19,7 @@
- import os
- import stat
- import ent
-+import grp
- import config
- import signal
- import subprocess
-@@ -481,3 +482,91 @@ def test_initgroups_case_insensitive_with_mc3(ldap_conn,
- 
-     assert_stored_last_initgroups(user1_case1, user1_case2, user1_case_last,
-                                   primary_gid, expected_gids)
-+
-+
-+def run_simple_test_with_initgroups():
-+    ent.assert_passwd_by_name(
-+        'user1',
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1001,
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+
-+    ent.assert_group_by_name(
-+        "group1",
-+        dict(mem=ent.contains_only("user1", "user11", "user21")))
-+    ent.assert_group_by_gid(
-+        2001,
-+        dict(mem=ent.contains_only("user1", "user11", "user21")))
-+
-+    # unrelated group to user1
-+    ent.assert_group_by_name(
-+        "group2",
-+        dict(mem=ent.contains_only("user2", "user12", "user22")))
-+    ent.assert_group_by_gid(
-+        2002,
-+        dict(mem=ent.contains_only("user2", "user12", "user22")))
-+
-+    assert_initgroups_equal("user1", 2001, [2000, 2001])
-+
-+
-+def test_invalidation_of_gids_after_initgroups(ldap_conn, sanity_rfc2307):
-+
-+    # the sssd cache was empty and not all user's group were
-+    # resolved with getgr{nm,gid}. Therefore there is a change in
-+    # group membership => user groups should be invalidated
-+    run_simple_test_with_initgroups()
-+    assert_initgroups_equal("user1", 2001, [2000, 2001])
-+
-+    stop_sssd()
-+
-+    ent.assert_passwd_by_name(
-+        'user1',
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1001,
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+
-+    # unrelated group to user1 must be returned
-+    ent.assert_group_by_name(
-+        "group2",
-+        dict(mem=ent.contains_only("user2", "user12", "user22")))
-+    ent.assert_group_by_gid(
-+        2002,
-+        dict(mem=ent.contains_only("user2", "user12", "user22")))
-+
-+    assert_initgroups_equal("user1", 2001, [2000, 2001])
-+
-+    # user groups must be invalidated
-+    for group in ["group1", "group0x"]:
-+        with pytest.raises(KeyError):
-+            grp.getgrnam(group)
-+
-+    for gid in [2000, 2001]:
-+        with pytest.raises(KeyError):
-+            grp.getgrgid(gid)
-+
-+
-+def test_initgroups_without_change_in_membership(ldap_conn, sanity_rfc2307):
-+
-+    # the sssd cache was empty and not all user's group were
-+    # resolved with getgr{nm,gid}. Therefore there is a change in
-+    # group membership => user groups should be invalidated
-+    run_simple_test_with_initgroups()
-+
-+    # invalidate cache
-+    subprocess.call(["sss_cache", "-E"])
-+
-+    # all users and groups will be just refreshed from LDAP
-+    # but there will not be a change in group membership
-+    # user groups should not be invlaidated
-+    run_simple_test_with_initgroups()
-+
-+    stop_sssd()
-+
-+    # everything should be in memory cache
-+    run_simple_test_with_initgroups()
--- 
-2.4.3
-
diff --git a/SOURCES/0047-sysdb-add-sysdb_get_user_members_recursively.patch b/SOURCES/0047-sysdb-add-sysdb_get_user_members_recursively.patch
new file mode 100644
index 0000000..037cdd0
--- /dev/null
+++ b/SOURCES/0047-sysdb-add-sysdb_get_user_members_recursively.patch
@@ -0,0 +1,103 @@
+From a1e606d051c54dd603bf09adb2bd6d0d7db2663f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 20 Jul 2016 18:42:27 +0200
+Subject: [PATCH 47/62] sysdb: add sysdb_get_user_members_recursively()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 17bfd9f69251781140e4b2b55ffeb649d7a79e86)
+---
+ src/db/sysdb.h     |  5 +++++
+ src/db/sysdb_ops.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 66 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 0cc550a4c389b4a1a2b78aff760f4b5cbf94e17f..405f89e2f1ac6fabc06e77c345de8693845f9d92 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1257,6 +1257,11 @@ errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
+                                   const char ***_dns,
+                                   size_t *_n);
+ 
++errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx,
++                                           struct sss_domain_info *dom,
++                                           struct ldb_dn *group_dn,
++                                           struct ldb_result **members);
++
+ errno_t sysdb_handle_original_uuid(const char *orig_name,
+                                    struct sysdb_attrs *src_attrs,
+                                    const char *src_name,
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 19d6be03ede1bcec3bc7a4ed777e326460d80591..9a8a55ed8aa69e1638d0ab6f636e43baa3d0bfea 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -4711,6 +4711,67 @@ done:
+     return ret;
+ }
+ 
++errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx,
++                                           struct sss_domain_info *dom,
++                                           struct ldb_dn *group_dn,
++                                           struct ldb_result **members)
++{
++    TALLOC_CTX *tmp_ctx;
++    int ret;
++    size_t count;
++    struct ldb_result *res;
++    struct ldb_dn *base_dn;
++    char *filter;
++    const char *attrs[] = SYSDB_PW_ATTRS;
++    struct ldb_message **msgs;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    base_dn = sysdb_base_dn(dom->sysdb, tmp_ctx);
++    if (base_dn == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_base_dn failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    filter = talloc_asprintf(tmp_ctx, "(&("SYSDB_UC")("SYSDB_MEMBEROF"=%s))",
++                             ldb_dn_get_linearized(group_dn));
++    if (filter == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sysdb_search_entry(tmp_ctx, dom->sysdb, base_dn, LDB_SCOPE_SUBTREE,
++                             filter, attrs, &count, &msgs);
++
++    res = talloc_zero(tmp_ctx, struct ldb_result);
++    if (res == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    res->count = count;
++    res->msgs = talloc_steal(res, msgs);
++
++    ret = EOK;
++
++done:
++    if (ret == EOK) {
++        *members = talloc_steal(mem_ctx, res);
++    } else if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
++    } else {
++        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
++    }
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ errno_t sysdb_handle_original_uuid(const char *orig_name,
+                                    struct sysdb_attrs *src_attrs,
+                                    const char *src_name,
+-- 
+2.4.11
+
diff --git a/SOURCES/0047-test_memory_cache-Test-invalidation-with-sss_cache.patch b/SOURCES/0047-test_memory_cache-Test-invalidation-with-sss_cache.patch
deleted file mode 100644
index 9706b50..0000000
--- a/SOURCES/0047-test_memory_cache-Test-invalidation-with-sss_cache.patch
+++ /dev/null
@@ -1,207 +0,0 @@
-From aae797abf3bfcfda124f111d8b4e805e77bee691 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 4 Aug 2015 12:47:58 +0200
-Subject: [PATCH 47/47] test_memory_cache: Test invalidation with sss_cache
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/tests/intg/test_memory_cache.py | 176 ++++++++++++++++++++++++++++++++++++
- 1 file changed, 176 insertions(+)
-
-diff --git a/src/tests/intg/test_memory_cache.py b/src/tests/intg/test_memory_cache.py
-index c809a4b6daacfd04834db46d21bfb97ad025ada6..1fd577e652d278c35211b55c871797a3dee98b13 100644
---- a/src/tests/intg/test_memory_cache.py
-+++ b/src/tests/intg/test_memory_cache.py
-@@ -20,6 +20,7 @@ import os
- import stat
- import ent
- import grp
-+import pwd
- import config
- import signal
- import subprocess
-@@ -570,3 +571,178 @@ def test_initgroups_without_change_in_membership(ldap_conn, sanity_rfc2307):
- 
-     # everything should be in memory cache
-     run_simple_test_with_initgroups()
-+
-+
-+def assert_mc_records_for_user1():
-+    ent.assert_passwd_by_name(
-+        'user1',
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1001,
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+
-+    ent.assert_group_by_name(
-+        "group1",
-+        dict(mem=ent.contains_only("user1", "user11", "user21")))
-+    ent.assert_group_by_gid(
-+        2001,
-+        dict(mem=ent.contains_only("user1", "user11", "user21")))
-+    ent.assert_group_by_name(
-+        "group0x",
-+        dict(mem=ent.contains_only("user1", "user2", "user3")))
-+    ent.assert_group_by_gid(
-+        2000,
-+        dict(mem=ent.contains_only("user1", "user2", "user3")))
-+
-+    assert_initgroups_equal("user1", 2001, [2000, 2001])
-+
-+
-+def assert_missing_mc_records_for_user1():
-+    with pytest.raises(KeyError):
-+        pwd.getpwnam("user1")
-+    with pytest.raises(KeyError):
-+        pwd.getpwuid(1001)
-+
-+    for gid in [2000, 2001]:
-+        with pytest.raises(KeyError):
-+            grp.getgrgid(gid)
-+    for group in ["group0x", "group1"]:
-+        with pytest.raises(KeyError):
-+            grp.getgrnam(group)
-+
-+    (res, err, _) = sssd_id.call_sssd_initgroups("user1", 2001)
-+    assert res == sssd_id.NssReturnCode.UNAVAIL, \
-+        "Initgroups should not find anything after invalidation of mc.\n" \
-+        "User %s, errno:%d" % (user, err)
-+
-+
-+def test_invalidate_user_before_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    subprocess.call(["sss_cache", "-u", "user1"])
-+    stop_sssd()
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_user_after_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    stop_sssd()
-+    subprocess.call(["sss_cache", "-u", "user1"])
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_users_before_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    subprocess.call(["sss_cache", "-U"])
-+    stop_sssd()
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_users_after_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    stop_sssd()
-+    subprocess.call(["sss_cache", "-U"])
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_group_before_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    subprocess.call(["sss_cache", "-g", "group1"])
-+    stop_sssd()
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_group_after_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    stop_sssd()
-+    subprocess.call(["sss_cache", "-g", "group1"])
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_groups_before_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    subprocess.call(["sss_cache", "-G"])
-+    stop_sssd()
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_groups_after_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    stop_sssd()
-+    subprocess.call(["sss_cache", "-G"])
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_everything_before_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    subprocess.call(["sss_cache", "-E"])
-+    stop_sssd()
-+
-+    assert_missing_mc_records_for_user1()
-+
-+
-+def test_invalidate_everything_after_stop(ldap_conn, sanity_rfc2307):
-+    # initialize cache with full ID
-+    (res, errno, _) = sssd_id.get_user_groups("user1")
-+    assert res == sssd_id.NssReturnCode.SUCCESS, \
-+        "Could not find groups for user1 %s, %d" % errno
-+    assert_mc_records_for_user1()
-+
-+    stop_sssd()
-+    subprocess.call(["sss_cache", "-E"])
-+
-+    assert_missing_mc_records_for_user1()
--- 
-2.4.3
-
diff --git a/SOURCES/0048-krb5-utils-add-sss_krb5_realm_has_proxy.patch b/SOURCES/0048-krb5-utils-add-sss_krb5_realm_has_proxy.patch
deleted file mode 100644
index 5ffa313..0000000
--- a/SOURCES/0048-krb5-utils-add-sss_krb5_realm_has_proxy.patch
+++ /dev/null
@@ -1,163 +0,0 @@
-From 5654903a0be960a2ec5be5bfb77cc3263e11e58c Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 30 Jul 2015 16:52:42 +0200
-Subject: [PATCH 48/57] krb5 utils: add sss_krb5_realm_has_proxy()
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                               |  1 +
- src/tests/krb5_proxy_check_test_data.conf |  8 +++++
- src/tests/krb5_utils-tests.c              | 17 +++++++++
- src/util/sss_krb5.c                       | 57 +++++++++++++++++++++++++++++++
- src/util/sss_krb5.h                       |  2 ++
- 5 files changed, 85 insertions(+)
- create mode 100644 src/tests/krb5_proxy_check_test_data.conf
-
-diff --git a/Makefile.am b/Makefile.am
-index 5345d90d22cd285a5268ac50a6b527645acdb351..8b64317d6dce9a1ee8614916395b9afd9f11f382 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -366,6 +366,7 @@ dist_noinst_SCRIPTS = \
-     src/tests/pysss_murmur-test.py2.sh \
-     src/tests/pysss_murmur-test.py3.sh \
-     src/tests/python-test.py \
-+    src/tests/krb5_proxy_check_test_data.conf \
-     $(NULL)
- 
- dist_noinst_DATA = \
-diff --git a/src/tests/krb5_proxy_check_test_data.conf b/src/tests/krb5_proxy_check_test_data.conf
-new file mode 100644
-index 0000000000000000000000000000000000000000..eb74dbfa47d643668688d5c789b5962698c3d17c
---- /dev/null
-+++ b/src/tests/krb5_proxy_check_test_data.conf
-@@ -0,0 +1,8 @@
-+[realms]
-+  REALM = {
-+    kdc = hello
-+  }
-+
-+  REALM_PROXY = {
-+    kdc = https://hello
-+  }
-diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
-index 650ed48592768c214156d5274e654a447be98e36..9a25b09cdc136651a7117327036dd51b8ff23606 100644
---- a/src/tests/krb5_utils-tests.c
-+++ b/src/tests/krb5_utils-tests.c
-@@ -684,6 +684,22 @@ START_TEST(test_parse_krb5_map_user)
- }
- END_TEST
- 
-+START_TEST(test_sss_krb5_realm_has_proxy)
-+{
-+    krb5_error_code kerr;
-+    long perr;
-+
-+    fail_unless(sss_krb5_realm_has_proxy(NULL) == false);
-+
-+    setenv("KRB5_CONFIG", "/dev/null", 1);
-+    fail_unless(sss_krb5_realm_has_proxy("REALM") == false);
-+
-+    setenv("KRB5_CONFIG", ABS_SRC_DIR"/src/tests/krb5_proxy_check_test_data.conf", 1);
-+    fail_unless(sss_krb5_realm_has_proxy("REALM") == false);
-+    fail_unless(sss_krb5_realm_has_proxy("REALM_PROXY") == true);
-+}
-+END_TEST
-+
- Suite *krb5_utils_suite (void)
- {
-     Suite *s = suite_create ("krb5_utils");
-@@ -723,6 +739,7 @@ Suite *krb5_utils_suite (void)
-     TCase *tc_krb5_helpers = tcase_create("Helper functions");
-     tcase_add_test(tc_krb5_helpers, test_compare_principal_realm);
-     tcase_add_test(tc_krb5_helpers, test_parse_krb5_map_user);
-+    tcase_add_test(tc_krb5_helpers, test_sss_krb5_realm_has_proxy);
-     suite_add_tcase(s, tc_krb5_helpers);
- 
-     return s;
-diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
-index e5c2121da575b174c8b6a9a90835f2c97f807f37..2e128db3c9fcb0dfa88cab1ed799abd714ad8ba6 100644
---- a/src/util/sss_krb5.c
-+++ b/src/util/sss_krb5.c
-@@ -20,6 +20,7 @@
- #include <stdio.h>
- #include <errno.h>
- #include <talloc.h>
-+#include <profile.h>
- 
- #include "config.h"
- 
-@@ -1069,3 +1070,59 @@ krb5_error_code sss_krb5_kt_have_content(krb5_context context,
-     return 0;
- #endif
- }
-+
-+#define KDC_PROXY_INDICATOR "https://"
-+#define KDC_PROXY_INDICATOR_LEN (sizeof(KDC_PROXY_INDICATOR) - 1)
-+
-+bool sss_krb5_realm_has_proxy(const char *realm)
-+{
-+    krb5_context context = NULL;
-+    krb5_error_code kerr;
-+    struct _profile_t *profile = NULL;
-+    const char  *profile_path[4] = {"realms", NULL, "kdc", NULL};
-+    char **list = NULL;
-+    bool res = false;
-+    size_t c;
-+
-+    if (realm == NULL) {
-+        return false;
-+    }
-+
-+    kerr = krb5_init_context(&context);
-+    if (kerr != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "krb5_init_context failed.\n");
-+        return false;
-+    }
-+
-+    kerr = krb5_get_profile(context, &profile);
-+    if (kerr != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "krb5_get_profile failed.\n");
-+        goto done;
-+    }
-+
-+    profile_path[1] = realm;
-+
-+    kerr = profile_get_values(profile, profile_path, &list);
-+    if (kerr != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "profile_get_values failed.\n");
-+        goto done;
-+    }
-+
-+    for (c = 0; list[c] != NULL; c++) {
-+        if (strncasecmp(KDC_PROXY_INDICATOR, list[c],
-+                        KDC_PROXY_INDICATOR_LEN) == 0) {
-+            DEBUG(SSSDBG_TRACE_ALL,
-+                  "Found KDC Proxy indicator [%s] in [%s].\n",
-+                  KDC_PROXY_INDICATOR, list[c]);
-+            res = true;
-+            break;
-+        }
-+    }
-+
-+done:
-+    profile_free_list(list);
-+    profile_release(profile);
-+    krb5_free_context(context);
-+
-+    return res;
-+}
-diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
-index 462dbbe0bda8969432c8ac2f062a0123c1f098f0..fdaeb49314764e096448f342a054dc6938f0c248 100644
---- a/src/util/sss_krb5.h
-+++ b/src/util/sss_krb5.h
-@@ -189,4 +189,6 @@ sss_krb5_get_primary(TALLOC_CTX *mem_ctx,
- 
- krb5_error_code sss_krb5_kt_have_content(krb5_context context,
-                                          krb5_keytab keytab);
-+
-+bool sss_krb5_realm_has_proxy(const char *realm);
- #endif /* __SSS_KRB5_H__ */
--- 
-2.4.3
-
diff --git a/SOURCES/0048-views-properly-override-group-member-names.patch b/SOURCES/0048-views-properly-override-group-member-names.patch
new file mode 100644
index 0000000..c86debf
--- /dev/null
+++ b/SOURCES/0048-views-properly-override-group-member-names.patch
@@ -0,0 +1,455 @@
+From 11f6fcedb0ac04528dd319fcf95d1fbaa4ea8bd1 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 7 Jul 2016 18:54:02 +0200
+Subject: [PATCH 48/62] views: properly override group member names
+
+Resolves https://fedorahosted.org/sssd/ticket/2948
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 1594701fbdc341069e11cff9a85e7a795e52db3d)
+---
+ src/db/sysdb.h                  |   3 +-
+ src/db/sysdb_search.c           |  99 ++++++++++++++++-------------
+ src/db/sysdb_views.c            | 136 ++++++++++++++++++----------------------
+ src/responder/nss/nsssrv_cmd.c  |   7 ++-
+ src/tests/cmocka/test_nss_srv.c |  18 +++---
+ 5 files changed, 134 insertions(+), 129 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 405f89e2f1ac6fabc06e77c345de8693845f9d92..a27552224bb40bd07c7dee4dfe35bfb7a0b4f2c3 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -572,7 +572,8 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+                                       const char **req_attrs);
+ 
+ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+-                                         struct ldb_message *obj);
++                                         struct ldb_message *obj,
++                                         bool expect_override_dn);
+ 
+ errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
+                                   struct sss_domain_info *domain,
+diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
+index e40b36c38e28992e185447497d1bf69cabc09821..cfee5784dbadd692f30d0758e7e5c3c9fb2814cb 100644
+--- a/src/db/sysdb_search.c
++++ b/src/db/sysdb_search.c
+@@ -771,28 +771,33 @@ int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx,
+ 
+     /* If there are views we have to check if override values must be added to
+      * the original object. */
+-    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+-        if (!is_local_view(domain->view_name)) {
+-            el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
+-            if (el != NULL && el->num_values != 0) {
+-                DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost "
+-                      "entries which must be resolved before overrides can be "
+-                      "applied.\n",
+-                      ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
+-                ret = ENOENT;
++    if (orig_obj->count == 1) {
++        if (DOM_HAS_VIEWS(domain)) {
++            if (!is_local_view(domain->view_name)) {
++                el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
++                if (el != NULL && el->num_values != 0) {
++                    DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost "
++                          "entries which must be resolved before overrides can be "
++                          "applied.\n",
++                          ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
++                    ret = ENOENT;
++                    goto done;
++                }
++            }
++
++            ret = sysdb_add_overrides_to_object(domain, orig_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;
+             }
+         }
+ 
+-        ret = sysdb_add_overrides_to_object(domain, orig_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;
+-        }
+-
+-        ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0]);
++        /* Must be called even without views to check to
++         * SYSDB_DEFAULT_OVERRIDE_NAME */
++        ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0],
++                                               DOM_HAS_VIEWS(domain));
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+                   "sysdb_add_group_member_overrides failed.\n");
+@@ -922,28 +927,33 @@ int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx,
+ 
+     /* If there are views we have to check if override values must be added to
+      * the original object. */
+-    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+-        if (!is_local_view(domain->view_name)) {
+-            el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
+-            if (el != NULL && el->num_values != 0) {
+-                DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost "
+-                      "entries which must be resolved before overrides can be "
+-                      "applied.\n",
+-                      ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
+-                ret = ENOENT;
++    if (orig_obj->count == 1) {
++        if (DOM_HAS_VIEWS(domain)) {
++            if (!is_local_view(domain->view_name)) {
++                el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
++                if (el != NULL && el->num_values != 0) {
++                    DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost "
++                          "entries which must be resolved before overrides can be "
++                          "applied.\n",
++                          ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
++                    ret = ENOENT;
++                    goto done;
++                }
++            }
++
++            ret = sysdb_add_overrides_to_object(domain, orig_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;
+             }
+         }
+ 
+-        ret = sysdb_add_overrides_to_object(domain, orig_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;
+-        }
+-
+-        ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0]);
++        /* Must be called even without views to check to
++         * SYSDB_DEFAULT_OVERRIDE_NAME */
++        ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0],
++                                               DOM_HAS_VIEWS(domain));
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+                   "sysdb_add_group_member_overrides failed.\n");
+@@ -1157,8 +1167,8 @@ int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    if (DOM_HAS_VIEWS(domain)) {
+-        for (c = 0; c < res->count; c++) {
++    for (c = 0; c < res->count; c++) {
++        if (DOM_HAS_VIEWS(domain)) {
+             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
+@@ -1167,13 +1177,14 @@ int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx,
+                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+                 goto done;
+             }
++        }
+ 
+-            ret = sysdb_add_group_member_overrides(domain, res->msgs[c]);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE,
+-                      "sysdb_add_group_member_overrides failed.\n");
+-                goto done;
+-            }
++        ret = sysdb_add_group_member_overrides(domain, res->msgs[c],
++                                               DOM_HAS_VIEWS(domain));
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "sysdb_add_group_member_overrides failed.\n");
++            goto done;
+         }
+     }
+ 
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 2b89e5ca41f719e1217ef3b9e0fd683656e05d42..79f513d13ba41212a6cd84e1d9e609df6acba29c 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -1348,14 +1348,13 @@ done:
+ }
+ 
+ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+-                                         struct ldb_message *obj)
++                                         struct ldb_message *obj,
++                                         bool expect_override_dn)
+ {
+     int ret;
+     size_t c;
+-    struct ldb_message_element *members;
++    struct ldb_result *res_members;
+     TALLOC_CTX *tmp_ctx;
+-    struct ldb_dn *member_dn;
+-    struct ldb_result *member_obj;
+     struct ldb_result *override_obj;
+     static const char *member_attrs[] = SYSDB_PW_ATTRS;
+     const char *override_dn_str;
+@@ -1366,12 +1365,6 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+     char *val;
+     struct sss_domain_info *orig_dom;
+ 
+-    members = ldb_msg_find_element(obj, SYSDB_MEMBER);
+-    if (members == NULL || members->num_values == 0) {
+-        DEBUG(SSSDBG_TRACE_ALL, "Group has no members.\n");
+-        return EOK;
+-    }
+-
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+@@ -1379,38 +1372,30 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+         goto done;
+     }
+ 
+-    for (c = 0; c < members->num_values; c++) {
+-        member_dn = ldb_dn_from_ldb_val(tmp_ctx, domain->sysdb->ldb,
+-                                        &members->values[c]);
+-        if (member_dn == NULL) {
+-            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_from_ldb_val failed.\n");
+-            ret = ENOMEM;
+-            goto done;
+-        }
++    ret = sysdb_get_user_members_recursively(tmp_ctx, domain, obj->dn,
++                                             &res_members);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "sysdb_get_user_members_recursively failed.\n");
++        goto done;
++    }
+ 
+-        ret = ldb_search(domain->sysdb->ldb, member_dn, &member_obj, member_dn,
+-                         LDB_SCOPE_BASE, member_attrs, NULL);
+-        if (ret != LDB_SUCCESS) {
+-            ret = sysdb_error_to_errno(ret);
+-            goto done;
+-        }
++    for (c = 0; c < res_members->count; c++) {
+ 
+-        if (member_obj->count != 1) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Base search for member object returned [%d] results.\n",
+-                  member_obj->count);
+-            ret = EINVAL;
+-            goto done;
+-        }
+-
+-        if (ldb_msg_find_attr_as_uint64(member_obj->msgs[0],
++        if (ldb_msg_find_attr_as_uint64(res_members->msgs[c],
+                                         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 (expect_override_dn) {
++            override_dn_str = ldb_msg_find_attr_as_string(res_members->msgs[c],
++                                                          SYSDB_OVERRIDE_DN,
++                                                          NULL);
++        } else {
++            override_dn_str = ldb_dn_get_linearized(res_members->msgs[c]->dn);
++        }
++
+         if (override_dn_str == NULL) {
+             if (is_local_view(domain->view_name)) {
+                 /* LOCAL view doesn't have to have overrideDN specified. */
+@@ -1420,12 +1405,12 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+ 
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "Missing override DN for object [%s].\n",
+-                  ldb_dn_get_linearized(member_obj->msgs[0]->dn));
++                  ldb_dn_get_linearized(res_members->msgs[c]->dn));
+             ret = ENOENT;
+             goto done;
+         }
+ 
+-        override_dn = ldb_dn_new(member_obj, domain->sysdb->ldb,
++        override_dn = ldb_dn_new(res_members, domain->sysdb->ldb,
+                                  override_dn_str);
+         if (override_dn == NULL) {
+             DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+@@ -1433,22 +1418,27 @@ 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],
++        orig_name = ldb_msg_find_attr_as_string(res_members->msgs[c],
+                                                 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));
++                  ldb_dn_get_linearized(res_members->msgs[c]->dn));
+             ret = EINVAL;
+             goto done;
+         }
+ 
+-        memberuid = NULL;
+-        if (ldb_dn_compare(member_obj->msgs[0]->dn, override_dn) != 0) {
++        /* start with default view name, if it exists or use NULL */
++        memberuid = ldb_msg_find_attr_as_string(res_members->msgs[c],
++                                                SYSDB_DEFAULT_OVERRIDE_NAME,
++                                                NULL);
++
++        /* If there is an override object, check if the name is overridden */
++        if (ldb_dn_compare(res_members->msgs[c]->dn, override_dn) != 0) {
+             DEBUG(SSSDBG_TRACE_ALL, "Checking override for object [%s].\n",
+-                  ldb_dn_get_linearized(member_obj->msgs[0]->dn));
++                  ldb_dn_get_linearized(res_members->msgs[c]->dn));
+ 
+-            ret = ldb_search(domain->sysdb->ldb, member_obj, &override_obj,
++            ret = ldb_search(domain->sysdb->ldb, res_members, &override_obj,
+                              override_dn, LDB_SCOPE_BASE, member_attrs, NULL);
+             if (ret != LDB_SUCCESS) {
+                 ret = sysdb_error_to_errno(ret);
+@@ -1458,43 +1448,44 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+             if (override_obj->count != 1) {
+                 DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Base search for override object returned [%d] results.\n",
+-                     member_obj->count);
++                    override_obj->count);
+                 ret = EINVAL;
+                 goto done;
+             }
+ 
+             memberuid = ldb_msg_find_attr_as_string(override_obj->msgs[0],
+                                                     SYSDB_NAME,
+-                                                    NULL);
++                                                    memberuid);
++        }
+ 
+-            if (memberuid != NULL) {
+-                ret = sss_parse_internal_fqname(tmp_ctx, orig_name,
+-                                                NULL, &orig_domain);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_OP_FAILURE,
+-                         "sss_parse_internal_fqname failed to split [%s].\n",
+-                         orig_name);
++        /* add domain name if memberuid is a short name */
++        if (memberuid != NULL && strchr(memberuid, '@') == NULL) {
++            ret = sss_parse_internal_fqname(tmp_ctx, orig_name,
++                                            NULL, &orig_domain);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                     "sss_parse_internal_fqname failed to split [%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 = ERR_DOMAIN_NOT_FOUND;
+                     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 = ERR_DOMAIN_NOT_FOUND;
+-                        goto done;
+-                    }
+-                    memberuid = sss_create_internal_fqname(tmp_ctx, memberuid,
+-                                                           orig_dom->name);
+-                    if (memberuid == NULL) {
+-                        DEBUG(SSSDBG_OP_FAILURE,
+-                              "sss_create_internal_fqname failed.\n");
+-                        ret = ENOMEM;
+-                        goto done;
+-                    }
++                memberuid = sss_create_internal_fqname(tmp_ctx, memberuid,
++                                                       orig_dom->name);
++                if (memberuid == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sss_create_internal_fqname failed.\n");
++                    ret = ENOMEM;
++                    goto done;
+                 }
+             }
+         }
+@@ -1521,9 +1512,6 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+         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. */
+-        talloc_free(member_dn);
+     }
+ 
+     ret = EOK;
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 1ae17969688fa29734ca14fd2b152decef1fdbca..4e84b3202cbf367e70a47a3c7edb06e357657538 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -2976,7 +2976,12 @@ static int fill_grent(struct sss_packet *packet,
+ 
+         memnum = 0;
+         if (!dom->ignore_group_members) {
+-            el = sss_view_ldb_msg_find_element(dom, msg, SYSDB_MEMBERUID);
++            /* unconditionally prefer OVERRIDE_PREFIX SYSDB_MEMBERUID, it
++             * might contain override names from the default view */
++            el = ldb_msg_find_element(msg, OVERRIDE_PREFIX SYSDB_MEMBERUID);
++            if (el == NULL) {
++                el = ldb_msg_find_element(msg, SYSDB_MEMBERUID);
++            }
+             if (el) {
+                 ret = fill_members(packet, nctx->rctx, dom, nctx, el,
+                                    &rzero, &rsize, &memnum);
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index 82a304feed864b09168d0f3e06a4e1bb120df7e4..41425e76f3b76fafa917f33fcfef0946f2f71c7d 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -1619,11 +1619,11 @@ static int test_nss_getgrnam_check_mix_dom(uint32_t status,
+     tmp_ctx = talloc_new(nss_test_ctx);
+     assert_non_null(tmp_ctx);
+ 
+-    exp_members[0] = testmember1.pw_name;
+-    exp_members[1] = testmember2.pw_name;
+-    exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
++    exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
+                                    nss_test_ctx->subdom, submember1.pw_name);
+-    assert_non_null(exp_members[2]);
++    assert_non_null(exp_members[0]);
++    exp_members[1] = testmember1.pw_name;
++    exp_members[2] = testmember2.pw_name;
+ 
+     assert_int_equal(status, EOK);
+ 
+@@ -1682,14 +1682,14 @@ static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status,
+     tmp_ctx = talloc_new(nss_test_ctx);
+     assert_non_null(tmp_ctx);
+ 
+-    exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
+-                                   nss_test_ctx->tctx->dom, testmember1.pw_name);
++    exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
++                                   nss_test_ctx->subdom, submember1.pw_name);
+     assert_non_null(exp_members[0]);
+     exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
+-                                   nss_test_ctx->tctx->dom, testmember2.pw_name);
++                                   nss_test_ctx->tctx->dom, testmember1.pw_name);
+     assert_non_null(exp_members[1]);
+-    exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
+-                                   nss_test_ctx->subdom, submember1.pw_name);
++    exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
++                                   nss_test_ctx->tctx->dom, testmember2.pw_name);
+     assert_non_null(exp_members[2]);
+ 
+     expected.gr_name = sss_tc_fqname(tmp_ctx,
+-- 
+2.4.11
+
diff --git a/SOURCES/0049-IPA-fix-lookup-by-UPN-for-subdomains.patch b/SOURCES/0049-IPA-fix-lookup-by-UPN-for-subdomains.patch
new file mode 100644
index 0000000..abd98c4
--- /dev/null
+++ b/SOURCES/0049-IPA-fix-lookup-by-UPN-for-subdomains.patch
@@ -0,0 +1,61 @@
+From 196e4a16c32e2f5d7e63f2dacd4f3cf4128f6814 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Jul 2016 17:35:43 +0200
+Subject: [PATCH 49/62] IPA: fix lookup by UPN for subdomains
+
+Currently the user name used in the extdom exop request is
+unconditionally set to the short name. While this is correct for the
+general name based lookups it breaks UPN/email based lookups where the
+name part after the @-sign might not match to domain name. I guess this
+was introduce during the sysdb refactoring.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 530458a4ef7cd8429d1db2f3dfae92d9c44e38ef)
+---
+ src/providers/ipa/ipa_subdomains_id.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 542c596a983bcb48f4eac699f78eb956326cefa2..002857699b65c86a6ed0c912a2a7ae06a8f9e507 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -344,6 +344,7 @@ struct ipa_get_subdom_acct {
+     int entry_type;
+     const char *filter;
+     int filter_type;
++    const char *extra_value;
+     bool use_pac;
+     struct ldb_message *user_msg;
+ 
+@@ -393,6 +394,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
+     state->entry_type = (ar->entry_type & BE_REQ_TYPE_MASK);
+     state->filter = ar->filter_value;
+     state->filter_type = ar->filter_type;
++    state->extra_value = ar->extra_value;
+ 
+     switch (state->entry_type) {
+         case BE_REQ_USER:
+@@ -499,10 +501,16 @@ static void ipa_get_subdom_acct_connected(struct tevent_req *subreq)
+     switch (state->filter_type) {
+         case BE_FILTER_NAME:
+             req_input->type = REQ_INP_NAME;
+-            /* The extdom plugin expects the shortname and domain separately */
+-            ret = sss_parse_internal_fqname(req_input, state->filter,
+-                                            &shortname, NULL);
+-            req_input->inp.name = talloc_steal(req_input, shortname);
++            /* The extdom plugin expects the shortname and domain separately,
++             * but for UPN/email lookup we need to send the raw name */
++            if (state->extra_value != NULL
++                    && strcmp(state->extra_value, EXTRA_NAME_IS_UPN) == 0) {
++                req_input->inp.name = talloc_strdup(req_input, state->filter);
++            } else {
++                ret = sss_parse_internal_fqname(req_input, state->filter,
++                                                &shortname, NULL);
++                req_input->inp.name = talloc_steal(req_input, shortname);
++            }
+             if (req_input->inp.name == NULL) {
+                 DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                 tevent_req_error(req, ENOMEM);
+-- 
+2.4.11
+
diff --git a/SOURCES/0049-krb5-do-not-create-kdcinfo-file-if-proxy-configurati.patch b/SOURCES/0049-krb5-do-not-create-kdcinfo-file-if-proxy-configurati.patch
deleted file mode 100644
index 86016bd..0000000
--- a/SOURCES/0049-krb5-do-not-create-kdcinfo-file-if-proxy-configurati.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 61faa93f3ad91afdeba09d4e248d596875aa6d5a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 31 Jul 2015 11:05:48 +0200
-Subject: [PATCH 49/57] krb5: do not create kdcinfo file if proxy configuration
- exists
-
-Resolves https://fedorahosted.org/sssd/ticket/2652
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_common.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
-index 81d4048b63dba98706bbef1936df7f10f79e1ae5..be6c9e3540ad470307f4edb168f0ff6cc581632f 100644
---- a/src/providers/krb5/krb5_common.c
-+++ b/src/providers/krb5/krb5_common.c
-@@ -428,6 +428,13 @@ errno_t write_krb5info_file(const char *realm, const char *server,
-         return EINVAL;
-     }
- 
-+    if (sss_krb5_realm_has_proxy(realm)) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "KDC Proxy available for realm [%s], no kdcinfo file created.\n",
-+              realm);
-+        return EOK;
-+    }
-+
-     if (strcmp(service, SSS_KRB5KDC_FO_SRV) == 0) {
-         name_tmpl = KDCINFO_TMPL;
-     } else if (strcmp(service, SSS_KRB5KPASSWD_FO_SRV) == 0) {
--- 
-2.4.3
-
diff --git a/SOURCES/0050-LDAP-allow-multiple-user-principals.patch b/SOURCES/0050-LDAP-allow-multiple-user-principals.patch
new file mode 100644
index 0000000..de62b4a
--- /dev/null
+++ b/SOURCES/0050-LDAP-allow-multiple-user-principals.patch
@@ -0,0 +1,70 @@
+From f1eb45c3e8a198615c6731dfe9d965ab421723e8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Jul 2016 12:19:26 +0200
+Subject: [PATCH 50/62] LDAP: allow multiple user principals
+
+In general a user can have multiple principals and recent IPA version
+added support to defined multiple principals. With this patch SSSD does
+not only store the first but all principals read by LDAP from a server.
+
+Resolves https://fedorahosted.org/sssd/ticket/2958
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 0d5d490fb5ec685fd8ef7a75e612e6ec7ef6bde3)
+---
+ src/providers/ldap/sdap_async_users.c | 32 ++++++++++++++++++--------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
+index e44c045b3f8ff6aed33a42cf2919bc01aa41a243..28101a2d8a38f97d09d50a9f7e071a030b4f9719 100644
+--- a/src/providers/ldap/sdap_async_users.c
++++ b/src/providers/ldap/sdap_async_users.c
+@@ -142,6 +142,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
+     char *sid_str;
+     char *dom_sid_str = NULL;
+     struct sss_domain_info *subdomain;
++    size_t c;
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "Save user\n");
+ 
+@@ -440,20 +441,23 @@ int sdap_save_user(TALLOC_CTX *memctx,
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "User principal is not available for [%s].\n", user_name);
+     } else {
+-        upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);
+-        if (!upn) {
+-            ret = ENOMEM;
+-            goto done;
+-        }
+-        if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
+-            make_realm_upper_case(upn);
+-        }
+-        DEBUG(SSSDBG_TRACE_FUNC,
+-              "Adding user principal [%s] to attributes of [%s].\n",
+-               upn, user_name);
+-        ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
+-        if (ret) {
+-            goto done;
++        for (c = 0; c < el->num_values; c++) {
++            upn = talloc_strdup(tmpctx, (const char*) el->values[c].data);
++            if (!upn) {
++                ret = ENOMEM;
++                goto done;
++            }
++
++            if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
++                make_realm_upper_case(upn);
++            }
++            DEBUG(SSSDBG_TRACE_FUNC,
++                  "Adding user principal [%s] to attributes of [%s].\n",
++                   upn, user_name);
++            ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
++            if (ret) {
++                goto done;
++            }
+         }
+     }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0050-krb5-assume-online-state-if-KDC-proxy-is-configured.patch b/SOURCES/0050-krb5-assume-online-state-if-KDC-proxy-is-configured.patch
deleted file mode 100644
index dc90393..0000000
--- a/SOURCES/0050-krb5-assume-online-state-if-KDC-proxy-is-configured.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 860b0e5e2f34a270a5e40912fd07efbe093a29f8 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 31 Jul 2015 11:06:54 +0200
-Subject: [PATCH 50/57] krb5: assume online state if KDC proxy is configured
-
-If a KDC proxy is configured a request in the KRB5 provider will assume
-online state even if the backend is offline without changing the state
-of the backend.
-
-Resolves https://fedorahosted.org/sssd/ticket/2700
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_auth.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
-index d1bf4025b052d82413d1f370a36b0b99720d6f05..da8309d0504a6815902513693343a3500f454557 100644
---- a/src/providers/krb5/krb5_auth.c
-+++ b/src/providers/krb5/krb5_auth.c
-@@ -754,6 +754,12 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
-         kr->is_offline = be_is_offline(state->be_ctx);
-     }
- 
-+    if (kr->is_offline
-+            && sss_krb5_realm_has_proxy(dp_opt_get_cstring(kr->krb5_ctx->opts,
-+                                        KRB5_REALM))) {
-+        kr->is_offline = false;
-+    }
-+
-     subreq = handle_child_send(state, state->ev, kr);
-     if (subreq == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_send failed.\n");
--- 
-2.4.3
-
diff --git a/SOURCES/0051-LDAP-new-attribute-option-ldap_user_email.patch b/SOURCES/0051-LDAP-new-attribute-option-ldap_user_email.patch
new file mode 100644
index 0000000..85b5898
--- /dev/null
+++ b/SOURCES/0051-LDAP-new-attribute-option-ldap_user_email.patch
@@ -0,0 +1,171 @@
+From 03d7bda082c8719bfb4ea63c9126442c98a27be1 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Sat, 18 Jun 2016 18:24:50 +0200
+Subject: [PATCH 51/62] LDAP: new attribute option ldap_user_email
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 83a796ec8de4bde65b11cc8032675406950641fa)
+---
+ 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                  | 13 +++++++++++++
+ src/providers/ad/ad_opts.c               |  1 +
+ src/providers/ipa/ipa_opts.c             |  1 +
+ src/providers/ldap/ldap_opts.c           |  3 +++
+ src/providers/ldap/sdap.h                |  1 +
+ 10 files changed, 24 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index b5e078d0118a15c10b43fbe050176943ec90e0ee..7856c4c6b2d675b7f7f0f5f2048086044e8fb5ea 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -325,6 +325,7 @@ option_strings = {
+     'ldap_user_ssh_public_key' : _('SSH public key attribute'),
+     'ldap_user_auth_type' : _('attribute listing allowed authentication types for a user'),
+     'ldap_user_certificate' : _('attribute containing the X509 certificate of the user'),
++    'ldap_user_email' : _('attribute containing the email address of the user'),
+ 
+     'ldap_user_extra_attrs' : _('A list of extra attributes to download along with the user entry'),
+ 
+diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
+index 23006d26ca6fe7ca2b912ef091b4c73d5d23bee1..87a74f4af0770874c71baaea02d2313721db78bf 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_pwd_attribute = str, None, false
+ ldap_user_ssh_public_key = str, None, false
+ ldap_user_auth_type = str, None, false
+ ldap_user_certificate = str, None, false
++ldap_user_email = str, None, false
+ ldap_group_search_base = str, None, false
+ ldap_group_search_scope = str, None, false
+ ldap_group_search_filter = 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 67a46102b4e8dfff2b44b21ac18c0ad8822d7f3a..88da36ef4a0a067530dfd44b7a231f4f74c800f2 100644
+--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
+@@ -92,6 +92,7 @@ ldap_pwd_attribute = str, None, false
+ ldap_user_ssh_public_key = str, None, false
+ ldap_user_auth_type = str, None, false
+ ldap_user_certificate = str, None, false
++ldap_user_email = str, None, false
+ ldap_group_search_base = str, None, false
+ ldap_group_search_scope = str, None, false
+ ldap_group_search_filter = 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 8b52f268af195bc68d45389cda52a0ad0aba1aa3..c2ad3463d26cd73b8146604c8060224449421fe6 100644
+--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
++++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
+@@ -86,6 +86,7 @@ ldap_user_nds_login_allowed_time_map = str, None, false
+ ldap_user_ssh_public_key = str, None, false
+ ldap_user_auth_type = str, None, false
+ ldap_user_certificate = str, None, false
++ldap_user_email = str, None, false
+ ldap_group_search_base = str, None, false
+ ldap_group_search_scope = str, None, false
+ ldap_group_search_filter = str, None, false
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index a27552224bb40bd07c7dee4dfe35bfb7a0b4f2c3..f3952f8a56f1c9f26f2167b64abdf3e9794af17e 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -139,6 +139,7 @@
+ 
+ #define SYSDB_AUTH_TYPE "authType"
+ #define SYSDB_USER_CERT "userCertificate"
++#define SYSDB_USER_EMAIL "mail"
+ 
+ #define SYSDB_SUBDOMAIN_REALM "realmName"
+ #define SYSDB_SUBDOMAIN_FLAT "flatName"
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index ce2051d9d3c7df51e26e54abf49e8a20bf5ba3d3..6009dd8dfa787874c085c293b2d1f8aac6d95714 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -828,6 +828,19 @@
+                 </varlistentry>
+ 
+                 <varlistentry>
++                    <term>ldap_user_email (string)</term>
++                    <listitem>
++                        <para>
++                            Name of the LDAP attribute containing the email
++                            address of the user.
++                        </para>
++                        <para>
++                            Default: mail
++                        </para>
++                    </listitem>
++                </varlistentry>
++
++                <varlistentry>
+                     <term>ldap_group_object_class (string)</term>
+                     <listitem>
+                         <para>
+diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
+index 57dfcca6b998083c7cf9ac0bcb142ff7736cc8b9..829f9d9556bc3fa74a95eb76db0e31b19befe8fe 100644
+--- a/src/providers/ad/ad_opts.c
++++ b/src/providers/ad/ad_opts.c
+@@ -218,6 +218,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
+     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
+     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL },
++    { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
+index a0c318a511693d884f03f0372c592d633ebdcbae..cd3fe9ae4302ff4837a500b9a0c834dadb11f87d 100644
+--- a/src/providers/ipa/ipa_opts.c
++++ b/src/providers/ipa/ipa_opts.c
+@@ -204,6 +204,7 @@ struct sdap_attr_map ipa_user_map[] = {
+     { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
+     { "ldap_user_auth_type", "ipaUserAuthType", SYSDB_AUTH_TYPE, NULL },
+     { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL },
++    { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
+index 524579d4fcd478f20678bebf2c3ce18f61ed0cb9..c6efe332f53c04f3cdc80875d5ca339ad90cb7ee 100644
+--- a/src/providers/ldap/ldap_opts.c
++++ b/src/providers/ldap/ldap_opts.c
+@@ -180,6 +180,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
+     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
+     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL },
++    { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+@@ -237,6 +238,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
+     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
+     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL },
++    { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+@@ -294,6 +296,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = {
+     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
+     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+     { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL },
++    { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
+ 
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index 81da1144c657cb71ac860bbe82127a18759e0439..e3cb8464ff40538e1e7f1ba853ed71d9a5cc3c98 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -284,6 +284,7 @@ enum sdap_user_attrs {
+     SDAP_AT_USER_SSH_PUBLIC_KEY,
+     SDAP_AT_USER_AUTH_TYPE,
+     SDAP_AT_USER_CERT,
++    SDAP_AT_USER_EMAIL,
+ 
+     SDAP_OPTS_USER /* attrs counter */
+ };
+-- 
+2.4.11
+
diff --git a/SOURCES/0051-sss_cache-Wait-a-while-for-invalidation-of-mc-by-nss.patch b/SOURCES/0051-sss_cache-Wait-a-while-for-invalidation-of-mc-by-nss.patch
deleted file mode 100644
index 78a6176..0000000
--- a/SOURCES/0051-sss_cache-Wait-a-while-for-invalidation-of-mc-by-nss.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From a09b3853da819cc773c0098100f9dd96af08f933 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 10 Aug 2015 10:16:58 +0200
-Subject: [PATCH 51/57] sss_cache: Wait a while for invalidation of mc by nss
- responder
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The sss_cache cannot invalidate memory cache directly
-because the nss responder owns file locks to memory caches.
-Therefore sss_cache just "tell" nss responder to invalidate
-memory cache.
-
-However there might be short interval between calling
-the utility sss_cache and stopping sssd. So nss responder
-needn't be so fast and therefore memory cache needn't be invalidated.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2748
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/tools/tools_mc_util.c | 34 ++++++++++++++++++++++++++++++++++
- 1 file changed, 34 insertions(+)
-
-diff --git a/src/tools/tools_mc_util.c b/src/tools/tools_mc_util.c
-index c1b5c616d0e6d50147ecd81308aaa1e69304af92..65c461093e859d4da73761782a3a694bf5bda8fb 100644
---- a/src/tools/tools_mc_util.c
-+++ b/src/tools/tools_mc_util.c
-@@ -21,6 +21,7 @@
- 
- #include <talloc.h>
- #include <fcntl.h>
-+#include <sys/stat.h>
- 
- #include "db/sysdb.h"
- #include "util/util.h"
-@@ -161,6 +162,33 @@ static int clear_fastcache(bool *sssd_nss_is_off)
-     return EOK;
- }
- 
-+static errno_t wait_till_nss_responder_invalidate_cache(void)
-+{
-+    struct stat stat_buf = { 0 };
-+    const time_t max_wait = 1000000; /* 1 second */
-+    const time_t step_time = 5000; /* 5 miliseconds */
-+    const size_t steps_count = max_wait / step_time;
-+    int ret;
-+
-+    for (size_t i = 0; i < steps_count; ++i) {
-+        ret = stat(SSS_NSS_MCACHE_DIR "/" CLEAR_MC_FLAG, &stat_buf);
-+        if (ret == -1) {
-+            ret = errno;
-+            if (ret == ENOENT) {
-+                /* nss responder has already invalidated memory caches */
-+                return EOK;
-+            }
-+
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "stat failed: %s (%d)\n", sss_strerror(ret), ret);
-+        }
-+
-+        usleep(step_time);
-+    }
-+
-+    return EAGAIN;
-+}
-+
- errno_t sss_memcache_clear_all(void)
- {
-     errno_t ret;
-@@ -196,6 +224,12 @@ errno_t sss_memcache_clear_all(void)
-                   "Failed to send SIGHUP to monitor.\n");
-             return EIO;
-         }
-+
-+        ret = wait_till_nss_responder_invalidate_cache();
-+        if (ret != EOK) {
-+            ERROR("The fast memory caches was not invalidated by NSS "
-+                  "responder.\n");
-+        }
-     }
- 
-     return EOK;
--- 
-2.4.3
-
diff --git a/SOURCES/0052-IFP-use-default-limit-if-provided-is-0.patch b/SOURCES/0052-IFP-use-default-limit-if-provided-is-0.patch
deleted file mode 100644
index 3c45595..0000000
--- a/SOURCES/0052-IFP-use-default-limit-if-provided-is-0.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 504604a3e90c8bad36d1919e13e0bf37f094ee2a Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 13 Aug 2015 12:46:59 +0200
-Subject: [PATCH 52/57] IFP: use default limit if provided is 0
-
-Returning zero values doesn't make any sense, so we may use it as
-"use sssd configuration instead".
-
-Reviewed-by: Petr Cech <pcech@redhat.com>
----
- src/responder/ifp/ifpsrv_util.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
-index 3b02fd06f5227e4ffc3d40ffb20fed981c5028a7..904c4f62ec5653a534877fd6870832128720b694 100644
---- a/src/responder/ifp/ifpsrv_util.c
-+++ b/src/responder/ifp/ifpsrv_util.c
-@@ -274,7 +274,9 @@ ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr)
- 
- static uint32_t ifp_list_limit(struct ifp_ctx *ctx, uint32_t limit)
- {
--    if (ctx->wildcard_limit) {
-+    if (limit == 0) {
-+        return ctx->wildcard_limit;
-+    } else if (ctx->wildcard_limit) {
-         return MIN(ctx->wildcard_limit, limit);
-     } else {
-         return limit;
--- 
-2.4.3
-
diff --git a/SOURCES/0052-sysdb-include-email-in-UPN-searches.patch b/SOURCES/0052-sysdb-include-email-in-UPN-searches.patch
new file mode 100644
index 0000000..4dd7f04
--- /dev/null
+++ b/SOURCES/0052-sysdb-include-email-in-UPN-searches.patch
@@ -0,0 +1,57 @@
+From 2e9ea4e5c12c0d50509904415beda6b841b91f65 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 20 Jun 2016 12:57:43 +0200
+Subject: [PATCH 52/62] sysdb: include email in UPN searches
+
+Email addresses and Kerberos user principals names (UPNs) do not only
+look similar they also can be used to identify a user uniquely.
+
+In future this approach should be replace by a more generic one where
+the attributes which can uniquely identifies a user can be configured to
+support even a wider range of login names.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 78677495a7762469002b0976809fa20ac2196f42)
+---
+ src/db/sysdb.h     | 2 +-
+ src/db/sysdb_ops.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index f3952f8a56f1c9f26f2167b64abdf3e9794af17e..c2f58ccb97c37d93391e72ee2d77835283a6c12f 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -185,7 +185,7 @@
+ #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_PWUPN_FILTER "(&("SYSDB_UC")(|("SYSDB_UPN"=%s)("SYSDB_CANONICAL_UPN"=%s)))"
++#define SYSDB_PWUPN_FILTER "(&("SYSDB_UC")(|("SYSDB_UPN"=%s)("SYSDB_CANONICAL_UPN"=%s)("SYSDB_USER_EMAIL"=%s)))"
+ #define SYSDB_PWENT_FILTER "("SYSDB_UC")"
+ 
+ #define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 9a8a55ed8aa69e1638d0ab6f636e43baa3d0bfea..ed177d1730723a61e01167a75a0baca6d81252f8 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -537,7 +537,7 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx,
+     struct ldb_dn *base_dn;
+     int ret;
+     const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN,
+-                                NULL };
++                                SYSDB_USER_EMAIL, NULL };
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -553,7 +553,7 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx,
+ 
+     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
+                      base_dn, LDB_SCOPE_SUBTREE, attrs ? attrs : def_attrs,
+-                     SYSDB_PWUPN_FILTER, upn, upn);
++                     SYSDB_PWUPN_FILTER, upn, upn, upn);
+     if (ret != EOK) {
+         ret = sysdb_error_to_errno(ret);
+         goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0053-LDAP-include-email-in-UPN-searches.patch b/SOURCES/0053-LDAP-include-email-in-UPN-searches.patch
new file mode 100644
index 0000000..878b42a
--- /dev/null
+++ b/SOURCES/0053-LDAP-include-email-in-UPN-searches.patch
@@ -0,0 +1,115 @@
+From c333512b85f979ae0694055a36d8dafcf4105248 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 20 Jun 2016 12:58:16 +0200
+Subject: [PATCH 53/62] LDAP: include email in UPN searches
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit ba9ebfc49ab3bacb96213c8620411128c09f39da)
+---
+ src/providers/ldap/ldap_id.c               | 18 +++++++++++++----
+ src/providers/ldap/sdap_async_initgroups.c | 32 ++++++++++++++++++++++++------
+ 2 files changed, 40 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index 0106a7b965b8d7debbefe82f60088df9ef8c608b..5b303ddbd46fd44646cdd50856c784640426ee25 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -127,12 +127,22 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+         break;
+     case BE_FILTER_NAME:
+         if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) {
+-            attr_name = ctx->opts->user_map[SDAP_AT_USER_PRINC].name;
+-
+             ret = sss_filter_sanitize(state, filter_value, &clean_value);
+             if (ret != EOK) {
+                 goto done;
+             }
++            /* TODO: Do we have to check the attribute names more carefully? */
++            user_filter = talloc_asprintf(state, "(|(%s=%s)(%s=%s))",
++                                   ctx->opts->user_map[SDAP_AT_USER_PRINC].name,
++                                   clean_value,
++                                   ctx->opts->user_map[SDAP_AT_USER_EMAIL].name,
++                                   clean_value);
++            talloc_zfree(clean_value);
++            if (user_filter == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++                ret = ENOMEM;
++                goto done;
++            }
+         } else {
+             attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name;
+ 
+@@ -242,8 +252,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+         goto done;
+     }
+ 
+-    if (attr_name == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Missing search attribute name.\n");
++    if (attr_name == NULL && user_filter == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "Missing search attribute name or filter.\n");
+         ret = EINVAL;
+         goto done;
+     }
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index 17593f0a268813662d6c7fbf658b1eb4599ce3c3..0a42b18662a8fe12cf048aadfef257b5d9cb48a3 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -2736,13 +2736,25 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
+         break;
+     case BE_FILTER_NAME:
+         if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) {
+-            search_attr =  state->opts->user_map[SDAP_AT_USER_PRINC].name;
+ 
+             ret = sss_filter_sanitize(state, state->filter_value, &clean_name);
+             if (ret != EOK) {
+                 talloc_zfree(req);
+                 return NULL;
+             }
++
++            state->user_base_filter =
++                    talloc_asprintf(state,
++                                 "(&(|(%s=%s)(%s=%s))(objectclass=%s)",
++                                 state->opts->user_map[SDAP_AT_USER_PRINC].name,
++                                 clean_name,
++                                 state->opts->user_map[SDAP_AT_USER_EMAIL].name,
++                                 clean_name,
++                                 state->opts->user_map[SDAP_OC_USER].name);
++            if (state->user_base_filter == NULL) {
++                talloc_zfree(req);
++                return NULL;
++            }
+         } else {
+             search_attr = state->opts->user_map[SDAP_AT_USER_NAME].name;
+ 
+@@ -2766,15 +2778,23 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
+         return NULL;
+     }
+ 
+-    state->user_base_filter =
+-            talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)",
+-                            search_attr, clean_name,
+-                            state->opts->user_map[SDAP_OC_USER].name);
+-    if (!state->user_base_filter) {
++    if (search_attr == NULL && state->user_base_filter == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "Missing search attribute name or filter.\n");
+         talloc_zfree(req);
+         return NULL;
+     }
+ 
++    if (state->user_base_filter == NULL) {
++        state->user_base_filter =
++                talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)",
++                                search_attr, clean_name,
++                                state->opts->user_map[SDAP_OC_USER].name);
++        if (!state->user_base_filter) {
++            talloc_zfree(req);
++            return NULL;
++        }
++    }
++
+     if (use_id_mapping) {
+         /* 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
+-- 
+2.4.11
+
diff --git a/SOURCES/0053-sudo-use-higher-value-wins-when-ordering-rules.patch b/SOURCES/0053-sudo-use-higher-value-wins-when-ordering-rules.patch
deleted file mode 100644
index b28cdf5..0000000
--- a/SOURCES/0053-sudo-use-higher-value-wins-when-ordering-rules.patch
+++ /dev/null
@@ -1,217 +0,0 @@
-From 7c3fefc9c840fd0eb46048d7d2be0a0b8347f713 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 29 Jul 2015 14:51:30 +0200
-Subject: [PATCH 53/57] sudo: use "higher value wins" when ordering rules
-
-This commit changes the default ordering logic (lower value wins) to
-a correct one that is used by native ldap support. It also adds a new
-option sudo_inverse_order to switch to the original SSSD (incorrect)
-behaviour if needed.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2682
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/confdb/confdb.h                        |  2 ++
- src/config/SSSDConfig/__init__.py.in       |  1 +
- src/config/etc/sssd.api.conf               |  1 +
- src/responder/sudo/sudosrv.c               | 11 ++++++
- src/responder/sudo/sudosrv_get_sudorules.c | 54 ++++++++++++++++++++++++------
- src/responder/sudo/sudosrv_private.h       |  1 +
- 6 files changed, 60 insertions(+), 10 deletions(-)
-
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index df454337ab4d89c5857e73ee0e5392c2b4bba8b4..9aa264899e789f2491b9873daf44bb55aff1c95d 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -124,6 +124,8 @@
- #define CONFDB_DEFAULT_SUDO_CACHE_TIMEOUT 180
- #define CONFDB_SUDO_TIMED "sudo_timed"
- #define CONFDB_DEFAULT_SUDO_TIMED false
-+#define CONFDB_SUDO_INVERSE_ORDER "sudo_inverse_order"
-+#define CONFDB_DEFAULT_SUDO_INVERSE_ORDER false
- 
- /* autofs */
- #define CONFDB_AUTOFS_CONF_ENTRY "config/autofs"
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index 7d361026c09ce8fd8d6a69f6bb3f3817bc3d68ba..fed2682f121103cefa27e689b29ce29b7d28f968 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -92,6 +92,7 @@ option_strings = {
- 
-     # [sudo]
-     'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'),
-+    'sudo_inverse_order' : _('If true, SSSD will switch back to lower-wins ordering logic'),
- 
-     # [autofs]
-     'autofs_negative_timeout' : _('Negative cache timeout length (seconds)'),
-diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
-index cf6ce63012176d49f757afbc8a343b24aef869e8..2e5b02e3e30c13f805e172eab481f7501f57bb05 100644
---- a/src/config/etc/sssd.api.conf
-+++ b/src/config/etc/sssd.api.conf
-@@ -63,6 +63,7 @@ pam_account_expired_message = str, None, false
- [sudo]
- # sudo service
- sudo_timed = bool, None, false
-+sudo_inverse_order = bool, None, false
- 
- [autofs]
- # autofs service
-diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
-index 2499586eb11e49f8652ce62e53c88d7a2e54fb32..ff5d92e7005db9f6e883c78cf1a6218e9a150e0a 100644
---- a/src/responder/sudo/sudosrv.c
-+++ b/src/responder/sudo/sudosrv.c
-@@ -167,6 +167,17 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
-         goto fail;
-     }
- 
-+    /* Get sudo_inverse_order option */
-+    ret = confdb_get_bool(sudo_ctx->rctx->cdb,
-+                          CONFDB_SUDO_CONF_ENTRY, CONFDB_SUDO_INVERSE_ORDER,
-+                          CONFDB_DEFAULT_SUDO_INVERSE_ORDER,
-+                          &sudo_ctx->inverse_order);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n",
-+              ret, strerror(ret));
-+        goto fail;
-+    }
-+
-     ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
-diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
-index 34d63bd74741c3cab5168fd0b0108cb05528d218..a0b09e69b71f963c353c9c6331c0708cc364924c 100644
---- a/src/responder/sudo/sudosrv_get_sudorules.c
-+++ b/src/responder/sudo/sudosrv_get_sudorules.c
-@@ -325,6 +325,7 @@ static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
-                                                  const char *username,
-                                                  uid_t uid,
-                                                  char **groupnames,
-+                                                 bool inverse_order,
-                                                  struct sysdb_attrs ***_rules,
-                                                  uint32_t *_count);
- 
-@@ -386,6 +387,7 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
-                                             cmd_ctx->domain, attrs, flags,
-                                             cmd_ctx->orig_username,
-                                             cmd_ctx->uid, groupnames,
-+                                            cmd_ctx->sudo_ctx->inverse_order,
-                                             &expired_rules, &expired_rules_num);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve expired sudo rules "
-@@ -597,6 +599,7 @@ static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
-                                             cmd_ctx->domain, attrs, flags,
-                                             cmd_ctx->orig_username,
-                                             cmd_ctx->uid, groupnames,
-+                                            cmd_ctx->sudo_ctx->inverse_order,
-                                             &rules, &num_rules);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -622,7 +625,7 @@ done:
- }
- 
- static errno_t
--sort_sudo_rules(struct sysdb_attrs **rules, size_t count);
-+sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool higher_wins);
- 
- static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
-                                                  struct sss_domain_info *domain,
-@@ -631,6 +634,7 @@ static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
-                                                  const char *username,
-                                                  uid_t uid,
-                                                  char **groupnames,
-+                                                 bool inverse_order,
-                                                  struct sysdb_attrs ***_rules,
-                                                  uint32_t *_count)
- {
-@@ -680,7 +684,7 @@ static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sort_sudo_rules(rules, count);
-+    ret = sort_sudo_rules(rules, count, inverse_order);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               "Could not sort rules by sudoOrder\n");
-@@ -697,7 +701,7 @@ done:
- }
- 
- static int
--sudo_order_cmp_fn(const void *a, const void *b)
-+sudo_order_cmp(const void *a, const void *b, bool lower_wins)
- {
-     struct sysdb_attrs *r1, *r2;
-     uint32_t o1, o2;
-@@ -730,19 +734,49 @@ sudo_order_cmp_fn(const void *a, const void *b)
-         return 0;
-     }
- 
--    if (o1 > o2) {
--        return 1;
--    } else if (o1 < o2) {
--        return -1;
-+    if (lower_wins) {
-+        /* The lowest value takes priority. Original wrong SSSD behaviour. */
-+        if (o1 > o2) {
-+            return 1;
-+        } else if (o1 < o2) {
-+            return -1;
-+        }
-+    } else {
-+        /* The higher value takes priority. Standard LDAP behaviour. */
-+        if (o1 < o2) {
-+            return 1;
-+        } else if (o1 > o2) {
-+            return -1;
-+        }
-     }
- 
-     return 0;
- }
- 
-+static int
-+sudo_order_low_cmp_fn(const void *a, const void *b)
-+{
-+    return sudo_order_cmp(a, b, true);
-+}
-+
-+static int
-+sudo_order_high_cmp_fn(const void *a, const void *b)
-+{
-+    return sudo_order_cmp(a, b, false);
-+}
-+
- static errno_t
--sort_sudo_rules(struct sysdb_attrs **rules, size_t count)
-+sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool lower_wins)
- {
--    qsort(rules, count, sizeof(struct sysdb_attrs *),
--          sudo_order_cmp_fn);
-+    if (lower_wins) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with lower-wins logic\n");
-+        qsort(rules, count, sizeof(struct sysdb_attrs *),
-+              sudo_order_low_cmp_fn);
-+    } else {
-+        DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with higher-wins logic\n");
-+        qsort(rules, count, sizeof(struct sysdb_attrs *),
-+              sudo_order_high_cmp_fn);
-+    }
-+
-     return EOK;
- }
-diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h
-index 3c53755f9e8ec56f3dea52021d14b50f715a54e7..186ed2cb5114d00524b41b801b5f32bac50f7153 100644
---- a/src/responder/sudo/sudosrv_private.h
-+++ b/src/responder/sudo/sudosrv_private.h
-@@ -50,6 +50,7 @@ struct sudo_ctx {
-      * options
-      */
-     bool timed;
-+    bool inverse_order;
- };
- 
- struct sudo_cmd_ctx {
--- 
-2.4.3
-
diff --git a/SOURCES/0054-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch b/SOURCES/0054-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch
deleted file mode 100644
index 6c277fd..0000000
--- a/SOURCES/0054-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 1d42e3c3a4f9536ee3539683a810c95314fd1c5d Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 10 Aug 2015 12:40:30 +0200
-Subject: [PATCH 54/57] LDAP: use ldb_binary_encode when printing attribute
- values
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/providers/ldap/sdap_utils.c | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c
-index f5ce8ee54f60a6c4c4cdbd5e50b20d973c175e83..9da46ea70bf80e7f4d12fdfc7d1c97e99de8d000 100644
---- a/src/providers/ldap/sdap_utils.c
-+++ b/src/providers/ldap/sdap_utils.c
-@@ -35,6 +35,7 @@ sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
-     const char *objname = name ?: "object";
-     const char *desc = attr_desc ?: attr_name;
-     unsigned int num_values, i;
-+    char *printable;
- 
-     ret = sysdb_attrs_get_el(ldap_attrs, attr_name, &el);
-     if (ret) {
-@@ -50,8 +51,16 @@ sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
-     } else {
-         num_values = multivalued ? el->num_values : 1;
-         for (i = 0; i < num_values; i++) {
-+            printable = ldb_binary_encode(ldap_attrs, el->values[i]);
-+            if (printable == NULL) {
-+                DEBUG(SSSDBG_MINOR_FAILURE, "ldb_binary_encode failed..\n");
-+                continue;
-+            }
-+
-             DEBUG(SSSDBG_TRACE_INTERNAL, "Adding %s [%s] to attributes "
--                  "of [%s].\n", desc, el->values[i].data, objname);
-+                  "of [%s].\n", desc, printable, objname);
-+
-+            talloc_zfree(printable);
- 
-             ret = sysdb_attrs_add_mem(attrs, attr_name, el->values[i].data,
-                                       el->values[i].length);
--- 
-2.4.3
-
diff --git a/SOURCES/0054-NSS-add-user-email-to-fill_orig.patch b/SOURCES/0054-NSS-add-user-email-to-fill_orig.patch
new file mode 100644
index 0000000..b748512
--- /dev/null
+++ b/SOURCES/0054-NSS-add-user-email-to-fill_orig.patch
@@ -0,0 +1,50 @@
+From ac8bc2cbea5081f1f0a9395fbaf76616fe5b6fb9 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 20 Jun 2016 13:37:56 +0200
+Subject: [PATCH 54/62] NSS: add user email to fill_orig()
+
+The IPA server must send the email address of a user to the clients to
+allow login by email.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 91767924bdf9b5a28e8902206a40348d6c83a139)
+---
+ src/db/sysdb.h                 | 1 +
+ src/responder/nss/nsssrv_cmd.c | 2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index c2f58ccb97c37d93391e72ee2d77835283a6c12f..8713efa6e8fcc6fb620340fe152989a5dae58434 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -220,6 +220,7 @@
+                         SYSDB_SID_STR, \
+                         SYSDB_UPN, \
+                         SYSDB_USER_CERT, \
++                        SYSDB_USER_EMAIL, \
+                         SYSDB_OVERRIDE_DN, \
+                         SYSDB_OVERRIDE_OBJECT_DN, \
+                         SYSDB_DEFAULT_OVERRIDE_NAME, \
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 4e84b3202cbf367e70a47a3c7edb06e357657538..77e540d8da969614e4ab40c62e6ae1f271962f31 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -4421,6 +4421,7 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
+                                    SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                    SYSDB_SSH_PUBKEY,
+                                    SYSDB_USER_CERT,
++                                   SYSDB_USER_EMAIL,
+                                    SYSDB_ORIG_DN,
+                                    SYSDB_ORIG_MEMBEROF,
+                                    SYSDB_DEFAULT_ATTRS, NULL};
+@@ -4977,6 +4978,7 @@ static errno_t fill_orig(struct sss_packet *packet,
+                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                     SYSDB_SSH_PUBKEY,
+                                     SYSDB_USER_CERT,
++                                    SYSDB_USER_EMAIL,
+                                     SYSDB_ORIG_DN,
+                                     SYSDB_ORIG_MEMBEROF,
+                                     NULL};
+-- 
+2.4.11
+
diff --git a/SOURCES/0055-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch b/SOURCES/0055-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch
deleted file mode 100644
index 14f2998..0000000
--- a/SOURCES/0055-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 4d400c7374e0ca6af7c8f990e27c1e58a18ad7d4 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 10 Aug 2015 12:40:39 +0200
-Subject: [PATCH 55/57] IPA: Change the default of ldap_user_certificate to
- userCertificate;binary
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This is safe from ldb point of view, because ldb gurantees the data is
-NULL-terminated. We must be careful before we save the data, though.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2742
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/man/sssd-ldap.5.xml      | 2 +-
- src/providers/ipa/ipa_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 9ac175f8d4a8aa01ca2434b800ebae1be88575f5..49e84560f825b1bff255c1ad131487ba3243300d 100644
---- a/src/man/sssd-ldap.5.xml
-+++ b/src/man/sssd-ldap.5.xml
-@@ -821,7 +821,7 @@
-                             certificate of the user.
-                         </para>
-                         <para>
--                            Default: no set in the general case, userCertificate
-+                            Default: no set in the general case, userCertificate;binary
-                             for IPA
-                         </para>
-                     </listitem>
-diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
-index 9576228d1bf3424c8867bda058b59c3ca6b2216b..f6c40dddbb58cd8af1079a351137422083e26cfe 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -204,7 +204,7 @@ struct sdap_attr_map ipa_user_map[] = {
-     { "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 },
--    { "ldap_user_certificate", "userCertificate", SYSDB_USER_CERT, NULL },
-+    { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0055-utils-add-is_email_from_domain.patch b/SOURCES/0055-utils-add-is_email_from_domain.patch
new file mode 100644
index 0000000..e75ddfc
--- /dev/null
+++ b/SOURCES/0055-utils-add-is_email_from_domain.patch
@@ -0,0 +1,102 @@
+From 3f7b69c3af7b810443a94a1004d41b87e5ca79d8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 20 Jun 2016 16:11:11 +0200
+Subject: [PATCH 55/62] utils: add is_email_from_domain()
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 04d4c4d45f3942a813b7f772737f801f877f4e64)
+---
+ src/tests/cmocka/test_utils.c | 21 +++++++++++++++++++++
+ src/util/domain_info_utils.c  | 27 +++++++++++++++++++++++++++
+ src/util/util.h               |  1 +
+ 3 files changed, 49 insertions(+)
+
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index 5349accc5c6b55f7d725bfdeaf318b90289880dd..09273692968b544aed88de00c747e85ff0b6695c 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -1842,6 +1842,25 @@ static void test_sss_get_domain_mappings_content(void **state)
+      * capaths might not be as expected. */
+ }
+ 
++static void test_is_email_from_domain(void **state)
++{
++    struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
++                                                      struct dom_list_test_ctx);
++    struct sss_domain_info *d;
++
++    d = find_domain_by_name(test_ctx->dom_list, "name_0.dom", false);
++    assert_non_null(d);
++
++    assert_false(is_email_from_domain(NULL, NULL));
++    assert_false(is_email_from_domain("hello", NULL));
++    assert_false(is_email_from_domain(NULL, d));
++    assert_false(is_email_from_domain("hello", d));
++    assert_false(is_email_from_domain("hello@hello", d));
++
++    assert_true(is_email_from_domain("hello@name_0.dom", d));
++    assert_true(is_email_from_domain("hello@NaMe_0.DoM", d));
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -1870,6 +1889,8 @@ int main(int argc, const char *argv[])
+                                         setup_dom_list, teardown_dom_list),
+         cmocka_unit_test_setup_teardown(test_find_domain_by_name_disabled,
+                                         setup_dom_list, teardown_dom_list),
++        cmocka_unit_test_setup_teardown(test_is_email_from_domain,
++                                        setup_dom_list, teardown_dom_list),
+ 
+         cmocka_unit_test_setup_teardown(test_sss_names_init,
+                                         confdb_test_setup,
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 587a6b993d2bd70662df8e0b0d5963fa00c84cf8..0feda148bd44b9cefc43c094ddc5a72820412322 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -824,3 +824,30 @@ void sss_domain_set_state(struct sss_domain_info *dom,
+ {
+     dom->state = state;
+ }
++
++bool is_email_from_domain(const char *email, struct sss_domain_info *dom)
++{
++    const char *p;
++
++    if (email == NULL || dom == NULL) {
++        return false;
++    }
++
++    p = strchr(email, '@');
++    if (p == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL,
++              "Input [%s] does not look like an email address.\n", email);
++        return false;
++    }
++
++    if (strcasecmp(p+1, dom->name) == 0) {
++        DEBUG(SSSDBG_TRACE_ALL, "Email [%s] is from domain [%s].\n", email,
++                                                                     dom->name);
++        return true;
++    }
++
++    DEBUG(SSSDBG_TRACE_ALL, "Email [%s] is not from domain [%s].\n", email,
++                                                                     dom->name);
++
++    return false;
++}
+diff --git a/src/util/util.h b/src/util/util.h
+index 122be90b967fb7793adaff95f3754d7a199fcf48..4449315f8b1a79ec915bc340b46188c440a27fa3 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -514,6 +514,7 @@ struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
+ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom);
+ void sss_domain_set_state(struct sss_domain_info *dom,
+                           enum sss_domain_state state);
++bool is_email_from_domain(const char *email, struct sss_domain_info *dom);
+ 
+ struct sss_domain_info*
+ sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
+-- 
+2.4.11
+
diff --git a/SOURCES/0056-LDAP-IPA-add-local-email-address-to-aliases.patch b/SOURCES/0056-LDAP-IPA-add-local-email-address-to-aliases.patch
new file mode 100644
index 0000000..51ebcba
--- /dev/null
+++ b/SOURCES/0056-LDAP-IPA-add-local-email-address-to-aliases.patch
@@ -0,0 +1,126 @@
+From 24ed6bff6cf81c7ba732a5515a2194d9e32cf354 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 20 Jun 2016 16:30:03 +0200
+Subject: [PATCH 56/62] LDAP/IPA: add local email address to aliases
+
+Adding email-addresses from the local domain to the alias names is
+strictly not needed by might help to speed up lookups in the NSS
+responder.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 9a310913d696d190db14c625080678db853a33fd)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 49 ++++++++++++++++++++++++++++++++++++++++
+ src/providers/ldap/sdap_utils.c  | 22 ++++++++++++++++++
+ 2 files changed, 71 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index b28cc415b1c6dfcf06e0cb9769a36135da01b991..255dad45037a6cb8f399bf2df500215f6fb25b59 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1885,6 +1885,49 @@ done:
+     return ret;
+ }
+ 
++static errno_t add_emails_to_aliases(struct sysdb_attrs *attrs,
++                                     struct sss_domain_info *dom)
++{
++    int ret;
++    const char **emails;
++    size_t c;
++    TALLOC_CTX *tmp_ctx;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    ret = sysdb_attrs_get_string_array(attrs, SYSDB_USER_EMAIL, tmp_ctx,
++                                       &emails);
++    if (ret == EOK) {
++        for (c = 0; emails[c] != NULL; c++) {
++            if (is_email_from_domain(emails[c], dom)) {
++                ret = sysdb_attrs_add_lc_name_alias_safe(attrs, emails[c]);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "Failed to add lower-cased version of email [%s] "
++                          "into the alias list\n", emails[c]);
++                    goto done;
++                }
++            }
++        }
++    } else if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_ALL, "No email addresses available.\n");
++    } else {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "sysdb_attrs_get_string_array failed, skipping ...\n");
++    }
++
++    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,
+@@ -2030,6 +2073,12 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 goto done;
+             }
+ 
++            ret = add_emails_to_aliases(attrs->sysdb_attrs, dom);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "add_emails_to_aliases failed, skipping ...\n");
++            }
++
+             if (upn == NULL) {
+                 /* We also have to store a fake UPN here, because otherwise the
+                  * krb5 child later won't be able to properly construct one as
+diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c
+index 696af51d66e279d718e9af142ce5ed871eae7727..a3a9642171ca057be5a59dfae192803b84c501c8 100644
+--- a/src/providers/ldap/sdap_utils.c
++++ b/src/providers/ldap/sdap_utils.c
+@@ -87,6 +87,7 @@ sdap_save_all_names(const char *name,
+     int i;
+     bool lowercase = !dom->case_sensitive;
+     bool store_as_fqdn;
++    const char **emails;
+ 
+     switch (entry_type) {
+     case SYSDB_MEMBER_USER:
+@@ -143,6 +144,27 @@ sdap_save_all_names(const char *name,
+ 
+     }
+ 
++    ret = sysdb_attrs_get_string_array(ldap_attrs, SYSDB_USER_EMAIL, tmp_ctx,
++                                       &emails);
++    if (ret == EOK) {
++        for (i = 0; emails[i] != NULL; i++) {
++            if (is_email_from_domain(emails[i], dom)) {
++                ret = sysdb_attrs_add_lc_name_alias_safe(attrs, emails[i]);
++                if (ret) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "Failed to add lower-cased version of email [%s] "
++                          "into the alias list\n", emails[i]);
++                    goto done;
++                }
++            }
++        }
++    } else if (ret == ENOENT) {
++        DEBUG(SSSDBG_TRACE_ALL, "No email addresses available.\n");
++    } else {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "sysdb_attrs_get_string_array failed, skipping ...\n");
++    }
++
+     ret = EOK;
+ done:
+     talloc_free(tmp_ctx);
+-- 
+2.4.11
+
diff --git a/SOURCES/0056-UTIL-Provide-a-common-interface-to-safely-create-tem.patch b/SOURCES/0056-UTIL-Provide-a-common-interface-to-safely-create-tem.patch
deleted file mode 100644
index 0d73afe..0000000
--- a/SOURCES/0056-UTIL-Provide-a-common-interface-to-safely-create-tem.patch
+++ /dev/null
@@ -1,377 +0,0 @@
-From 2b13d8192f0d7a08bb16a3e488e772d54b10d81a Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 12 Aug 2015 12:41:44 +0200
-Subject: [PATCH 56/57] UTIL: Provide a common interface to safely create
- temporary files
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/tests/cmocka/test_utils.c | 175 ++++++++++++++++++++++++++++++++++++++++++
- src/util/util.c               | 127 ++++++++++++++++++++++++++++++
- src/util/util.h               |  21 +++++
- 3 files changed, 323 insertions(+)
-
-diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
-index d3d00feda0bdd4048519f90ba48ae9d1042a95a1..c7ebe0997ec00197e8852bedbcf26ef1f6394fc3 100644
---- a/src/tests/cmocka/test_utils.c
-+++ b/src/tests/cmocka/test_utils.c
-@@ -1212,6 +1212,168 @@ void test_fix_domain_in_name_list(void **state)
-     talloc_free(dom);
- }
- 
-+struct unique_file_test_ctx {
-+    char *filename;
-+};
-+
-+static int unique_file_test_setup(void **state)
-+{
-+    struct unique_file_test_ctx *test_ctx;
-+
-+    assert_true(leak_check_setup());
-+    check_leaks_push(global_talloc_context);
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct unique_file_test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    test_ctx->filename = talloc_strdup(test_ctx, "test_unique_file_XXXXXX");
-+    assert_non_null(test_ctx);
-+
-+    *state = test_ctx;
-+    return 0;
-+}
-+
-+static int unique_file_test_teardown(void **state)
-+{
-+    struct unique_file_test_ctx *test_ctx;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type(*state, struct unique_file_test_ctx);
-+
-+    errno = 0;
-+    ret = unlink(test_ctx->filename);
-+    if (ret != 0 && errno != ENOENT) {
-+        fail();
-+    }
-+
-+    talloc_free(test_ctx);
-+    assert_true(check_leaks_pop(global_talloc_context) == true);
-+    assert_true(leak_check_teardown());
-+    return 0;
-+}
-+
-+static void assert_destructor(TALLOC_CTX *owner,
-+                              struct unique_file_test_ctx *test_ctx)
-+{
-+    int fd;
-+    errno_t ret;
-+    char *check_filename;
-+
-+    /* Test that the destructor works */
-+    if (owner == NULL) {
-+        return;
-+    }
-+
-+    check_filename = talloc_strdup(test_ctx, test_ctx->filename);
-+    assert_non_null(check_filename);
-+
-+    talloc_free(owner);
-+
-+    ret = check_and_open_readonly(test_ctx->filename, &fd,
-+                                  geteuid(), getegid(),
-+                                  (S_IRUSR | S_IWUSR | S_IFREG), 0);
-+    close(fd);
-+    assert_int_not_equal(ret, EOK);
-+}
-+
-+static void sss_unique_file_test(struct unique_file_test_ctx *test_ctx,
-+                                 bool test_destructor)
-+{
-+    int fd;
-+    errno_t ret;
-+    struct stat sb;
-+    TALLOC_CTX *owner = NULL;
-+
-+    if (test_destructor) {
-+        owner = talloc_new(test_ctx);
-+        assert_non_null(owner);
-+    }
-+
-+    fd = sss_unique_file(owner, test_ctx->filename, &ret);
-+    assert_int_not_equal(fd, -1);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = check_fd(fd, geteuid(), getegid(),
-+                   (S_IRUSR | S_IWUSR | S_IFREG), 0, &sb);
-+    close(fd);
-+    assert_int_equal(ret, EOK);
-+
-+    assert_destructor(owner, test_ctx);
-+}
-+
-+static void test_sss_unique_file(void **state)
-+{
-+    struct unique_file_test_ctx *test_ctx;
-+    test_ctx = talloc_get_type(*state, struct unique_file_test_ctx);
-+    sss_unique_file_test(test_ctx, false);
-+}
-+
-+static void test_sss_unique_file_destruct(void **state)
-+{
-+    struct unique_file_test_ctx *test_ctx;
-+    test_ctx = talloc_get_type(*state, struct unique_file_test_ctx);
-+    sss_unique_file_test(test_ctx, true);
-+}
-+
-+static void test_sss_unique_file_neg(void **state)
-+{
-+    int fd;
-+    errno_t ret;
-+
-+    fd = sss_unique_file(NULL, discard_const("badpattern"), &ret);
-+    assert_int_equal(fd, -1);
-+    assert_int_equal(ret, EINVAL);
-+}
-+
-+static void sss_unique_filename_test(struct unique_file_test_ctx *test_ctx,
-+                                     bool test_destructor)
-+{
-+    int fd;
-+    errno_t ret;
-+    char *tmp_filename;
-+    TALLOC_CTX *owner = NULL;
-+
-+    tmp_filename = talloc_strdup(test_ctx, test_ctx->filename);
-+    assert_non_null(tmp_filename);
-+
-+    if (test_destructor) {
-+        owner = talloc_new(test_ctx);
-+        assert_non_null(owner);
-+    }
-+
-+    ret = sss_unique_filename(owner, test_ctx->filename);
-+    assert_int_equal(ret, EOK);
-+
-+    assert_int_equal(strncmp(test_ctx->filename,
-+                             tmp_filename,
-+                             strlen(tmp_filename) - sizeof("XXXXXX")),
-+                     0);
-+
-+    ret = check_and_open_readonly(test_ctx->filename, &fd,
-+                                  geteuid(), getegid(),
-+                                  (S_IRUSR | S_IWUSR | S_IFREG), 0);
-+    close(fd);
-+    assert_int_equal(ret, EOK);
-+
-+    assert_destructor(owner, test_ctx);
-+}
-+
-+static void test_sss_unique_filename(void **state)
-+{
-+    struct unique_file_test_ctx *test_ctx;
-+
-+    test_ctx = talloc_get_type(*state, struct unique_file_test_ctx);
-+    sss_unique_filename_test(test_ctx, false);
-+}
-+
-+static void test_sss_unique_filename_destruct(void **state)
-+{
-+    struct unique_file_test_ctx *test_ctx;
-+
-+    test_ctx = talloc_get_type(*state, struct unique_file_test_ctx);
-+    sss_unique_filename_test(test_ctx, true);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -1275,6 +1437,19 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_fix_domain_in_name_list,
-                                         confdb_test_setup,
-                                         confdb_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_unique_file,
-+                                        unique_file_test_setup,
-+                                        unique_file_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_unique_file_destruct,
-+                                        unique_file_test_setup,
-+                                        unique_file_test_teardown),
-+        cmocka_unit_test(test_sss_unique_file_neg),
-+        cmocka_unit_test_setup_teardown(test_sss_unique_filename,
-+                                        unique_file_test_setup,
-+                                        unique_file_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_unique_filename_destruct,
-+                                        unique_file_test_setup,
-+                                        unique_file_test_teardown),
-     };
- 
-     /* 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 782cd026b7928e607a8980fb5f333c794feb5b1a..f0925051a08970b191f61a533cd49dd53ae128e0 100644
---- a/src/util/util.c
-+++ b/src/util/util.c
-@@ -979,3 +979,130 @@ errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *_unix_tim
-     *_unix_time = ut;
-     return EOK;
- }
-+
-+struct tmpfile_watch {
-+    const char *filename;
-+};
-+
-+static int unlink_dbg(const char *filename)
-+{
-+    errno_t ret;
-+
-+    ret = unlink(filename);
-+    if (ret != 0) {
-+        if (errno == 2) {
-+            DEBUG(SSSDBG_TRACE_INTERNAL,
-+                  "File already removed: [%s]\n", filename);
-+            return 0;
-+        } else {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Cannot remove temporary file [%s]\n", filename);
-+            return -1;
-+        }
-+    }
-+
-+    return 0;
-+}
-+
-+static int unique_filename_destructor(void *memptr)
-+{
-+    struct tmpfile_watch *tw = talloc_get_type(memptr, struct tmpfile_watch);
-+
-+    if (tw == NULL || tw->filename == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong private pointer\n");
-+        return -1;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", tw->filename);
-+
-+    return unlink_dbg(tw->filename);
-+}
-+
-+static struct tmpfile_watch *tmpfile_watch_set(TALLOC_CTX *owner,
-+                                               const char *filename)
-+{
-+    struct tmpfile_watch *tw = NULL;
-+
-+    tw = talloc_zero(owner, struct tmpfile_watch);
-+    if (tw == NULL) {
-+        return NULL;
-+    }
-+
-+    tw->filename = talloc_strdup(tw, filename);
-+    if (tw->filename == NULL) {
-+        talloc_free(tw);
-+        return NULL;
-+    }
-+
-+    talloc_set_destructor((TALLOC_CTX *) tw,
-+                          unique_filename_destructor);
-+    return tw;
-+}
-+
-+int sss_unique_file_ex(TALLOC_CTX *owner,
-+                       char *path_tmpl,
-+                       mode_t file_umask,
-+                       errno_t *_err)
-+{
-+    size_t tmpl_len;
-+    errno_t ret;
-+    int fd = -1;
-+    mode_t old_umask;
-+    struct tmpfile_watch *tw = NULL;
-+
-+    tmpl_len = strlen(path_tmpl);
-+    if (tmpl_len < 6 || strcmp(path_tmpl + (tmpl_len - 6), "XXXXXX") != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Template too short or doesn't end with XXXXXX!\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    old_umask = umask(file_umask);
-+    fd = mkstemp(path_tmpl);
-+    umask(old_umask);
-+    if (fd == -1) {
-+        ret = errno;
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "mkstemp(\"%s\") failed [%d]: %s!\n",
-+              path_tmpl, ret, strerror(ret));
-+        goto done;
-+    }
-+
-+    if (owner != NULL) {
-+        tw = tmpfile_watch_set(owner, path_tmpl);
-+        if (tw == NULL) {
-+            unlink_dbg(path_tmpl);
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+done:
-+    if (_err) {
-+        *_err = ret;
-+    }
-+    return fd;
-+}
-+
-+int sss_unique_file(TALLOC_CTX *owner,
-+                    char *path_tmpl,
-+                    errno_t *_err)
-+{
-+    return sss_unique_file_ex(owner, path_tmpl, 077, _err);
-+}
-+
-+errno_t sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl)
-+{
-+    int fd;
-+    errno_t ret;
-+
-+    fd = sss_unique_file(owner, path_tmpl, &ret);
-+    /* We only care about a unique file name */
-+    if (fd >= 0) {
-+        close(fd);
-+    }
-+
-+    return ret;
-+}
-diff --git a/src/util/util.h b/src/util/util.h
-index 94a3ddea839f0998cb7796f1d2fe13f743de3aaf..a20d1d82eb8f10dac515ad25e7e424713bb1c099 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -658,4 +658,25 @@ int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name,
- /* convert time from generalized form to unix time */
- errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time);
- 
-+/* Creates a unique file using mkstemp with provided umask. The template
-+ * must end with XXXXXX. Returns the fd, sets _err to an errno value on error.
-+ *
-+ * Prefer using sss_unique_file() as it uses a secure umask internally.
-+ */
-+int sss_unique_file_ex(TALLOC_CTX *mem_ctx,
-+                       char *path_tmpl,
-+                       mode_t file_umask,
-+                       errno_t *_err);
-+int sss_unique_file(TALLOC_CTX *owner,
-+                    char *path_tmpl,
-+                    errno_t *_err);
-+
-+/* Creates a unique filename using mkstemp with secure umask. The template
-+ * must end with XXXXXX
-+ *
-+ * path_tmpl must be a talloc context. Destructor would be set on the filename
-+ * so that it's guaranteed the file is removed.
-+ */
-+int sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl);
-+
- #endif /* __SSSD_UTIL_H__ */
--- 
-2.4.3
-
diff --git a/SOURCES/0057-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch b/SOURCES/0057-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch
deleted file mode 100644
index dabccbf..0000000
--- a/SOURCES/0057-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch
+++ /dev/null
@@ -1,447 +0,0 @@
-From 366631d15723db68fdb5c47e18ff9253689648ab Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 24 Jul 2015 13:13:08 +0200
-Subject: [PATCH 57/57] IPA: Always re-fetch the keytab from the IPA server
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Even if a keytab for one-way trust exists, re-fetch the keytab again and
-try to use it. Fall back to the previous one if it exists.
-
-This is in order to allow the admin to re-establish the trust keytabs
-with a simple sssd restart.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- Makefile.am                                   |   2 +
- src/providers/ipa/ipa_subdomains.c            |   4 +-
- src/providers/ipa/ipa_subdomains_server.c     |  83 +++++++++----
- src/tests/cmocka/test_ipa_subdomains_server.c | 166 ++++++++++++++++++++++++--
- 4 files changed, 221 insertions(+), 34 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index 8b64317d6dce9a1ee8614916395b9afd9f11f382..ed107fd5dc76b768176a3d7236b0bf1c75f212bf 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -2550,6 +2550,8 @@ test_ipa_subdom_server_LDFLAGS = \
-     -Wl,-wrap,krb5_kt_default \
-     -Wl,-wrap,execle \
-     -Wl,-wrap,execve \
-+    -Wl,-wrap,rename \
-+    -Wl,-wrap,sss_unique_filename \
-     $(NULL)
- test_ipa_subdom_server_LDADD = \
-     $(PAM_LIBS) \
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index cec8b3918b8f832e2c7376a867448fe876da6ffc..b2e2fec353f7b168d28a880cb0f1b6181abb1ccb 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -264,7 +264,7 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-         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"));
-+            DEBUG(SSSDBG_OP_FAILURE, "get_idmap_data_from_range failed.\n");
-             goto done;
-         }
-         for (d = 0; d < c; d++) {
-@@ -272,7 +272,7 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
-                                             &sid2, &rid2, &range2, &mapping2);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      ("get_idmap_data_from_range failed.\n"));
-+                      "get_idmap_data_from_range failed.\n");
-                 goto done;
-             }
- 
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index 4bfea61e6dd0a02f6b723a39f7ba236c914009b0..dfecab1bc362b5772379bae6d51f9cef8443f225 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -445,6 +445,17 @@ static void ipa_getkeytab_exec(const char *ccache,
-         exit(1);
-     }
- 
-+    /* ipa-getkeytab cannot add keys to an empty file, let's unlink it and only
-+     * use the filename */
-+    ret = unlink(keytab_path);
-+    if (ret == -1) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to unlink the temporary ccname [%d][%s]\n",
-+              ret, sss_strerror(ret));
-+        exit(1);
-+    }
-+
-     errno = 0;
-     ret = execle(IPA_GETKEYTAB_PATH, IPA_GETKEYTAB_PATH,
-                  "-r", "-s", server, "-p", principal, "-k", keytab_path, NULL,
-@@ -561,6 +572,7 @@ struct ipa_server_trust_add_state {
-     uint32_t direction;
-     const char *forest;
-     const char *keytab;
-+    char *new_keytab;
-     const char *principal;
-     const char *forest_realm;
-     const char *ccache;
-@@ -660,21 +672,20 @@ static errno_t ipa_server_trust_add_1way(struct tevent_req *req)
-         return EIO;
-     }
- 
--    ret = ipa_check_keytab(state->keytab,
--                           state->id_ctx->server_mode->kt_owner_uid,
--                           state->id_ctx->server_mode->kt_owner_gid);
--    if (ret == EOK) {
--        DEBUG(SSSDBG_TRACE_FUNC,
--              "Keytab already present, can add the trust\n");
--        return EOK;
--    } else if (ret != ENOENT) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Failed to check for keytab: %d\n", ret);
-+    state->new_keytab = talloc_asprintf(state, "%sXXXXXX", state->keytab);
-+    if (state->new_keytab == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_unique_filename(state, state->new_keytab);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create temporary keytab name\n");
-         return ret;
-     }
- 
-     DEBUG(SSSDBG_TRACE_FUNC,
--          "No keytab for %s\n", state->subdom->name);
-+          "Will re-fetch keytab for %s\n", state->subdom->name);
- 
-     hostname = dp_opt_get_string(state->id_ctx->ipa_options->basic,
-                                  IPA_HOSTNAME);
-@@ -691,7 +702,7 @@ static errno_t ipa_server_trust_add_1way(struct tevent_req *req)
-                                 state->ccache,
-                                 hostname,
-                                 state->principal,
--                                state->keytab);
-+                                state->new_keytab);
-     if (subreq == NULL) {
-         return ENOMEM;
-     }
-@@ -710,23 +721,49 @@ static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq)
-     ret = ipa_getkeytab_recv(subreq, NULL);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, "ipa_getkeytab_recv failed: %d\n", ret);
--        tevent_req_error(req, ret);
--        return;
-+        /* Do not fail here, but try to check and use the previous keytab,
-+         * if any */
-+        DEBUG(SSSDBG_MINOR_FAILURE, "ipa_getkeytab_recv failed: %d\n", ret);
-+    } else {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "Keytab successfully retrieved to %s\n", state->new_keytab);
-     }
- 
--    DEBUG(SSSDBG_TRACE_FUNC,
--          "Keytab successfully retrieved to %s\n", state->keytab);
--
--    ret = ipa_check_keytab(state->keytab,
-+    ret = ipa_check_keytab(state->new_keytab,
-                            state->id_ctx->server_mode->kt_owner_uid,
-                            state->id_ctx->server_mode->kt_owner_gid);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, "ipa_check_keytab failed: %d\n", ret);
--        tevent_req_error(req, ret);
--        return;
-+    if (ret == EOK) {
-+        ret = rename(state->new_keytab, state->keytab);
-+        if (ret == -1) {
-+            ret = errno;
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                "rename failed [%d][%s].\n", ret, strerror(ret));
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+        DEBUG(SSSDBG_TRACE_INTERNAL, "Keytab renamed to %s\n", state->keytab);
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Trying to recover and use the previous keytab, if available\n");
-+        ret = ipa_check_keytab(state->keytab,
-+                               state->id_ctx->server_mode->kt_owner_uid,
-+                               state->id_ctx->server_mode->kt_owner_gid);
-+        if (ret == EOK) {
-+            DEBUG(SSSDBG_TRACE_FUNC,
-+                  "The previous keytab %s contains the expected principal\n",
-+                  state->keytab);
-+        } else {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Cannot use the old keytab: %d\n", ret);
-+            /* Nothing we can do now */
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-     }
- 
-+    DEBUG(SSSDBG_TRACE_FUNC,
-+          "Keytab %s contains the expected principals\n", state->new_keytab);
-+
-     ret = ipa_server_trust_add_step(req);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
-diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c
-index a4cb8c2b7538dc84b74e0227205b73780844b652..fb9bd80e299c05fa230599d442fa361ae757dcd3 100644
---- a/src/tests/cmocka/test_ipa_subdomains_server.c
-+++ b/src/tests/cmocka/test_ipa_subdomains_server.c
-@@ -66,33 +66,79 @@
- #define ONEWAY_PRINC    DOM_FLAT"$"
- #define ONEWAY_AUTHID   ONEWAY_PRINC"@"SUBDOM_REALM
- 
-+static bool global_rename_called;
-+
- krb5_error_code __wrap_krb5_kt_default(krb5_context context, krb5_keytab *id)
- {
-     return krb5_kt_resolve(context, KEYTAB_PATH, id);
- }
- 
--static void create_dummy_keytab(void)
-+static void create_dummy_keytab(const char *dummy_kt)
- {
-     errno_t ret;
- 
--    assert_non_null(ONEWAY_KEYTAB);
-+    assert_non_null(dummy_kt);
-     mock_keytab_with_contents(global_talloc_context,
--                              ONEWAY_KEYTAB, ONEWAY_AUTHID);
-+                              dummy_kt, ONEWAY_AUTHID);
- 
--    ret = access(ONEWAY_KEYTAB, R_OK);
-+    ret = access(dummy_kt, R_OK);
-     assert_int_equal(ret, 0);
- }
- 
-+static int wrap_exec(void)
-+{
-+    const char *test_kt;
-+    const char *fail_creating_kt;
-+
-+    test_kt = getenv("TEST_KT_ENV");
-+    if (test_kt == NULL) {
-+        _exit(1);
-+    }
-+    unsetenv("TEST_KT_ENV");
-+
-+    fail_creating_kt = getenv("KT_CREATE_FAIL");
-+    if (fail_creating_kt != NULL) {
-+        _exit(1);
-+    }
-+
-+    create_dummy_keytab(test_kt);
-+    _exit(0);
-+
-+    return 1;   /* Should not happen */
-+}
-+
- int __wrap_execle(const char *path, const char *arg, ...)
- {
--    create_dummy_keytab();
--    _exit(0);
-+    return wrap_exec();
- }
- 
- int __wrap_execve(const char *path, const char *arg, ...)
- {
--    create_dummy_keytab();
--    _exit(0);
-+    return wrap_exec();
-+}
-+
-+errno_t __real_sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl);
-+
-+errno_t __wrap_sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl)
-+{
-+    int ret;
-+    int sret;
-+
-+    ret = __real_sss_unique_filename(owner, path_tmpl);
-+    if (ret == EOK) {
-+
-+        sret = setenv("TEST_KT_ENV", path_tmpl, 1);
-+        assert_int_equal(sret, 0);
-+    }
-+    return ret;
-+}
-+
-+int __real_rename(const char *old, const char *new);
-+
-+int __wrap_rename(const char *old, const char *new)
-+{
-+    global_rename_called = true;
-+    return __real_rename(old, new);
- }
- 
- struct trust_test_ctx {
-@@ -100,6 +146,7 @@ struct trust_test_ctx {
-     struct be_ctx *be_ctx;
- 
-     struct ipa_id_ctx *ipa_ctx;
-+    bool expect_rename;
- };
- 
- static struct ipa_id_ctx *mock_ipa_ctx(TALLOC_CTX *mem_ctx,
-@@ -244,6 +291,8 @@ static int test_ipa_server_create_trusts_setup(void **state)
- 
-     mock_keytab_with_contents(test_ctx, KEYTAB_PATH, KEYTAB_TEST_PRINC);
- 
-+    global_rename_called = false;
-+
-     *state = test_ctx;
-     return 0;
- }
-@@ -260,6 +309,11 @@ static int test_ipa_server_create_trusts_teardown(void **state)
-     unlink(ONEWAY_KEYTAB);
-     /* Ignore failures */
- 
-+    /* If a test needs this variable, it should be set again in
-+     * each test
-+     */
-+    unsetenv("KT_CREATE_FAIL");
-+
-     talloc_free(test_ctx);
-     return 0;
- }
-@@ -612,6 +666,8 @@ static void test_ipa_server_create_oneway(void **state)
- 
-     assert_null(test_ctx->ipa_ctx->server_mode->trusts);
- 
-+    test_ctx->expect_rename = true;
-+
-     req = ipa_server_create_trusts_send(test_ctx,
-                                         test_ctx->tctx->ev,
-                                         test_ctx->be_ctx,
-@@ -635,6 +691,8 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req)
-     talloc_zfree(req);
-     assert_int_equal(ret, EOK);
- 
-+    assert_true(test_ctx->expect_rename == global_rename_called);
-+
-     ret = access(ONEWAY_KEYTAB, R_OK);
-     assert_int_equal(ret, 0);
- 
-@@ -674,10 +732,46 @@ static void test_ipa_server_create_oneway_kt_exists(void **state)
- 
-     add_test_1way_subdomains(test_ctx);
- 
--    create_dummy_keytab();
-+    create_dummy_keytab(ONEWAY_KEYTAB);
-     ret = access(ONEWAY_KEYTAB, R_OK);
-     assert_int_equal(ret, 0);
- 
-+    test_ctx->expect_rename = true;
-+
-+    assert_null(test_ctx->ipa_ctx->server_mode->trusts);
-+
-+    req = ipa_server_create_trusts_send(test_ctx,
-+                                        test_ctx->tctx->ev,
-+                                        test_ctx->be_ctx,
-+                                        test_ctx->ipa_ctx,
-+                                        test_ctx->be_ctx->domain);
-+    assert_non_null(req);
-+
-+    tevent_req_set_callback(req, test_ipa_server_create_trusts_oneway, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+}
-+
-+/* Test scenario where a keytab already exists, but refresh fails. In this case,
-+ * sssd should attempt to reuse the previous keytab
-+ */
-+static void test_ipa_server_create_oneway_kt_refresh_fallback(void **state)
-+{
-+    struct trust_test_ctx *test_ctx =
-+        talloc_get_type(*state, struct trust_test_ctx);
-+    struct tevent_req *req;
-+    errno_t ret;
-+
-+    add_test_1way_subdomains(test_ctx);
-+
-+    create_dummy_keytab(ONEWAY_KEYTAB);
-+    ret = access(ONEWAY_KEYTAB, R_OK);
-+    assert_int_equal(ret, 0);
-+
-+    setenv("KT_CREATE_FAIL", "1", 1);
-+    test_ctx->expect_rename = false;
-+
-     assert_null(test_ctx->ipa_ctx->server_mode->trusts);
- 
-     req = ipa_server_create_trusts_send(test_ctx,
-@@ -693,6 +787,54 @@ static void test_ipa_server_create_oneway_kt_exists(void **state)
-     assert_int_equal(ret, ERR_OK);
- }
- 
-+/* Tests case where there's no keytab and retrieving fails. Just fail the
-+ * request in that case
-+ */
-+static void test_ipa_server_create_trusts_oneway_fail(struct tevent_req *req);
-+
-+static void test_ipa_server_create_oneway_kt_refresh_fail(void **state)
-+{
-+    struct trust_test_ctx *test_ctx =
-+        talloc_get_type(*state, struct trust_test_ctx);
-+    struct tevent_req *req;
-+    errno_t ret;
-+
-+    add_test_1way_subdomains(test_ctx);
-+
-+    setenv("KT_CREATE_FAIL", "1", 1);
-+    test_ctx->expect_rename = false;
-+
-+    assert_null(test_ctx->ipa_ctx->server_mode->trusts);
-+
-+    req = ipa_server_create_trusts_send(test_ctx,
-+                                        test_ctx->tctx->ev,
-+                                        test_ctx->be_ctx,
-+                                        test_ctx->ipa_ctx,
-+                                        test_ctx->be_ctx->domain);
-+    assert_non_null(req);
-+
-+    tevent_req_set_callback(req,
-+                            test_ipa_server_create_trusts_oneway_fail,
-+                            test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, ERR_OK);
-+}
-+
-+static void test_ipa_server_create_trusts_oneway_fail(struct tevent_req *req)
-+{
-+    struct trust_test_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct trust_test_ctx);
-+    errno_t ret;
-+
-+    ret = ipa_server_create_trusts_recv(req);
-+    assert_int_not_equal(ret, EOK);
-+
-+    assert_true(test_ctx->expect_rename == global_rename_called);
-+
-+    test_ev_done(test_ctx->tctx, EOK);
-+}
-+
- static void test_ipa_server_trust_oneway_init(void **state)
- {
-     struct trust_test_ctx *test_ctx =
-@@ -749,6 +891,12 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_exists,
-                                         test_ipa_server_create_trusts_setup,
-                                         test_ipa_server_create_trusts_teardown),
-+        cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_refresh_fallback,
-+                                        test_ipa_server_create_trusts_setup,
-+                                        test_ipa_server_create_trusts_teardown),
-+        cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_refresh_fail,
-+                                        test_ipa_server_create_trusts_setup,
-+                                        test_ipa_server_create_trusts_teardown),
-         cmocka_unit_test_setup_teardown(test_ipa_server_trust_oneway_init,
-                                         test_ipa_server_create_trusts_setup,
-                                         test_ipa_server_create_trusts_teardown),
--- 
-2.4.3
-
diff --git a/SOURCES/0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch b/SOURCES/0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch
new file mode 100644
index 0000000..0155ae1
--- /dev/null
+++ b/SOURCES/0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch
@@ -0,0 +1,98 @@
+From 481bd8fd5db7a92954ff351ab64ab32b4249bf19 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 21 Jun 2016 11:06:19 +0200
+Subject: [PATCH 57/62] NSS: continue with UPN/email search if name was not
+ found
+
+Currently we only search for UPNs if the domain part of the name was not
+know, with Kerberos aliases and email addresses we have to do this even
+if the domain name is a know domain.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 447b1da857368678990b54cd6b9cfed940357c44)
+---
+ src/responder/nss/nsssrv_cmd.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 77e540d8da969614e4ab40c62e6ae1f271962f31..cd15b41886ad046d1d70dbd8ad54af5a4eccee5d 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -980,6 +980,7 @@ done:
+ 
+ static void nss_cmd_getby_dp_callback(uint16_t err_maj, uint32_t err_min,
+                                       const char *err_msg, void *ptr);
++static int nss_cmd_assume_upn(struct nss_dom_ctx *dctx);
+ 
+ /* search for a user.
+  * Returns:
+@@ -1051,6 +1052,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
+             /* There are no further domains or this was a
+              * fully-qualified user request.
+              */
++
+             return ENOENT;
+         }
+ 
+@@ -1144,8 +1146,6 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
+                 if (dom) continue;
+             }
+ 
+-            DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");
+-
+             /* User not found in ldb -> delete user from memory cache. */
+             ret = delete_entry_from_memcache(dctx->domain, name, nctx->rctx,
+                                              nctx->pwd_mc_ctx, SSS_MC_PASSWD);
+@@ -1163,6 +1163,8 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
+                       "Deleting user from memcache failed.\n");
+             }
+ 
++            DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");
++
+             return ENOENT;
+         }
+ 
+@@ -1215,7 +1217,7 @@ static int nss_cmd_assume_upn(struct nss_dom_ctx *dctx)
+ {
+     int ret;
+ 
+-    if (dctx->domain == NULL) {
++    if (dctx->cmdctx->name_is_upn == false) {
+         dctx->domain = dctx->cmdctx->cctx->rctx->domains;
+         dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
+         dctx->cmdctx->check_next = true;
+@@ -1563,6 +1565,7 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx)
+ 
+     rawname = (const char *)body;
+     dctx->mc_name = rawname;
++    dctx->rawname = rawname;
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "Running command [%d][%s] with input [%s].\n",
+           cmd, sss_cmd2str(dctx->cmdctx->cmd), rawname);
+@@ -1588,7 +1591,6 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx)
+         if (req == NULL) {
+             ret = ENOMEM;
+         } else {
+-            dctx->rawname = rawname;
+             tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx);
+             ret = EAGAIN;
+         }
+@@ -1604,7 +1606,6 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx)
+         if (req == NULL) {
+             ret = ENOMEM;
+         } else {
+-            dctx->rawname = rawname;
+             tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx);
+             ret = EAGAIN;
+         }
+@@ -1626,7 +1627,6 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx)
+         }
+     } else {
+         /* this is a multidomain search */
+-        dctx->rawname = rawname;
+         dctx->domain = cctx->rctx->domains;
+         cmdctx->check_next = true;
+         if (cctx->rctx->get_domains_last_call.tv_sec == 0) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch b/SOURCES/0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch
new file mode 100644
index 0000000..3910eb3
--- /dev/null
+++ b/SOURCES/0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch
@@ -0,0 +1,90 @@
+From d8c0b5421934cae887a44be42250d5df5631d3de Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 22 Jun 2016 18:21:11 +0200
+Subject: [PATCH 58/62] PAM: continue with UPN/email search if name was not
+ found
+
+Currently we only search for UPNs if the domain part of the name was not
+know, with Kerberos aliases and email addresses we have to do this even
+if the domain name is a know domain.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 3381d9736b698d6111d10e219a0b5b898a4c757c)
+---
+ src/responder/pam/pamsrv_cmd.c | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 3a35c3f08821aa23051989599d45b8b7b0677da4..1c759f009321cbb322fce624b506ed07f93f997b 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -924,6 +924,39 @@ static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
+ static int pam_check_user_search(struct pam_auth_req *preq);
+ static int pam_check_user_done(struct pam_auth_req *preq, int ret);
+ 
++static errno_t pam_cmd_assume_upn(struct pam_auth_req *preq)
++{
++    int ret;
++
++    if (!preq->pd->name_is_upn
++            && preq->pd->logon_name != NULL
++            && strchr(preq->pd->logon_name, '@') != NULL) {
++        DEBUG(SSSDBG_TRACE_ALL,
++              "No entry found so far, trying UPN/email lookup with [%s].\n",
++              preq->pd->logon_name);
++        /* Assuming Kerberos principal */
++        preq->domain = preq->cctx->rctx->domains;
++        preq->check_provider =
++                            NEED_CHECK_PROVIDER(preq->domain->provider);
++        preq->pd->user = talloc_strdup(preq->pd, preq->pd->logon_name);
++        if (preq->pd->user == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++            return ENOMEM;
++        }
++        preq->pd->name_is_upn = true;
++        preq->pd->domain = NULL;
++
++        ret = pam_check_user_search(preq);
++        if (ret == EOK) {
++            pam_dom_forwarder(preq);
++        }
++        return EOK;
++    }
++
++    return ENOENT;
++}
++
++
+ /* TODO: we should probably return some sort of cookie that is set in the
+  * PAM_ENVIRONMENT, so that we can save performing some calls and cache
+  * data. */
+@@ -1220,6 +1253,8 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+     ret = pam_check_user_search(preq);
+     if (ret == EOK) {
+         pam_dom_forwarder(preq);
++    } else if (ret == ENOENT) {
++        ret = pam_cmd_assume_upn(preq);
+     }
+ 
+ done:
+@@ -1417,6 +1452,8 @@ static void pam_forwarder_cb(struct tevent_req *req)
+     ret = pam_check_user_search(preq);
+     if (ret == EOK) {
+         pam_dom_forwarder(preq);
++    } else if  (ret == ENOENT) {
++        ret = pam_cmd_assume_upn(preq);
+     }
+ 
+ done:
+@@ -1694,6 +1731,8 @@ static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
+         }
+ 
+         pam_dom_forwarder(preq);
++    } else if (ret == ENOENT) {
++        ret = pam_cmd_assume_upn(preq);
+     }
+ 
+     ret = pam_check_user_done(preq, ret);
+-- 
+2.4.11
+
diff --git a/SOURCES/0058-p11child-set-restrictive-umask-and-clear-environment.patch b/SOURCES/0058-p11child-set-restrictive-umask-and-clear-environment.patch
deleted file mode 100644
index e2448b9..0000000
--- a/SOURCES/0058-p11child-set-restrictive-umask-and-clear-environment.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 5845a325b10e48b1e4c21976b0856ad1d012bbb4 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 5 Aug 2015 17:25:20 +0200
-Subject: [PATCH 58/59] p11child: set restrictive umask and clear environment
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2754
-
-Before doing any calls, set a very restrictive umask and clear
-environment variables to harden p11child execution.
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
----
- src/p11_child/p11_child_nss.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index 6948c142aa7843cda5ff6d18f5853b10c387c224..44ba6678893408dbfc0c6c7cfd5edcdaa789f518 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -481,6 +481,9 @@ 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;
- 
-+    clearenv();
-+    umask(077);
-+
-     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
-     while ((opt = poptGetNextOpt(pc)) != -1) {
-         switch(opt) {
--- 
-2.4.3
-
diff --git a/SOURCES/0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch b/SOURCES/0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch
new file mode 100644
index 0000000..e77eb21
--- /dev/null
+++ b/SOURCES/0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch
@@ -0,0 +1,59 @@
+From e5b8922062e127d1014609df16f1909da49850bf Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Jul 2016 16:01:38 +0200
+Subject: [PATCH 59/62] NSS: use different neg cache name for UPN searches
+
+If Kerberos principals or email address have the same domain suffix as
+the domain itself the first user lookup by name might have already added
+the name to the negative cache and the second lookup by UPN/email will
+skip the domain because of the neg cache entry. To avoid this a special
+name with a '@' prefix is used here.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 62df78512145db94b51c5573d4df1737197e368a)
+---
+ src/responder/nss/nsssrv_cmd.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index cd15b41886ad046d1d70dbd8ad54af5a4eccee5d..f3b6ac4afb5d1571f283933b48e0256b91c56391 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -1002,6 +1002,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
+     struct ldb_message *msg;
+     const char *extra_flag = NULL;
+     const char *sysdb_name;
++    char *neg_cache_name;
+ 
+     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
+ 
+@@ -1031,9 +1032,15 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
+             return ENOMEM;
+         }
+ 
++        if (cmdctx->name_is_upn) {
++            neg_cache_name = talloc_asprintf(name, "@%s", name);
++        } else {
++            neg_cache_name = name;
++        }
++
+         /* verify this user has not yet been negatively cached,
+         * or has been permanently filtered */
+-        ret = sss_ncache_check_user(nctx->rctx->ncache, dom, name);
++        ret = sss_ncache_check_user(nctx->rctx->ncache, dom, neg_cache_name);
+ 
+         /* if neg cached, return we didn't find it */
+         if (ret == EEXIST) {
+@@ -1130,7 +1137,8 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
+ 
+         if (dctx->res->count == 0 && !dctx->check_provider) {
+             /* set negative cache only if not result of cache check */
+-            ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom, name);
++            ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom,
++                                      neg_cache_name);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s\n",
+                       name);
+-- 
+2.4.11
+
diff --git a/SOURCES/0059-pam-Incerease-p11-child-timeout.patch b/SOURCES/0059-pam-Incerease-p11-child-timeout.patch
deleted file mode 100644
index 8ff29a0..0000000
--- a/SOURCES/0059-pam-Incerease-p11-child-timeout.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From 8cc5a9b94d6d660d61cce62543b6714d95e19697 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 13 Aug 2015 14:03:24 +0200
-Subject: [PATCH 59/59] pam: Incerease p11 child timeout
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Ticket:
-https://fedorahosted.org/sssd/ticket/2746
-
-It was timeouting often in CI machines.
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
----
- Makefile.am                    | 1 +
- src/responder/pam/pamsrv_cmd.c | 9 +++++++--
- 2 files changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index ed107fd5dc76b768176a3d7236b0bf1c75f212bf..7dc4875c9cb05bf146505c0dc0dab543fb326bd3 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1892,6 +1892,7 @@ pam_srv_tests_SOURCES = \
- pam_srv_tests_CFLAGS = \
-     -U SSSD_LIBEXEC_PATH -DSSSD_LIBEXEC_PATH=\"$(abs_builddir)\" \
-     $(AM_CFLAGS) \
-+    -DSSS_P11_CHILD_TIMEOUT=30 \
-     $(NULL)
- pam_srv_tests_LDFLAGS = \
-     -Wl,-wrap,sss_packet_get_body \
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index 3b84fb864c5a1b08dc4126ff97e258a792f312bc..aa5c20906a36351e425304122517c81676e730b7 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -43,6 +43,11 @@ enum pam_verbosity {
- 
- #define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT
- 
-+/* TODO: Should we make this configurable? */
-+#ifndef SSS_P11_CHILD_TIMEOUT
-+#define SSS_P11_CHILD_TIMEOUT 10
-+#endif
-+
- static errno_t
- pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
-                                           const char *username);
-@@ -1122,7 +1127,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
- 
-     if (may_do_cert_auth(pctx, pd)) {
-         req = pam_check_cert_send(cctx, cctx->ev, pctx->p11_child_debug_fd,
--                                  pctx->nss_db, 10, pd);
-+                                  pctx->nss_db, SSS_P11_CHILD_TIMEOUT, pd);
-         if (req == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
-             ret = ENOMEM;
-@@ -1338,7 +1343,7 @@ static void pam_forwarder_cb(struct tevent_req *req)
- 
-     if (may_do_cert_auth(pctx, pd)) {
-         req = pam_check_cert_send(cctx, cctx->ev, pctx->p11_child_debug_fd,
--                                  pctx->nss_db, 10, pd);
-+                                  pctx->nss_db, SSS_P11_CHILD_TIMEOUT, pd);
-         if (req == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
-             ret = ENOMEM;
--- 
-2.4.3
-
diff --git a/SOURCES/0060-PAM-Fix-domain-for-UPN-based-lookups.patch b/SOURCES/0060-PAM-Fix-domain-for-UPN-based-lookups.patch
new file mode 100644
index 0000000..ca64d2b
--- /dev/null
+++ b/SOURCES/0060-PAM-Fix-domain-for-UPN-based-lookups.patch
@@ -0,0 +1,52 @@
+From 3467754b1e32e648b3013244dcbac51677a089eb Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Jul 2016 17:34:20 +0200
+Subject: [PATCH 60/62] PAM: Fix domain for UPN based lookups
+
+Since sysdb_search_user_by_upn() searches the whole cache we have to set
+the domain so that it matches the result.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 9b8fcf685c5ca70a5067a621385bcdc8d9fd6469)
+---
+ src/responder/pam/pamsrv_cmd.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 1c759f009321cbb322fce624b506ed07f93f997b..66564f5d301a53dcdb5967f43ef4afdb897e9974 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -1474,6 +1474,7 @@ static int pam_check_user_search(struct pam_auth_req *preq)
+     static const char *user_attrs[] = SYSDB_PW_ATTRS;
+     struct ldb_message *msg;
+     struct ldb_result *res;
++    const char *sysdb_name;
+ 
+     while (dom) {
+        /* if it is a domainless search, skip domains that require fully
+@@ -1533,6 +1534,22 @@ static int pam_check_user_search(struct pam_auth_req *preq)
+ 
+         if (preq->pd->name_is_upn) {
+             ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg);
++
++            /* Since sysdb_search_user_by_upn() searches the whole cache we
++             * have to set the domain so that it matches the result. */
++            sysdb_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
++            if (sysdb_name == NULL) {
++                DEBUG(SSSDBG_CRIT_FAILURE, "Cached entry has no name.\n");
++                return EINVAL;
++            }
++            preq->domain = find_domain_by_object_name(get_domains_head(dom),
++                                                      sysdb_name);
++            if (preq->domain == NULL) {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Cannot find matching domain for [%s].\n",
++                      sysdb_name);
++                return EINVAL;
++            }
+         } else {
+             ret = sysdb_getpwnam_with_views(preq, dom, name, &res);
+             if (res->count > 1) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0060-SYSDB-Index-the-objectSIDString-attribute.patch b/SOURCES/0060-SYSDB-Index-the-objectSIDString-attribute.patch
deleted file mode 100644
index 660e3a1..0000000
--- a/SOURCES/0060-SYSDB-Index-the-objectSIDString-attribute.patch
+++ /dev/null
@@ -1,130 +0,0 @@
-From c50681fc7a1296c278466e834eaddfbf2bc54afb Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 25 Jun 2015 17:33:47 +0200
-Subject: [PATCH] SYSDB: Index the objectSIDString attribute
-
----
- src/db/sysdb.c         |  7 +++++++
- src/db/sysdb_private.h |  5 ++++-
- src/db/sysdb_upgrade.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 61 insertions(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb.c b/src/db/sysdb.c
-index 9da655759c0c35d52854b668693195b3360c5f8b..07a83a8a8e30df1b8e461a8d04866f2dbc53baf8 100644
---- a/src/db/sysdb.c
-+++ b/src/db/sysdb.c
-@@ -1265,6 +1265,13 @@ int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx,
-             }
-         }
- 
-+        if (strcmp(version, SYSDB_VERSION_0_16) == 0) {
-+            ret = sysdb_upgrade_16(sysdb, &version);
-+            if (ret != EOK) {
-+                goto done;
-+            }
-+        }
-+
-         /* The version should now match SYSDB_VERSION.
-          * If not, it means we didn't match any of the
-          * known older versions. The DB might be
-diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
-index 2adb9ff9166441014a8b446ffc170225f2a9629d..c2c8d7a0585463806997c43bd020436edddd8517 100644
---- a/src/db/sysdb_private.h
-+++ b/src/db/sysdb_private.h
-@@ -23,6 +23,7 @@
- #ifndef __INT_SYS_DB_H__
- #define __INT_SYS_DB_H__
- 
-+#define SYSDB_VERSION_0_17 "0.17"
- #define SYSDB_VERSION_0_16 "0.16"
- #define SYSDB_VERSION_0_15 "0.15"
- #define SYSDB_VERSION_0_14 "0.14"
-@@ -40,7 +41,7 @@
- #define SYSDB_VERSION_0_2 "0.2"
- #define SYSDB_VERSION_0_1 "0.1"
- 
--#define SYSDB_VERSION SYSDB_VERSION_0_16
-+#define SYSDB_VERSION SYSDB_VERSION_0_17
- 
- #define SYSDB_BASE_LDIF \
-      "dn: @ATTRIBUTES\n" \
-@@ -68,6 +69,7 @@
-      "@IDXATTR: serviceProtocol\n" \
-      "@IDXATTR: sudoUser\n" \
-      "@IDXATTR: sshKnownHostsExpire\n" \
-+     "@IDXATTR: objectSIDString\n" \
-      "@IDXONE: 1\n" \
-      "\n" \
-      "dn: @MODULES\n" \
-@@ -120,6 +122,7 @@ int sysdb_upgrade_12(struct sysdb_ctx *sysdb, const char **ver);
- int sysdb_upgrade_13(struct sysdb_ctx *sysdb, const char **ver);
- int sysdb_upgrade_14(struct sysdb_ctx *sysdb, const char **ver);
- int sysdb_upgrade_15(struct sysdb_ctx *sysdb, const char **ver);
-+int sysdb_upgrade_16(struct sysdb_ctx *sysdb, const char **ver);
- 
- int add_string(struct ldb_message *msg, int flags,
-                const char *attr, const char *value);
-diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
-index 6cebc877b86df7a8035bf95cfa51aa4dae464372..113f24644e3e3de1d4c46d375492c2fe1e6b2f83 100644
---- a/src/db/sysdb_upgrade.c
-+++ b/src/db/sysdb_upgrade.c
-@@ -1584,6 +1584,56 @@ done:
-     return ret;
- }
- 
-+int sysdb_upgrade_16(struct sysdb_ctx *sysdb, const char **ver)
-+{
-+    struct ldb_message *msg;
-+    struct upgrade_ctx *ctx;
-+    errno_t ret;
-+
-+    ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_17, &ctx);
-+    if (ret) {
-+        return ret;
-+    }
-+
-+    msg = ldb_msg_new(ctx);
-+    if (msg == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
-+    if (msg->dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    /* add index for objectSIDString */
-+    ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_msg_add_string(msg, "@IDXATTR", "objectSIDString");
-+    if (ret != LDB_SUCCESS) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_modify(sysdb->ldb, msg);
-+    if (ret != LDB_SUCCESS) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    /* conversion done, update version number */
-+    ret = update_version(ctx);
-+
-+done:
-+    ret = finish_upgrade(ret, &ctx, ver);
-+    return ret;
-+}
-+
- /*
-  * Example template for future upgrades.
-  * Copy and change version numbers as appropriate.
--- 
-2.4.3
-
diff --git a/SOURCES/0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch b/SOURCES/0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch
new file mode 100644
index 0000000..13145e0
--- /dev/null
+++ b/SOURCES/0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch
@@ -0,0 +1,56 @@
+From c2fe77b2277513d01b56dc26391e8e7cfcbe7429 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Jul 2016 12:20:33 +0200
+Subject: [PATCH 61/62] SDAP: add special handling for IPA Kerberos enterprise
+ principal strings
+
+Unfortunately principal aliases with an alternative realm are stored in
+IPA as the string representation of an enterprise principal, i.e.
+name\@alt.realm@IPA.REALM. To allow searches with the plain alias
+'name@alt.realm' the returned value is converted before it is saved to
+the cache.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 15694ca762f61a414f0017c57ed97a8d57456b80)
+---
+ src/providers/ldap/sdap_async_users.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
+index 28101a2d8a38f97d09d50a9f7e071a030b4f9719..cccd2506b3e1849101a8a06c39fe6cab263777b6 100644
+--- a/src/providers/ldap/sdap_async_users.c
++++ b/src/providers/ldap/sdap_async_users.c
+@@ -143,6 +143,8 @@ int sdap_save_user(TALLOC_CTX *memctx,
+     char *dom_sid_str = NULL;
+     struct sss_domain_info *subdomain;
+     size_t c;
++    char *p1;
++    char *p2;
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "Save user\n");
+ 
+@@ -448,6 +450,21 @@ int sdap_save_user(TALLOC_CTX *memctx,
+                 goto done;
+             }
+ 
++            /* Check for IPA Kerberos enterprise principal strings
++             * 'user\@my.realm@IPA.REALM' and use 'user@my.realm' */
++            if ( (p1 = strchr(upn,'\\')) != NULL
++                    && *(p1 + 1) == '@'
++                    && (p2 = strchr(p1 + 2, '@')) != NULL) {
++                *p1 = '\0';
++                *p2 = '\0';
++                upn = talloc_asprintf(tmpctx, "%s%s", upn, p1 + 1);
++                if (upn == NULL) {
++                    DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++                    ret = ENOMEM;
++                    goto done;
++                }
++            }
++
+             if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
+                 make_realm_upper_case(upn);
+             }
+-- 
+2.4.11
+
diff --git a/SOURCES/0061-sss_override-print-input-name-if-unable-to-parse-it.patch b/SOURCES/0061-sss_override-print-input-name-if-unable-to-parse-it.patch
deleted file mode 100644
index 88aa0bb..0000000
--- a/SOURCES/0061-sss_override-print-input-name-if-unable-to-parse-it.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 90c45ac5b4e67703455b2cf04334ae0fc90188b3 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Sat, 15 Aug 2015 13:53:25 +0200
-Subject: [PATCH 61/66] sss_override: print input name if unable to parse it
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tools/sss_override.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
-index 5e901e2e31de64dacb171337defc03d428f8ed57..e84a7b922dfcf179f8010dc4cced0eafd89a2c76 100644
---- a/src/tools/sss_override.c
-+++ b/src/tools/sss_override.c
-@@ -74,7 +74,7 @@ static int parse_cmdline(struct sss_cmdline *cmdline,
-     ret = sss_tool_parse_name(tool_ctx, tool_ctx, input_name,
-                               &orig_name, &domain);
-     if (ret != EOK) {
--        fprintf(stderr, _("Unable to parse name.\n"));
-+        fprintf(stderr, _("Unable to parse name %s.\n"), input_name);
-         return ret;
-     }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch b/SOURCES/0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch
new file mode 100644
index 0000000..2077c69
--- /dev/null
+++ b/SOURCES/0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch
@@ -0,0 +1,201 @@
+From 0274cb7aa22e388e46580b288a7dd957ad955e04 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Jul 2016 20:10:42 +0200
+Subject: [PATCH 62/62] SDAP: add enterprise principal strings for user
+ searches
+
+Unfortunately principal aliases with an alternative realm are stored in
+IPA as the string representation of an enterprise principal, i.e.
+name\@alt.realm@IPA.REALM. To be able to lookup the alternative
+principal in LDAP properly the UPN search filter is extended to search
+for this type of name as well.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 50a7a92f92e1584702bf25e61a50cb1c09c7e260)
+---
+ src/providers/ldap/ldap_common.h           |  5 +++++
+ src/providers/ldap/ldap_id.c               | 10 +++++++--
+ src/providers/ldap/sdap_async_initgroups.c |  9 ++++++--
+ src/providers/ldap/sdap_utils.c            | 28 ++++++++++++++++++++++++
+ src/tests/cmocka/test_nested_groups.c      | 34 ++++++++++++++++++++++++++++++
+ 5 files changed, 82 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index b39f6789275cf49dd69068ae3de0628b582e4cc5..acdcf47cc5992609cdbf73e4ed9655eade55e214 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -300,6 +300,11 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx,
+                            const char *base_filter,
+                            const char *extra_filter);
+ 
++char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx,
++                                             const char *attr_name,
++                                             const char *princ,
++                                             struct dp_option *sdap_basic_opts);
++
+ char *sdap_get_access_filter(TALLOC_CTX *mem_ctx,
+                              const char *base_filter);
+ 
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index 5b303ddbd46fd44646cdd50856c784640426ee25..beb31fba16be76ba2ac01f99b87ee6362704f417 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -89,6 +89,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+     enum idmap_error_code err;
+     char *sid;
+     char *user_filter = NULL;
++    char *ep_filter;
+ 
+     req = tevent_req_create(memctx, &state, struct users_get_state);
+     if (!req) return NULL;
+@@ -131,12 +132,17 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+             if (ret != EOK) {
+                 goto done;
+             }
++
++            ep_filter = get_enterprise_principal_string_filter(state,
++                                   ctx->opts->user_map[SDAP_AT_USER_PRINC].name,
++                                   clean_value, ctx->opts->basic);
+             /* TODO: Do we have to check the attribute names more carefully? */
+-            user_filter = talloc_asprintf(state, "(|(%s=%s)(%s=%s))",
++            user_filter = talloc_asprintf(state, "(|(%s=%s)(%s=%s)%s)",
+                                    ctx->opts->user_map[SDAP_AT_USER_PRINC].name,
+                                    clean_value,
+                                    ctx->opts->user_map[SDAP_AT_USER_EMAIL].name,
+-                                   clean_value);
++                                   clean_value,
++                                   ep_filter == NULL ? "" : ep_filter);
+             talloc_zfree(clean_value);
+             if (user_filter == NULL) {
+                 DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index 0a42b18662a8fe12cf048aadfef257b5d9cb48a3..7029427724cc37a4508e11ef5448b421e94dc787 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -2682,7 +2682,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
+     int ret;
+     char *clean_name;
+     bool use_id_mapping;
+-    const char *search_attr;
++    const char *search_attr = NULL;
++    char *ep_filter;
+ 
+     DEBUG(SSSDBG_TRACE_ALL, "Retrieving info for initgroups call\n");
+ 
+@@ -2743,13 +2744,17 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
+                 return NULL;
+             }
+ 
++            ep_filter = get_enterprise_principal_string_filter(state,
++                                 state->opts->user_map[SDAP_AT_USER_PRINC].name,
++                                 clean_name, state->opts->basic);
+             state->user_base_filter =
+                     talloc_asprintf(state,
+-                                 "(&(|(%s=%s)(%s=%s))(objectclass=%s)",
++                                 "(&(|(%s=%s)(%s=%s)%s)(objectclass=%s)",
+                                  state->opts->user_map[SDAP_AT_USER_PRINC].name,
+                                  clean_name,
+                                  state->opts->user_map[SDAP_AT_USER_EMAIL].name,
+                                  clean_name,
++                                 ep_filter == NULL ? "" : ep_filter,
+                                  state->opts->user_map[SDAP_OC_USER].name);
+             if (state->user_base_filter == NULL) {
+                 talloc_zfree(req);
+diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c
+index a3a9642171ca057be5a59dfae192803b84c501c8..0ac3ab2e416d887d00480b5123859c611f514274 100644
+--- a/src/providers/ldap/sdap_utils.c
++++ b/src/providers/ldap/sdap_utils.c
+@@ -227,3 +227,31 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx,
+ {
+     return sdap_combine_filters_ex(mem_ctx, '&', base_filter, extra_filter);
+ }
++
++char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx,
++                                             const char *attr_name,
++                                             const char *princ,
++                                             struct dp_option *sdap_basic_opts)
++{
++    const char *realm;
++    char *p;
++
++    if (attr_name == NULL || princ == NULL || sdap_basic_opts == NULL) {
++        return NULL;
++    }
++
++    realm = dp_opt_get_cstring(sdap_basic_opts, SDAP_KRB5_REALM);
++    if (realm == NULL) {
++        return NULL;
++    }
++
++    p = strchr(princ, '@');
++    if (p == NULL) {
++        return NULL;
++    }
++
++    return talloc_asprintf(mem_ctx, "(%s=%.*s\\\\@%s@%s)", attr_name,
++                                                           (int) (p - princ),
++                                                           princ,
++                                                           p + 1, realm);
++}
+diff --git a/src/tests/cmocka/test_nested_groups.c b/src/tests/cmocka/test_nested_groups.c
+index 6af7e1f4393992e7f16d72b86e40664487896ea1..c8e80f29fb65f8f8935fea32cd4bf3e16de7d06f 100644
+--- a/src/tests/cmocka/test_nested_groups.c
++++ b/src/tests/cmocka/test_nested_groups.c
+@@ -31,6 +31,7 @@
+ #include "providers/ldap/sdap.h"
+ #include "providers/ldap/sdap_idmap.h"
+ #include "providers/ldap/sdap_async_private.h"
++#include "providers/ldap/ldap_opts.h"
+ 
+ #define TESTS_PATH "tp_" BASE_FILE_STEM
+ #define TEST_CONF_DB "test_ldap_nested_groups_conf.ldb"
+@@ -1242,6 +1243,38 @@ static void nested_group_external_member_test(void **state)
+                      nested_group.gr_name);
+ }
+ 
++static void test_get_enterprise_principal_string_filter(void **state)
++{
++    int ret;
++    char *ep_filter;
++    struct dp_option *no_krb5_realm_opt = default_basic_opts;
++
++    struct dp_option *krb5_realm_opt;
++
++    ret = dp_copy_defaults(NULL, default_basic_opts, SDAP_OPTS_BASIC,
++                           &krb5_realm_opt);
++    assert_int_equal(ret, EOK);
++
++    ret = dp_opt_set_string(krb5_realm_opt, SDAP_KRB5_REALM, "TEST.DOM");
++    assert_int_equal(ret, EOK);
++
++    ep_filter = get_enterprise_principal_string_filter(NULL, NULL, NULL, NULL);
++    assert_null(ep_filter);
++
++    ep_filter = get_enterprise_principal_string_filter(NULL, "aBC", "p@d.c",
++                                                       no_krb5_realm_opt);
++    assert_null(ep_filter);
++
++    ep_filter = get_enterprise_principal_string_filter(NULL, "aBC", "p",
++                                                       krb5_realm_opt);
++    assert_null(ep_filter);
++
++    ep_filter = get_enterprise_principal_string_filter(NULL, "aBC", "p@d.c",
++                                                       krb5_realm_opt);
++    assert_non_null(ep_filter);
++    assert_string_equal(ep_filter, "(aBC=p\\\\@d.c@TEST.DOM)");
++    talloc_free(ep_filter);
++}
+ 
+ int main(int argc, const char *argv[])
+ {
+@@ -1268,6 +1301,7 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(nested_group_external_member_test,
+                                         nested_group_external_member_setup,
+                                         nested_group_external_member_teardown),
++        cmocka_unit_test(test_get_enterprise_principal_string_filter),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.4.11
+
diff --git a/SOURCES/0062-sss_override-support-domains-that-require-fqname.patch b/SOURCES/0062-sss_override-support-domains-that-require-fqname.patch
deleted file mode 100644
index 366c47c..0000000
--- a/SOURCES/0062-sss_override-support-domains-that-require-fqname.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-From 83e150a2b200ec50f2f02229d9662e1468e286df Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 19 Aug 2015 12:28:21 +0200
-Subject: [PATCH 62/66] sss_override: support domains that require fqname
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2757
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tools/sss_override.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 57 insertions(+), 2 deletions(-)
-
-diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
-index e84a7b922dfcf179f8010dc4cced0eafd89a2c76..84b51c537842b7281a523f58c2cfbdfd38e54c72 100644
---- a/src/tools/sss_override.c
-+++ b/src/tools/sss_override.c
-@@ -272,6 +272,54 @@ static struct sysdb_attrs *build_group_attrs(TALLOC_CTX *mem_ctx,
-     return build_attrs(mem_ctx, group->name, 0, group->gid, 0, NULL, NULL);
- }
- 
-+static char *get_fqname(TALLOC_CTX *mem_ctx,
-+                        struct sss_domain_info *domain,
-+                        const char *name)
-+{
-+    char *fqname;
-+    size_t fqlen;
-+    size_t check;
-+
-+    if (domain == NULL) {
-+        return NULL;
-+    }
-+
-+    /* Get length. */
-+    fqlen = sss_fqname(NULL, 0, domain->names, domain, name);
-+    if (fqlen > 0) {
-+        fqlen++; /* \0 */
-+    } else {
-+        return NULL;
-+    }
-+
-+    fqname = talloc_zero_array(mem_ctx, char, fqlen);
-+    if (fqname == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
-+        return NULL;
-+    }
-+
-+    check = sss_fqname(fqname, fqlen, domain->names, domain, name);
-+    if (check != fqlen - 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate a fully qualified name "
-+              "for user [%s] in [%s]! Skipping user.\n", name, domain->name);
-+        talloc_free(fqname);
-+        return NULL;
-+    }
-+
-+    return fqname;
-+}
-+
-+static char *get_sysname(TALLOC_CTX *mem_ctx,
-+                         struct sss_domain_info *domain,
-+                         const char *name)
-+{
-+    if (domain == NULL || !domain->fqnames) {
-+        return talloc_strdup(mem_ctx, name);
-+    }
-+
-+    return get_fqname(mem_ctx, domain, name);
-+}
-+
- static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx,
-                                          enum sysdb_member_type type,
-                                          const char *name,
-@@ -284,6 +332,7 @@ static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx,
-     struct ldb_result *res;
-     const char *dn;
-     const char *strtype;
-+    char *sysname;
-     bool check_next;
-     errno_t ret;
- 
-@@ -292,16 +341,22 @@ static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx,
-         return NULL;
-     }
- 
-+    sysname = get_sysname(tmp_ctx, domain, name);
-+    if (sysname == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     /* Ensure that the object is in cache. */
-     switch (type) {
-     case SYSDB_MEMBER_USER:
--        if (getpwnam(name) == NULL) {
-+        if (getpwnam(sysname) == NULL) {
-             ret = ENOENT;
-             goto done;
-         }
-         break;
-     case SYSDB_MEMBER_GROUP:
--        if (getgrnam(name) == NULL) {
-+        if (getgrnam(sysname) == NULL) {
-             ret = ENOENT;
-             goto done;
-         }
--- 
-2.4.3
-
diff --git a/SOURCES/0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch b/SOURCES/0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch
new file mode 100644
index 0000000..ea50e9c
--- /dev/null
+++ b/SOURCES/0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch
@@ -0,0 +1,70 @@
+From e84b8e754f007cd94d9b535d562d8d315f692e8f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 8 Jul 2016 13:19:31 +0200
+Subject: [PATCH 63/74] LDAP: Fix storing initgroups for users with no
+ supplementary groups
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If there are no supplementary groups, we tried to qualify a NULL pointer
+to an array which resulted in an error.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ldap/sdap_async_initgroups.c | 32 +++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index 7029427724cc37a4508e11ef5448b421e94dc787..cc63dff781338e33a9802f97d98174fce2167b4b 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -301,13 +301,15 @@ int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
+     /* Find the differences between the sysdb and LDAP lists
+      * Groups in the sysdb only must be removed.
+      */
+-    ldap_fqdnlist = sss_create_internal_fqname_list(
+-                                        tmp_ctx,
+-                                        (const char * const *) ldap_grouplist,
+-                                        domain->name);
+-    if (ldap_fqdnlist == NULL) {
+-        ret = ENOMEM;
+-        goto done;
++    if (ldap_grouplist != NULL) {
++        ldap_fqdnlist = sss_create_internal_fqname_list(
++                                            tmp_ctx,
++                                            (const char * const *) ldap_grouplist,
++                                            domain->name);
++        if (ldap_fqdnlist == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
+     }
+ 
+     ret = diff_string_lists(tmp_ctx, ldap_fqdnlist, sysdb_grouplist,
+@@ -1288,13 +1290,15 @@ sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state)
+         }
+     }
+ 
+-    ldap_fqdnlist = sss_create_internal_fqname_list(
+-                                tmp_ctx,
+-                                (const char * const *) ldap_parent_name_list,
+-                                state->dom->name);
+-    if (ldap_fqdnlist == NULL) {
+-        ret = ENOMEM;
+-        goto done;
++    if (ldap_parent_name_list) {
++        ldap_fqdnlist = sss_create_internal_fqname_list(
++                                  tmp_ctx,
++                                  (const char * const *) ldap_parent_name_list,
++                                  state->dom->name);
++        if (ldap_fqdnlist == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
+     }
+ 
+     ret = sysdb_get_direct_parents(tmp_ctx, state->dom, SYSDB_MEMBER_USER,
+-- 
+2.4.11
+
diff --git a/SOURCES/0063-TOOLS-add-sss_colondb-API.patch b/SOURCES/0063-TOOLS-add-sss_colondb-API.patch
deleted file mode 100644
index 0ca7cd6..0000000
--- a/SOURCES/0063-TOOLS-add-sss_colondb-API.patch
+++ /dev/null
@@ -1,408 +0,0 @@
-From d28ed42ad2030090bc511f5b3381b5137885175d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 19 Aug 2015 12:34:08 +0200
-Subject: [PATCH 63/66] TOOLS: add sss_colondb API
-
-To simplify import/export users and groups.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tools/common/sss_colondb.c | 305 +++++++++++++++++++++++++++++++++++++++++
- src/tools/common/sss_colondb.h |  73 ++++++++++
- 2 files changed, 378 insertions(+)
- create mode 100644 src/tools/common/sss_colondb.c
- create mode 100644 src/tools/common/sss_colondb.h
-
-diff --git a/src/tools/common/sss_colondb.c b/src/tools/common/sss_colondb.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..6b340c80e703342defb8582537db2e4ef3926155
---- /dev/null
-+++ b/src/tools/common/sss_colondb.c
-@@ -0,0 +1,305 @@
-+/*
-+    Authors:
-+        Pavel Březina <pbrezina@redhat.com>
-+
-+    Copyright (C) 2015 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 <stdlib.h>
-+
-+#include "util/util.h"
-+#include "util/strtonum.h"
-+#include "tools/common/sss_colondb.h"
-+
-+#define IS_STD_FILE(db) ((db)->file == stdin || (db)->file == stdout)
-+
-+static char *read_field_as_string(char *line,
-+                                  const char **_value)
-+{
-+    char *rest;
-+    char *value;
-+
-+    if (line == NULL || *line == '\n' || *line == '\0') {
-+        /* There is nothing else to read. */
-+        rest = NULL;
-+        value = NULL;
-+        goto done;
-+    }
-+
-+    if (*line == ':') {
-+        /* Special case for empty value. */
-+        *line = '\0';
-+        rest = line + 1;
-+        value = NULL;
-+        goto done;
-+    }
-+
-+    /* Value starts at current position. */
-+    value = line;
-+
-+    /* Find next field delimiter. */
-+    rest = strchr(line, ':');
-+    if (rest == NULL) {
-+        /* There is no more field. Remove \n from the end. */
-+        rest = strchr(line, '\n');
-+        if (rest != NULL) {
-+            *rest = '\0';
-+            rest = NULL;
-+        }
-+        goto done;
-+    }
-+
-+    /* Remove it and step one character further. */
-+    *rest = '\0';
-+    rest++;
-+
-+done:
-+    *_value = value;
-+
-+    return rest;
-+}
-+
-+static char *read_field_as_uint32(char *line,
-+                                  uint32_t *_value)
-+{
-+    const char *str;
-+    char *rest;
-+    errno_t ret;
-+
-+    rest = read_field_as_string(line, &str);
-+    if (str == NULL) {
-+        *_value = 0;
-+        return rest;
-+    }
-+
-+    *_value = strtouint32(str, NULL, 10);
-+    if (errno != 0) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse number [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+
-+        *_value = 0;
-+    }
-+
-+    return rest;
-+}
-+
-+struct sss_colondb {
-+    FILE *file;
-+    enum sss_colondb_mode mode;
-+};
-+
-+errno_t sss_colondb_readline(TALLOC_CTX *mem_ctx,
-+                             struct sss_colondb *db,
-+                             struct sss_colondb_read_field *table)
-+{
-+    int readchars;
-+    size_t linelen = 0;
-+    char *line = NULL;
-+    char *tcline;
-+    char *rest;
-+    errno_t ret;
-+    int i;
-+
-+    if (db->mode != SSS_COLONDB_READ) {
-+        return ERR_INTERNAL;
-+    }
-+
-+    readchars = getline(&line, &linelen, db->file);
-+    if (readchars == -1) {
-+        /* Nothing was read. */
-+        if (errno != 0) {
-+            ret = errno;
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read line [%d]: %s",
-+                  ret, sss_strerror(ret));
-+            return ret;
-+        }
-+
-+        return EOF;
-+    }
-+
-+    /* Copy line to mem_ctx. */
-+    tcline = talloc_strdup(mem_ctx, line);
-+
-+    free(line);
-+    line = NULL;
-+
-+    if (tcline == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
-+        return ENOMEM;
-+    }
-+
-+    rest = tcline;
-+    for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
-+        switch (table[i].type) {
-+        case SSS_COLONDB_UINT32:
-+            rest = read_field_as_uint32(rest, table[i].data.uint32);
-+            break;
-+        case SSS_COLONDB_STRING:
-+            rest = read_field_as_string(rest, table[i].data.str);
-+            break;
-+        case SSS_COLONDB_SENTINEL:
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-+
-+        if (rest == NULL && table[i + 1].type != SSS_COLONDB_SENTINEL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Line contains less values than expected!\n");
-+            ret = EINVAL;
-+            goto done;
-+        } else if (rest != NULL && table[i + 1].type == SSS_COLONDB_SENTINEL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Line contains more values than expected!\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(tcline);
-+    }
-+
-+    return ret;
-+}
-+
-+errno_t sss_colondb_writeline(struct sss_colondb *db,
-+                              struct sss_colondb_write_field *table)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    char *line = NULL;
-+    errno_t ret;
-+    int i;
-+
-+    if (db->mode != SSS_COLONDB_WRITE) {
-+        return ERR_INTERNAL;
-+    }
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
-+        switch (table[i].type) {
-+        case SSS_COLONDB_UINT32:
-+            if (table[i].data.uint32 == 0) {
-+                line = talloc_asprintf_append(line, ":");
-+            } else {
-+                line = talloc_asprintf_append(line, ":%u", table[i].data.uint32);
-+            }
-+            break;
-+        case SSS_COLONDB_STRING:
-+            if (table[i].data.str == NULL) {
-+                line = talloc_asprintf_append(line, ":");
-+            } else {
-+                line = talloc_asprintf_append(line, ":%s", table[i].data.str);
-+            }
-+            break;
-+        case SSS_COLONDB_SENTINEL:
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-+
-+        if (line == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    /* Remove starting : */
-+    line++;
-+
-+    fprintf(db->file, "%s\n", line);
-+    fflush(db->file);
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-+
-+static int sss_colondb_close(void *pvt)
-+{
-+    struct sss_colondb *db = talloc_get_type(pvt, struct sss_colondb);
-+
-+    if (db->file == NULL || IS_STD_FILE(db)) {
-+        return 0;
-+    }
-+
-+    fclose(db->file);
-+    db->file = NULL;
-+
-+    return 0;
-+}
-+
-+static FILE *open_db(const char *filename, enum sss_colondb_mode mode)
-+{
-+    FILE *fp = NULL;
-+    errno_t ret;
-+
-+    errno = 0;
-+
-+    switch (mode) {
-+    case SSS_COLONDB_READ:
-+        fp = filename == NULL ? stdin : fopen(filename, "r");
-+        break;
-+    case SSS_COLONDB_WRITE:
-+        fp = filename == NULL ? stdout : fopen(filename, "w");
-+        break;
-+    }
-+
-+    if (fp == NULL && filename != NULL) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to open file %s [%d]: %s\n",
-+              filename, ret, sss_strerror(ret));
-+    }
-+
-+    return fp;
-+}
-+
-+struct sss_colondb *sss_colondb_open(TALLOC_CTX *mem_ctx,
-+                                     enum sss_colondb_mode mode,
-+                                     const char *filename)
-+{
-+    struct sss_colondb *db;
-+
-+    db = talloc_zero(mem_ctx, struct sss_colondb);
-+    if (db == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
-+        return NULL;
-+    }
-+
-+    db->file = open_db(filename, mode);
-+    db->mode = mode;
-+
-+    if (db->file == NULL) {
-+        talloc_free(db);
-+        return NULL;
-+    }
-+
-+    talloc_set_destructor((TALLOC_CTX *)db, sss_colondb_close);
-+
-+    return db;
-+}
-diff --git a/src/tools/common/sss_colondb.h b/src/tools/common/sss_colondb.h
-new file mode 100644
-index 0000000000000000000000000000000000000000..6edd99cbe3b9ef5c86a48632ac3fc71e8a3e55fe
---- /dev/null
-+++ b/src/tools/common/sss_colondb.h
-@@ -0,0 +1,73 @@
-+/*
-+    Authors:
-+        Pavel Březina <pbrezina@redhat.com>
-+
-+    Copyright (C) 2015 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/>.
-+*/
-+
-+#ifndef _SSS_COLONDB_H_
-+#define _SSS_COLONDB_H_
-+
-+#include <stdlib.h>
-+#include <stdint.h>
-+#include <errno.h>
-+#include <talloc.h>
-+
-+struct sss_colondb;
-+
-+enum sss_colondb_mode {
-+    SSS_COLONDB_READ,
-+    SSS_COLONDB_WRITE
-+};
-+
-+enum sss_colondb_type {
-+    SSS_COLONDB_UINT32,
-+    SSS_COLONDB_STRING,
-+    SSS_COLONDB_SENTINEL
-+};
-+
-+union sss_colondb_write_data {
-+    uint32_t uint32;
-+    const char *str;
-+};
-+
-+union sss_colondb_read_data {
-+    uint32_t *uint32;
-+    const char **str;
-+};
-+
-+struct sss_colondb_write_field {
-+    enum sss_colondb_type type;
-+    union sss_colondb_write_data data;
-+};
-+
-+struct sss_colondb_read_field {
-+    enum sss_colondb_type type;
-+    union sss_colondb_read_data data;
-+};
-+
-+struct sss_colondb *sss_colondb_open(TALLOC_CTX *mem_ctx,
-+                                     enum sss_colondb_mode mode,
-+                                     const char *filename);
-+
-+errno_t sss_colondb_readline(TALLOC_CTX *mem_ctx,
-+                             struct sss_colondb *db,
-+                             struct sss_colondb_read_field *table);
-+
-+errno_t sss_colondb_writeline(struct sss_colondb *db,
-+                              struct sss_colondb_write_field *table);
-+
-+#endif /* _SSS_COLONDB_H_ */
--- 
-2.4.3
-
diff --git a/SOURCES/0064-LDAP-Changing-of-confusing-debug-message.patch b/SOURCES/0064-LDAP-Changing-of-confusing-debug-message.patch
new file mode 100644
index 0000000..915b84e
--- /dev/null
+++ b/SOURCES/0064-LDAP-Changing-of-confusing-debug-message.patch
@@ -0,0 +1,31 @@
+From 256f6eafd5ca3cf1ea0a573ec44b3e5e4b74919c Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 12 Jul 2016 09:32:44 +0200
+Subject: [PATCH 64/74] LDAP: Changing of confusing debug message
+
+This debug message used to confuse our customer. So this patch changes it.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3091
+
+Reviewed-by: Stephen Gallagher <sgallagh@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 0c67e54c8a981442b7983a3f68db1bde3a2a6280..4195ba95d911f3956f8cca665310b4b92091e6cd 100644
+--- a/src/providers/ldap/sdap_async.c
++++ b/src/providers/ldap/sdap_async.c
+@@ -167,7 +167,7 @@ static void sdap_process_result(struct tevent_context *ev, void *pvt)
+     if (ret == 0) {
+         /* this almost always means we have reached the end of
+          * the list of received messages */
+-        DEBUG(SSSDBG_TRACE_INTERNAL, "Trace: ldap_result found nothing!\n");
++        DEBUG(SSSDBG_TRACE_INTERNAL, "Trace: end of ldap_result list\n");
+         return;
+     }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0064-sss_override-decompose-code-better.patch b/SOURCES/0064-sss_override-decompose-code-better.patch
deleted file mode 100644
index d1d078a..0000000
--- a/SOURCES/0064-sss_override-decompose-code-better.patch
+++ /dev/null
@@ -1,478 +0,0 @@
-From fdc64e169e988c4d1bc105ad6ccdfe4817db4c53 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 19 Aug 2015 12:43:15 +0200
-Subject: [PATCH 64/66] sss_override: decompose code better
-
-Preparation for:
-https://fedorahosted.org/sssd/ticket/2737
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tools/sss_override.c | 290 +++++++++++++++++++++++++++++------------------
- 1 file changed, 181 insertions(+), 109 deletions(-)
-
-diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
-index 84b51c537842b7281a523f58c2cfbdfd38e54c72..9e2ce3325c0bfa33fadb970f725098d7d12ac432 100644
---- a/src/tools/sss_override.c
-+++ b/src/tools/sss_override.c
-@@ -171,6 +171,22 @@ done:
-     return ret;
- }
- 
-+errno_t prepare_view_msg(struct sss_domain_info *domain)
-+{
-+    errno_t ret;
-+
-+    ret = prepare_view(domain);
-+    if (ret == EEXIST) {
-+        fprintf(stderr, _("Other than " LOCALVIEW " view already exist "
-+                "in domain %s.\n"), domain->name);
-+    } else if (ret != EOK) {
-+        fprintf(stderr, _("Unable to prepare " LOCALVIEW
-+                " view in domain %s.\n"), domain->name);
-+    }
-+
-+    return ret;
-+}
-+
- static char *build_anchor(TALLOC_CTX *mem_ctx, const char *obj_dn)
- {
-     char *anchor;
-@@ -320,17 +336,15 @@ static char *get_sysname(TALLOC_CTX *mem_ctx,
-     return get_fqname(mem_ctx, domain, name);
- }
- 
--static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx,
--                                         enum sysdb_member_type type,
--                                         const char *name,
--                                         struct sss_domain_info *domain,
--                                         struct sss_domain_info *domains,
--                                         struct sss_domain_info **_new_domain)
-+static struct sss_domain_info *
-+get_object_domain(enum sysdb_member_type type,
-+                  const char *name,
-+                  struct sss_domain_info *domain,
-+                  struct sss_domain_info *domains)
- {
-     TALLOC_CTX *tmp_ctx;
-     struct sss_domain_info *dom;
-     struct ldb_result *res;
--    const char *dn;
-     const char *strtype;
-     char *sysname;
-     bool check_next;
-@@ -427,18 +441,6 @@ static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx,
-     DEBUG(SSSDBG_TRACE_FUNC, "Domain of %s %s is %s\n",
-           strtype, name, dom->name);
- 
--    dn = ldb_dn_get_linearized(res->msgs[0]->dn);
--    if (dn == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "ldb_dn_get_linearized() failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
--
--    talloc_steal(mem_ctx, dn);
--    *_new_domain = dom;
--
--    ret = EOK;
--
- done:
-     talloc_free(tmp_ctx);
- 
-@@ -446,35 +448,94 @@ done:
-         return NULL;
-     }
- 
--    return dn;
-+    return dom;
- }
- 
--static const char * get_user_dn_and_domain(TALLOC_CTX *mem_ctx,
--                                           struct sss_domain_info *domains,
--                                           struct override_user *user)
-+static errno_t get_user_domain_msg(struct sss_tool_ctx *tool_ctx,
-+                                   struct override_user *user)
- {
--    return get_object_dn_and_domain(mem_ctx, SYSDB_MEMBER_USER,
--                         user->orig_name, user->domain, domains,
--                         &user->domain);
-+    struct sss_domain_info *newdom;
-+    const char *domname;
-+
-+    newdom = get_object_domain(SYSDB_MEMBER_USER, user->orig_name,
-+                               user->domain, tool_ctx->domains);
-+    if (newdom == NULL) {
-+        domname = user->domain == NULL ? "[unknown]" : user->domain->name;
-+        fprintf(stderr, _("Unable to find user %s@%s.\n"),
-+                user->orig_name, domname);
-+        return ENOENT;
-+    }
-+
-+    user->domain = newdom;
-+    return EOK;
-+}
-+
-+static errno_t get_group_domain_msg(struct sss_tool_ctx *tool_ctx,
-+                                    struct override_group *group)
-+{
-+    struct sss_domain_info *newdom;
-+    const char *domname;
-+
-+    newdom = get_object_domain(SYSDB_MEMBER_GROUP, group->orig_name,
-+                               group->domain, tool_ctx->domains);
-+    if (newdom == NULL) {
-+        domname = group->domain == NULL ? "[unknown]" : group->domain->name;
-+        fprintf(stderr, _("Unable to find group %s@%s.\n"),
-+                group->orig_name, domname);
-+        return ENOENT;
-+    }
-+
-+    group->domain = newdom;
-+    return EOK;
- }
- 
--static const char * get_group_dn_and_domain(TALLOC_CTX *mem_ctx,
--                                            struct sss_domain_info *domains,
--                                            struct override_group *group)
-+static errno_t get_object_dn(TALLOC_CTX *mem_ctx,
-+                             struct sss_domain_info *domain,
-+                             enum sysdb_member_type type,
-+                             const char *name,
-+                             struct ldb_dn **_ldb_dn,
-+                             const char **_str_dn)
- {
--    return get_object_dn_and_domain(mem_ctx, SYSDB_MEMBER_GROUP,
--                         group->orig_name, group->domain, domains,
--                         &group->domain);
-+    struct ldb_dn *ldb_dn;
-+
-+    switch (type) {
-+    case SYSDB_MEMBER_USER:
-+       ldb_dn = sysdb_user_dn(mem_ctx, domain, name);
-+       break;
-+    case SYSDB_MEMBER_GROUP:
-+       ldb_dn = sysdb_group_dn(mem_ctx, domain, name);
-+       break;
-+    default:
-+       DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported member type %d\n", type);
-+       return ERR_INTERNAL;
-+    }
-+
-+    if (ldb_dn == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    if (_str_dn != NULL) {
-+        *_str_dn = ldb_dn_get_linearized(ldb_dn);
-+    }
-+
-+    if (_ldb_dn != NULL) {
-+        *_ldb_dn = ldb_dn;
-+    } else {
-+        talloc_free(ldb_dn);
-+    }
-+
-+    return EOK;
- }
- 
- static errno_t override_object_add(struct sss_domain_info *domain,
-                                    enum sysdb_member_type type,
-                                    struct sysdb_attrs *attrs,
--                                   const char *obj_dn)
-+                                   const char *name)
- {
-     TALLOC_CTX *tmp_ctx;
-     const char *anchor;
-     struct ldb_dn *ldb_dn;
-+    const char *str_dn;
-     errno_t ret;
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -482,13 +543,12 @@ static errno_t override_object_add(struct sss_domain_info *domain,
-         return ENOMEM;
-     }
- 
--    ldb_dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb), obj_dn);
--    if (ldb_dn == NULL) {
--        ret = ENOMEM;
-+    ret = get_object_dn(tmp_ctx, domain, type, name, &ldb_dn, &str_dn);
-+    if (ret != EOK) {
-         goto done;
-     }
- 
--    anchor = build_anchor(tmp_ctx, obj_dn);
-+    anchor = build_anchor(tmp_ctx, str_dn);
-     if (anchor == NULL) {
-         ret = ENOMEM;
-         goto done;
-@@ -499,7 +559,7 @@ static errno_t override_object_add(struct sss_domain_info *domain,
-         goto done;
-     }
- 
--    DEBUG(SSSDBG_TRACE_FUNC, "Creating override for %s\n", obj_dn);
-+    DEBUG(SSSDBG_TRACE_FUNC, "Creating override for %s\n", str_dn);
- 
-     ret = sysdb_store_override(domain, LOCALVIEW, type, attrs, ldb_dn);
- 
-@@ -508,13 +568,70 @@ done:
-     return ret;
- }
- 
-+static errno_t override_user(struct sss_tool_ctx *tool_ctx,
-+                             struct override_user *user)
-+{
-+    struct sysdb_attrs *attrs;
-+    errno_t ret;
-+
-+    ret = prepare_view_msg(user->domain);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    attrs = build_user_attrs(tool_ctx, user);
-+    if (attrs == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = override_object_add(user->domain, SYSDB_MEMBER_USER, attrs,
-+                              user->orig_name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        return ret;
-+    }
-+
-+    return EOK;
-+}
-+
-+static errno_t override_group(struct sss_tool_ctx *tool_ctx,
-+                              struct override_group *group)
-+{
-+    struct sysdb_attrs *attrs;
-+    errno_t ret;
-+
-+    ret = prepare_view_msg(group->domain);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    attrs = build_group_attrs(tool_ctx, group);
-+    if (attrs == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = override_object_add(group->domain, SYSDB_MEMBER_GROUP, attrs,
-+                              group->orig_name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        return ret;
-+    }
-+
-+    return EOK;
-+}
-+
- static errno_t override_object_del(struct sss_domain_info *domain,
--                                   const char *obj_dn)
-+                                   enum sysdb_member_type type,
-+                                   const char *name)
- {
-     TALLOC_CTX *tmp_ctx;
--    const char *anchor;
--    struct ldb_dn *override_dn;
-     struct ldb_message *msg;
-+    struct ldb_dn *override_dn;
-+    struct ldb_dn *ldb_dn;
-+    const char *str_dn;
-+    const char *anchor;
-     errno_t ret;
-     int sret;
-     bool in_transaction = false;
-@@ -525,7 +642,12 @@ static errno_t override_object_del(struct sss_domain_info *domain,
-         return ENOMEM;
-     }
- 
--    anchor = build_anchor(tmp_ctx, obj_dn);
-+    ret = get_object_dn(tmp_ctx, domain, type, name, &ldb_dn, &str_dn);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    anchor = build_anchor(tmp_ctx, str_dn);
-     if (anchor == NULL) {
-         ret = ENOMEM;
-         goto done;
-@@ -538,7 +660,7 @@ static errno_t override_object_del(struct sss_domain_info *domain,
-         goto done;
-     }
- 
--    DEBUG(SSSDBG_TRACE_FUNC, "Removing override for %s\n", obj_dn);
-+    DEBUG(SSSDBG_TRACE_FUNC, "Removing override for %s\n", str_dn);
- 
-     ret = sysdb_transaction_start(domain->sysdb);
-     if (ret != EOK) {
-@@ -559,7 +681,7 @@ static errno_t override_object_del(struct sss_domain_info *domain,
-         goto done;
-     }
- 
--    msg->dn = ldb_dn_new(msg, ldb, obj_dn);
-+    msg->dn = talloc_steal(msg, ldb_dn);
-     if (msg->dn == NULL) {
-         ret = ENOMEM;
-         goto done;
-@@ -607,8 +729,6 @@ static int override_user_add(struct sss_cmdline *cmdline,
-                              void *pvt)
- {
-     struct override_user user = {NULL};
--    struct sysdb_attrs *attrs;
--    const char *dn;
-     int ret;
- 
-     ret = parse_cmdline_user_add(cmdline, tool_ctx, &user);
-@@ -617,34 +737,13 @@ static int override_user_add(struct sss_cmdline *cmdline,
-         return EXIT_FAILURE;
-     }
- 
--    dn = get_user_dn_and_domain(tool_ctx, tool_ctx->domains, &user);
--    if (dn == NULL) {
--        fprintf(stderr, _("Unable to find user %s@%s.\n"),
--                user.orig_name,
--                user.domain == NULL ? "[unknown]" : user.domain->name);
--        return EXIT_FAILURE;
--    }
--
--    ret = prepare_view(user.domain);
--    if (ret == EEXIST) {
--        fprintf(stderr, _("Other than LOCAL view already exist in "
--                "domain %s.\n"), user.domain->name);
--        return EXIT_FAILURE;
--    } else if (ret != EOK) {
--        fprintf(stderr, _("Unable to prepare view [%d]: %s.\n"),
--                ret, sss_strerror(ret));
--        return EXIT_FAILURE;
--    }
--
--    attrs = build_user_attrs(tool_ctx, &user);
--    if (attrs == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
-+    ret = get_user_domain_msg(tool_ctx, &user);
-+    if (ret != EOK) {
-         return EXIT_FAILURE;
-     }
- 
--    ret = override_object_add(user.domain, SYSDB_MEMBER_USER, attrs, dn);
-+    ret = override_user(tool_ctx, &user);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-         return EXIT_FAILURE;
-     }
- 
-@@ -656,7 +755,6 @@ static int override_user_del(struct sss_cmdline *cmdline,
-                              void *pvt)
- {
-     struct override_user user = {NULL};
--    const char *dn;
-     int ret;
- 
-     ret = parse_cmdline_user_del(cmdline, tool_ctx, &user);
-@@ -665,16 +763,14 @@ static int override_user_del(struct sss_cmdline *cmdline,
-         return EXIT_FAILURE;
-     }
- 
--    dn = get_user_dn_and_domain(tool_ctx, tool_ctx->domains, &user);
--    if (dn == NULL) {
--        fprintf(stderr, _("Unable to find user %s@%s.\n"),
--                user.orig_name, user.domain->name);
-+    ret = get_user_domain_msg(tool_ctx, &user);
-+    if (ret != EOK) {
-         return EXIT_FAILURE;
-     }
- 
--    ret = override_object_del(user.domain, dn);
-+    ret = override_object_del(user.domain, SYSDB_MEMBER_USER, user.orig_name);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to delete override object.\n");
-         return EXIT_FAILURE;
-     }
- 
-@@ -686,8 +782,6 @@ static int override_group_add(struct sss_cmdline *cmdline,
-                               void *pvt)
- {
-     struct override_group group = {NULL};
--    struct sysdb_attrs *attrs;
--    const char *dn;
-     int ret;
- 
-     ret = parse_cmdline_group_add(cmdline, tool_ctx, &group);
-@@ -696,33 +790,13 @@ static int override_group_add(struct sss_cmdline *cmdline,
-         return EXIT_FAILURE;
-     }
- 
--    dn = get_group_dn_and_domain(tool_ctx, tool_ctx->domains, &group);
--    if (dn == NULL) {
--        fprintf(stderr, _("Unable to find group %s@%s.\n"),
--                group.orig_name, group.domain->name);
--        return EXIT_FAILURE;
--    }
--
--    ret = prepare_view(group.domain);
--    if (ret == EEXIST) {
--        fprintf(stderr, _("Other than LOCAL view already exist in "
--                "domain %s.\n"), group.domain->name);
--        return EXIT_FAILURE;
--    } else if (ret != EOK) {
--        fprintf(stderr, _("Unable to prepare view [%d]: %s.\n"),
--                ret, sss_strerror(ret));
--        return EXIT_FAILURE;
--    }
--
--    attrs = build_group_attrs(tool_ctx, &group);
--    if (attrs == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
-+    ret = get_group_domain_msg(tool_ctx, &group);
-+    if (ret != EOK) {
-         return EXIT_FAILURE;
-     }
- 
--    ret = override_object_add(group.domain, SYSDB_MEMBER_GROUP, attrs, dn);
-+    ret = override_group(tool_ctx, &group);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-         return EXIT_FAILURE;
-     }
- 
-@@ -734,7 +808,6 @@ static int override_group_del(struct sss_cmdline *cmdline,
-                               void *pvt)
- {
-     struct override_group group = {NULL};
--    const char *dn;
-     int ret;
- 
-     ret = parse_cmdline_group_del(cmdline, tool_ctx, &group);
-@@ -743,16 +816,15 @@ static int override_group_del(struct sss_cmdline *cmdline,
-         return EXIT_FAILURE;
-     }
- 
--    dn = get_group_dn_and_domain(tool_ctx, tool_ctx->domains, &group);
--    if (dn == NULL) {
--        fprintf(stderr, _("Unable to find group %s@%s.\n"),
--                group.orig_name, group.domain->name);
-+    ret = get_group_domain_msg(tool_ctx, &group);
-+    if (ret != EOK) {
-         return EXIT_FAILURE;
-     }
- 
--    ret = override_object_del(group.domain, dn);
-+    ret = override_object_del(group.domain, SYSDB_MEMBER_GROUP,
-+                              group.orig_name);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to delete override object.\n");
-         return EXIT_FAILURE;
-     }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch b/SOURCES/0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch
new file mode 100644
index 0000000..d381162
--- /dev/null
+++ b/SOURCES/0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch
@@ -0,0 +1,35 @@
+From 8798dbf0af2850c5775e0d50165d70b17a031050 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 3 Aug 2016 13:18:51 +0200
+Subject: [PATCH 65/74] LDAP: Use FQDN when linking parent LDAP groups
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+    https://fedorahosted.org/sssd/ticket/3093
+
+Because we compare the list of LDAP names with the list of sysdb names,
+we need to qualify the list of LDAP names before running the diff.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ldap/sdap_async_initgroups.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index cc63dff781338e33a9802f97d98174fce2167b4b..82c708c226bf1a645ff5a395947dfdbad71e0f1f 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -2080,7 +2080,7 @@ rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data)
+     }
+ 
+     if (group->parents_count > 0) {
+-        ret = sysdb_attrs_primary_name_list(mstate->dom, tmp_ctx,
++        ret = sysdb_attrs_primary_fqdn_list(mstate->dom, tmp_ctx,
+                             group->ldap_parents, group->parents_count,
+                             mstate->opts->group_map[SDAP_AT_GROUP_NAME].name,
+                             &ldap_parents_names_list);
+-- 
+2.4.11
+
diff --git a/SOURCES/0065-sss_override-support-import-and-export.patch b/SOURCES/0065-sss_override-support-import-and-export.patch
deleted file mode 100644
index f9d2098..0000000
--- a/SOURCES/0065-sss_override-support-import-and-export.patch
+++ /dev/null
@@ -1,794 +0,0 @@
-From ee8f6d929ab3a047e05b4522cb0d61273293e2c4 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 19 Aug 2015 12:35:12 +0200
-Subject: [PATCH 65/66] sss_override: support import and export
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2737
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                |   2 +
- src/man/sss_override.8.xml |  88 +++++++
- src/tools/sss_override.c   | 588 ++++++++++++++++++++++++++++++++++++++++++++-
- 3 files changed, 675 insertions(+), 3 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index 7dc4875c9cb05bf146505c0dc0dab543fb326bd3..e1102333b019e32c516c59c5fa969c970b688737 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -651,6 +651,7 @@ dist_noinst_HEADERS = \
-     src/lib/sifp/sss_sifp_private.h \
-     src/tests/cmocka/test_utils.h \
-     src/tools/common/sss_tools.h \
-+    src/tools/common/sss_colondb.h \
-     $(NULL)
- 
- 
-@@ -1331,6 +1332,7 @@ sss_signal_LDADD = \
- 
- sss_override_SOURCES = \
-     src/tools/sss_override.c \
-+    src/tools/common/sss_colondb.c \
-     $(SSSD_TOOLS_OBJ) \
-     $(NULL)
- sss_override_LDADD = \
-diff --git a/src/man/sss_override.8.xml b/src/man/sss_override.8.xml
-index ec9a7bb75c13f4f18ece7f5f84baede14a8a1e2e..d289f5b7dfa7fbd328831b4c71d45b4c555225cf 100644
---- a/src/man/sss_override.8.xml
-+++ b/src/man/sss_override.8.xml
-@@ -77,6 +77,50 @@
-             </varlistentry>
-             <varlistentry>
-                 <term>
-+                    <option>user-import</option>
-+                    <emphasis>FILE</emphasis>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Import user overrides from <emphasis>FILE</emphasis>.
-+                        Data format is similar to standard passwd file.
-+                        The format is:
-+                    </para>
-+                    <para>
-+                        original_name:name:uid:gid:gecos:home:shell
-+                    </para>
-+                    <para>
-+                        where original_name is original name of the user whose
-+                        attributes should be overridden. The rest of fields
-+                        correspond to new values. You can omit a value simply
-+                        by leaving corresponding field empty.
-+                    </para>
-+                    <para>
-+                        Examples:
-+                    </para>
-+                    <para>
-+                        ckent:superman::::::
-+                    </para>
-+                    <para>
-+                        ckent@krypton.com::501:501:Superman:/home/earth:/bin/bash
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>user-export</option>
-+                    <emphasis>FILE</emphasis>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Export all overridden attributes and store them in
-+                        <emphasis>FILE</emphasis>. See
-+                        <emphasis>user-import</emphasis> for data format.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-                     <option>group-add</option>
-                     <emphasis>NAME</emphasis>
-                     <optional><option>-n,--name</option> NAME</optional>
-@@ -99,6 +143,50 @@
-                     </para>
-                 </listitem>
-             </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>group-import</option>
-+                    <emphasis>FILE</emphasis>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Import group overrides from <emphasis>FILE</emphasis>.
-+                        Data format is similar to standard group file.
-+                        The format is:
-+                    </para>
-+                    <para>
-+                        original_name:name:gid
-+                    </para>
-+                    <para>
-+                        where original_name is original name of the group whose
-+                        attributes should be overridden. The rest of fields
-+                        correspond to new values. You can omit a value simply
-+                        by leaving corresponding field empty.
-+                    </para>
-+                    <para>
-+                        Examples:
-+                    </para>
-+                    <para>
-+                        admins:administrators:
-+                    </para>
-+                    <para>
-+                        Domain Users:Users:501
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>group-export</option>
-+                    <emphasis>FILE</emphasis>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Export all overridden attributes and store them in
-+                        <emphasis>FILE</emphasis>. See
-+                        <emphasis>group-import</emphasis> for data format.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-         </variablelist>
-     </refsect1>
- 
-diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
-index 9e2ce3325c0bfa33fadb970f725098d7d12ac432..ee8351ea97e5efe0d449dc646c6136b32ceec2c6 100644
---- a/src/tools/sss_override.c
-+++ b/src/tools/sss_override.c
-@@ -23,8 +23,10 @@
- #include "util/util.h"
- #include "db/sysdb.h"
- #include "tools/common/sss_tools.h"
-+#include "tools/common/sss_colondb.h"
- 
- #define LOCALVIEW SYSDB_LOCAL_VIEW_NAME
-+#define ORIGNAME "originalName"
- 
- struct override_user {
-     const char *input_name;
-@@ -135,6 +137,40 @@ static int parse_cmdline_group_del(struct sss_cmdline *cmdline,
-                          &group->orig_name, &group->domain);
- }
- 
-+static int parse_cmdline_import(struct sss_cmdline *cmdline,
-+                                struct sss_tool_ctx *tool_ctx,
-+                                const char **_file)
-+{
-+    int ret;
-+
-+    ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL,
-+                           NULL, NULL, "FILE", "File to import the data from.",
-+                           _file);
-+    if (ret != EXIT_SUCCESS) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
-+        return ret;
-+    }
-+
-+    return EXIT_SUCCESS;
-+}
-+
-+static int parse_cmdline_export(struct sss_cmdline *cmdline,
-+                                struct sss_tool_ctx *tool_ctx,
-+                                const char **_file)
-+{
-+    int ret;
-+
-+    ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL,
-+                           NULL, NULL, "FILE", "File to export the data to.",
-+                           _file);
-+    if (ret != EXIT_SUCCESS) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
-+        return ret;
-+    }
-+
-+    return EXIT_SUCCESS;
-+}
-+
- static errno_t prepare_view(struct sss_domain_info *domain)
- {
-     char *viewname = NULL;
-@@ -293,8 +329,8 @@ static char *get_fqname(TALLOC_CTX *mem_ctx,
-                         const char *name)
- {
-     char *fqname;
--    size_t fqlen;
--    size_t check;
-+    int fqlen;
-+    int check;
- 
-     if (domain == NULL) {
-         return NULL;
-@@ -315,7 +351,7 @@ static char *get_fqname(TALLOC_CTX *mem_ctx,
-     }
- 
-     check = sss_fqname(fqname, fqlen, domain->names, domain, name);
--    if (check != fqlen - 1) {
-+    if (check < 0 || check != fqlen - 1) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate a fully qualified name "
-               "for user [%s] in [%s]! Skipping user.\n", name, domain->name);
-         talloc_free(fqname);
-@@ -724,6 +760,246 @@ done:
-     return ret;
- }
- 
-+static errno_t append_name(struct sss_domain_info *domain,
-+                           struct ldb_message *override)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_context *ldb = sysdb_ctx_get_ldb(domain->sysdb);
-+    struct ldb_dn *dn;
-+    struct ldb_message **msgs;
-+    const char *attrs[] = {SYSDB_NAME, NULL};
-+    const char *name;
-+    const char *fqname;
-+    size_t count;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, override,
-+                                 SYSDB_OVERRIDE_OBJECT_DN);
-+    if (dn == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing overrideObjectDN?\n");
-+        ret = ERR_INTERNAL;
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, dn, LDB_SCOPE_BASE,
-+                             NULL, attrs, &count, &msgs);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry() failed [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    } else if (count != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "More than one user found?\n");
-+        ret = ERR_INTERNAL;
-+        goto done;
-+    }
-+
-+    name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
-+    if (name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Object with no name?\n");
-+        ret = ERR_INTERNAL;
-+        goto done;
-+    }
-+
-+    fqname = get_fqname(tmp_ctx, domain, name);
-+    if (fqname == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get fqname\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_msg_add_string(override, ORIGNAME, fqname);
-+    if (ret != LDB_SUCCESS) {
-+        ret = sysdb_error_to_errno(ret);
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute to msg\n");
-+        goto done;
-+    }
-+
-+    talloc_steal(override, fqname);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-+
-+static errno_t list_overrides(TALLOC_CTX *mem_ctx,
-+                              const char *filter,
-+                              const char **attrs,
-+                              struct sss_domain_info *domain,
-+                              size_t *_count,
-+                              struct ldb_message ***_msgs)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_dn *dn;
-+    struct ldb_context *ldb = sysdb_ctx_get_ldb(domain->sysdb);
-+    size_t count;
-+    struct ldb_message **msgs;
-+    size_t i;
-+    int ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    /* Acquire list of override objects. */
-+    dn = ldb_dn_new_fmt(tmp_ctx, ldb, SYSDB_TMPL_VIEW_SEARCH_BASE, LOCALVIEW);
-+    if (dn == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt() failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, dn, LDB_SCOPE_SUBTREE,
-+                             filter, attrs, &count, &msgs);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry() failed [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    /* Amend messages with original name. */
-+    for (i = 0; i < count; i++) {
-+        ret = append_name(domain, msgs[i]);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to append name [%d]: %s\n",
-+                  ret, sss_strerror(ret));
-+            goto done;
-+        }
-+    }
-+
-+    *_msgs = talloc_steal(mem_ctx, msgs);
-+    *_count = count;
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-+
-+static struct override_user *
-+list_user_overrides(TALLOC_CTX *mem_ctx,
-+                    struct sss_domain_info *domain)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct override_user *objs;
-+    struct ldb_message **msgs;
-+    size_t count;
-+    size_t i;
-+    errno_t ret;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return NULL;
-+    }
-+
-+    ret = list_overrides(tmp_ctx, "(objectClass=" SYSDB_OVERRIDE_USER_CLASS ")",
-+                         attrs, domain, &count, &msgs);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    objs = talloc_zero_array(tmp_ctx, struct override_user, count + 1);
-+    if (objs == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    for (i = 0; i < count; i++) {
-+        objs[i].orig_name = ldb_msg_find_attr_as_string(msgs[i], ORIGNAME,
-+                                                        NULL);
-+        if (objs[i].orig_name == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Missing name?!\n");
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-+
-+        objs[i].name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
-+        objs[i].uid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_UIDNUM, 0);
-+        objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
-+        objs[i].home = ldb_msg_find_attr_as_string(msgs[i], SYSDB_HOMEDIR, NULL);
-+        objs[i].shell = ldb_msg_find_attr_as_string(msgs[i], SYSDB_SHELL, NULL);
-+        objs[i].gecos = ldb_msg_find_attr_as_string(msgs[i], SYSDB_GECOS, NULL);
-+    }
-+
-+    talloc_steal(mem_ctx, objs);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    if (ret != EOK) {
-+        return NULL;
-+    }
-+
-+    return objs;
-+}
-+
-+static struct override_group *
-+list_group_overrides(TALLOC_CTX *mem_ctx,
-+                     struct sss_domain_info *domain)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct override_group *objs;
-+    struct ldb_message **msgs;
-+    size_t count;
-+    size_t i;
-+    errno_t ret;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return NULL;
-+    }
-+
-+    ret = list_overrides(tmp_ctx, "(objectClass=" SYSDB_OVERRIDE_GROUP_CLASS ")",
-+                         attrs, domain, &count, &msgs);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    objs = talloc_zero_array(tmp_ctx, struct override_group, count + 1);
-+    if (objs == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    for (i = 0; i < count; i++) {
-+        objs[i].orig_name = ldb_msg_find_attr_as_string(msgs[i], ORIGNAME,
-+                                                        NULL);
-+        if (objs[i].orig_name == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Missing name?!\n");
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-+
-+        objs[i].name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
-+        objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
-+    }
-+
-+    talloc_steal(mem_ctx, objs);
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    if (ret != EOK) {
-+        return NULL;
-+    }
-+
-+    return objs;
-+}
-+
- static int override_user_add(struct sss_cmdline *cmdline,
-                              struct sss_tool_ctx *tool_ctx,
-                              void *pvt)
-@@ -777,6 +1053,161 @@ static int override_user_del(struct sss_cmdline *cmdline,
-     return EXIT_SUCCESS;
- }
- 
-+static int override_user_import(struct sss_cmdline *cmdline,
-+                                struct sss_tool_ctx *tool_ctx,
-+                                void *pvt)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct sss_colondb *db;
-+    const char *filename;
-+    struct override_user obj;
-+    int linenum = 1;
-+    errno_t ret;
-+    int exit;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    /**
-+     * Format: orig_name:name:uid:gid:gecos:home:shell
-+     */
-+    struct sss_colondb_read_field table[] = {
-+        {SSS_COLONDB_STRING, {.str = &obj.input_name}},
-+        {SSS_COLONDB_STRING, {.str = &obj.name}},
-+        {SSS_COLONDB_UINT32, {.uint32 = &obj.uid}},
-+        {SSS_COLONDB_UINT32, {.uint32 = &obj.gid}},
-+        {SSS_COLONDB_STRING, {.str = &obj.gecos}},
-+        {SSS_COLONDB_STRING, {.str = &obj.home}},
-+        {SSS_COLONDB_STRING, {.str = &obj.shell}},
-+        {SSS_COLONDB_SENTINEL, {0}}
-+    };
-+
-+    ret = parse_cmdline_import(cmdline, tool_ctx, &filename);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    db = sss_colondb_open(tool_ctx, SSS_COLONDB_READ, filename);
-+    if (db == NULL) {
-+        fprintf(stderr, _("Unable to open %s.\n"), filename);
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    while ((ret = sss_colondb_readline(tmp_ctx, db, table)) == EOK) {
-+        linenum++;
-+
-+        ret = sss_tool_parse_name(tool_ctx, tool_ctx, obj.input_name,
-+                                  &obj.orig_name, &obj.domain);
-+        if (ret != EOK) {
-+            fprintf(stderr, _("Unable to parse name %s.\n"), obj.input_name);
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        ret = get_user_domain_msg(tool_ctx, &obj);
-+        if (ret != EOK) {
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        ret = override_user(tool_ctx, &obj);
-+        if (ret != EOK) {
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        talloc_free_children(tmp_ctx);
-+    }
-+
-+    if (ret != EOF) {
-+        fprintf(stderr, _("Invalid format on line %d. "
-+                "Use --debug option for more information.\n"), linenum);
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    exit = EXIT_SUCCESS;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return exit;
-+}
-+
-+static int override_user_export(struct sss_cmdline *cmdline,
-+                                struct sss_tool_ctx *tool_ctx,
-+                                void *pvt)
-+{
-+    struct sss_colondb *db;
-+    const char *filename;
-+    struct override_user *objs;
-+    struct sss_domain_info *dom;
-+    errno_t ret;
-+    int exit;
-+    int i;
-+
-+    ret = parse_cmdline_export(cmdline, tool_ctx, &filename);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    db = sss_colondb_open(tool_ctx, SSS_COLONDB_WRITE, filename);
-+    if (db == NULL) {
-+        fprintf(stderr, _("Unable to open %s.\n"), filename);
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    dom = tool_ctx->domains;
-+    do {
-+        objs = list_user_overrides(tool_ctx, tool_ctx->domains);
-+        if (objs == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get override objects\n");
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        for (i = 0; objs[i].orig_name != NULL; i++) {
-+            /**
-+             * Format: orig_name:name:uid:gid:gecos:home:shell
-+             */
-+            struct sss_colondb_write_field table[] = {
-+                {SSS_COLONDB_STRING, {.str = objs[i].orig_name}},
-+                {SSS_COLONDB_STRING, {.str = objs[i].name}},
-+                {SSS_COLONDB_UINT32, {.uint32 = objs[i].uid}},
-+                {SSS_COLONDB_UINT32, {.uint32 = objs[i].gid}},
-+                {SSS_COLONDB_STRING, {.str = objs[i].gecos}},
-+                {SSS_COLONDB_STRING, {.str = objs[i].home}},
-+                {SSS_COLONDB_STRING, {.str = objs[i].shell}},
-+                {SSS_COLONDB_SENTINEL, {0}}
-+            };
-+
-+            ret = sss_colondb_writeline(db, table);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CRIT_FAILURE, "Unable to write line to db\n");
-+                exit = EXIT_FAILURE;
-+                goto done;
-+            }
-+        }
-+
-+        /* All overrides are under the same subtree, so we don't want to
-+         * descent into subdomains. */
-+        dom = get_next_domain(dom, false);
-+    } while (dom != NULL);
-+
-+    exit = EXIT_SUCCESS;
-+
-+done:
-+    return exit;
-+}
-+
- static int override_group_add(struct sss_cmdline *cmdline,
-                               struct sss_tool_ctx *tool_ctx,
-                               void *pvt)
-@@ -831,13 +1262,164 @@ static int override_group_del(struct sss_cmdline *cmdline,
-     return EXIT_SUCCESS;
- }
- 
-+static int override_group_import(struct sss_cmdline *cmdline,
-+                                 struct sss_tool_ctx *tool_ctx,
-+                                 void *pvt)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct sss_colondb *db;
-+    const char *filename;
-+    struct override_group obj;
-+    int linenum = 1;
-+    errno_t ret;
-+    int exit;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
-+        return EXIT_FAILURE;
-+    }
-+
-+    /**
-+     * Format: orig_name:name:gid
-+     */
-+    struct sss_colondb_read_field table[] = {
-+        {SSS_COLONDB_STRING, {.str = &obj.input_name}},
-+        {SSS_COLONDB_STRING, {.str = &obj.name}},
-+        {SSS_COLONDB_UINT32, {.uint32 = &obj.gid}},
-+        {SSS_COLONDB_SENTINEL, {0}}
-+    };
-+
-+    ret = parse_cmdline_import(cmdline, tool_ctx, &filename);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    db = sss_colondb_open(tool_ctx, SSS_COLONDB_READ, filename);
-+    if (db == NULL) {
-+        fprintf(stderr, _("Unable to open %s.\n"), filename);
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    while ((ret = sss_colondb_readline(tmp_ctx, db, table)) == EOK) {
-+        linenum++;
-+
-+        ret = sss_tool_parse_name(tool_ctx, tool_ctx, obj.input_name,
-+                                  &obj.orig_name, &obj.domain);
-+        if (ret != EOK) {
-+            fprintf(stderr, _("Unable to parse name %s.\n"), obj.input_name);
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        ret = get_group_domain_msg(tool_ctx, &obj);
-+        if (ret != EOK) {
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        ret = override_group(tool_ctx, &obj);
-+        if (ret != EOK) {
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        talloc_free_children(tmp_ctx);
-+    }
-+
-+    if (ret != EOF) {
-+        fprintf(stderr, _("Invalid format on line %d. "
-+                "Use --debug option for more information.\n"), linenum);
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    exit = EXIT_SUCCESS;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return exit;
-+}
-+
-+static int override_group_export(struct sss_cmdline *cmdline,
-+                                 struct sss_tool_ctx *tool_ctx,
-+                                 void *pvt)
-+{
-+    struct sss_colondb *db;
-+    const char *filename;
-+    struct override_group *objs;
-+    struct sss_domain_info *dom;
-+    errno_t ret;
-+    int exit;
-+    int i;
-+
-+    ret = parse_cmdline_export(cmdline, tool_ctx, &filename);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    db = sss_colondb_open(tool_ctx, SSS_COLONDB_WRITE, filename);
-+    if (db == NULL) {
-+        fprintf(stderr, _("Unable to open %s.\n"), filename);
-+        exit = EXIT_FAILURE;
-+        goto done;
-+    }
-+
-+    dom = tool_ctx->domains;
-+    do {
-+        objs = list_group_overrides(tool_ctx, tool_ctx->domains);
-+        if (objs == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get override objects\n");
-+            exit = EXIT_FAILURE;
-+            goto done;
-+        }
-+
-+        for (i = 0; objs[i].orig_name != NULL; i++) {
-+            /**
-+             * Format: orig_name:name:uid:gid:gecos:home:shell
-+             */
-+            struct sss_colondb_write_field table[] = {
-+                {SSS_COLONDB_STRING, {.str = objs[i].orig_name}},
-+                {SSS_COLONDB_STRING, {.str = objs[i].name}},
-+                {SSS_COLONDB_UINT32, {.uint32 = objs[i].gid}},
-+                {SSS_COLONDB_SENTINEL, {0}}
-+            };
-+
-+            ret = sss_colondb_writeline(db, table);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CRIT_FAILURE, "Unable to write line to db\n");
-+                exit = EXIT_FAILURE;
-+                goto done;
-+            }
-+        }
-+
-+        /* All overrides are under the same subtree, so we don't want to
-+         * descent into subdomains. */
-+        dom = get_next_domain(dom, false);
-+    } while (dom != NULL);
-+
-+    exit = EXIT_SUCCESS;
-+
-+done:
-+    return exit;
-+}
-+
- int main(int argc, const char **argv)
- {
-     struct sss_route_cmd commands[] = {
-         {"user-add", override_user_add},
-         {"user-del", override_user_del},
-+        {"user-import", override_user_import},
-+        {"user-export", override_user_export},
-         {"group-add", override_group_add},
-         {"group-del", override_group_del},
-+        {"group-import", override_group_import},
-+        {"group-export", override_group_export},
-         {NULL, NULL}
-     };
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0066-NSS-Fix-use-after-free.patch b/SOURCES/0066-NSS-Fix-use-after-free.patch
deleted file mode 100644
index 8b2a8f4..0000000
--- a/SOURCES/0066-NSS-Fix-use-after-free.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From ddcdb9ecfbbfb7e3ce57c7b97eefa3e59b5a0e78 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 7 Aug 2015 14:29:45 +0200
-Subject: [PATCH 66/66] NSS: Fix use after free
-
-It can happed if there are two domains and user is not found
-in the first one.
-
-==29279== Invalid read of size 1
-==29279==    at 0x4C2CBA2: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
-==29279==    by 0x89A7AC4: talloc_strdup (in /usr/lib64/libtalloc.so.2.1.2)
-==29279==    by 0x11668A: nss_cmd_initgroups_search (nsssrv_cmd.c:4191)
-==29279==    by 0x118B27: nss_cmd_getby_dp_callback (nsssrv_cmd.c:1208)
-==29279==    by 0x10F2B4: nsssrv_dp_send_acct_req_done (nsssrv_cmd.c:759)
-==29279==    by 0x126AFB: sss_dp_internal_get_done (responder_dp.c:802)
-==29279==    by 0x56EA861: ??? (in /usr/lib64/libdbus-1.so.3.7.4)
-==29279==    by 0x56EDB50: dbus_connection_dispatch (in /usr/lib64/libdbus-1.so.3.7.4)
-==29279==    by 0x50721E1: sbus_dispatch (sssd_dbus_connection.c:96)
-==29279==    by 0x879B22E: tevent_common_loop_timer_delay (tevent_timed.c:341)
-==29279==    by 0x879C239: epoll_event_loop_once (tevent_epoll.c:911)
-==29279==    by 0x879A936: std_event_loop_once (tevent_standard.c:114)
-==29279==  Address 0xbbad240 is 96 bytes inside a block of size 106 free'd
-==29279==    at 0x4C2AD17: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
-==29279==    by 0x89A46E3: _talloc_free (in /usr/lib64/libtalloc.so.2.1.2)
-==29279==    by 0x116679: nss_cmd_initgroups_search (nsssrv_cmd.c:4190)
-==29279==    by 0x118B27: nss_cmd_getby_dp_callback (nsssrv_cmd.c:1208)
-==29279==    by 0x10F2B4: nsssrv_dp_send_acct_req_done (nsssrv_cmd.c:759)
-==29279==    by 0x126AFB: sss_dp_internal_get_done (responder_dp.c:802)
-==29279==    by 0x56EA861: ??? (in /usr/lib64/libdbus-1.so.3.7.4)
-==29279==    by 0x56EDB50: dbus_connection_dispatch (in /usr/lib64/libdbus-1.so.3.7.4)
-==29279==    by 0x50721E1: sbus_dispatch (sssd_dbus_connection.c:96)
-==29279==    by 0x879B22E: tevent_common_loop_timer_delay (tevent_timed.c:341)
-==29279==    by 0x879C239: epoll_event_loop_once (tevent_epoll.c:911)
-==29279==    by 0x879A936: std_event_loop_once (tevent_standard.c:114)
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2749
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/responder/nss/nsssrv_cmd.c     | 6 +++---
- src/responder/nss/nsssrv_private.h | 1 +
- 2 files changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index aa64432d51f15ed17212b8c40eebf5c9322bc784..459634b8d7a590a196ad47a17cd52729fc633ee2 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -4107,7 +4107,7 @@ static int nss_cmd_initgr_send_reply(struct nss_dom_ctx *dctx)
-     }
- 
-     ret = fill_initgr(cctx->creq->out, dctx->domain, dctx->res, nctx,
--                      dctx->mc_name, cmdctx->name);
-+                      dctx->mc_name, cmdctx->normalized_name);
-     if (ret) {
-         return ret;
-     }
-@@ -4151,14 +4151,14 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
-         /* make sure to update the dctx if we changed domain */
-         dctx->domain = dom;
- 
--        talloc_free(name);
-+        talloc_zfree(cmdctx->normalized_name);
-         name = sss_get_cased_name(dctx, cmdctx->name, dom->case_sensitive);
-         if (!name) return ENOMEM;
- 
-         name = sss_reverse_replace_space(cmdctx, name,
-                                          nctx->rctx->override_space);
-         /* save name so it can be used in initgr reply */
--        cmdctx->name = name;
-+        cmdctx->normalized_name = name;
-         if (name == NULL) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "sss_reverse_replace_space failed\n");
-diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h
-index e5a2486f1fb9a8de39ec90f802f596b2c2f6af7f..72f7b75604567f9b95937018e54ba2d60b771f9b 100644
---- a/src/responder/nss/nsssrv_private.h
-+++ b/src/responder/nss/nsssrv_private.h
-@@ -31,6 +31,7 @@ struct nss_cmd_ctx {
-     struct cli_ctx *cctx;
-     enum sss_cli_command cmd;
-     char *name;
-+    const char *normalized_name;
-     bool name_is_upn;
-     uint32_t id;
-     char *secid;
--- 
-2.4.3
-
diff --git a/SOURCES/0066-sssctl-Consistent-commands-naming.patch b/SOURCES/0066-sssctl-Consistent-commands-naming.patch
new file mode 100644
index 0000000..35bd2e2
--- /dev/null
+++ b/SOURCES/0066-sssctl-Consistent-commands-naming.patch
@@ -0,0 +1,330 @@
+From 6f36e763802e35ff2c431e67be20664e221de85f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 25 Jul 2016 13:50:13 +0200
+Subject: [PATCH 66/74] sssctl: Consistent commands naming
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use TOPIC-ACTION pattern for sssctl command
+names.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3087
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tools/common/sss_tools.h      |  2 ++
+ src/tools/sss_override.c          | 26 +++++++++++------------
+ src/tools/sssctl/sssctl.c         | 22 ++++++++++----------
+ src/tools/sssctl/sssctl.h         | 43 +++++++++++++++++++--------------------
+ src/tools/sssctl/sssctl_cache.c   | 18 ++++++++--------
+ src/tools/sssctl/sssctl_data.c    | 16 +++++++--------
+ src/tools/sssctl/sssctl_domains.c |  6 +++---
+ src/tools/sssctl/sssctl_logs.c    |  4 ++--
+ 8 files changed, 69 insertions(+), 68 deletions(-)
+
+diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h
+index a9ebabe21df14eba52f348046c179a91a6394b97..41c8b10e8c2dd8d6a86297b42a71dd5aaf9e556a 100644
+--- a/src/tools/common/sss_tools.h
++++ b/src/tools/common/sss_tools.h
+@@ -46,7 +46,9 @@ typedef errno_t
+                 void *pvt);
+ 
+ #define SSS_TOOL_COMMAND(cmd, msg, err, fn) {cmd, _(msg), err, fn}
++#define SSS_TOOL_COMMAND_NOMSG(cmd, err, fn) {cmd, NULL, err, fn}
+ #define SSS_TOOL_DELIMITER(message) {"", (message), 0, NULL}
++#define SSS_TOOL_LAST {NULL, NULL, 0, NULL}
+ 
+ struct sss_route_cmd {
+     const char *command;
+diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
+index 45a28fd7f5366cd85e6ecd13a4846917d18e9613..d41da52e69acdb67b5a6d624254e3b89a8aa27b8 100644
+--- a/src/tools/sss_override.c
++++ b/src/tools/sss_override.c
+@@ -1913,19 +1913,19 @@ static int override_group_export(struct sss_cmdline *cmdline,
+ int main(int argc, const char **argv)
+ {
+     struct sss_route_cmd commands[] = {
+-        {"user-add", NULL, 0, override_user_add},
+-        {"user-del", NULL, 0, override_user_del},
+-        {"user-find", NULL, 0, override_user_find},
+-        {"user-show", NULL, 0, override_user_show},
+-        {"user-import", NULL, 0, override_user_import},
+-        {"user-export", NULL, 0, override_user_export},
+-        {"group-add", NULL, 0, override_group_add},
+-        {"group-del", NULL, 0, override_group_del},
+-        {"group-find", NULL, 0, override_group_find},
+-        {"group-show", NULL, 0, override_group_show},
+-        {"group-import", NULL, 0, override_group_import},
+-        {"group-export", NULL, 0, override_group_export},
+-        {NULL, NULL, 0, NULL}
++        SSS_TOOL_COMMAND_NOMSG("user-add", 0, override_user_add),
++        SSS_TOOL_COMMAND_NOMSG("user-del", 0, override_user_del),
++        SSS_TOOL_COMMAND_NOMSG("user-find", 0, override_user_find),
++        SSS_TOOL_COMMAND_NOMSG("user-show", 0, override_user_show),
++        SSS_TOOL_COMMAND_NOMSG("user-import", 0, override_user_import),
++        SSS_TOOL_COMMAND_NOMSG("user-export", 0, override_user_export),
++        SSS_TOOL_COMMAND_NOMSG("group-add", 0, override_group_add),
++        SSS_TOOL_COMMAND_NOMSG("group-del", 0, override_group_del),
++        SSS_TOOL_COMMAND_NOMSG("group-find", 0, override_group_find),
++        SSS_TOOL_COMMAND_NOMSG("group-show", 0, override_group_show),
++        SSS_TOOL_COMMAND_NOMSG("group-import", 0, override_group_import),
++        SSS_TOOL_COMMAND_NOMSG("group-export", 0, override_group_export),
++        SSS_TOOL_LAST
+     };
+ 
+     return sss_tool_main(argc, argv, commands, NULL);
+diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
+index 86656f136c00234a230b8fc779a0d245f0d125d5..20ea26f8f71c26a925f5c37327635e346f497891 100644
+--- a/src/tools/sssctl/sssctl.c
++++ b/src/tools/sssctl/sssctl.c
+@@ -257,25 +257,25 @@ int main(int argc, const char **argv)
+ {
+     struct sss_route_cmd commands[] = {
+         SSS_TOOL_DELIMITER("SSSD Status:"),
+-        SSS_TOOL_COMMAND("list-domains", "List available domains", 0, sssctl_list_domains),
++        SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list),
+         SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status),
+         SSS_TOOL_DELIMITER("Information about cached content:"),
+-        SSS_TOOL_COMMAND("user", "Information about cached user", 0, sssctl_user),
+-        SSS_TOOL_COMMAND("group", "Information about cached group", 0, sssctl_group),
+-        SSS_TOOL_COMMAND("netgroup", "Information about cached netgroup", 0, sssctl_netgroup),
++        SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show),
++        SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show),
++        SSS_TOOL_COMMAND("netgroup-show", "Information about cached netgroup", 0, sssctl_netgroup_show),
+         SSS_TOOL_DELIMITER("Local data tools:"),
+-        SSS_TOOL_COMMAND("backup-local-data", "Backup local data", 0, sssctl_backup_local_data),
+-        SSS_TOOL_COMMAND("restore-local-data", "Restore local data from backup", 0, sssctl_restore_local_data),
+-        SSS_TOOL_COMMAND("remove-cache", "Backup local data and remove cached content", 0, sssctl_remove_cache),
+-        SSS_TOOL_COMMAND("upgrade-cache", "Perform cache upgrade", ERR_SYSDB_VERSION_TOO_OLD, sssctl_upgrade_cache),
++        SSS_TOOL_COMMAND("client-data-backup", "Backup local data", 0, sssctl_client_data_backup),
++        SSS_TOOL_COMMAND("client-data-restore", "Restore local data from backup", 0, sssctl_client_data_restore),
++        SSS_TOOL_COMMAND("cache-remove", "Backup local data and remove cached content", 0, sssctl_cache_remove),
++        SSS_TOOL_COMMAND("cache-upgrade", "Perform cache upgrade", ERR_SYSDB_VERSION_TOO_OLD, sssctl_cache_upgrade),
+         SSS_TOOL_DELIMITER("Log files tools:"),
+-        SSS_TOOL_COMMAND("remove-logs", "Remove existing SSSD log files", 0, sssctl_remove_logs),
+-        SSS_TOOL_COMMAND("fetch-logs", "Archive SSSD log files in tarball", 0, sssctl_fetch_logs),
++        SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove),
++        SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch),
+ #ifdef HAVE_LIBINI_CONFIG_V1_3
+         SSS_TOOL_DELIMITER("Configuration files tools:"),
+         SSS_TOOL_COMMAND("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check),
+ #endif
+-        {NULL, NULL, 0, NULL}
++        SSS_TOOL_LAST
+     };
+ 
+     return sss_tool_main(argc, argv, commands, NULL);
+diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
+index be624755de531df9ff5a97f5640266801695ef6e..72930ee5c3a1195e90c6e35768f715cbf6a1c4e1 100644
+--- a/src/tools/sssctl/sssctl.h
++++ b/src/tools/sssctl/sssctl.h
+@@ -56,52 +56,51 @@ void _sssctl_sifp_error(sss_sifp_ctx *sifp,
+ #define sssctl_sifp_error(sifp, error, message) \
+     _sssctl_sifp_error(sifp, error, _(message))
+ 
+-errno_t sssctl_list_domains(struct sss_cmdline *cmdline,
+-                            struct sss_tool_ctx *tool_ctx,
+-                            void *pvt);
++errno_t sssctl_domain_list(struct sss_cmdline *cmdline,
++                           struct sss_tool_ctx *tool_ctx,
++                           void *pvt);
+ 
+ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
+                              struct sss_tool_ctx *tool_ctx,
+                              void *pvt);
+ 
+-errno_t sssctl_backup_local_data(struct sss_cmdline *cmdline,
+-                                 struct sss_tool_ctx *tool_ctx,
+-                                 void *pvt);
+-
+-errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline,
++errno_t sssctl_client_data_backup(struct sss_cmdline *cmdline,
+                                   struct sss_tool_ctx *tool_ctx,
+                                   void *pvt);
+ 
+-errno_t sssctl_remove_cache(struct sss_cmdline *cmdline,
++errno_t sssctl_client_data_restore(struct sss_cmdline *cmdline,
++                                   struct sss_tool_ctx *tool_ctx,
++                                   void *pvt);
++
++errno_t sssctl_cache_remove(struct sss_cmdline *cmdline,
+                             struct sss_tool_ctx *tool_ctx,
+                             void *pvt);
+ 
+-errno_t sssctl_upgrade_cache(struct sss_cmdline *cmdline,
++errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline,
+                              struct sss_tool_ctx *tool_ctx,
+                              void *pvt);
+ 
+-errno_t sssctl_remove_logs(struct sss_cmdline *cmdline,
++errno_t sssctl_logs_remove(struct sss_cmdline *cmdline,
+                            struct sss_tool_ctx *tool_ctx,
+                            void *pvt);
+ 
+-errno_t sssctl_fetch_logs(struct sss_cmdline *cmdline,
++errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline,
+                           struct sss_tool_ctx *tool_ctx,
+                           void *pvt);
+ 
+-errno_t sssctl_user(struct sss_cmdline *cmdline,
+-                    struct sss_tool_ctx *tool_ctx,
+-                    void *pvt);
++errno_t sssctl_user_show(struct sss_cmdline *cmdline,
++                         struct sss_tool_ctx *tool_ctx,
++                         void *pvt);
+ 
+-errno_t sssctl_group(struct sss_cmdline *cmdline,
+-                     struct sss_tool_ctx *tool_ctx,
+-                     void *pvt);
++errno_t sssctl_group_show(struct sss_cmdline *cmdline,
++                          struct sss_tool_ctx *tool_ctx,
++                          void *pvt);
+ 
+-errno_t sssctl_netgroup(struct sss_cmdline *cmdline,
+-                        struct sss_tool_ctx *tool_ctx,
+-                        void *pvt);
++errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline,
++                             struct sss_tool_ctx *tool_ctx,
++                             void *pvt);
+ 
+ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
+                             struct sss_tool_ctx *tool_ctx,
+                             void *pvt);
+-
+ #endif /* _SSSCTL_H_ */
+diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
+index 4a1f3558ed7064ca40ccf9313d99fbab36e6e4c9..b1a7cc933d58d99fe34a05cb6eabe11a5270cee1 100644
+--- a/src/tools/sssctl/sssctl_cache.c
++++ b/src/tools/sssctl/sssctl_cache.c
+@@ -569,9 +569,9 @@ struct sssctl_cache_opts {
+     int id;
+ };
+ 
+-errno_t sssctl_user(struct sss_cmdline *cmdline,
+-                    struct sss_tool_ctx *tool_ctx,
+-                    void *pvt)
++errno_t sssctl_user_show(struct sss_cmdline *cmdline,
++                         struct sss_tool_ctx *tool_ctx,
++                         void *pvt)
+ {
+     struct sssctl_cache_opts opts = {0};
+     const char *attr;
+@@ -616,9 +616,9 @@ errno_t sssctl_user(struct sss_cmdline *cmdline,
+     return EOK;
+ }
+ 
+-errno_t sssctl_group(struct sss_cmdline *cmdline,
+-                     struct sss_tool_ctx *tool_ctx,
+-                     void *pvt)
++errno_t sssctl_group_show(struct sss_cmdline *cmdline,
++                          struct sss_tool_ctx *tool_ctx,
++                          void *pvt)
+ {
+     struct sssctl_cache_opts opts = {0};
+     const char *attr;
+@@ -662,9 +662,9 @@ errno_t sssctl_group(struct sss_cmdline *cmdline,
+     return EOK;
+ }
+ 
+-errno_t sssctl_netgroup(struct sss_cmdline *cmdline,
+-                        struct sss_tool_ctx *tool_ctx,
+-                        void *pvt)
++errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline,
++                             struct sss_tool_ctx *tool_ctx,
++                             void *pvt)
+ {
+     struct sssctl_cache_opts opts = {0};
+     errno_t ret;
+diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c
+index 3ab2ddf20006b2d5a26e2f167819677431854eb6..a26ddd8d5200319e75282b738791cf270f0d75a8 100644
+--- a/src/tools/sssctl/sssctl_data.c
++++ b/src/tools/sssctl/sssctl_data.c
+@@ -124,9 +124,9 @@ static errno_t sssctl_backup(bool force)
+     return ret;
+ }
+ 
+-errno_t sssctl_backup_local_data(struct sss_cmdline *cmdline,
+-                                 struct sss_tool_ctx *tool_ctx,
+-                                 void *pvt)
++errno_t sssctl_client_data_backup(struct sss_cmdline *cmdline,
++                                  struct sss_tool_ctx *tool_ctx,
++                                  void *pvt)
+ {
+     struct sssctl_data_opts opts = {0};
+     errno_t ret;
+@@ -184,9 +184,9 @@ static errno_t sssctl_restore(bool force_start, bool force_restart)
+     return ret;
+ }
+ 
+-errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline,
+-                                  struct sss_tool_ctx *tool_ctx,
+-                                  void *pvt)
++errno_t sssctl_client_data_restore(struct sss_cmdline *cmdline,
++                                   struct sss_tool_ctx *tool_ctx,
++                                   void *pvt)
+ {
+     struct sssctl_data_opts opts = {0};
+     errno_t ret;
+@@ -207,7 +207,7 @@ errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline,
+     return sssctl_restore(opts.start, opts.restart);
+ }
+ 
+-errno_t sssctl_remove_cache(struct sss_cmdline *cmdline,
++errno_t sssctl_cache_remove(struct sss_cmdline *cmdline,
+                             struct sss_tool_ctx *tool_ctx,
+                             void *pvt)
+ {
+@@ -259,7 +259,7 @@ errno_t sssctl_remove_cache(struct sss_cmdline *cmdline,
+     return EOK;
+ }
+ 
+-errno_t sssctl_upgrade_cache(struct sss_cmdline *cmdline,
++errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline,
+                              struct sss_tool_ctx *tool_ctx,
+                              void *pvt)
+ {
+diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c
+index 5aaaf770981a92b80b9376fd244d2d97e0502dac..cfc4e56133213e27496350033d4d28c3f5b5c63d 100644
+--- a/src/tools/sssctl/sssctl_domains.c
++++ b/src/tools/sssctl/sssctl_domains.c
+@@ -27,9 +27,9 @@
+ #include "sbus/sssd_dbus.h"
+ #include "responder/ifp/ifp_iface.h"
+ 
+-errno_t sssctl_list_domains(struct sss_cmdline *cmdline,
+-                            struct sss_tool_ctx *tool_ctx,
+-                            void *pvt)
++errno_t sssctl_domain_list(struct sss_cmdline *cmdline,
++                           struct sss_tool_ctx *tool_ctx,
++                           void *pvt)
+ {
+     sss_sifp_ctx *sifp;
+     sss_sifp_error error;
+diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c
+index a203474648e3c1719e16146f8f7b484f9d62541c..883f2ac2fa688b672cd8f388e4c571d1a12a32af 100644
+--- a/src/tools/sssctl/sssctl_logs.c
++++ b/src/tools/sssctl/sssctl_logs.c
+@@ -34,7 +34,7 @@ struct sssctl_logs_opts {
+     int archived;
+ };
+ 
+-errno_t sssctl_remove_logs(struct sss_cmdline *cmdline,
++errno_t sssctl_logs_remove(struct sss_cmdline *cmdline,
+                            struct sss_tool_ctx *tool_ctx,
+                            void *pvt)
+ {
+@@ -74,7 +74,7 @@ errno_t sssctl_remove_logs(struct sss_cmdline *cmdline,
+     return EOK;
+ }
+ 
+-errno_t sssctl_fetch_logs(struct sss_cmdline *cmdline,
++errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline,
+                           struct sss_tool_ctx *tool_ctx,
+                           void *pvt)
+ {
+-- 
+2.4.11
+
diff --git a/SOURCES/0067-SDAP-sanitize-member-name-before-using-in-filter.patch b/SOURCES/0067-SDAP-sanitize-member-name-before-using-in-filter.patch
new file mode 100644
index 0000000..ed5cdfa
--- /dev/null
+++ b/SOURCES/0067-SDAP-sanitize-member-name-before-using-in-filter.patch
@@ -0,0 +1,57 @@
+From a711326867dd901d349c648392b55b6e318196db Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 2 Aug 2016 15:20:35 +0200
+Subject: [PATCH 67/74] SDAP: sanitize member name before using in filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It caused an errors.
+
+(Tue Aug  2 06:29:39 2016) [sssd[be[LDAP]]] [sysdb_cache_search_users]
+(0x2000): Search users with filter:
+(&(objectclass=user)(nameAlias=t(u)ser@ldap))
+(Tue Aug  2 06:29:39 2016) [sssd[be[LDAP]]] [sysdb_cache_search_users]
+(0x0080): Error: 5 (Input/output error)
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3121
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ldap/sdap_async_groups.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
+index 102c1c0384be6da8732d56b7a318ded5a5132360..f19b68b8c403734f88b51a411ba0d009977d3491 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -1501,6 +1501,7 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state,
+     const char *filter;
+     const char *username;
+     const char *user_dn;
++    char *sanitized_name;
+     size_t count;
+     struct ldb_message **msgs = NULL;
+     static const char *attrs[] = { SYSDB_NAME, NULL };
+@@ -1508,8 +1509,16 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state,
+     tmp_ctx = talloc_new(NULL);
+     if (!tmp_ctx) return ENOMEM;
+ 
++    ret = sss_filter_sanitize(tmp_ctx, member_name, &sanitized_name);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to sanitize the given name:'%s'.\n", member_name);
++        goto done;
++    }
++
+     /* Check for the alias in the sysdb */
+-    filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS, member_name);
++    filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS,
++                             sanitized_name);
+     if (!filter) {
+         ret = ENOMEM;
+         goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0067-sss_override-document-debug-options.patch b/SOURCES/0067-sss_override-document-debug-options.patch
deleted file mode 100644
index 3dadc13..0000000
--- a/SOURCES/0067-sss_override-document-debug-options.patch
+++ /dev/null
@@ -1,122 +0,0 @@
-From c8fcc0597ad6399fe42111512d5dc2ff1362f3c8 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 25 Aug 2015 12:58:45 +0200
-Subject: [PATCH 67/68] sss_override: document --debug options
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2758
-
-Reviewed-by: Petr Cech <pcech@redhat.com>
----
- src/man/sss_override.8.xml   | 16 ++++++++++++++++
- src/tools/common/sss_tools.c | 25 +++++++++++++++++++++----
- 2 files changed, 37 insertions(+), 4 deletions(-)
-
-diff --git a/src/man/sss_override.8.xml b/src/man/sss_override.8.xml
-index d289f5b7dfa7fbd328831b4c71d45b4c555225cf..c2ec5dd41703c7272acf7c9d2c30f20351099791 100644
---- a/src/man/sss_override.8.xml
-+++ b/src/man/sss_override.8.xml
-@@ -190,6 +190,22 @@
-         </variablelist>
-     </refsect1>
- 
-+    <refsect1 id='options'>
-+        <title>COMMON OPTIONS</title>
-+        <para>
-+            Those options are available with all commands.
-+        </para>
-+        <variablelist remap='IP'>
-+            <varlistentry>
-+                <term>
-+                    <option>-d</option>,<option>--debug</option>
-+                    <replaceable>LEVEL</replaceable>
-+                </term>
-+                <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/debug_levels.xml" />
-+            </varlistentry>
-+        </variablelist>
-+    </refsect1>
-+
-     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" />
- 
- </refentry>
-diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
-index 6bbce3a25ddddc0b23ebc108a917a38e94981b65..d50e9af7d348e984687108895f0fd3448ee9add0 100644
---- a/src/tools/common/sss_tools.c
-+++ b/src/tools/common/sss_tools.c
-@@ -36,6 +36,13 @@ struct sss_cmdline {
-     const char **argv;
- };
- 
-+static void sss_tool_print_common_opts(void)
-+{
-+    fprintf(stderr, _("Common options:\n"));
-+    fprintf(stderr, "  --debug=INT            %s\n",
-+                    _("Enable debug at level"));
-+}
-+
- static void sss_tool_common_opts(struct sss_tool_ctx *tool_ctx,
-                                  int *argc, const char **argv)
- {
-@@ -201,6 +208,9 @@ int sss_tool_usage(const char *tool_name,
-         fprintf(stderr, "* %s\n", commands[i].command);
-     }
- 
-+    fprintf(stderr, _("\n"));
-+    sss_tool_print_common_opts();
-+
-     return EXIT_FAILURE;
- }
- 
-@@ -237,6 +247,13 @@ int sss_tool_route(int argc, const char **argv,
-     return sss_tool_usage(argv[0], commands);
- }
- 
-+static void sss_tool_popt_print_help(poptContext pc)
-+{
-+    poptPrintHelp(pc, stderr, 0);
-+    fprintf(stderr, "\n");
-+    sss_tool_print_common_opts();
-+}
-+
- int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-                      struct poptOption *options,
-                      enum sss_tool_opt require_option,
-@@ -286,7 +303,7 @@ int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-         } else {
-             fprintf(stderr, _("Invalid option %s: %s\n\n"),
-                     poptBadOption(pc, 0), poptStrerror(ret));
--            poptPrintHelp(pc, stderr, 0);
-+            sss_tool_popt_print_help(pc);
-             ret = EXIT_FAILURE;
-             goto done;
-         }
-@@ -297,7 +314,7 @@ int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-         *_fopt = poptGetArg(pc);
-         if (*_fopt == NULL) {
-             fprintf(stderr, _("Missing option: %s\n\n"), fopt_help);
--            poptPrintHelp(pc, stderr, 0);
-+            sss_tool_popt_print_help(pc);
-             ret = EXIT_FAILURE;
-             goto done;
-         }
-@@ -305,7 +322,7 @@ int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-         /* No more arguments expected. If something follows it is an error. */
-         if (poptGetArg(pc)) {
-             fprintf(stderr, _("Only one free argument is expected!\n\n"));
--            poptPrintHelp(pc, stderr, 0);
-+            sss_tool_popt_print_help(pc);
-             ret = EXIT_FAILURE;
-             goto done;
-         }
-@@ -315,7 +332,7 @@ int sss_tool_popt_ex(struct sss_cmdline *cmdline,
-     if (require_option == SSS_TOOL_OPT_REQUIRED
-             && ((_fopt != NULL && cmdline->argc < 2) || cmdline->argc < 1)) {
-         fprintf(stderr, _("At least one option is required!\n\n"));
--        poptPrintHelp(pc, stderr, 0);
-+        sss_tool_popt_print_help(pc);
-         ret = EXIT_FAILURE;
-         goto done;
-     }
--- 
-2.4.3
-
diff --git a/SOURCES/0068-NSS-Don-t-ignore-backslash-in-usernames-with-ldap-pr.patch b/SOURCES/0068-NSS-Don-t-ignore-backslash-in-usernames-with-ldap-pr.patch
deleted file mode 100644
index e3ac8f9..0000000
--- a/SOURCES/0068-NSS-Don-t-ignore-backslash-in-usernames-with-ldap-pr.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From eaccdcf75b651a0cc4fc02526180f5991a16c553 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Fri, 28 Aug 2015 07:07:40 +0200
-Subject: [PATCH 68/68] NSS: Don't ignore backslash in usernames with ldap
- provider
-
-The regression was caused by changing default domain regex
-for ldap provider in ticket #2717
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2772
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/responder/nss/nsssrv.c      |  4 ++--
- src/tests/cmocka/test_nss_srv.c |  4 ++--
- src/util/usertools.c            | 11 ++++++++++-
- src/util/util.h                 |  3 +++
- 4 files changed, 17 insertions(+), 5 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
-index 2b3bca892a5b9c483d1f6f099fd4a6493e9afcab..d8eff7968c4929663412aa56d08414689b921a22 100644
---- a/src/responder/nss/nsssrv.c
-+++ b/src/responder/nss/nsssrv.c
-@@ -552,9 +552,9 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
-         goto fail;
-     }
- 
--    ret = sss_names_init(nctx, nctx->rctx->cdb, NULL, &nctx->global_names);
-+    ret = sss_ad_default_names_ctx(nctx, &nctx->global_names);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "sss_names_init failed.\n");
-+        DEBUG(SSSDBG_CRIT_FAILURE, "sss_ad_default_names_ctx failed.\n");
-         goto fail;
-     }
- 
-diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
-index 84d3413be70bc0af433b7fd23cf7d78b4b9298f1..3cf9f06e61b9e4f13d5d755f7cbd8020194d52d6 100644
---- a/src/tests/cmocka/test_nss_srv.c
-+++ b/src/tests/cmocka/test_nss_srv.c
-@@ -1043,8 +1043,8 @@ void test_nss_setup(struct sss_test_conf_param params[],
-     nss_test_ctx->nctx = mock_nctx(nss_test_ctx);
-     assert_non_null(nss_test_ctx->nctx);
- 
--    ret = sss_names_init(nss_test_ctx->nctx, nss_test_ctx->tctx->confdb,
--                         NULL, &nss_test_ctx->nctx->global_names);
-+    ret = sss_ad_default_names_ctx(nss_test_ctx->nctx,
-+                                   &nss_test_ctx->nctx->global_names);
-     assert_int_equal(ret, EOK);
-     assert_non_null(nss_test_ctx->nctx->global_names);
- 
-diff --git a/src/util/usertools.c b/src/util/usertools.c
-index 87a8d7411312c3a80c32374a1fd93bbf0e767a91..ccbf7a0c8c2fb6d1d07afbfe46d978fc33093432 100644
---- a/src/util/usertools.c
-+++ b/src/util/usertools.c
-@@ -249,7 +249,8 @@ int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
-     }
- 
-     if (!re_pattern) {
--        re_pattern = talloc_strdup(tmpctx, IPA_AD_DEFAULT_RE);
-+        re_pattern = talloc_strdup(tmpctx,
-+                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)");
-         if (!re_pattern) {
-             ret = ENOMEM;
-             goto done;
-@@ -294,6 +295,14 @@ done:
-     return ret;
- }
- 
-+int sss_ad_default_names_ctx(TALLOC_CTX *mem_ctx,
-+                             struct sss_names_ctx **_out)
-+{
-+    return sss_names_init_from_args(mem_ctx, IPA_AD_DEFAULT_RE,
-+                                    CONFDB_DEFAULT_FULL_NAME_FORMAT,
-+                                    _out);
-+}
-+
- int sss_parse_name(TALLOC_CTX *memctx,
-                    struct sss_names_ctx *snctx,
-                    const char *orig, char **_domain, char **_name)
-diff --git a/src/util/util.h b/src/util/util.h
-index a20d1d82eb8f10dac515ad25e7e424713bb1c099..c998e91f92b0a86e0f4308ff0c07ff802588b5cf 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -298,6 +298,9 @@ int sss_names_init(TALLOC_CTX *mem_ctx,
-                    const char *domain,
-                    struct sss_names_ctx **out);
- 
-+int sss_ad_default_names_ctx(TALLOC_CTX *mem_ctx,
-+                             struct sss_names_ctx **_out);
-+
- int sss_parse_name(TALLOC_CTX *memctx,
-                    struct sss_names_ctx *snctx,
-                    const char *orig, char **_domain, char **_name);
--- 
-2.4.3
-
diff --git a/SOURCES/0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch b/SOURCES/0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch
new file mode 100644
index 0000000..f82f6d8
--- /dev/null
+++ b/SOURCES/0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch
@@ -0,0 +1,51 @@
+From 4e1111d869c8980f81a17b58844c48f1a342d774 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Thu, 4 Aug 2016 08:50:50 +0200
+Subject: [PATCH 68/74] SDAP: sysdb_search_users does not set users_count for
+ failures
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+==32577== Conditional jump or move depends on uninitialised value(s)
+==32577==    at 0x140DCE10: sdap_process_missing_member_2307 (sdap_async_groups.c:1556)
+==32577==    by 0x140DCE10: sdap_process_group_members_2307 (sdap_async_groups.c:1625)
+==32577==    by 0x140DCE10: sdap_process_group_send (sdap_async_groups.c:1298)
+==32577==    by 0x140DCE10: sdap_get_groups_process (sdap_async_groups.c:2130)
+==32577==    by 0x140CFDA8: generic_ext_search_handler.isra.3 (sdap_async.c:1688)
+==32577==    by 0x140D2416: sdap_get_generic_op_finished (sdap_async.c:1578)
+==32577==    by 0x140D0DFC: sdap_process_message (sdap_async.c:353)
+==32577==    by 0x140D0DFC: sdap_process_result (sdap_async.c:197)
+==32577==    by 0x8BF1B4E: tevent_common_loop_timer_delay (tevent_timed.c:341)
+==32577==    by 0x8BF2B59: epoll_event_loop_once (tevent_epoll.c:911)
+==32577==    by 0x8BF1256: std_event_loop_once (tevent_standard.c:114)
+==32577==    by 0x8BED40C: _tevent_loop_once (tevent.c:533)
+==32577==    by 0x8BED5AA: tevent_common_loop_wait (tevent.c:637)
+==32577==    by 0x8BF11F6: std_event_loop_wait (tevent_standard.c:140)
+==32577==    by 0x529DD02: server_loop (server.c:702)
+==32577==    by 0x110951: main (data_provider_be.c:587)
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3121
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ 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 f19b68b8c403734f88b51a411ba0d009977d3491..72760b75acae4cb6ce15c72f16dae8e859d89847 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -1553,7 +1553,7 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state,
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "Could not add group member %s\n", username);
+         }
+-    } else if (ret == ENOENT || count == 0) {
++    } else if (ret == ENOENT) {
+         /* The entry really does not exist, add a ghost */
+         DEBUG(SSSDBG_TRACE_FUNC, "Adding a ghost entry\n");
+         ret = sdap_add_group_member_2307(state->ghost_dns, member_name);
+-- 
+2.4.11
+
diff --git a/SOURCES/0069-GPO-fix-memory-leak.patch b/SOURCES/0069-GPO-fix-memory-leak.patch
deleted file mode 100644
index 7eb04e9..0000000
--- a/SOURCES/0069-GPO-fix-memory-leak.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 69bf6ed59e73e92a52c080b4af57f554f703ab52 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Thu, 3 Sep 2015 04:46:50 -0400
-Subject: [PATCH 69/73] GPO: fix memory leak
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2777
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/providers/ad/ad_gpo.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
-index 974fd04b99709055f25ed2a3b77821b3caec09ad..a7ba4b2210115a19a3e4430744d36fe76da20f09 100644
---- a/src/providers/ad/ad_gpo.c
-+++ b/src/providers/ad/ad_gpo.c
-@@ -560,14 +560,14 @@ ad_gpo_get_sids(TALLOC_CTX *mem_ctx,
-         DEBUG(SSSDBG_OP_FAILURE,
-               "sysdb_initgroups failed: [%d](%s)\n",
-               ret, sss_strerror(ret));
--        return ret;
-+        goto done;
-     }
- 
-     if (res->count == 0) {
-         ret = ENOENT;
-         DEBUG(SSSDBG_OP_FAILURE,
-               "sysdb_initgroups returned empty result\n");
--        return ret;
-+        goto done;
-     }
- 
-     user_sid = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SID_STR, NULL);
-@@ -602,7 +602,7 @@ ad_gpo_get_sids(TALLOC_CTX *mem_ctx,
-     *_group_size = num_group_sids + 1;
-     *_group_sids = talloc_steal(mem_ctx, group_sids);
-     *_user_sid = talloc_steal(mem_ctx, user_sid);
--    return EOK;
-+    ret = EOK;
- 
-  done:
-     talloc_free(tmp_ctx);
--- 
-2.4.3
-
diff --git a/SOURCES/0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch b/SOURCES/0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch
new file mode 100644
index 0000000..24ea5be
--- /dev/null
+++ b/SOURCES/0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch
@@ -0,0 +1,69 @@
+From 0bb66d94542920870effa808861c0c20180111ba Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 2 Aug 2016 15:20:19 +0200
+Subject: [PATCH 69/74] SYSDB: Sanitize dn in
+ sysdb_get_user_members_recursively
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There was a crash in nss responder when a group contained
+a user with special charactes which shoudl be sanitized before
+using in filter.
+
+==31651== Conditional jump or move depends on uninitialised value(s)
+==31651==    at 0x8BEA7DE: _talloc_steal_loc (talloc.c:1215)
+==31651==    by 0x5264889: sysdb_get_user_members_recursively (sysdb_ops.c:4759)
+==31651==    by 0x5278F61: sysdb_add_group_member_overrides (sysdb_views.c:1375)
+==31651==    by 0x526677C: sysdb_getgrnam_with_views (sysdb_search.c:799)
+==31651==    by 0x1172F6: nss_cmd_getgrnam_search (nsssrv_cmd.c:3168)
+==31651==    by 0x119C67: nss_cmd_getby_dp_callback (nsssrv_cmd.c:1382)
+==31651==    by 0x10FD14: nsssrv_dp_send_acct_req_done (nsssrv_cmd.c:916)
+==31651==    by 0x12898B: sss_dp_internal_get_done (responder_dp.c:791)
+==31651==    by 0x58FF861: complete_pending_call_and_unlock (dbus-connection.c:2314)
+==31651==    by 0x5902B50: dbus_connection_dispatch (dbus-connection.c:4580)
+==31651==    by 0x527F261: sbus_dispatch (sssd_dbus_connection.c:96)
+==31651==    by 0x89D8B4E: tevent_common_loop_timer_delay (tevent_timed.c:341)
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3121
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/db/sysdb_ops.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index ed177d1730723a61e01167a75a0baca6d81252f8..342e16fb20e2c418745b137162425509ca1fd0cb 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -4722,6 +4722,7 @@ errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx,
+     struct ldb_result *res;
+     struct ldb_dn *base_dn;
+     char *filter;
++    char *sanitized_name;
+     const char *attrs[] = SYSDB_PW_ATTRS;
+     struct ldb_message **msgs;
+ 
+@@ -4737,8 +4738,17 @@ errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
++    ret = sss_filter_sanitize(tmp_ctx, ldb_dn_get_linearized(group_dn),
++                              &sanitized_name);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to sanitize the given name:'%s'.\n",
++              ldb_dn_get_linearized(group_dn));
++        goto done;
++    }
++
+     filter = talloc_asprintf(tmp_ctx, "(&("SYSDB_UC")("SYSDB_MEMBEROF"=%s))",
+-                             ldb_dn_get_linearized(group_dn));
++                             sanitized_name);
+     if (filter == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+         ret = ENOMEM;
+-- 
+2.4.11
+
diff --git a/SOURCES/0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch b/SOURCES/0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch
new file mode 100644
index 0000000..bed5cd3
--- /dev/null
+++ b/SOURCES/0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch
@@ -0,0 +1,178 @@
+From ba87a54746b417ad32362f3c6e565c7af8d21afa Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 3 Aug 2016 14:23:39 +0200
+Subject: [PATCH 70/74] SYSDB: Fix setting dataExpireTimestamp if sysdb is
+ supposed to set the current time
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sysdb is already able to retrieve the current timestamp if the caller
+doesn't specify it. However, for the timestamp cache this came too late
+and the timestamp cache used zero as the 'now' time.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3064
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/db/sysdb_ops.c                     | 20 ++++----
+ src/tests/cmocka/test_sysdb_ts_cache.c | 83 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 93 insertions(+), 10 deletions(-)
+
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 342e16fb20e2c418745b137162425509ca1fd0cb..67006c155098b9fde00a01d424014852c383a325 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -2465,6 +2465,11 @@ int sysdb_store_user(struct sss_domain_info *domain,
+     errno_t sret = EOK;
+     bool in_transaction = false;
+ 
++    /* get transaction timestamp */
++    if (now == 0) {
++        now = time(NULL);
++    }
++
+     ret = sysdb_check_and_update_ts_usr(domain, name, attrs,
+                                         cache_timeout, now);
+     if (ret == EOK) {
+@@ -2508,11 +2513,6 @@ int sysdb_store_user(struct sss_domain_info *domain,
+         DEBUG(SSSDBG_TRACE_LIBS, "User %s does not exist.\n", name);
+     }
+ 
+-    /* get transaction timestamp */
+-    if (!now) {
+-        now = time(NULL);
+-    }
+-
+     if (ret == ENOENT) {
+         /* the user doesn't exist, turn into adding a user */
+         ret = sysdb_store_new_user(domain, name, uid, gid, gecos, homedir,
+@@ -2700,6 +2700,11 @@ int sysdb_store_group(struct sss_domain_info *domain,
+     errno_t sret = EOK;
+     bool in_transaction = false;
+ 
++    /* get transaction timestamp */
++    if (!now) {
++        now = time(NULL);
++    }
++
+     ret = sysdb_check_and_update_ts_grp(domain, name, attrs,
+                                         cache_timeout, now);
+     if (ret == EOK) {
+@@ -2741,11 +2746,6 @@ int sysdb_store_group(struct sss_domain_info *domain,
+         }
+     }
+ 
+-    /* get transaction timestamp */
+-    if (!now) {
+-        now = time(NULL);
+-    }
+-
+     if (new_group) {
+         ret = sysdb_store_new_group(domain, name, gid, attrs,
+                                     cache_timeout, now);
+diff --git a/src/tests/cmocka/test_sysdb_ts_cache.c b/src/tests/cmocka/test_sysdb_ts_cache.c
+index d5492299647f54e379ea3f305ccc1501c7f6c79f..aa857e7e4823d2d8ba1e1a794b3e2474876e9ab0 100644
+--- a/src/tests/cmocka/test_sysdb_ts_cache.c
++++ b/src/tests/cmocka/test_sysdb_ts_cache.c
+@@ -1348,6 +1348,86 @@ static void test_user_byupn(void **state)
+     talloc_free(res);
+ }
+ 
++static void test_sysdb_zero_now(void **state)
++{
++    int ret;
++    struct sysdb_ts_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                     struct sysdb_ts_test_ctx);
++    struct ldb_result *res = NULL;
++    uint64_t cache_expire_sysdb;
++    uint64_t cache_expire_ts;
++    struct sysdb_attrs *attrs = NULL;
++
++    /* Nothing must be stored in either cache at the beginning of the test */
++    res = sysdb_getpwnam_res(test_ctx, test_ctx->tctx->dom, TEST_USER_NAME);
++    assert_int_equal(res->count, 0);
++    talloc_free(res);
++
++    res = sysdb_getgrnam_res(test_ctx, test_ctx->tctx->dom, TEST_GROUP_NAME);
++    assert_int_equal(res->count, 0);
++    talloc_free(res);
++
++    attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(attrs);
++
++    ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME, NULL,
++                           TEST_USER_UID, TEST_USER_GID, TEST_USER_NAME,
++                           "/home/"TEST_USER_NAME, "/bin/bash", NULL,
++                           attrs, NULL, TEST_CACHE_TIMEOUT,
++                           0);
++    talloc_zfree(attrs);
++    assert_int_equal(ret, EOK);
++
++    attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(attrs);
++
++    ret = sysdb_store_group(test_ctx->tctx->dom,
++                            TEST_GROUP_NAME,
++                            TEST_GROUP_GID,
++                            attrs,
++                            TEST_CACHE_TIMEOUT,
++                            0);
++    talloc_zfree(attrs);
++    assert_int_equal(ret, EOK);
++    talloc_zfree(attrs);
++
++    attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(attrs);
++
++    ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME, NULL,
++                           TEST_USER_UID, TEST_USER_GID, TEST_USER_NAME,
++                           "/home/"TEST_USER_NAME, "/bin/bash", NULL,
++                           attrs, NULL, TEST_CACHE_TIMEOUT,
++                           0);
++    talloc_zfree(attrs);
++    assert_int_equal(ret, EOK);
++
++    attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(attrs);
++
++    ret = sysdb_store_group(test_ctx->tctx->dom,
++                            TEST_GROUP_NAME,
++                            TEST_GROUP_GID,
++                            attrs,
++                            TEST_CACHE_TIMEOUT,
++                            0);
++    talloc_zfree(attrs);
++    assert_int_equal(ret, EOK);
++
++    /* Even though we passed zero as the timestamp, the timestamp cache should
++     * have used the current time instead
++     */
++    get_pw_timestamp_attrs(test_ctx, TEST_USER_NAME,
++                           &cache_expire_sysdb, &cache_expire_ts);
++    assert_true(cache_expire_sysdb > TEST_CACHE_TIMEOUT);
++    assert_true(cache_expire_ts > TEST_CACHE_TIMEOUT);
++
++    get_gr_timestamp_attrs(test_ctx, TEST_GROUP_NAME,
++                           &cache_expire_sysdb, &cache_expire_ts);
++    assert_true(cache_expire_sysdb > TEST_CACHE_TIMEOUT);
++    assert_true(cache_expire_ts > TEST_CACHE_TIMEOUT);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int rv;
+@@ -1396,6 +1476,9 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(test_user_byupn,
+                                         test_sysdb_ts_setup,
+                                         test_sysdb_ts_teardown),
++        cmocka_unit_test_setup_teardown(test_sysdb_zero_now,
++                                        test_sysdb_ts_setup,
++                                        test_sysdb_ts_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.4.11
+
diff --git a/SOURCES/0070-sss_override-support-fqn-in-override-name.patch b/SOURCES/0070-sss_override-support-fqn-in-override-name.patch
deleted file mode 100644
index 838a47e..0000000
--- a/SOURCES/0070-sss_override-support-fqn-in-override-name.patch
+++ /dev/null
@@ -1,172 +0,0 @@
-From 90611687b8b7b9a4d2be4625c97301660412b605 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 15 Sep 2015 11:38:40 +0200
-Subject: [PATCH 70/73] sss_override: support fqn in override name
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2782
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tools/sss_override.c | 111 +++++++++++++++++++++++++++++++++++++++--------
- 1 file changed, 93 insertions(+), 18 deletions(-)
-
-diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
-index ee8351ea97e5efe0d449dc646c6136b32ceec2c6..0d7a4690634a3993dee2119ee09fea328e494f1a 100644
---- a/src/tools/sss_override.c
-+++ b/src/tools/sss_override.c
-@@ -604,58 +604,133 @@ done:
-     return ret;
- }
- 
-+static errno_t override_fqn(TALLOC_CTX *mem_ctx,
-+                            struct sss_tool_ctx *tool_ctx,
-+                            struct sss_domain_info *domain,
-+                            const char *input,
-+                            const char **_name)
-+{
-+    struct sss_domain_info *dom;
-+    errno_t ret;
-+
-+    if (input == NULL) {
-+        return EOK;
-+    }
-+
-+    ret = sss_tool_parse_name(mem_ctx, tool_ctx, input, _name, &dom);
-+    if (ret == EAGAIN) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Unable to find domain from "
-+              "fqn %s\n", input);
-+        fprintf(stderr, _("Changing domain is not allowed!\n"));
-+        ret = EINVAL;
-+    } else if (ret == EOK && dom != NULL && dom != domain) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Trying to change domain from "
-+              "%s to %s, not allowed!\n", domain->name, dom->name);
-+        fprintf(stderr, _("Changing domain is not allowed!\n"));
-+        ret = EINVAL;
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name %s [%d]: %s\n",
-+              input, ret, sss_strerror(ret));
-+    }
-+
-+    return ret;
-+}
-+
- static errno_t override_user(struct sss_tool_ctx *tool_ctx,
--                             struct override_user *user)
-+                             struct override_user *input_user)
- {
-+    TALLOC_CTX *tmp_ctx;
-+    struct override_user user;
-     struct sysdb_attrs *attrs;
-     errno_t ret;
- 
--    ret = prepare_view_msg(user->domain);
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-+        return ENOMEM;
-+    }
-+
-+    user = *input_user;
-+
-+    /* We need to parse the name and ensure that domain did not change. */
-+    ret = override_fqn(tmp_ctx, tool_ctx, user.domain, user.name, &user.name);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    ret = prepare_view_msg(user.domain);
-     if (ret != EOK) {
--        return ret;
-+        goto done;
-     }
- 
--    attrs = build_user_attrs(tool_ctx, user);
-+    attrs = build_user_attrs(tool_ctx, &user);
-     if (attrs == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
--        return ENOMEM;
-+        ret = ENOMEM;
-+        goto done;
-     }
- 
--    ret = override_object_add(user->domain, SYSDB_MEMBER_USER, attrs,
--                              user->orig_name);
-+    ret = override_object_add(user.domain, SYSDB_MEMBER_USER, attrs,
-+                              user.orig_name);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
--        return ret;
-+        goto done;
-     }
- 
--    return EOK;
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
- }
- 
- static errno_t override_group(struct sss_tool_ctx *tool_ctx,
--                              struct override_group *group)
-+                              struct override_group *input_group)
- {
-+    TALLOC_CTX *tmp_ctx;
-+    struct override_group group;
-     struct sysdb_attrs *attrs;
-     errno_t ret;
- 
--    ret = prepare_view_msg(group->domain);
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-+        return ENOMEM;
-+    }
-+
-+    group = *input_group;
-+
-+    /* We need to parse the name and ensure that domain did not change. */
-+    ret = override_fqn(tmp_ctx, tool_ctx, group.domain, group.name,
-+                       &group.name);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    ret = prepare_view_msg(group.domain);
-     if (ret != EOK) {
--        return ret;
-+        goto done;
-     }
- 
--    attrs = build_group_attrs(tool_ctx, group);
-+    attrs = build_group_attrs(tool_ctx, &group);
-     if (attrs == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
--        return ENOMEM;
-+        ret = ENOMEM;
-+        goto done;
-     }
- 
--    ret = override_object_add(group->domain, SYSDB_MEMBER_GROUP, attrs,
--                              group->orig_name);
-+    ret = override_object_add(group.domain, SYSDB_MEMBER_GROUP, attrs,
-+                              group.orig_name);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
--        return ret;
-+        goto done;
-     }
- 
--    return EOK;
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
- }
- 
- static errno_t override_object_del(struct sss_domain_info *domain,
--- 
-2.4.3
-
diff --git a/SOURCES/0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch b/SOURCES/0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch
new file mode 100644
index 0000000..0caae35
--- /dev/null
+++ b/SOURCES/0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch
@@ -0,0 +1,44 @@
+From e4fd5c67a8f63062b17e615ce746a19994ee310c Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Wed, 27 Jul 2016 11:13:04 +0200
+Subject: [PATCH 71/74] Revert "LDAP: Lookup services by all protocols unless a
+ protocol is specified"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit aa58e216c1f794bd335151f19e79adbb3ddf4c73.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ldap/ldap_id_services.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c
+index 401228c20af31ae2df9bb3d35ed25fb6f06b1839..77215127b53297d840eaa4d2f35a75eedb085e43 100644
+--- a/src/providers/ldap/ldap_id_services.c
++++ b/src/providers/ldap/ldap_id_services.c
+@@ -89,9 +89,6 @@ services_get_send(TALLOC_CTX *mem_ctx,
+     state->sysdb = sdom->dom->sysdb;
+     state->name = name;
+     state->protocol = protocol;
+-    if (state->protocol != NULL && state->protocol[0] == '\0') {
+-        state->protocol = NULL;
+-    }
+     state->filter_type = filter_type;
+     state->noexist_delete = noexist_delete;
+ 
+@@ -117,8 +114,8 @@ services_get_send(TALLOC_CTX *mem_ctx,
+     ret = sss_filter_sanitize(state, name, &clean_name);
+     if (ret != EOK)  goto error;
+ 
+-    if (state->protocol != NULL) {
+-        ret = sss_filter_sanitize(state, state->protocol, &clean_protocol);
++    if (protocol) {
++        ret = sss_filter_sanitize(state, protocol, &clean_protocol);
+         if (ret != EOK)  goto error;
+     }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0071-views-do-not-require-overrideDN-in-grous-when-LOCAL-.patch b/SOURCES/0071-views-do-not-require-overrideDN-in-grous-when-LOCAL-.patch
deleted file mode 100644
index a92663d..0000000
--- a/SOURCES/0071-views-do-not-require-overrideDN-in-grous-when-LOCAL-.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 58c6f691bed13095a48b4587e5baa7bb4dc7dae5 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 17 Sep 2015 11:34:40 +0200
-Subject: [PATCH 71/73] views: do not require overrideDN in grous when LOCAL
- view is set
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2790
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/db/sysdb_views.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
-index 1db6c892de9e4764b673608166830800744b1148..82b1f187dbc6aab032403854714474301ae3324c 100644
---- a/src/db/sysdb_views.c
-+++ b/src/db/sysdb_views.c
-@@ -1337,6 +1337,12 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
-         override_dn_str = ldb_msg_find_attr_as_string(member_obj->msgs[0],
-                                                       SYSDB_OVERRIDE_DN, NULL);
-         if (override_dn_str == NULL) {
-+            if (is_local_view(domain->view_name)) {
-+                /* LOCAL view doesn't have to have overrideDN specified. */
-+                ret = EOK;
-+                goto done;
-+            }
-+
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Missing override DN for objext [%s].\n",
-                   ldb_dn_get_linearized(member_obj->msgs[0]->dn));
--- 
-2.4.3
-
diff --git a/SOURCES/0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch b/SOURCES/0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch
new file mode 100644
index 0000000..1e57a7b
--- /dev/null
+++ b/SOURCES/0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch
@@ -0,0 +1,59 @@
+From 0edb93b54bf79df41aa34a77e9a173cf8529559a Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Wed, 27 Jul 2016 11:13:32 +0200
+Subject: [PATCH 72/74] PROVIDER: Conversion empty string from D-Bus to NULL
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch fixes the issue with empty string recieving from D-Bus.
+Data providers obtains NULL. So this is simple conversin.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3084
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/data_provider/dp_target_id.c | 6 +++---
+ src/providers/ldap/ldap_id_services.c      | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
+index 7c882be2c17650d818cb3907197e381a8f635a77..1b06cbe5b96f56c33dd048cf6211b7c97819db8c 100644
+--- a/src/providers/data_provider/dp_target_id.c
++++ b/src/providers/data_provider/dp_target_id.c
+@@ -62,15 +62,15 @@ static bool check_and_parse_filter(struct be_acct_req *data,
+                  {0, 0, 0}};
+     int i;
+ 
+-    if (filter == NULL) {
++    if (SBUS_IS_STRING_EMPTY(filter)) {
+         return false;
+     }
+ 
+     for (i = 0; types[i].name != NULL; i++) {
+         if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
+             data->filter_type = types[i].type;
+-            data->filter_value = &filter[types[i].lenght];
+-            data->extra_value = extra;
++            data->filter_value = SBUS_SET_STRING(&filter[types[i].lenght]);
++            data->extra_value = SBUS_SET_STRING(extra);
+             return true;
+         }
+     }
+diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c
+index 77215127b53297d840eaa4d2f35a75eedb085e43..e91fc52d731eaa22be7e98365fc75e7057cb8f1f 100644
+--- a/src/providers/ldap/ldap_id_services.c
++++ b/src/providers/ldap/ldap_id_services.c
+@@ -114,7 +114,7 @@ services_get_send(TALLOC_CTX *mem_ctx,
+     ret = sss_filter_sanitize(state, name, &clean_name);
+     if (ret != EOK)  goto error;
+ 
+-    if (protocol) {
++    if (protocol == NULL) {
+         ret = sss_filter_sanitize(state, protocol, &clean_protocol);
+         if (ret != EOK)  goto error;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0072-views-fix-two-typos-in-debug-messages.patch b/SOURCES/0072-views-fix-two-typos-in-debug-messages.patch
deleted file mode 100644
index 454537c..0000000
--- a/SOURCES/0072-views-fix-two-typos-in-debug-messages.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 82a09d64a35e560d3715484b2f3f8e6e7c0af48c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 17 Sep 2015 11:35:56 +0200
-Subject: [PATCH 72/73] views: fix two typos in debug messages
-
-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 82b1f187dbc6aab032403854714474301ae3324c..f0459fc174b94d7a735b7c416555eb5aaac42b7c 100644
---- a/src/db/sysdb_views.c
-+++ b/src/db/sysdb_views.c
-@@ -1193,7 +1193,7 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
-             }
- 
-             DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Missing override DN for objext [%s].\n",
-+                  "Missing override DN for object [%s].\n",
-                   ldb_dn_get_linearized(obj->dn));
- 
-             ret = ENOENT;
-@@ -1344,7 +1344,7 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
-             }
- 
-             DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Missing override DN for objext [%s].\n",
-+                  "Missing override DN for object [%s].\n",
-                   ldb_dn_get_linearized(member_obj->msgs[0]->dn));
-             ret = ENOENT;
-             goto done;
--- 
-2.4.3
-
diff --git a/SOURCES/0073-LDAP-Fix-Dereference-after-NULL-check.patch b/SOURCES/0073-LDAP-Fix-Dereference-after-NULL-check.patch
new file mode 100644
index 0000000..3d467ba
--- /dev/null
+++ b/SOURCES/0073-LDAP-Fix-Dereference-after-NULL-check.patch
@@ -0,0 +1,36 @@
+From 33649cb41206f568e2bef582e13edbc721184a29 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 8 Aug 2016 09:03:47 +0200
+Subject: [PATCH 73/74] LDAP: Fix Dereference after NULL check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The commit dc30c60f166ad9adc63a47a1013508a71624ac87
+changed the logic in NULL check
+ -    if (protocol) {
+ +    if (protocol == NULL) {
+
+Found by Coverity:
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+---
+ src/providers/ldap/ldap_id_services.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c
+index e91fc52d731eaa22be7e98365fc75e7057cb8f1f..638cb619b39f135307090dcf0f2c6ab2cc4119d0 100644
+--- a/src/providers/ldap/ldap_id_services.c
++++ b/src/providers/ldap/ldap_id_services.c
+@@ -114,7 +114,7 @@ services_get_send(TALLOC_CTX *mem_ctx,
+     ret = sss_filter_sanitize(state, name, &clean_name);
+     if (ret != EOK)  goto error;
+ 
+-    if (protocol == NULL) {
++    if (protocol != NULL) {
+         ret = sss_filter_sanitize(state, protocol, &clean_protocol);
+         if (ret != EOK)  goto error;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0073-views-allow-ghost-members-for-LOCAL-view.patch b/SOURCES/0073-views-allow-ghost-members-for-LOCAL-view.patch
deleted file mode 100644
index ade6944..0000000
--- a/SOURCES/0073-views-allow-ghost-members-for-LOCAL-view.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From 8d728461964488b29cdcd431210872eaee9bc9f7 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 17 Sep 2015 14:46:34 +0200
-Subject: [PATCH 73/73] views: allow ghost members for LOCAL view
-
-LOCAL view does not allow the case when both ghost member and
-user override is created so it is safe to allow ghost members
-for this view.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2790
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/db/sysdb_search.c          | 36 ++++++++++++++++++++----------------
- src/responder/nss/nsssrv_cmd.c |  3 ++-
- 2 files changed, 22 insertions(+), 17 deletions(-)
-
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index 4f617b841bf3b3760d9cb05a06f4b46ea0c58ff5..efd583beefe78bb6bb26263a9833bf3bfafd0083 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -482,14 +482,16 @@ int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx,
-     /* If there are views we have to check if override values must be added to
-      * the original object. */
-     if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
--        el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
--        if (el != NULL && el->num_values != 0) {
--            DEBUG(SSSDBG_TRACE_ALL,
--                  "Group object [%s], contains ghost entries which must be " \
--                  "resolved before overrides can be applied.\n",
--                   ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
--            ret = ENOENT;
--            goto done;
-+        if (!is_local_view(domain->view_name)) {
-+            el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
-+            if (el != NULL && el->num_values != 0) {
-+                DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost "
-+                      "entries which must be resolved before overrides can be "
-+                      "applied.\n",
-+                      ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
-+                ret = ENOENT;
-+                goto done;
-+            }
-         }
- 
-         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
-@@ -634,14 +636,16 @@ int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx,
-     /* If there are views we have to check if override values must be added to
-      * the original object. */
-     if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
--        el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
--        if (el != NULL && el->num_values != 0) {
--            DEBUG(SSSDBG_TRACE_ALL,
--                  "Group object [%s], contains ghost entries which must be " \
--                  "resolved before overrides can be applied.\n",
--                   ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
--            ret = ENOENT;
--            goto done;
-+        if (!is_local_view(domain->view_name)) {
-+            el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
-+            if (el != NULL && el->num_values != 0) {
-+                DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost "
-+                      "entries which must be resolved before overrides can be "
-+                      "applied.\n",
-+                      ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
-+                ret = ENOENT;
-+                goto done;
-+            }
-         }
- 
-         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index 459634b8d7a590a196ad47a17cd52729fc633ee2..d177135db00369c2af69eb62f6a4a4aaf54ba510 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -2909,7 +2909,8 @@ static int fill_grent(struct sss_packet *packet,
-             }
-             el = ldb_msg_find_element(msg, SYSDB_GHOST);
-             if (el) {
--                if (DOM_HAS_VIEWS(dom) && el->num_values != 0) {
-+                if (DOM_HAS_VIEWS(dom) && !is_local_view(dom->view_name)
-+                        && el->num_values != 0) {
-                     DEBUG(SSSDBG_CRIT_FAILURE,
-                           "Domain has a view [%s] but group [%s] still has " \
-                           "ghost members.\n", dom->view_name, orig_name);
--- 
-2.4.3
-
diff --git a/SOURCES/0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch b/SOURCES/0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch
new file mode 100644
index 0000000..913b219
--- /dev/null
+++ b/SOURCES/0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch
@@ -0,0 +1,32 @@
+From 89f9598e19000fed30c1069eec01b094eeae0377 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 2 Aug 2016 10:11:14 +0200
+Subject: [PATCH 74/74] LDAP: Fixing wrong pam error code for passwd
+
+This patch adds right pam error code for sssd offline state.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3109
+---
+ src/providers/ldap/ldap_auth.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
+index 107f6ded1a903904e088f0b6b0320fe82a52af52..35f16b0d4a6f8e566b0cf63b65ba46f31e7c1bcd 100644
+--- a/src/providers/ldap/ldap_auth.c
++++ b/src/providers/ldap/ldap_auth.c
+@@ -1101,6 +1101,11 @@ sdap_pam_chpass_handler_send(TALLOC_CTX *mem_ctx,
+     state->auth_ctx = auth_ctx;
+     state->ev = params->ev;
+ 
++    if (be_is_offline(state->be_ctx)) {
++        pd->pam_status = PAM_AUTHINFO_UNAVAIL;
++        goto immediately;
++    }
++
+     if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) &&
+         (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+-- 
+2.4.11
+
diff --git a/SOURCES/0074-UTIL-Convert-domain-disabled-into-tri-state-with-dom.patch b/SOURCES/0074-UTIL-Convert-domain-disabled-into-tri-state-with-dom.patch
deleted file mode 100644
index 55c4880..0000000
--- a/SOURCES/0074-UTIL-Convert-domain-disabled-into-tri-state-with-dom.patch
+++ /dev/null
@@ -1,303 +0,0 @@
-From 875a41bcd24d1deb2bd190eaaaf7a366de128cee Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 18 Aug 2015 15:15:44 +0000
-Subject: [PATCH 74/87] UTIL: Convert domain->disabled into tri-state with
- domain states
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Required for:
-https://fedorahosted.org/sssd/ticket/2637
-
-This is a first step towards making it possible for domain to be around,
-but not contacted by Data Provider.
-
-Also explicitly create domains as active, previously we only relied on
-talloc_zero marking dom->disabled as false.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/confdb/confdb.c                      |  2 ++
- src/confdb/confdb.h                      | 19 ++++++++++++++++++-
- src/db/sysdb_subdomains.c                |  7 +++++--
- src/providers/ad/ad_subdomains.c         |  2 +-
- src/providers/ipa/ipa_subdomains.c       |  2 +-
- src/responder/common/responder_common.c  |  5 +++--
- src/tests/cmocka/test_sysdb_subdomains.c |  6 +++++-
- src/tests/cmocka/test_utils.c            |  6 +++---
- src/util/domain_info_utils.c             | 20 +++++++++++++++++---
- src/util/util.h                          |  3 +++
- src/util/util_errors.c                   |  1 +
- src/util/util_errors.h                   |  1 +
- 12 files changed, 60 insertions(+), 14 deletions(-)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index 3a8a1c01b92e62302ac4f787ccd085be9d8f05c3..c097aad7745eda4fff051c7da027776f95db0f03 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -1342,6 +1342,8 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
-     domain->has_views = false;
-     domain->view_name = NULL;
- 
-+    domain->state = DOM_ACTIVE;
-+
-     *_domain = domain;
-     ret = EOK;
- done:
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 9aa264899e789f2491b9873daf44bb55aff1c95d..e8c1caa67852a8f3d9d74fc61dbe6f8b4169daf7 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -215,6 +215,23 @@
- struct confdb_ctx;
- struct config_file_ctx;
- 
-+/** sssd domain state */
-+enum sss_domain_state {
-+    /** Domain is usable by both responders and providers. This
-+     * is the default state after creating a new domain
-+     */
-+    DOM_ACTIVE,
-+    /** Domain was removed, should not be used be neither responders
-+     * not providers.
-+     */
-+    DOM_DISABLED,
-+    /** Domain cannot be contacted. Providers return an offline error code
-+     * when receiving request for inactive domain, but responders should
-+     * return cached data
-+     */
-+    DOM_INACTIVE,
-+};
-+
- /**
-  * Data structure storing all of the basic features
-  * of a domain.
-@@ -277,7 +294,7 @@ struct sss_domain_info {
-     struct sss_domain_info *prev;
-     struct sss_domain_info *next;
- 
--    bool disabled;
-+    enum sss_domain_state state;
-     char **sd_inherit;
- 
-     /* Do not use the forest pointer directly in new code, but rather the
-diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
-index 142520c1836d74ef7bc5c5269487b8971f261b88..546dc1c8d7e5e30ce9e0b56b097894d24d8c94a7 100644
---- a/src/db/sysdb_subdomains.c
-+++ b/src/db/sysdb_subdomains.c
-@@ -111,6 +111,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
-     dom->enumerate = enumerate;
-     dom->fqnames = true;
-     dom->mpg = mpg;
-+    dom->state = DOM_ACTIVE;
-+
-     /* If the parent domain filters out group members, the subdomain should
-      * as well if configured */
-     inherit_option = string_in_list(CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS,
-@@ -268,7 +270,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
-     /* disable all domains,
-      * let the search result refresh any that are still valid */
-     for (dom = domain->subdomains; dom; dom = get_next_domain(dom, false)) {
--        dom->disabled = true;
-+        sss_domain_set_state(dom, DOM_DISABLED);
-     }
- 
-     if (res->count == 0) {
-@@ -312,7 +314,8 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
-         /* explicitly use dom->next as we need to check 'disabled' domains */
-         for (dom = domain->subdomains; dom; dom = dom->next) {
-             if (strcasecmp(dom->name, name) == 0) {
--                dom->disabled = false;
-+                sss_domain_set_state(dom, DOM_ACTIVE);
-+
-                 /* in theory these may change, but it should never happen */
-                 if (strcasecmp(dom->realm, realm) != 0) {
-                     DEBUG(SSSDBG_TRACE_INTERNAL,
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 9b42f03a0067ab5844432a0f19dd2930dcc200c9..d1d468043410c80e6bf7f0f48a13bd9e962552af 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -376,7 +376,7 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
- 
-         if (c >= count) {
-             /* ok this subdomain does not exist anymore, let's clean up */
--            dom->disabled = true;
-+            sss_domain_set_state(dom, DOM_DISABLED);
-             ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
-             if (ret != EOK) {
-                 goto done;
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index b2e2fec353f7b168d28a880cb0f1b6181abb1ccb..089736b47d8f384a8024682dd203d324292df9ce 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -528,7 +528,7 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
- 
-         if (c >= count) {
-             /* ok this subdomain does not exist anymore, let's clean up */
--            dom->disabled = true;
-+            sss_domain_set_state(dom, DOM_DISABLED);
-             ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
-             if (ret != EOK) {
-                 goto done;
-diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
-index 36e7f15948632e9c637886dee259b494e46ceecb..2097004cb0fc24d8b356f9d924243f948227ef58 100644
---- a/src/responder/common/responder_common.c
-+++ b/src/responder/common/responder_common.c
-@@ -923,7 +923,7 @@ responder_get_domain(struct resp_ctx *rctx, const char *name)
-     struct sss_domain_info *ret_dom = NULL;
- 
-     for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
--        if (dom->disabled) {
-+        if (sss_domain_get_state(dom) == DOM_DISABLED) {
-             continue;
-         }
- 
-@@ -958,7 +958,8 @@ errno_t responder_get_domain_by_id(struct resp_ctx *rctx, const char *id,
-     id_len = strlen(id);
- 
-     for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
--        if (dom->disabled || dom->domain_id == NULL) {
-+        if (sss_domain_get_state(dom) == DOM_DISABLED ||
-+                dom->domain_id == NULL) {
-             continue;
-         }
- 
-diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
-index 82e77815ec848afcdedc90e35e440f7532b5c0b2..8d1a26a5918eaa9dec975c360f69840400e4bd2c 100644
---- a/src/tests/cmocka/test_sysdb_subdomains.c
-+++ b/src/tests/cmocka/test_sysdb_subdomains.c
-@@ -151,7 +151,11 @@ static void test_sysdb_subdomain_create(void **state)
-     ret = sysdb_update_subdomains(test_ctx->tctx->dom);
-     assert_int_equal(ret, EOK);
- 
--    assert_true(test_ctx->tctx->dom->subdomains->disabled);
-+    assert_int_equal(sss_domain_get_state(test_ctx->tctx->dom->subdomains),
-+                     DOM_DISABLED);
-+    assert_int_equal(
-+            sss_domain_get_state(test_ctx->tctx->dom->subdomains->next),
-+            DOM_DISABLED);
- }
- 
- static void test_sysdb_master_domain_ops(void **state)
-diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
-index c7ebe0997ec00197e8852bedbcf26ef1f6394fc3..0f72434ca77fbfe1bd88a75fd932719dbfc59444 100644
---- a/src/tests/cmocka/test_utils.c
-+++ b/src/tests/cmocka/test_utils.c
-@@ -259,7 +259,7 @@ void test_find_domain_by_name_disabled(void **state)
-         dom = dom->next;
-     }
-     assert_non_null(dom);
--    dom->disabled = true;
-+    sss_domain_set_state(dom, DOM_DISABLED);
- 
-     for (c = 0; c < test_ctx->dom_count; c++) {
-         name = talloc_asprintf(global_talloc_context, DOMNAME_TMPL, c);
-@@ -426,7 +426,7 @@ void test_find_domain_by_sid_disabled(void **state)
-         dom = dom->next;
-     }
-     assert_non_null(dom);
--    dom->disabled = true;
-+    sss_domain_set_state(dom, DOM_DISABLED);
- 
-     for (c = 0; c < test_ctx->dom_count; c++) {
-         name = talloc_asprintf(global_talloc_context, DOMNAME_TMPL, c);
-@@ -578,7 +578,7 @@ static void test_get_next_domain_disabled(void **state)
-     struct sss_domain_info *dom = NULL;
- 
-     for (dom = test_ctx->dom_list; dom; dom = get_next_domain(dom, true)) {
--        dom->disabled = true;
-+        sss_domain_set_state(dom, DOM_DISABLED);
-     }
- 
-     dom = get_next_domain(test_ctx->dom_list, true);
-diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
-index 4eabcff7a0e0af342ec3833d24da26ede0cb5148..ffbb9475b27a45c07e2e0936464c6e68ed682052 100644
---- a/src/util/domain_info_utils.c
-+++ b/src/util/domain_info_utils.c
-@@ -50,7 +50,10 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
-         } else {
-             dom = NULL;
-         }
--        if (dom && !dom->disabled) break;
-+
-+        if (dom && sss_domain_get_state(dom) != DOM_DISABLED) {
-+            break;
-+        }
-     }
- 
-     return dom;
-@@ -91,7 +94,7 @@ struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
-         return NULL;
-     }
- 
--    while (dom && dom->disabled) {
-+    while (dom && sss_domain_get_state(dom) == DOM_DISABLED) {
-         dom = get_next_domain(dom, true);
-     }
-     while (dom) {
-@@ -119,7 +122,7 @@ struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
- 
-     sid_len = strlen(sid);
- 
--    while (dom && dom->disabled) {
-+    while (dom && sss_domain_get_state(dom) == DOM_DISABLED) {
-         dom = get_next_domain(dom, true);
-     }
- 
-@@ -730,3 +733,14 @@ done:
- 
-     return ret;
- }
-+
-+enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom)
-+{
-+    return dom->state;
-+}
-+
-+void sss_domain_set_state(struct sss_domain_info *dom,
-+                          enum sss_domain_state state)
-+{
-+    dom->state = state;
-+}
-diff --git a/src/util/util.h b/src/util/util.h
-index c998e91f92b0a86e0f4308ff0c07ff802588b5cf..4655e90a89b0ff3c457b80c943aefc4d6cf8e21f 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -565,6 +565,9 @@ struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
-                                             bool match_any);
- struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
-                                            const char *sid);
-+enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom);
-+void sss_domain_set_state(struct sss_domain_info *dom,
-+                          enum sss_domain_state state);
- 
- struct sss_domain_info*
- sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 735f6dcfc7af33edcc886fd106cb3655bcc9566a..0e288e3908bf03b4906bb449bd0f3445d22a303e 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -79,6 +79,7 @@ struct err_string error_to_str[] = {
-     { "Retrieving keytab failed" }, /* ERR_IPA_GETKEYTAB_FAILED */
-     { "Trusted forest root unknown" }, /* ERR_TRUST_FOREST_UNKNOWN */
-     { "p11_child failed" }, /* ERR_P11_CHILD */
-+    { "Subdomain is inactive" }, /* ERR_SUBDOM_INACTIVE */
-     { "ERR_LAST" } /* ERR_LAST */
- };
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index fbfbdef334be1fb8a525b78ab6336d616b31a189..da926db00121f569048ec515e95f0547ae6c4e35 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -101,6 +101,7 @@ enum sssd_errors {
-     ERR_IPA_GETKEYTAB_FAILED,
-     ERR_TRUST_FOREST_UNKNOWN,
-     ERR_P11_CHILD,
-+    ERR_SUBDOM_INACTIVE,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0075-DP-Provide-a-way-to-mark-subdomain-as-disabled-and-a.patch b/SOURCES/0075-DP-Provide-a-way-to-mark-subdomain-as-disabled-and-a.patch
deleted file mode 100644
index 32ad0fd..0000000
--- a/SOURCES/0075-DP-Provide-a-way-to-mark-subdomain-as-disabled-and-a.patch
+++ /dev/null
@@ -1,499 +0,0 @@
-From 6c1e606c3e9da9910554e48a6409a9b3001deedb Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 4 Sep 2015 09:27:17 +0200
-Subject: [PATCH 75/87] DP: Provide a way to mark subdomain as disabled and
- auto-enable it later with offline_timeout
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2637
-
-Adds a new Data Provider function be_mark_dom_offline() that is a
-replacement for be_mark_offline(). When called, the function would
-either set the whole back end offline, just like be_mark_offline or just
-set the subdomain status to inactive.
-
-When a subdomain is inactive, there is a singleton timed task that would
-re-set the subdomin after offline_timeout seconds.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- Makefile.am                              |  26 +++
- src/providers/data_provider_be.c         | 102 +++++++++++-
- src/providers/dp_backend.h               |   1 +
- src/tests/cmocka/test_data_provider_be.c | 275 +++++++++++++++++++++++++++++++
- 4 files changed, 395 insertions(+), 9 deletions(-)
- create mode 100644 src/tests/cmocka/test_data_provider_be.c
-
-diff --git a/Makefile.am b/Makefile.am
-index e1102333b019e32c516c59c5fa969c970b688737..4e80701872c0e4e1391f0c6de8a2f68e719f8236 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -236,6 +236,7 @@ if HAVE_CMOCKA
-         test_ipa_subdom_server \
-         test_krb5_wait_queue \
-         test_cert_utils \
-+        test_data_provider_be \
-         $(NULL)
- 
- if HAVE_LIBRESOLV
-@@ -2603,6 +2604,31 @@ test_cert_utils_LDADD = \
-     libsss_cert.la \
-     libsss_crypt.la \
-     $(NULL)
-+
-+test_data_provider_be_SOURCES = \
-+    $(sssd_be_SOURCES) \
-+    src/tests/cmocka/test_data_provider_be.c \
-+    src/tests/cmocka/common_mock_be.c \
-+    $(NULL)
-+test_data_provider_be_CFLAGS = \
-+    $(AM_CFLAGS) \
-+    -DUNIT_TESTING \
-+    $(CRYPTO_CFLAGS) \
-+    $(NULL)
-+test_data_provider_be_LDFLAGS = \
-+    -Wl,-wrap,_tevent_add_timer \
-+    $(NULL)
-+test_data_provider_be_LDADD = \
-+    $(CMOCKA_LIBS) \
-+    $(CARES_LIBS) \
-+    $(POPT_LIBS) \
-+    $(PAM_LIBS) \
-+    $(TALLOC_LIBS) \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    libsss_debug.la \
-+    libsss_test_common.la \
-+    $(NULL)
-+
- endif # HAVE_CMOCKA
- 
- noinst_PROGRAMS = pam_test_client
-diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
-index d147630248f0a24f5a632760b55b9284a6928e40..f477ac8bde2b1e3eea862e8e8f503566282ea8f3 100644
---- a/src/providers/data_provider_be.c
-+++ b/src/providers/data_provider_be.c
-@@ -478,6 +478,24 @@ try_to_go_online(TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
-+static int get_offline_timeout(struct be_ctx *ctx)
-+{
-+    errno_t ret;
-+    int offline_timeout;
-+
-+    ret = confdb_get_int(ctx->cdb, ctx->conf_path,
-+                         CONFDB_DOMAIN_OFFLINE_TIMEOUT, 60,
-+                         &offline_timeout);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to get offline_timeout from confdb. "
-+              "Will use 60 seconds.\n");
-+        offline_timeout = 60;
-+    }
-+
-+    return offline_timeout;
-+}
-+
- void be_mark_offline(struct be_ctx *ctx)
- {
-     int offline_timeout;
-@@ -493,15 +511,9 @@ void be_mark_offline(struct be_ctx *ctx)
-         /* This is the first time we go offline - create a periodic task
-          * to check if we can switch to online. */
-         DEBUG(SSSDBG_TRACE_INTERNAL, "Initialize check_if_online_ptask.\n");
--        ret = confdb_get_int(ctx->cdb, ctx->conf_path,
--                             CONFDB_DOMAIN_OFFLINE_TIMEOUT, 60,
--                             &offline_timeout);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Failed to get offline_timeout from confdb. "
--                  "Will use 60 seconds.\n");
--            offline_timeout = 60;
--        }
-+
-+        offline_timeout = get_offline_timeout(ctx);
-+
-         ret = be_ptask_create_sync(ctx, ctx,
-                                    offline_timeout, offline_timeout,
-                                    offline_timeout, 30, offline_timeout,
-@@ -524,10 +536,82 @@ void be_mark_offline(struct be_ctx *ctx)
-     be_run_offline_cb(ctx);
- }
- 
-+static void be_subdom_reset_status(struct tevent_context *ev,
-+                                  struct tevent_timer *te,
-+                                  struct timeval current_time,
-+                                  void *pvt)
-+{
-+    struct sss_domain_info *subdom = talloc_get_type(pvt,
-+                                                     struct sss_domain_info);
-+
-+    DEBUG(SSSDBG_TRACE_LIBS, "Resetting subdomain %s\n", subdom->name);
-+    subdom->state = DOM_ACTIVE;
-+}
-+
-+static void be_mark_subdom_offline(struct sss_domain_info *subdom,
-+                                   struct be_ctx *be_ctx)
-+{
-+    struct timeval tv;
-+    struct tevent_timer *timeout = NULL;
-+    int reset_status_timeout;
-+
-+    reset_status_timeout = get_offline_timeout(be_ctx);
-+    tv = tevent_timeval_current_ofs(reset_status_timeout, 0);
-+
-+    switch (subdom->state) {
-+    case DOM_DISABLED:
-+        DEBUG(SSSDBG_MINOR_FAILURE, "Won't touch disabled subdomain\n");
-+        return;
-+    case DOM_INACTIVE:
-+        DEBUG(SSSDBG_TRACE_ALL, "Subdomain already inactive\n");
-+        return;
-+    case DOM_ACTIVE:
-+        DEBUG(SSSDBG_TRACE_LIBS,
-+              "Marking subdomain %s as inactive\n", subdom->name);
-+        break;
-+    }
-+
-+    timeout = tevent_add_timer(be_ctx->ev, be_ctx, tv,
-+                               be_subdom_reset_status, subdom);
-+    if (timeout == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Cannot create timer\n");
-+        return;
-+    }
-+
-+    subdom->state = DOM_INACTIVE;
-+}
-+
-+void be_mark_dom_offline(struct sss_domain_info *dom, struct be_ctx *ctx)
-+{
-+    if (IS_SUBDOMAIN(dom) == false) {
-+        DEBUG(SSSDBG_TRACE_LIBS, "Marking back end offline\n");
-+        be_mark_offline(ctx);
-+    } else {
-+        DEBUG(SSSDBG_TRACE_LIBS, "Marking subdomain %s offline\n", dom->name);
-+        be_mark_subdom_offline(dom, ctx);
-+    }
-+}
-+
-+static void reactivate_subdoms(struct sss_domain_info *head)
-+{
-+    struct sss_domain_info *dom;
-+
-+    DEBUG(SSSDBG_TRACE_LIBS, "Resetting all subdomains");
-+
-+    for (dom = head; dom; dom = get_next_domain(dom, true)) {
-+        if (sss_domain_get_state(dom) == DOM_INACTIVE) {
-+            sss_domain_set_state(dom, DOM_ACTIVE);
-+        }
-+    }
-+}
-+
- static void be_reset_offline(struct be_ctx *ctx)
- {
-     ctx->offstat.went_offline = 0;
-     ctx->offstat.offline = false;
-+
-+    reactivate_subdoms(ctx->domain);
-+
-     be_ptask_disable(ctx->check_if_online_ptask);
-     be_run_online_cb(ctx);
- }
-diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
-index e4e22ea343a5cbf4c75f176c3002dc579c2893fe..4d54bf547682379bcb8cf855b8fae39214495728 100644
---- a/src/providers/dp_backend.h
-+++ b/src/providers/dp_backend.h
-@@ -189,6 +189,7 @@ struct be_host_req {
- 
- bool be_is_offline(struct be_ctx *ctx);
- void be_mark_offline(struct be_ctx *ctx);
-+void be_mark_dom_offline(struct sss_domain_info *dom, struct be_ctx *ctx);
- 
- int be_add_reconnect_cb(TALLOC_CTX *mem_ctx,
-                         struct be_ctx *ctx,
-diff --git a/src/tests/cmocka/test_data_provider_be.c b/src/tests/cmocka/test_data_provider_be.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..68eb5841bee568bef64cb62461403036b1320bec
---- /dev/null
-+++ b/src/tests/cmocka/test_data_provider_be.c
-@@ -0,0 +1,275 @@
-+/*
-+    Copyright (C) 2015 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 <talloc.h>
-+#include <tevent.h>
-+#include <errno.h>
-+#include <popt.h>
-+#include <time.h>
-+
-+#include "providers/dp_backend.h"
-+#include "tests/cmocka/common_mock.h"
-+#include "tests/cmocka/common_mock_be.h"
-+#include "tests/common.h"
-+
-+#define TESTS_PATH "tests_dp_be"
-+#define TEST_CONF_DB "test_dp_be_conf.ldb"
-+#define TEST_DOM_NAME "dp_be_test"
-+#define TEST_ID_PROVIDER "ldap"
-+
-+#define OFFLINE_TIMEOUT 2
-+#define AS_STR(param) (#param)
-+
-+static TALLOC_CTX *global_mock_context = NULL;
-+static bool global_timer_added;
-+
-+struct tevent_timer *__real__tevent_add_timer(struct tevent_context *ev,
-+                                              TALLOC_CTX *mem_ctx,
-+                                              struct timeval next_event,
-+                                              tevent_timer_handler_t handler,
-+                                              void *private_data,
-+                                              const char *handler_name,
-+                                              const char *location);
-+
-+struct tevent_timer *__wrap__tevent_add_timer(struct tevent_context *ev,
-+                                              TALLOC_CTX *mem_ctx,
-+                                              struct timeval next_event,
-+                                              tevent_timer_handler_t handler,
-+                                              void *private_data,
-+                                              const char *handler_name,
-+                                              const char *location)
-+{
-+    global_timer_added = true;
-+
-+    return __real__tevent_add_timer(ev, mem_ctx, next_event,
-+                                    handler, private_data, handler_name,
-+                                    location);
-+}
-+
-+
-+struct test_ctx {
-+    struct sss_test_ctx *tctx;
-+    struct be_ctx *be_ctx;
-+};
-+
-+static struct sss_domain_info *named_domain(TALLOC_CTX *mem_ctx,
-+                                            const char *name,
-+                                            struct sss_domain_info *parent)
-+{
-+    struct sss_domain_info *dom = NULL;
-+
-+    dom = talloc_zero(mem_ctx, struct sss_domain_info);
-+    assert_non_null(dom);
-+
-+    dom->name = talloc_strdup(dom, name);
-+    assert_non_null(dom->name);
-+
-+    dom->parent = parent;
-+
-+    return dom;
-+}
-+
-+static int test_setup(void **state)
-+{
-+    struct test_ctx *test_ctx = NULL;
-+    struct sss_test_conf_param params[] = {
-+        { "offline_timeout", AS_STR(OFFLINE_TIMEOUT) },
-+        { NULL, NULL },             /* Sentinel */
-+    };
-+
-+    assert_true(leak_check_setup());
-+    global_mock_context = talloc_new(global_talloc_context);
-+    assert_non_null(global_mock_context);
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct test_ctx);
-+    assert_non_null(test_ctx);
-+
-+    test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH,
-+                                         TEST_CONF_DB, TEST_DOM_NAME,
-+                                         TEST_ID_PROVIDER, params);
-+    assert_non_null(test_ctx->tctx);
-+
-+    test_ctx->be_ctx = mock_be_ctx(test_ctx, test_ctx->tctx);
-+    assert_non_null(test_ctx->be_ctx);
-+
-+    test_ctx->be_ctx->domain->subdomains = named_domain(test_ctx,
-+                                                        "subdomains",
-+                                                        test_ctx->be_ctx->domain);
-+    assert_non_null(test_ctx->be_ctx->domain->subdomains);
-+
-+    *state = test_ctx;
-+
-+    return 0;
-+}
-+
-+static int test_teardown(void **state)
-+{
-+    talloc_zfree(*state);
-+    assert_true(leak_check_teardown());
-+    return 0;
-+}
-+
-+static void assert_domain_state(struct sss_domain_info *dom,
-+                                enum sss_domain_state expected_state)
-+{
-+    enum sss_domain_state dom_state;
-+
-+    dom_state = sss_domain_get_state(dom);
-+    assert_int_equal(dom_state, expected_state);
-+}
-+
-+static void test_mark_subdom_offline_check(struct tevent_context *ev,
-+                                           struct tevent_timer *te,
-+                                           struct timeval current_time,
-+                                           void *pvt)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type(pvt, struct test_ctx);
-+
-+    assert_domain_state(test_ctx->be_ctx->domain->subdomains,
-+                        DOM_ACTIVE);
-+
-+    test_ctx->tctx->done = true;
-+    test_ctx->tctx->error = EOK;
-+}
-+
-+static void test_mark_dom_offline(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
-+
-+    assert_domain_state(test_ctx->be_ctx->domain, DOM_ACTIVE);
-+    assert_false(be_is_offline(test_ctx->be_ctx));
-+
-+    be_mark_dom_offline(test_ctx->be_ctx->domain, test_ctx->be_ctx);
-+
-+    assert_true(be_is_offline(test_ctx->be_ctx));
-+    assert_domain_state(test_ctx->be_ctx->domain, DOM_ACTIVE);
-+}
-+
-+static void test_mark_subdom_offline(void **state)
-+{
-+    struct timeval tv;
-+    struct tevent_timer *check_ev = NULL;
-+    struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
-+    errno_t ret;
-+
-+    assert_domain_state(test_ctx->be_ctx->domain->subdomains,
-+                        DOM_ACTIVE);
-+    assert_false(be_is_offline(test_ctx->be_ctx));
-+
-+    global_timer_added = false;
-+    be_mark_dom_offline(test_ctx->be_ctx->domain->subdomains, test_ctx->be_ctx);
-+    assert_domain_state(test_ctx->be_ctx->domain->subdomains,
-+                        DOM_INACTIVE);
-+
-+    /* A timer must be added that resets the state back */
-+    assert_true(global_timer_added);
-+
-+    /* Global offline state must not change */
-+    assert_false(be_is_offline(test_ctx->be_ctx));
-+
-+    /* Make sure we don't add a second timer */
-+    global_timer_added = false;
-+    be_mark_dom_offline(test_ctx->be_ctx->domain->subdomains, test_ctx->be_ctx);
-+    assert_domain_state(test_ctx->be_ctx->domain->subdomains,
-+                        DOM_INACTIVE);
-+    assert_false(global_timer_added);
-+
-+    /* Wait for the internal timer to reset our subdomain back */
-+    tv = tevent_timeval_current_ofs(OFFLINE_TIMEOUT + 1, 0);
-+
-+    check_ev = tevent_add_timer(test_ctx->tctx->ev, test_ctx, tv,
-+                                test_mark_subdom_offline_check,
-+                                test_ctx);
-+    if (check_ev == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Cannot create timer\n");
-+        return;
-+    }
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+static void test_mark_subdom_offline_disabled(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
-+
-+    sss_domain_set_state(test_ctx->be_ctx->domain->subdomains, DOM_DISABLED);
-+    assert_domain_state(test_ctx->be_ctx->domain->subdomains,
-+                        DOM_DISABLED);
-+
-+    be_mark_dom_offline(test_ctx->be_ctx->domain->subdomains, test_ctx->be_ctx);
-+    assert_domain_state(test_ctx->be_ctx->domain->subdomains,
-+                        DOM_DISABLED);
-+}
-+
-+int main(int argc, const char *argv[])
-+{
-+    poptContext pc;
-+    int opt;
-+    int rv;
-+    int no_cleanup = 0;
-+    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 struct CMUnitTest tests[] = {
-+        cmocka_unit_test_setup_teardown(test_mark_dom_offline,
-+                                        test_setup,
-+                                        test_teardown),
-+        cmocka_unit_test_setup_teardown(test_mark_subdom_offline,
-+                                        test_setup,
-+                                        test_teardown),
-+        cmocka_unit_test_setup_teardown(test_mark_subdom_offline_disabled,
-+                                        test_setup,
-+                                        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);
-+
-+    /* 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_DOM_NAME);
-+    test_dom_suite_setup(TESTS_PATH);
-+
-+    rv = cmocka_run_group_tests(tests, NULL, NULL);
-+    if (rv == 0 && !no_cleanup) {
-+        test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
-+    }
-+    return rv;
-+
-+    return cmocka_run_group_tests(tests, NULL, NULL);
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch b/SOURCES/0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch
new file mode 100644
index 0000000..8adb0ca
--- /dev/null
+++ b/SOURCES/0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch
@@ -0,0 +1,60 @@
+From 86f099e6ca0e09dd5fe44816238a4323c63f9ee7 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 3 Aug 2016 17:43:14 +0200
+Subject: [PATCH 75/82] PAM: Do not act on ldb_message in case of a failure
+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/pam/pamsrv_cmd.c | 33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 66564f5d301a53dcdb5967f43ef4afdb897e9974..be54fbf9b627d0ec1c3b0416401885245794cf9f 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -1534,21 +1534,24 @@ static int pam_check_user_search(struct pam_auth_req *preq)
+ 
+         if (preq->pd->name_is_upn) {
+             ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg);
+-
+-            /* Since sysdb_search_user_by_upn() searches the whole cache we
+-             * have to set the domain so that it matches the result. */
+-            sysdb_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+-            if (sysdb_name == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Cached entry has no name.\n");
+-                return EINVAL;
+-            }
+-            preq->domain = find_domain_by_object_name(get_domains_head(dom),
+-                                                      sysdb_name);
+-            if (preq->domain == NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Cannot find matching domain for [%s].\n",
+-                      sysdb_name);
+-                return EINVAL;
++            if (ret == EOK) {
++                /* Since sysdb_search_user_by_upn() searches the whole cache we
++                * have to set the domain so that it matches the result. */
++                sysdb_name = ldb_msg_find_attr_as_string(msg,
++                                                         SYSDB_NAME, NULL);
++                if (sysdb_name == NULL) {
++                    DEBUG(SSSDBG_CRIT_FAILURE, "Cached entry has no name.\n");
++                    return EINVAL;
++                }
++                preq->domain = find_domain_by_object_name(
++                                                        get_domains_head(dom),
++                                                        sysdb_name);
++                if (preq->domain == NULL) {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Cannot find matching domain for [%s].\n",
++                          sysdb_name);
++                    return EINVAL;
++                }
+             }
+         } else {
+             ret = sysdb_getpwnam_with_views(preq, dom, name, &res);
+-- 
+2.4.11
+
diff --git a/SOURCES/0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch b/SOURCES/0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch
new file mode 100644
index 0000000..1dfbf21
--- /dev/null
+++ b/SOURCES/0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch
@@ -0,0 +1,38 @@
+From 2e027e43f0adb1b7c80e51d5613fca5a497ca331 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 3 Aug 2016 18:03:59 +0200
+Subject: [PATCH 76/82] IPA: Check the return value of
+ sss_parse_internal_fqname
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We should fail the request if sss_parse_internal_fqname() fails.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains_id.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
+index 002857699b65c86a6ed0c912a2a7ae06a8f9e507..2299523d0c52e3277db6d1061c79b320e78c8f72 100644
+--- a/src/providers/ipa/ipa_subdomains_id.c
++++ b/src/providers/ipa/ipa_subdomains_id.c
+@@ -509,6 +509,14 @@ static void ipa_get_subdom_acct_connected(struct tevent_req *subreq)
+             } else {
+                 ret = sss_parse_internal_fqname(req_input, state->filter,
+                                                 &shortname, NULL);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Cannot parse internal name [%s]: %d\n",
++                          state->filter, ret);
++                    tevent_req_error(req, ret);
++                    return;
++                }
++
+                 req_input->inp.name = talloc_steal(req_input, shortname);
+             }
+             if (req_input->inp.name == NULL) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0076-SDAP-Do-not-set-is_offline-if-ignore_mark_offline-is.patch b/SOURCES/0076-SDAP-Do-not-set-is_offline-if-ignore_mark_offline-is.patch
deleted file mode 100644
index 58bc0b3..0000000
--- a/SOURCES/0076-SDAP-Do-not-set-is_offline-if-ignore_mark_offline-is.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From d170e144a1ae702ba55c508599ffbda4e95919e5 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Sep 2015 13:40:48 +0200
-Subject: [PATCH 76/87] SDAP: Do not set is_offline if ignore_mark_offline is
- set
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Required for:
-https://fedorahosted.org/sssd/ticket/2637
-
-The caller of the sdap_id_op requests can set the ignore_mark_offline
-flag to avoid the sdap_id_op from marking the whole back end as offline.
-
-However, there was a small bug - the is_offline internal sdap_id_op flag
-was still being set. As a consequence, the error code from the
-connection was ignored and EAGAIN was always returned.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 0561d532cf76b035b73cfed929a6896071dac407)
----
- src/providers/ldap/sdap_id_op.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c
-index 508bbd2ad3ebb3f9159a8b7f48258ff31a7cd6e2..0474a9cb7828ef43ef76cf6bebac077315296875 100644
---- a/src/providers/ldap/sdap_id_op.c
-+++ b/src/providers/ldap/sdap_id_op.c
-@@ -567,9 +567,9 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq)
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Failed to connect, going offline (%d [%s])\n",
-                    ret, strerror(ret));
-+            is_offline = true;
-             be_mark_offline(conn_cache->id_conn->id_ctx->be);
-         }
--        is_offline = true;
-     }
- 
-     if (ret == EOK) {
--- 
-2.4.3
-
diff --git a/SOURCES/0077-AD-Only-ignore-errors-from-SDAP-lookups-if-there-s-a.patch b/SOURCES/0077-AD-Only-ignore-errors-from-SDAP-lookups-if-there-s-a.patch
deleted file mode 100644
index 2cf3e51..0000000
--- a/SOURCES/0077-AD-Only-ignore-errors-from-SDAP-lookups-if-there-s-a.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 4b9db04661f30625fb00bb22dc7ff84e77d2efb2 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Sep 2015 13:42:06 +0200
-Subject: [PATCH 77/87] AD: Only ignore errors from SDAP lookups if there's
- another connection to fallback to
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Required for:
-https://fedorahosted.org/sssd/ticket/2637
-
-The AD lookup code honors the ignore_mark_offline flag in the sense that
-if it's set, the sdap return code is not reported to the upper layer,
-but EOK is returned as request status and the sdap return code is
-returned separately.
-
-This patch modifies the behaviour further to only apply if there is
-another connection to fall back to.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 7fc8692d49cdaa0368072f196433c07b475da679)
----
- 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 7a0c6eccd2d2f0d4f8a545a9d4873a9447179a00..4f327f823173eb113153a556322dae4cc4b42f3e 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -146,6 +146,7 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
- 
-     ret = sdap_handle_acct_req_recv(subreq, &dp_error, &err, &sdap_err);
-     if (dp_error == DP_ERR_OFFLINE
-+        && state->conn[state->cindex+1] != NULL
-         && state->conn[state->cindex]->ignore_mark_offline) {
-          /* This is a special case: GC does not work.
-           *  We need to Fall back to ldap
--- 
-2.4.3
-
diff --git a/SOURCES/0077-DP-Initialize-D-Bus-as-soon-as-possible.patch b/SOURCES/0077-DP-Initialize-D-Bus-as-soon-as-possible.patch
new file mode 100644
index 0000000..9641722
--- /dev/null
+++ b/SOURCES/0077-DP-Initialize-D-Bus-as-soon-as-possible.patch
@@ -0,0 +1,93 @@
+From 178e61b6dc5b547bd77998f586f118bfa9b06d30 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Fri, 5 Aug 2016 11:32:43 +0200
+Subject: [PATCH 77/82] DP: Initialize D-Bus as soon as possible
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3111
+
+Reviewed-by: Petr Cech <pcech@redhat.com>
+---
+ src/providers/data_provider/dp.c         | 34 +++++++++++++++++++-------------
+ src/providers/data_provider/dp_methods.c |  6 ++++++
+ 2 files changed, 26 insertions(+), 14 deletions(-)
+
+diff --git a/src/providers/data_provider/dp.c b/src/providers/data_provider/dp.c
+index c4590e3152126fe166d0bc9e3be2a14978f90168..b672370aa153c9cd2031399a8d61c95fb16cd641 100644
+--- a/src/providers/data_provider/dp.c
++++ b/src/providers/data_provider/dp.c
+@@ -86,6 +86,7 @@ errno_t dp_init(struct tevent_context *ev,
+     provider->gid = gid;
+     provider->be_ctx = be_ctx;
+ 
++    /* Initialize request table. */
+     ret = dp_req_table_init(provider, &provider->requests.reply_table);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize request table "
+@@ -93,20 +94,11 @@ errno_t dp_init(struct tevent_context *ev,
+         goto done;
+     }
+ 
+-    ret = dp_init_modules(provider, &provider->modules);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP modules "
+-              "[%d]: %s\n", ret, sss_strerror(ret));
+-        goto done;
+-    }
+-
+-    ret = dp_init_targets(provider, be_ctx, provider, provider->modules);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP targets "
+-              "[%d]: %s\n", ret, sss_strerror(ret));
+-        goto done;
+-    }
+-
++    /* Initialize data provider bus. Data provider can receive client
++     * registration and other D-Bus methods. However no data provider
++     * request will be executed as long as the modules and targets
++     * are not initialized.
++     */
+     talloc_set_destructor(provider, dp_destructor);
+ 
+     ret = dp_init_dbus_server(provider);
+@@ -118,6 +110,20 @@ errno_t dp_init(struct tevent_context *ev,
+ 
+     be_ctx->provider = provider;
+ 
++    ret = dp_init_modules(provider, &provider->modules);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP modules "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        goto done;
++    }
++
++    ret = dp_init_targets(provider, be_ctx, provider, provider->modules);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP targets "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        goto done;
++    }
++
+     ret = EOK;
+ 
+ done:
+diff --git a/src/providers/data_provider/dp_methods.c b/src/providers/data_provider/dp_methods.c
+index e4290beeeef3c0c4d156271ad88f891d3245af08..498676d1bec2da300ca4b33f7110debcbf0aac00 100644
+--- a/src/providers/data_provider/dp_methods.c
++++ b/src/providers/data_provider/dp_methods.c
+@@ -76,6 +76,12 @@ bool dp_method_enabled(struct data_provider *provider,
+         return false;
+     }
+ 
++    if (provider == NULL || provider->targets == NULL) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Target %s is not yet initialized\n",
++              dp_target_to_string(target));
++        return false;
++    }
++
+     dp_target = provider->targets[target];
+     if (dp_target == NULL || dp_target->initialized == false) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Target %s is not configured\n",
+-- 
+2.4.11
+
diff --git a/SOURCES/0078-KRB5-Offline-operation-with-disabled-domain.patch b/SOURCES/0078-KRB5-Offline-operation-with-disabled-domain.patch
deleted file mode 100644
index 690f4ac..0000000
--- a/SOURCES/0078-KRB5-Offline-operation-with-disabled-domain.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From adbeda40c0b39918b12c4f72c97a89156c6360c2 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Sep 2015 15:53:34 +0200
-Subject: [PATCH 78/87] KRB5: Offline operation with disabled domain
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2637
-
-If a subdomain is in the disabled state, switch krb5_child operation
-into offline mode.
-
-Similarly, instead of marking the whole back end as offline, mark just
-the domain as offline -- depending on the domain type, this would mark
-the whole back end or just inactivate subdomain.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit dd0a21738e1b71940bba11134734b5999e9fd8e9)
----
- src/providers/krb5/krb5_auth.c | 12 +++++++++++-
- 1 file changed, 11 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
-index da8309d0504a6815902513693343a3500f454557..7ee7fa738db32abeb4709927956d1297325e2d5b 100644
---- a/src/providers/krb5/krb5_auth.c
-+++ b/src/providers/krb5/krb5_auth.c
-@@ -720,7 +720,7 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
-              * was found good, setting offline,
-              * but we still have to call the child to setup
-              * the ccache file if we are performing auth */
--            be_mark_offline(state->be_ctx);
-+            be_mark_dom_offline(state->domain, state->be_ctx);
-             kr->is_offline = true;
- 
-             if (kr->pd->cmd == SSS_PAM_CHAUTHTOK ||
-@@ -754,9 +754,19 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
-         kr->is_offline = be_is_offline(state->be_ctx);
-     }
- 
-+    if (!kr->is_offline
-+            && sss_domain_get_state(state->domain) == DOM_INACTIVE) {
-+        DEBUG(SSSDBG_TRACE_INTERNAL,
-+              "Subdomain %s is inactive, will proceed offline\n",
-+              state->domain->name);
-+        kr->is_offline = true;
-+    }
-+
-     if (kr->is_offline
-             && sss_krb5_realm_has_proxy(dp_opt_get_cstring(kr->krb5_ctx->opts,
-                                         KRB5_REALM))) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "Resetting offline status, KDC proxy is in use\n");
-         kr->is_offline = false;
-     }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch b/SOURCES/0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch
new file mode 100644
index 0000000..bff746f
--- /dev/null
+++ b/SOURCES/0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch
@@ -0,0 +1,58 @@
+From 44b93ae9e80652661da7c1f35aa5aec532e6f04d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Tue, 26 Jul 2016 16:35:55 +0200
+Subject: [PATCH 78/82] sssctl: Generic help for cache-upgrade and config-check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sssctl COMMAND --help should print at least
+generic help, even if the command does not
+accept any command specific options.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3086
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/tools/sssctl/sssctl_config.c | 6 ++++++
+ src/tools/sssctl/sssctl_data.c   | 6 ++++++
+ 2 files changed, 12 insertions(+)
+
+diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c
+index a66d7749c4aee9bd00c0ad2d296292658ffdb9b2..630df3c8ff5368ef253bb9753380e94c8c0a307d 100644
+--- a/src/tools/sssctl/sssctl_config.c
++++ b/src/tools/sssctl/sssctl_config.c
+@@ -47,6 +47,12 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
+     char **strs = NULL;
+     TALLOC_CTX *tmp_ctx = NULL;
+ 
++    ret = sss_tool_popt(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
++        return ret;
++    }
++
+     tmp_ctx = talloc_new(NULL);
+     init_data = sss_ini_initdata_init(tmp_ctx);
+     if (!init_data) {
+diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c
+index a26ddd8d5200319e75282b738791cf270f0d75a8..72823ab254344bba6f7679882a733b6ef2250525 100644
+--- a/src/tools/sssctl/sssctl_data.c
++++ b/src/tools/sssctl/sssctl_data.c
+@@ -266,6 +266,12 @@ errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline,
+     struct sysdb_upgrade_ctx db_up_ctx;
+     errno_t ret;
+ 
++    ret = sss_tool_popt(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
++        return ret;
++    }
++
+     if (sss_deamon_running()) {
+         return ERR_SSSD_RUNNING;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0079-AD-Do-not-mark-the-whole-back-end-as-offline-if-subd.patch b/SOURCES/0079-AD-Do-not-mark-the-whole-back-end-as-offline-if-subd.patch
deleted file mode 100644
index f299514..0000000
--- a/SOURCES/0079-AD-Do-not-mark-the-whole-back-end-as-offline-if-subd.patch
+++ /dev/null
@@ -1,197 +0,0 @@
-From 1055c11f7cafae490221e9203f33ddfa94f47c48 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Sep 2015 15:52:51 +0200
-Subject: [PATCH 79/87] AD: Do not mark the whole back end as offline if
- subdomain lookup fails
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Required for:
-https://fedorahosted.org/sssd/ticket/2637
-
-Rather mark the domain as inactive. It will be marked as active later,
-in the meantime the main domain can continue to work online and
-subdomain requests will be answered from cache.
-
-The lookup request itself just returns a special error code and lets the
-caller handle the error code as appropriate (normally by disabling the
-subdomain temporarily).
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 64d4b1e5fd4a3c99ef8d8fef6ad0db52c5152c1c)
----
- src/providers/ad/ad_id.c | 81 +++++++++++++++++++++++++++++++++++++++---------
- 1 file changed, 67 insertions(+), 14 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 4f327f823173eb113153a556322dae4cc4b42f3e..ecaf6c993bf7ddb7ba565d40ef0ad250114f5536 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -91,17 +91,27 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
-     state->ad_options = ad_options;
-     state->cindex = 0;
- 
-+    if (sss_domain_get_state(sdom->dom) == DOM_INACTIVE) {
-+        ret = ERR_SUBDOM_INACTIVE;
-+        goto immediate;
-+    }
-+
-     ret = ad_handle_acct_info_step(req);
--    if (ret == EOK) {
--        tevent_req_done(req);
--        tevent_req_post(req, be_ctx->ev);
--    } else if (ret != EAGAIN) {
--        tevent_req_error(req, ret);
--        tevent_req_post(req, be_ctx->ev);
-+    if (ret != EAGAIN) {
-+        goto immediate;
-     }
- 
-     /* Lookup in progress */
-     return req;
-+
-+immediate:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+    } else {
-+        tevent_req_done(req);
-+    }
-+    tevent_req_post(req, be_ctx->ev);
-+    return req;
- }
- 
- static errno_t
-@@ -160,8 +170,7 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
-         state->dp_error = dp_error;
-         state->err = err;
- 
--        tevent_req_error(req, ret);
--        return;
-+        goto fail;
-     }
- 
-     if (sdap_err == EOK) {
-@@ -170,8 +179,8 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
-     } else if (sdap_err == ERR_NO_POSIX) {
-         disable_gc(state->ad_options);
-     } else if (sdap_err != ENOENT) {
--        tevent_req_error(req, EIO);
--        return;
-+        ret = EIO;
-+        goto fail;
-     }
- 
-     /* Ret is only ENOENT or ERR_NO_POSIX now. Try the next connection */
-@@ -188,12 +197,27 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
-             /* No more connections */
-             tevent_req_done(req);
-         } else {
--            tevent_req_error(req, ret);
-+            goto fail;
-         }
-         return;
-     }
- 
-     /* Another lookup in progress */
-+    return;
-+
-+fail:
-+    if (IS_SUBDOMAIN(state->sdom->dom)) {
-+        /* Deactivate subdomain on lookup errors instead of going
-+         * offline completely.
-+         * This is a stopgap, until our failover is per-domain,
-+         * not per-backend. Unfortunately, we can't rewrite the error
-+         * code on some reported codes only, because sdap_id_op code
-+         * encapsulated the failover as well..
-+         */
-+        ret = ERR_SUBDOM_INACTIVE;
-+    }
-+    tevent_req_error(req, ret);
-+    return;
- }
- 
- errno_t
-@@ -258,6 +282,16 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-         break;
-     }
- 
-+    /* Regardless of connection types, a subdomain error must not be allowed
-+     * to set the whole back end offline, rather report an error and let the
-+     * caller deal with it (normally disable the subdomain
-+     */
-+    if (IS_SUBDOMAIN(dom)) {
-+        for (cindex = 0; clist[cindex] != NULL; cindex++) {
-+            clist[cindex]->ignore_mark_offline = true;
-+        }
-+    }
-+
-     return clist;
- }
- 
-@@ -328,6 +362,11 @@ done:
- 
- static void ad_account_info_complete(struct tevent_req *req);
- 
-+struct ad_account_info_state {
-+    struct be_req *be_req;
-+    struct sss_domain_info *dom;
-+};
-+
- void
- ad_account_info_handler(struct be_req *be_req)
- {
-@@ -341,6 +380,7 @@ ad_account_info_handler(struct be_req *be_req)
-     struct sdap_id_conn_ctx **clist;
-     bool shortcut;
-     errno_t ret;
-+    struct ad_account_info_state *state;
- 
-     ad_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
-                              struct ad_id_ctx);
-@@ -391,13 +431,21 @@ ad_account_info_handler(struct be_req *be_req)
-         goto fail;
-     }
- 
-+    state = talloc(be_req, struct ad_account_info_state);
-+    if (state == NULL) {
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+    state->dom = sdom->dom;
-+    state->be_req = be_req;
-+
-     req = ad_handle_acct_info_send(be_req, be_req, ar, sdap_id_ctx,
-                                    ad_ctx->ad_options, sdom, clist);
-     if (req == NULL) {
-         ret = ENOMEM;
-         goto fail;
-     }
--    tevent_req_set_callback(req, ad_account_info_complete, be_req);
-+    tevent_req_set_callback(req, ad_account_info_complete, state);
-     return;
- 
- fail:
-@@ -412,12 +460,17 @@ ad_account_info_complete(struct tevent_req *req)
-     int dp_error;
-     const char *error_text = "Internal error";
-     const char *req_error_text;
-+    struct ad_account_info_state *state;
- 
--    be_req = tevent_req_callback_data(req, struct be_req);
-+    state = tevent_req_callback_data(req, struct ad_account_info_state);
-+    be_req = state->be_req;
- 
-     ret = ad_handle_acct_info_recv(req, &dp_error, &req_error_text);
-     talloc_zfree(req);
--    if (dp_error == DP_ERR_OK) {
-+    if (ret == ERR_SUBDOM_INACTIVE) {
-+        be_mark_dom_offline(state->dom, be_req_get_be_ctx(be_req));
-+        return be_req_terminate(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
-+    } else if (dp_error == DP_ERR_OK) {
-         if (ret == EOK) {
-             error_text = NULL;
-         } else {
--- 
-2.4.3
-
diff --git a/SOURCES/0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch b/SOURCES/0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch
new file mode 100644
index 0000000..b4c2e9e
--- /dev/null
+++ b/SOURCES/0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch
@@ -0,0 +1,166 @@
+From acb2de04987b163d602aa02155b34c50bce93584 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 8 Aug 2016 13:55:52 +0200
+Subject: [PATCH 79/82] NSS: Do not check local users with disabled
+ local_negative_timeout
+
+sssd_nss can set different negative timeout for local users
+and groups. However, checking whether user/group is local
+is quite expensive operation. We can avoid such operations
+if local_negative_timeout is not set.
+
+This fix improve performance(40%) of lookup non-existing
+entries in offline mode and with disabled local_negative_timeout.
+
+  sh$ cat pok.sh
+  for i in {1..10000}; do
+    getent passwd -s sss temp$i
+    getent group -s sss temp$i
+  done
+
+  #without patch
+  sh $time /bin/bash pok.sh
+  real    0m41.534s
+  user    0m3.580s
+  sys     0m14.202s
+
+  #with patch
+  sh $time /bin/bash pok.sh
+  real    0m26.686s
+  user    0m3.292s
+  sys     0m13.165s
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3122
+
+Reviewed-by: Petr Cech <pcech@redhat.com>
+---
+ src/responder/common/negcache.c | 45 ++++++++++++++++++++++++-----------------
+ 1 file changed, 27 insertions(+), 18 deletions(-)
+
+diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
+index dfeb0d483e4db34cb2f25e1f82884611a707aabe..5b7ad69f432518be94b88e92e24265add722c852 100644
+--- a/src/responder/common/negcache.c
++++ b/src/responder/common/negcache.c
+@@ -143,7 +143,7 @@ done:
+ }
+ 
+ static int sss_ncache_set_str(struct sss_nc_ctx *ctx, char *str,
+-                              bool permanent, bool is_local)
++                              bool permanent, bool use_local_negative)
+ {
+     TDB_DATA key;
+     TDB_DATA data;
+@@ -157,15 +157,16 @@ static int sss_ncache_set_str(struct sss_nc_ctx *ctx, char *str,
+     if (permanent) {
+         timest = talloc_strdup(ctx, "0");
+     } else {
+-        if (is_local == true && ctx->local_timeout > 0) {
+-            timell = (unsigned long long int)time(NULL) + ctx->local_timeout;
++        if (use_local_negative == true && ctx->local_timeout > ctx->timeout) {
++            timell = ctx->local_timeout;
+         } else {
+-            if (ctx->timeout > 0) {
+-                timell = (unsigned long long int)time(NULL) + ctx->timeout;
+-            } else {
++            /* EOK is tested in cwrap based unit test */
++            if (ctx->timeout == 0) {
+                 return EOK;
+             }
++            timell = ctx->timeout;
+         }
++        timell += (unsigned long long int)time(NULL);
+         timest = talloc_asprintf(ctx, "%llu", timell);
+     }
+     if (!timest) return ENOMEM;
+@@ -457,7 +458,7 @@ int sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert)
+ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
+ {
+-    bool is_local;
++    bool use_local_negative = false;
+     char *str;
+     int ret;
+ 
+@@ -466,8 +467,10 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+     str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);
+     if (!str) return ENOMEM;
+ 
+-    is_local = is_user_local_by_name(name);
+-    ret = sss_ncache_set_str(ctx, str, permanent, is_local);
++    if (ctx->local_timeout > 0) {
++        use_local_negative = is_user_local_by_name(name);
++    }
++    ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+     talloc_free(str);
+     return ret;
+@@ -476,7 +479,7 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+ static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent,
+                                     const char *domain, const char *name)
+ {
+-    bool is_local;
++    bool use_local_negative = false;
+     char *str;
+     int ret;
+ 
+@@ -485,8 +488,10 @@ static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent,
+     str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);
+     if (!str) return ENOMEM;
+ 
+-    is_local = is_group_local_by_name(name);
+-    ret = sss_ncache_set_str(ctx, str, permanent, is_local);
++    if (ctx->local_timeout > 0) {
++        use_local_negative = is_group_local_by_name(name);
++    }
++    ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+     talloc_free(str);
+     return ret;
+@@ -550,7 +555,7 @@ int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
+ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent,
+                        struct sss_domain_info *dom, uid_t uid)
+ {
+-    bool is_local;
++    bool use_local_negative = false;
+     char *str;
+     int ret;
+ 
+@@ -562,8 +567,10 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent,
+     }
+     if (!str) return ENOMEM;
+ 
+-    is_local = is_user_local_by_uid(uid);
+-    ret = sss_ncache_set_str(ctx, str, permanent, is_local);
++    if (ctx->local_timeout > 0) {
++        use_local_negative = is_user_local_by_uid(uid);
++    }
++    ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+     talloc_free(str);
+     return ret;
+@@ -572,7 +579,7 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent,
+ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent,
+                        struct sss_domain_info *dom, gid_t gid)
+ {
+-    bool is_local;
++    bool use_local_negative = false;
+     char *str;
+     int ret;
+ 
+@@ -584,8 +591,10 @@ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent,
+     }
+     if (!str) return ENOMEM;
+ 
+-    is_local = is_group_local_by_gid(gid);
+-    ret = sss_ncache_set_str(ctx, str, permanent, is_local);
++    if (ctx->local_timeout > 0) {
++        use_local_negative = is_group_local_by_gid(gid);
++    }
++    ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+     talloc_free(str);
+     return ret;
+-- 
+2.4.11
+
diff --git a/SOURCES/0080-AD-Set-ignore_mark_offline-false-when-resolving-AD-r.patch b/SOURCES/0080-AD-Set-ignore_mark_offline-false-when-resolving-AD-r.patch
deleted file mode 100644
index 61941b7..0000000
--- a/SOURCES/0080-AD-Set-ignore_mark_offline-false-when-resolving-AD-r.patch
+++ /dev/null
@@ -1,157 +0,0 @@
-From d89c2dc276a8974b20a77b54ba663d4a1fa5acd2 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Sep 2015 12:10:03 +0000
-Subject: [PATCH 80/87] AD: Set ignore_mark_offline=false when resolving AD
- root domain
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2637
-
-Avoid going offline in cases where SSSD is connected to a child domain
-but the root domain is not accessible.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit ece345a74cec793e6d970a4955beb3d4a05935b3)
----
- src/providers/ad/ad_subdomains.c | 56 +++++++++++++++++++++++-----------------
- 1 file changed, 33 insertions(+), 23 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index d1d468043410c80e6bf7f0f48a13bd9e962552af..8ed3dab0995f78a16f4a7df2e729ea88a39a782c 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -80,7 +80,8 @@ struct ad_subdomains_req_ctx {
-     struct ad_id_ctx *root_id_ctx;
-     struct sdap_id_op *root_op;
-     size_t root_base_iter;
--    struct sysdb_attrs *root_domain;
-+    struct sysdb_attrs *root_domain_attrs;
-+    struct sss_domain_info *root_domain;
- 
-     size_t reply_count;
-     struct sysdb_attrs **reply;
-@@ -689,6 +690,7 @@ static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx)
-     return EAGAIN;
- }
- 
-+static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx);
- 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);
- 
-@@ -769,7 +771,14 @@ static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
-         }
-     }
- 
--    ctx->root_domain = reply[0];
-+    ctx->root_domain_attrs = reply[0];
-+    ctx->root_domain = ads_get_root_domain(ctx);
-+    if (ctx->root_domain == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
-+        ret = EFAULT;
-+        goto fail;
-+    }
-+
-     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");
-@@ -803,15 +812,13 @@ fail:
-     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)
-+static struct sss_domain_info *ads_get_root_domain(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);
-+    ret = sysdb_attrs_get_string(ctx->root_domain_attrs, AD_AT_TRUST_PARTNER, &name);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
-         return NULL;
-@@ -820,32 +827,40 @@ static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
-     /* With a subsequent run, the root should already be known */
-     root = find_domain_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);
-+    return root;
-+}
-+
-+static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
-+{
-+    errno_t ret;
-+    struct sdap_domain *sdom;
-+    struct ad_id_ctx *root_id_ctx;
-+
-+    sdom = sdap_domain_get(ctx->sd_ctx->ad_id_ctx->sdap_id_ctx->opts,
-+                           ctx->root_domain);
-     if (sdom == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE,
--              "Cannot get the sdom for %s!\n", root->name);
-+              "Cannot get the sdom for %s!\n", ctx->root_domain->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,
-+                                   ctx->root_domain,
-                                    &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;
-     }
- 
-+    root_id_ctx->ldap_ctx->ignore_mark_offline = true;
-     return root_id_ctx;
- }
- 
-@@ -860,16 +875,11 @@ static void ad_subdomains_root_conn_done(struct tevent_req *req)
-     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));
--        }
-+        be_mark_dom_offline(ctx->root_domain, be_req_get_be_ctx(ctx->be_req));
- 
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Failed to connect to AD server: [%d](%s)\n",
-+              ret, strerror(ret));
-         goto fail;
-     }
- 
-@@ -1040,7 +1050,7 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
-      */
-     ret = ad_subdomains_process(ctx, ctx->sd_ctx->be_ctx->domain,
-                                 ctx->reply_count, ctx->reply,
--                                ctx->root_domain, &nsubdoms, &subdoms);
-+                                ctx->root_domain_attrs, &nsubdoms, &subdoms);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, ("Cannot process subdomain list\n"));
-         tevent_req_error(req, ret);
--- 
-2.4.3
-
diff --git a/SOURCES/0080-config_schema-Add-ldap_user_email-to-schema.patch b/SOURCES/0080-config_schema-Add-ldap_user_email-to-schema.patch
new file mode 100644
index 0000000..416c768
--- /dev/null
+++ b/SOURCES/0080-config_schema-Add-ldap_user_email-to-schema.patch
@@ -0,0 +1,31 @@
+From fad4c17acbc0170110a98806886e0eeec793c0c6 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Wed, 10 Aug 2016 08:17:02 +0200
+Subject: [PATCH 80/82] config_schema: Add ldap_user_email to schema
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3068
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+---
+ src/config/cfg_rules.ini | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 635c078436e8ca47f60e8d82341cb131469fe4c9..09f53fa41eb2904f11a78af333b6d79619d2759c 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -588,6 +588,7 @@ option = ldap_user_authorized_host
+ option = ldap_user_authorized_service
+ option = ldap_user_auth_type
+ option = ldap_user_certificate
++option = ldap_user_email
+ option = ldap_user_entry_usn
+ option = ldap_user_extra_attrs
+ option = ldap_user_fullname
+-- 
+2.4.11
+
diff --git a/SOURCES/0081-IPA-Do-not-allow-the-AD-lookup-code-to-set-backend-a.patch b/SOURCES/0081-IPA-Do-not-allow-the-AD-lookup-code-to-set-backend-a.patch
deleted file mode 100644
index 8b3f8b2..0000000
--- a/SOURCES/0081-IPA-Do-not-allow-the-AD-lookup-code-to-set-backend-a.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From fbf7fe9a713948eaf5e47518c776f2ad664b9e46 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 2 Sep 2015 13:41:26 +0200
-Subject: [PATCH 81/87] IPA: Do not allow the AD lookup code to set backend as
- offline in server mode
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2637
-
-In server mode, we should not allow the AD lookups to set the backend
-offline. Rather just let them report an error and deal with the error
-separately.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 20162352030d1c577bb69d44e967d2c5839e5c0e)
----
- src/providers/ipa/ipa_subdomains_id.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 610b1c58b3b180201cfb5b22f870f8937673e02e..ff14b4a4c68cb5c6e9865a66931ee4ecd6e49211 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -633,6 +633,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-             ret = ENOMEM;
-             goto fail;
-         }
-+        clist[1]->ignore_mark_offline = true;
-         break;
-     default:
-         clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2);
-@@ -641,6 +642,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-             goto fail;
-         }
-         clist[0] = ad_id_ctx->ldap_ctx;
-+        clist[0]->ignore_mark_offline = true;
-         clist[1] = NULL;
-     }
- 
-@@ -1036,7 +1038,11 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
- 
-     ret = ad_handle_acct_info_recv(subreq, &state->dp_error, NULL);
-     talloc_zfree(subreq);
--    if (ret != EOK) {
-+    if (ret == ERR_SUBDOM_INACTIVE) {
-+        be_mark_dom_offline(state->obj_dom, be_req_get_be_ctx(state->be_req));
-+        tevent_req_error(req, ret);
-+        return;
-+    } else if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "AD lookup failed: %d\n", ret);
-         tevent_req_error(req, ret);
-         return;
--- 
-2.4.3
-
diff --git a/SOURCES/0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch b/SOURCES/0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch
new file mode 100644
index 0000000..3cc0985
--- /dev/null
+++ b/SOURCES/0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch
@@ -0,0 +1,113 @@
+From 1d0a914578ce72bad86cbe9e0beeda0c3b2d1dee Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 8 Aug 2016 17:30:29 +0200
+Subject: [PATCH 81/82] NSS: Use correct name for invalidating memory cache
+
+After refactoring of sysdb, we get and internal fully qualified
+name from backend in org.freedesktop.sssd.dataprovider_rev.initgrCheck
+Previously we got short name and we created fq name in
+nss_update_initgr_memcache. Memory cache still need to use short names
+if it was specified.
+
+This patch uses right name in different places.
+
+Reviewed-by: Petr Cech <pcech@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/nss/nsssrv_cmd.c     | 31 +++++++++++++++++--------------
+ src/responder/nss/nsssrv_private.h |  2 +-
+ 2 files changed, 18 insertions(+), 15 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index f3b6ac4afb5d1571f283933b48e0256b91c56391..573959ea76fc1277fe84f40b88dcd34093da468d 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -3961,13 +3961,13 @@ done:
+ }
+ 
+ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+-                                const char *name, const char *domain,
++                                const char *fq_name, const char *domain,
+                                 int gnum, uint32_t *groups)
+ {
+     TALLOC_CTX *tmp_ctx = NULL;
+     struct sss_domain_info *dom;
+     struct ldb_result *res;
+-    struct sized_string delete_name;
++    struct sized_string *delete_name;
+     bool changed = false;
+     uint32_t id;
+     uint32_t gids[gnum];
+@@ -3987,8 +3987,19 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+     }
+ 
+     tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return;
++    }
+ 
+-    ret = sysdb_initgroups(tmp_ctx, dom, name, &res);
++    ret = sized_output_name(tmp_ctx, nctx->rctx, fq_name, dom, &delete_name);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "sized_output_name failed for '%s': %d [%s]\n",
++              fq_name, ret, sss_strerror(ret));
++        goto done;
++    }
++
++    ret = sysdb_initgroups(tmp_ctx, dom, fq_name, &res);
+     if (ret != EOK && ret != ENOENT) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Failed to make request to our cache! [%d][%s]\n",
+@@ -4002,8 +4013,7 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+ 
+     if (ret == ENOENT || res->count == 0) {
+         /* The user is gone. Invalidate the mc record */
+-        to_sized_string(&delete_name, name);
+-        ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &delete_name);
++        ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, delete_name);
+         if (ret != EOK && ret != ENOENT) {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "Internal failure in memory cache code: %d [%s]\n",
+@@ -4047,13 +4057,6 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+     }
+ 
+     if (changed) {
+-        char *fq_name = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
+-        if (!fq_name) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Could not create fq name\n");
+-            goto done;
+-        }
+-
+         for (i = 0; i < gnum; i++) {
+             id = groups[i];
+ 
+@@ -4065,9 +4068,9 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+             }
+         }
+ 
+-        to_sized_string(&delete_name, fq_name);
++        to_sized_string(delete_name, fq_name);
+         ret = sss_mmap_cache_initgr_invalidate(nctx->initgr_mc_ctx,
+-                                               &delete_name);
++                                               delete_name);
+         if (ret != EOK && ret != ENOENT) {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "Internal failure in memory cache code: %d [%s]\n",
+diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h
+index 79c7b7265f66f57e0ea89fe192a1da4f8992f1a3..391eaaf40f84a7436bee63fd699241e4957fdbeb 100644
+--- a/src/responder/nss/nsssrv_private.h
++++ b/src/responder/nss/nsssrv_private.h
+@@ -146,7 +146,7 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
+ void nss_update_pw_memcache(struct nss_ctx *nctx);
+ void nss_update_gr_memcache(struct nss_ctx *nctx);
+ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+-                                const char *name, const char *domain,
++                                const char *fq_name, const char *domain,
+                                 int gnum, uint32_t *groups);
+ 
+ int nss_connection_setup(struct cli_ctx *cctx);
+-- 
+2.4.11
+
diff --git a/SOURCES/0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch b/SOURCES/0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch
new file mode 100644
index 0000000..9e36f14
--- /dev/null
+++ b/SOURCES/0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch
@@ -0,0 +1,89 @@
+From d3925525068798e92cee1da95dbee0f838b2f36f Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Wed, 3 Aug 2016 18:48:04 +0200
+Subject: [PATCH 82/82] SYSDB: Avoid optimisation with modifyTimestamp for
+ users
+
+The usage of modifyTimestamp needn't be a reliable way
+for detecting of changes in user entry in LDAP.
+The authorisation need to rely current data from LDAP
+and therefore we will temporary disable optimisation with
+modifyTimestamp and we will rather rely on deep comparison
+of attributes. In he future, it might be changed and
+responders might control the optimization level.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3110
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 00f3c5cd03625357e226552084e499965512bf53)
+---
+ src/db/sysdb_ops.c                     | 19 -------------------
+ src/tests/cmocka/test_sysdb_ts_cache.c | 14 --------------
+ 2 files changed, 33 deletions(-)
+
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 67006c155098b9fde00a01d424014852c383a325..44fb5b70e6d33fffbca5824f831a3229254ecb57 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -1101,16 +1101,6 @@ done:
+     return ret;
+ }
+ 
+-static errno_t sysdb_check_and_update_ts_usr(struct sss_domain_info *domain,
+-                                             const char *grp_name,
+-                                             struct sysdb_attrs *attrs,
+-                                             uint64_t cache_timeout,
+-                                             time_t now)
+-{
+-    return sysdb_check_and_update_ts_obj(domain, SYSDB_USER, grp_name,
+-                                         attrs, cache_timeout, now);
+-}
+-
+ static errno_t sysdb_check_and_update_ts_grp(struct sss_domain_info *domain,
+                                              const char *grp_name,
+                                              struct sysdb_attrs *attrs,
+@@ -2470,15 +2460,6 @@ int sysdb_store_user(struct sss_domain_info *domain,
+         now = time(NULL);
+     }
+ 
+-    ret = sysdb_check_and_update_ts_usr(domain, name, attrs,
+-                                        cache_timeout, now);
+-    if (ret == EOK) {
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "The user record of %s did not change, only updated "
+-              "the timestamp cache\n", name);
+-        return EOK;
+-    }
+-
+     tmp_ctx = talloc_new(NULL);
+     if (!tmp_ctx) {
+         return ENOMEM;
+diff --git a/src/tests/cmocka/test_sysdb_ts_cache.c b/src/tests/cmocka/test_sysdb_ts_cache.c
+index aa857e7e4823d2d8ba1e1a794b3e2474876e9ab0..e950f88631e4c78573bbb7290edfe94b5ced57cd 100644
+--- a/src/tests/cmocka/test_sysdb_ts_cache.c
++++ b/src/tests/cmocka/test_sysdb_ts_cache.c
+@@ -980,20 +980,6 @@ static void test_sysdb_user_update(void **state)
+     assert_int_equal(cache_expire_sysdb, TEST_CACHE_TIMEOUT + TEST_NOW_2);
+     assert_int_equal(cache_expire_ts, TEST_CACHE_TIMEOUT + TEST_NOW_2);
+ 
+-    /* Update the same attrs and the same modifyTimestamp.
+-     * Only the timestamp cache must be bumped */
+-    ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME, NULL,
+-                           TEST_USER_UID, TEST_USER_GID, TEST_USER_NAME,
+-                           "/home/"TEST_USER_NAME, "/bin/bash", NULL,
+-                           user_attrs, NULL, TEST_CACHE_TIMEOUT,
+-                           TEST_NOW_3);
+-    assert_int_equal(ret, EOK);
+-
+-    get_pw_timestamp_attrs(test_ctx, TEST_USER_NAME,
+-                           &cache_expire_sysdb, &cache_expire_ts);
+-    assert_int_equal(cache_expire_sysdb, TEST_CACHE_TIMEOUT + TEST_NOW_2);
+-    assert_int_equal(cache_expire_ts, TEST_CACHE_TIMEOUT + TEST_NOW_3);
+-
+     /* Update with different modifyTimestamp but same attrs as previously
+      * saved to the timestamp cache. We should detect the 'real' attributes
+      * are the same and only bump the timestamp cache
+-- 
+2.4.11
+
diff --git a/SOURCES/0082-sss_override-remove-d-from-manpage.patch b/SOURCES/0082-sss_override-remove-d-from-manpage.patch
deleted file mode 100644
index 0d6456c..0000000
--- a/SOURCES/0082-sss_override-remove-d-from-manpage.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 76eb4e29154a9cea4b9189db0b6a0c4ee19e5231 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 18 Sep 2015 15:55:13 +0200
-Subject: [PATCH 82/87] sss_override: remove -d from manpage
-
-Short version of --debug is not acepted.
-
-Reviewed-by: Pavel Reichl <preichl@redhat.com>
-(cherry picked from commit 8ca1a503cf82fe2c9ed6af9d5903a158496be122)
----
- src/man/sss_override.8.xml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/man/sss_override.8.xml b/src/man/sss_override.8.xml
-index c2ec5dd41703c7272acf7c9d2c30f20351099791..6381d7731761d3aa9e976475bae40941eb2264eb 100644
---- a/src/man/sss_override.8.xml
-+++ b/src/man/sss_override.8.xml
-@@ -198,7 +198,7 @@
-         <variablelist remap='IP'>
-             <varlistentry>
-                 <term>
--                    <option>-d</option>,<option>--debug</option>
-+                    <option>--debug</option>
-                     <replaceable>LEVEL</replaceable>
-                 </term>
-                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/debug_levels.xml" />
--- 
-2.4.3
-
diff --git a/SOURCES/0083-LDAP-imposing-sizelimit-1-for-single-entry-searches-.patch b/SOURCES/0083-LDAP-imposing-sizelimit-1-for-single-entry-searches-.patch
deleted file mode 100644
index ecc6841..0000000
--- a/SOURCES/0083-LDAP-imposing-sizelimit-1-for-single-entry-searches-.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From 075a5e689eb6983f412724b0324cec59726ae6e9 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 21 Jul 2015 21:00:27 +0200
-Subject: [PATCH 83/86] LDAP: imposing sizelimit=1 for single-entry searches
- breaks overlapping domains
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2723
-
-In case there are overlapping sdap domains, a search for a single user
-might match and return multiple entries. For instance, with AD domains
-represented by search bases:
-    DC=win,DC=trust,DC=test
-    DC=child,DC=win,DC=trust,DC=test
-
-A search for user from win.trust.test would be based at:
-    DC=win,DC=trust,DC=test
-but would match both search bases and return both users.
-
-Instead of performing complex filtering, just save both users. The
-responder would select the entry that matches the user's search.
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit 67625b1b4f856510bf4e169649b3fb30c2c14152)
----
- src/providers/ldap/sdap_async_groups.c | 10 ----------
- src/providers/ldap/sdap_async_users.c  |  3 ---
- 2 files changed, 13 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 525c6fa09553d8c0232ce2317751184f83632d86..57a53af3f4eb46e6f31af9ee7c4d4625239d2a54 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -1874,8 +1874,6 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
- 
-     switch (state->lookup_type) {
-     case SDAP_LOOKUP_SINGLE:
--        sizelimit = 1;
--        need_paging = false;
-         break;
-     /* Only requests that can return multiple entries should require
-      * the paging control
-@@ -1885,7 +1883,6 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
-         need_paging = true;
-         break;
-     case SDAP_LOOKUP_ENUMERATE:
--        sizelimit = 0;  /* unlimited */
-         need_paging = true;
-         break;
-     }
-@@ -1934,13 +1931,6 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
-     DEBUG(SSSDBG_TRACE_FUNC,
-           "Search for groups, returned %zu results.\n", count);
- 
--    if (state->lookup_type == SDAP_LOOKUP_SINGLE && count > 1) {
--        DEBUG(SSSDBG_MINOR_FAILURE,
--              "Individual group search returned multiple results\n");
--        tevent_req_error(req, EINVAL);
--        return;
--    }
--
-     if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
-             state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
-         count == 0) {
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index a864a8b2187de7972aa963b355856e97f7c692a9..e38f4cd1610e62aa2cf9f4add3a5f7ad5290e748 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -692,8 +692,6 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
- 
-     switch (state->lookup_type) {
-     case SDAP_LOOKUP_SINGLE:
--        sizelimit = 1;
--        need_paging = false;
-         break;
-     /* Only requests that can return multiple entries should require
-      * the paging control
-@@ -703,7 +701,6 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
-         need_paging = true;
-         break;
-     case SDAP_LOOKUP_ENUMERATE:
--        sizelimit = 0;  /* unlimited */
-         need_paging = true;
-         break;
-     }
--- 
-2.4.3
-
diff --git a/SOURCES/0083-SIMPLE-Do-not-parse-names-on-startup.patch b/SOURCES/0083-SIMPLE-Do-not-parse-names-on-startup.patch
new file mode 100644
index 0000000..8185485
--- /dev/null
+++ b/SOURCES/0083-SIMPLE-Do-not-parse-names-on-startup.patch
@@ -0,0 +1,48 @@
+From 701cabea51526c3bd40607761dc02069c9c2e499 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 21 Jul 2016 12:18:01 +0200
+Subject: [PATCH 83/86] SIMPLE: Do not parse names on startup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It's not required to parse names on SSSD startup in the simple access
+provider. We can instead just parse the name when the access request is
+processed.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3101
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/simple/simple_access.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
+index cb72ada20727c63452936647876ef297106e17b0..ae90215351fe7db834898067d3b4bad71015ec5f 100644
+--- a/src/providers/simple/simple_access.c
++++ b/src/providers/simple/simple_access.c
+@@ -284,7 +284,6 @@ errno_t sssm_simple_access_init(TALLOC_CTX *mem_ctx,
+                                 struct dp_method *dp_methods)
+ {
+     struct simple_ctx *ctx;
+-    errno_t ret;
+ 
+     ctx = talloc_zero(mem_ctx, struct simple_ctx);
+     if (ctx == NULL) {
+@@ -296,12 +295,6 @@ errno_t sssm_simple_access_init(TALLOC_CTX *mem_ctx,
+     ctx->be_ctx = be_ctx;
+     ctx->last_refresh_of_filter_lists = 0;
+ 
+-    ret = simple_access_obtain_filter_lists(ctx);
+-    if (ret != EOK) {
+-        talloc_free(ctx);
+-        return ret;
+-    }
+-
+     dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
+                   simple_access_handler_send, simple_access_handler_recv, ctx,
+                   struct simple_ctx, struct pam_data, struct pam_data *);
+-- 
+2.4.11
+
diff --git a/SOURCES/0084-DYNDNS-Add-a-new-option-dyndns_server.patch b/SOURCES/0084-DYNDNS-Add-a-new-option-dyndns_server.patch
deleted file mode 100644
index 8fa1811..0000000
--- a/SOURCES/0084-DYNDNS-Add-a-new-option-dyndns_server.patch
+++ /dev/null
@@ -1,208 +0,0 @@
-From b280fc0d8287e9bee25516eddc1a6670691c24a1 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 6 Jul 2014 22:53:27 +0200
-Subject: [PATCH 84/90] DYNDNS: Add a new option dyndns_server
-
-Some environments use a different DNS server than identity server. For
-these environments, it would be useful to be able to override the DNS
-server used to perform DNS updates.
-
-This patch adds a new option dyndns_server that, if set, would be used
-to hardcode a DNS server address into the nsupdate message.
-
-Reviewed-by: Pavel Reichl <preichl@redhat.com>
-(cherry picked from commit 8145ab51b05aa86b2f1a21b49383f55e50b0a2e3)
----
- src/config/SSSDConfig/__init__.py.in |  1 +
- src/config/SSSDConfigTest.py         |  2 ++
- src/config/etc/sssd.api.conf         |  1 +
- src/man/sssd-ad.5.xml                | 20 ++++++++++++++++++++
- src/man/sssd-ipa.5.xml               | 19 +++++++++++++++++++
- src/providers/ad/ad_opts.h           |  1 +
- src/providers/dp_dyndns.c            |  1 +
- src/providers/dp_dyndns.h            |  1 +
- src/providers/ipa/ipa_opts.h         |  1 +
- src/providers/ldap/sdap_dyndns.c     |  7 +++++++
- 10 files changed, 54 insertions(+)
-
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index fed2682f121103cefa27e689b29ce29b7d28f968..a7cd1dd243a53e7038dc69628475c76ccdd93260 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -148,6 +148,7 @@ option_strings = {
-     'dyndns_update_ptr' : _("Whether the provider should explicitly update the PTR record as well"),
-     'dyndns_force_tcp' : _("Whether the nsupdate utility should default to using TCP"),
-     'dyndns_auth' : _("What kind of authentication should be used to perform the DNS update"),
-+    'dyndns_server' : _("Override the DNS server used to perform the DNS update"),
-     'subdomain_enumerate' : _('Control enumeration of trusted domains'),
-     'subdomain_refresh_interval' : _('How often should subdomains list be refreshed'),
-     'subdomain_inherit' : _('List of options that should be inherited into a subdomain'),
-diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
-index 1d6107ceac1bde7acbfd2682cc144a4ef0881311..166ecd0ff0f5cfb38eefb1711e4ac5dd9f805d43 100755
---- a/src/config/SSSDConfigTest.py
-+++ b/src/config/SSSDConfigTest.py
-@@ -527,6 +527,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
-             'dyndns_update_ptr',
-             'dyndns_force_tcp',
-             'dyndns_auth',
-+            'dyndns_server',
-             'subdomain_enumerate',
-             'override_gid',
-             'case_sensitive',
-@@ -891,6 +892,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
-             'dyndns_update_ptr',
-             'dyndns_force_tcp',
-             'dyndns_auth',
-+            'dyndns_server',
-             'subdomain_enumerate',
-             'override_gid',
-             'case_sensitive',
-diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
-index 2e5b02e3e30c13f805e172eab481f7501f57bb05..f28054860205831b0452e409c109e3c62aa8d28a 100644
---- a/src/config/etc/sssd.api.conf
-+++ b/src/config/etc/sssd.api.conf
-@@ -155,6 +155,7 @@ dyndns_refresh_interval = int, None, false
- dyndns_update_ptr = bool, None, false
- dyndns_force_tcp = bool, None, false
- dyndns_auth = str, None, false
-+dyndns_server = str, None, false
- 
- # Special providers
- [provider/permit]
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 3cbc10520098372d984d00425d03832d002d6672..7ccd29794a89fa6b69b744a47da04f908efc7ef9 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -812,6 +812,26 @@ ad_gpo_map_deny = +my_pam_service
-                     </listitem>
-                 </varlistentry>
- 
-+                <varlistentry>
-+                    <term>dyndns_server (string)</term>
-+                    <listitem>
-+                        <para>
-+                            The DNS server to use when performing a DNS
-+                            update. In most setups, it's recommended to leave
-+                            this option unset.
-+                        </para>
-+                        <para>
-+                            Setting this option makes sense for environments
-+                            where the DNS server is different from the identity
-+                            server.
-+                        </para>
-+                        <para>
-+                            Default: None (let nsupdate choose the server)
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-+
-                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/override_homedir.xml" />
-                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/homedir_substring.xml" />
- 
-diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
-index 2e985991fde10827aff0e7c8e67f29a009683450..871c41607b97bd24fe5feaa282258def0fd0cc8b 100644
---- a/src/man/sssd-ipa.5.xml
-+++ b/src/man/sssd-ipa.5.xml
-@@ -263,6 +263,25 @@
-                 </varlistentry>
- 
-                 <varlistentry>
-+                    <term>dyndns_server (string)</term>
-+                    <listitem>
-+                        <para>
-+                            The DNS server to use when performing a DNS
-+                            update. In most setups, it's recommended to leave
-+                            this option unset.
-+                        </para>
-+                        <para>
-+                            Setting this option makes sense for environments
-+                            where the DNS server is different from the identity
-+                            server.
-+                        </para>
-+                        <para>
-+                            Default: None (let nsupdate choose the server)
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-+
-+                <varlistentry>
-                     <term>ipa_hbac_search_base (string)</term>
-                     <listitem>
-                         <para>
-diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
-index d685edcb44c771b0afc7a232a82c21fc9d1c89f9..00586a7ada63ad4c89630e9589d3ff75d1726703 100644
---- a/src/providers/ad/ad_opts.h
-+++ b/src/providers/ad/ad_opts.h
-@@ -275,6 +275,7 @@ struct dp_option ad_dyndns_opts[] = {
-     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
-     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
-     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
-+    { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-     DP_OPTION_TERMINATOR
- };
- 
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index c254d78936f412626db0533f559350de57017618..9a726bd431854342993212ce0a9759b86069cd5e 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -1180,6 +1180,7 @@ static struct dp_option default_dyndns_opts[] = {
-     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE },
-     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
-     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
-+    { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
- 
-     DP_OPTION_TERMINATOR
- };
-diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
-index a8a20ec6f8a1a63cd8c85aaec3f54f9fddb42049..3cc8d122646590365a3fb6dafa6a0f699b620ad9 100644
---- a/src/providers/dp_dyndns.h
-+++ b/src/providers/dp_dyndns.h
-@@ -55,6 +55,7 @@ enum dp_dyndns_opts {
-     DP_OPT_DYNDNS_UPDATE_PTR,
-     DP_OPT_DYNDNS_FORCE_TCP,
-     DP_OPT_DYNDNS_AUTH,
-+    DP_OPT_DYNDNS_SERVER,
- 
-     DP_OPT_DYNDNS /* attrs counter */
- };
-diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
-index f6c40dddbb58cd8af1079a351137422083e26cfe..78949e3ddec95f7f4303eab905bbbf6ec14ed6ae 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -62,6 +62,7 @@ struct dp_option ipa_dyndns_opts[] = {
-     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
-     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
-     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
-+    { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-     DP_OPTION_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index a463a2fce08f42b325010cd37c501ef23aee173f..01f4f17226f1b7dd417699403b425c571b780c3a 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -92,6 +92,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     struct tevent_req *req;
-     struct tevent_req *subreq;
-     struct sdap_dyndns_update_state *state;
-+    const char *conf_servername;
- 
-     req = tevent_req_create(mem_ctx, &state, struct sdap_dyndns_update_state);
-     if (req == NULL) {
-@@ -111,6 +112,12 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     state->auth_type = auth_type;
-     state->pass_num = 0;
- 
-+    conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
-+    if (conf_servername != NULL) {
-+        state->servername = conf_servername;
-+        state->use_server_with_nsupdate = true;
-+    }
-+
-     if (ifname) {
-        /* Unless one family is restricted, just replace all
-         * address families during the update
--- 
-2.4.3
-
diff --git a/SOURCES/0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch b/SOURCES/0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch
new file mode 100644
index 0000000..375b95e
--- /dev/null
+++ b/SOURCES/0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch
@@ -0,0 +1,40 @@
+From b40c53b524816f9308c90d79662f887e6a2ac1eb Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 21 Jul 2016 13:33:18 +0200
+Subject: [PATCH 84/86] SIMPLE: Fail on any error parsing the access control
+ list
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Luckily this error was hidden by the fact that SSSD didn't start at all
+when an unparseable name was encountered after startup. Otherwise, this
+would have been a security issue.
+
+Nonetheless, we should just fail and deny access if we can't parse a
+name in a simple access list.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/simple/simple_access.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
+index ae90215351fe7db834898067d3b4bad71015ec5f..577e8354e9b574764734248b2bde4ef06c6fb4fc 100644
+--- a/src/providers/simple/simple_access.c
++++ b/src/providers/simple/simple_access.c
+@@ -211,7 +211,10 @@ simple_access_handler_send(TALLOC_CTX *mem_ctx,
+ 
+         ret = simple_access_obtain_filter_lists(simple_ctx);
+         if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Failed to refresh filter lists\n");
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Failed to refresh filter lists, denying all access\n");
++            pd->pam_status = PAM_PERM_DENIED;
++            goto immediately;
+         }
+         simple_ctx->last_refresh_of_filter_lists = now;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0085-DYNDNS-Don-t-use-server-cmd-in-nsupdate-by-default.patch b/SOURCES/0085-DYNDNS-Don-t-use-server-cmd-in-nsupdate-by-default.patch
deleted file mode 100644
index 5e9f538..0000000
--- a/SOURCES/0085-DYNDNS-Don-t-use-server-cmd-in-nsupdate-by-default.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From 6d1ba78ff110ee424e54025c3d823fb5c504aefa Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Thu, 23 Jul 2015 04:40:03 -0400
-Subject: [PATCH 85/90] DYNDNS: Don't use server cmd in nsupdate by default
-
-nsupdate command `server` should not be used for the first attempt
-to udpate DNS. It should be used only in subsequent attempts after the
-first attempt failed.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2495
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 7c3cc1ee2914bc7b38a992c1af254fc76af5a1ad)
----
- src/man/sssd-ad.5.xml            | 6 +++++-
- src/man/sssd-ipa.5.xml           | 5 +++++
- src/providers/ldap/sdap_dyndns.c | 2 +-
- 3 files changed, 11 insertions(+), 2 deletions(-)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 7ccd29794a89fa6b69b744a47da04f908efc7ef9..127e96582d71e8216db88d37a16d37d01748131d 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -826,12 +826,16 @@ ad_gpo_map_deny = +my_pam_service
-                             server.
-                         </para>
-                         <para>
-+                            Please note that this option will be only used in
-+                            fallback attempt when previous attempt using
-+                            autodetected settings failed.
-+                        </para>
-+                        <para>
-                             Default: None (let nsupdate choose the server)
-                         </para>
-                     </listitem>
-                 </varlistentry>
- 
--
-                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/override_homedir.xml" />
-                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/homedir_substring.xml" />
- 
-diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
-index 871c41607b97bd24fe5feaa282258def0fd0cc8b..be390d58dd3ce5a6ca6d5212d2c7aa176d3a74c4 100644
---- a/src/man/sssd-ipa.5.xml
-+++ b/src/man/sssd-ipa.5.xml
-@@ -276,6 +276,11 @@
-                             server.
-                         </para>
-                         <para>
-+                            Please note that this option will be only used in
-+                            fallback attempt when previous attempt using
-+                            autodetected settings failed.
-+                        </para>
-+                        <para>
-                             Default: None (let nsupdate choose the server)
-                         </para>
-                     </listitem>
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index 01f4f17226f1b7dd417699403b425c571b780c3a..0f0e63ee2259d017c3e94afca5f3148f4fc2ce04 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -112,10 +112,10 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     state->auth_type = auth_type;
-     state->pass_num = 0;
- 
-+    /* fallback servername is overriden by user option */
-     conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
-     if (conf_servername != NULL) {
-         state->servername = conf_servername;
--        state->use_server_with_nsupdate = true;
-     }
- 
-     if (ifname) {
--- 
-2.4.3
-
diff --git a/SOURCES/0085-SIMPLE-Make-the-DP-handlers-testable.patch b/SOURCES/0085-SIMPLE-Make-the-DP-handlers-testable.patch
new file mode 100644
index 0000000..62c43fa
--- /dev/null
+++ b/SOURCES/0085-SIMPLE-Make-the-DP-handlers-testable.patch
@@ -0,0 +1,113 @@
+From ab6ee9104826e286e0c67c9176c08b9a239e0622 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 26 Jul 2016 12:13:43 +0200
+Subject: [PATCH 85/86] SIMPLE: Make the DP handlers testable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+To make it possible to call the whole DP handler in the unit test, not
+just the evaluator part.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am                              |  1 +
+ src/providers/simple/simple_access.c     |  5 ++--
+ src/providers/simple/simple_access_pvt.h | 43 ++++++++++++++++++++++++++++++++
+ 3 files changed, 47 insertions(+), 2 deletions(-)
+ create mode 100644 src/providers/simple/simple_access_pvt.h
+
+diff --git a/Makefile.am b/Makefile.am
+index cefd9a43442fc19933f1e373d4f2ed4bb3ba3201..ee9b48c666a44781b582ba5d83102b705e898f29 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -665,6 +665,7 @@ dist_noinst_HEADERS = \
+     src/providers/fail_over_srv.h \
+     src/util/child_common.h \
+     src/providers/simple/simple_access.h \
++    src/providers/simple/simple_access_pvt.h \
+     src/providers/krb5/krb5_auth.h \
+     src/providers/krb5/krb5_common.h \
+     src/providers/krb5/krb5_utils.h \
+diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
+index 577e8354e9b574764734248b2bde4ef06c6fb4fc..521beee84833b47b547bd1045c24e3384aa4d9a5 100644
+--- a/src/providers/simple/simple_access.c
++++ b/src/providers/simple/simple_access.c
+@@ -22,6 +22,7 @@
+ #include <security/pam_modules.h>
+ 
+ #include "providers/simple/simple_access.h"
++#include "providers/simple/simple_access_pvt.h"
+ #include "util/sss_utf8.h"
+ #include "providers/backend.h"
+ #include "db/sysdb.h"
+@@ -176,7 +177,7 @@ struct simple_access_handler_state {
+ 
+ static void simple_access_handler_done(struct tevent_req *subreq);
+ 
+-static struct tevent_req *
++struct tevent_req *
+ simple_access_handler_send(TALLOC_CTX *mem_ctx,
+                            struct simple_ctx *simple_ctx,
+                            struct pam_data *pd,
+@@ -265,7 +266,7 @@ done:
+     tevent_req_done(req);
+ }
+ 
+-static errno_t
++errno_t
+ simple_access_handler_recv(TALLOC_CTX *mem_ctx,
+                        struct tevent_req *req,
+                        struct pam_data **_data)
+diff --git a/src/providers/simple/simple_access_pvt.h b/src/providers/simple/simple_access_pvt.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..c133e1c5531be35861178e0b23aa7a09db9f7703
+--- /dev/null
++++ b/src/providers/simple/simple_access_pvt.h
+@@ -0,0 +1,43 @@
++/*
++   SSSD
++
++   Simple access control
++
++   Copyright (C) Sumit Bose <sbose@redhat.com> 2010
++
++   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/>.
++*/
++
++#ifndef __SIMPLE_ACCESS_PVT_H__
++#define __SIMPLE_ACCESS_PVT_H__
++
++#include "providers/data_provider/dp.h"
++
++/* We only 'export' the functions in a private header file to be able to call
++ * them from unit tests
++ */
++struct tevent_req *
++simple_access_handler_send(TALLOC_CTX *mem_ctx,
++                           struct simple_ctx *simple_ctx,
++                           struct pam_data *pd,
++                           struct dp_req_params *params);
++
++errno_t
++simple_access_handler_recv(TALLOC_CTX *mem_ctx,
++                           struct tevent_req *req,
++                           struct pam_data **_data);
++
++int simple_access_obtain_filter_lists(struct simple_ctx *ctx);
++
++#endif /* __SIMPLE_ACCESS_PVT_H__ */
+-- 
+2.4.11
+
diff --git a/SOURCES/0086-DYNDNS-remove-redundant-talloc_steal.patch b/SOURCES/0086-DYNDNS-remove-redundant-talloc_steal.patch
deleted file mode 100644
index 8bbb5ed..0000000
--- a/SOURCES/0086-DYNDNS-remove-redundant-talloc_steal.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From efbf0e362238eaf0330384caf057521968f25758 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Thu, 23 Jul 2015 04:50:38 -0400
-Subject: [PATCH 86/90] DYNDNS: remove redundant talloc_steal()
-
-String 'update_msg' was already allocated on mem_ctx, so, there is no
-need to steal it.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e4d6e9ccac14044d6bcd5a0dce7f45fdfab6bf3d)
----
- src/providers/dp_dyndns.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 9a726bd431854342993212ce0a9759b86069cd5e..3171e6909e5f92a98cd506278e6e8c3418b979fe 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -525,7 +525,8 @@ be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
-           update_msg);
- 
-     ret = ERR_OK;
--    *_update_msg = talloc_steal(mem_ctx, update_msg);
-+    *_update_msg = update_msg;
-+
- done:
-     return ret;
- }
--- 
-2.4.3
-
diff --git a/SOURCES/0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch b/SOURCES/0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch
new file mode 100644
index 0000000..4eed171
--- /dev/null
+++ b/SOURCES/0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch
@@ -0,0 +1,308 @@
+From 157781d8a05975c034858a38d2c00cdd94d374b0 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 26 Jul 2016 12:14:47 +0200
+Subject: [PATCH 86/86] TESTS: Use the DP handlers in simple provider tests,
+ add more tests
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use the full simple access control handlers, just like SSSD does in the
+tests.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/cmocka/test_simple_access.c | 186 ++++++++++++++++++++++++++++++----
+ 1 file changed, 165 insertions(+), 21 deletions(-)
+
+diff --git a/src/tests/cmocka/test_simple_access.c b/src/tests/cmocka/test_simple_access.c
+index 1f093cf7fee4d046dcc727aa8815fb9aafb68c52..d41bb295e24ef2104cf17636f37d487fd14d0b93 100644
+--- a/src/tests/cmocka/test_simple_access.c
++++ b/src/tests/cmocka/test_simple_access.c
+@@ -21,12 +21,14 @@
+ #include <tevent.h>
+ #include <errno.h>
+ #include <popt.h>
++#include <security/pam_appl.h>
+ 
+ #include "tests/cmocka/common_mock.h"
+ #include "tests/cmocka/common_mock_be.h"
+ #include "tests/cmocka/common_mock_resp.h"
+ #include "db/sysdb_private.h"   /* new_subdomain() */
+ #include "providers/simple/simple_access.h"
++#include "providers/simple/simple_access_pvt.h"
+ 
+ #define TESTS_PATH "tp_" BASE_FILE_STEM
+ #define TEST_CONF_DB "test_simple_conf.ldb"
+@@ -34,8 +36,6 @@
+ #define TEST_SUBDOM_NAME "test.subdomain"
+ #define TEST_ID_PROVIDER "ldap"
+ 
+-int simple_access_obtain_filter_lists(struct simple_ctx *ctx);
+-
+ struct simple_test_ctx {
+     struct sss_test_ctx *tctx;
+     struct be_ctx *be_ctx;
+@@ -43,6 +43,8 @@ struct simple_test_ctx {
+ 
+     bool access_granted;
+     struct simple_ctx *ctx;
++    struct pam_data *pd;
++    struct dp_req_params *params;
+ };
+ 
+ static int test_simple_setup(struct sss_test_conf_param params[], void **state)
+@@ -75,6 +77,19 @@ static int test_simple_setup(struct sss_test_conf_param params[], void **state)
+         return ENOMEM;
+     }
+ 
++    simple_test_ctx->pd = talloc_zero(simple_test_ctx, struct pam_data);
++    if (simple_test_ctx->pd == NULL) {
++        return ENOMEM;
++    }
++    simple_test_ctx->pd->cmd = SSS_PAM_ACCT_MGMT;
++
++    simple_test_ctx->params = talloc_zero(simple_test_ctx,
++                                          struct dp_req_params);
++    if (simple_test_ctx->params == NULL) {
++        return ENOMEM;
++    }
++    simple_test_ctx->params->ev = simple_test_ctx->tctx->ev;
++
+     *state = simple_test_ctx;
+     return 0;
+ }
+@@ -122,7 +137,7 @@ static int setup_with_params(struct simple_test_ctx *test_ctx,
+         return ret;
+     }
+ 
+-    test_ctx->ctx = talloc(test_ctx, struct simple_ctx);
++    test_ctx->ctx = talloc_zero(test_ctx, struct simple_ctx);
+     if (test_ctx->ctx == NULL) {
+         return ENOMEM;
+     }
+@@ -130,11 +145,6 @@ static int setup_with_params(struct simple_test_ctx *test_ctx,
+     test_ctx->ctx->be_ctx = test_ctx->be_ctx;
+     test_ctx->ctx->domain = test_ctx->tctx->dom;
+ 
+-    ret = simple_access_obtain_filter_lists(test_ctx->ctx);
+-    if (ret != EOK) {
+-        return ret;
+-    }
+-
+     return EOK;
+ }
+ 
+@@ -155,13 +165,14 @@ static int simple_test_teardown(void **state)
+     return 0;
+ }
+ 
+-static void simple_access_check_done(struct tevent_req *req)
++static void simple_access_handler_done(struct tevent_req *req)
+ {
+     struct simple_test_ctx *simple_test_ctx =
+                         tevent_req_callback_data(req, struct simple_test_ctx);
+ 
+-    simple_test_ctx->tctx->error = simple_access_check_recv(req,
+-                                              &simple_test_ctx->access_granted);
++    simple_test_ctx->tctx->error = simple_access_handler_recv(simple_test_ctx,
++                                                    req, &simple_test_ctx->pd);
++    simple_test_ctx->access_granted = (simple_test_ctx->pd->pam_status == PAM_SUCCESS);
+     talloc_free(req);
+     simple_test_ctx->tctx->done = true;
+ }
+@@ -175,10 +186,13 @@ static void run_simple_access_check(struct simple_test_ctx *simple_test_ctx,
+     struct tevent_req *req;
+ 
+     simple_test_ctx->tctx->done = false;
+-    req = simple_access_check_send(simple_test_ctx, simple_test_ctx->tctx->ev,
+-                                   simple_test_ctx->ctx, username);
++    simple_test_ctx->pd->user = discard_const(username);
++    req = simple_access_handler_send(simple_test_ctx,
++                                     simple_test_ctx->ctx,
++                                     simple_test_ctx->pd,
++                                     simple_test_ctx->params);
+     assert_non_null(req);
+-    tevent_req_set_callback(req, simple_access_check_done, simple_test_ctx);
++    tevent_req_set_callback(req, simple_access_handler_done, simple_test_ctx);
+ 
+     ret = test_ev_loop(simple_test_ctx->tctx);
+     assert_int_equal(ret, expected_rv);
+@@ -487,23 +501,29 @@ static void test_group_allow_empty(void **state)
+         { NULL, NULL },
+     };
+ 
+-    ret = setup_with_params(simple_test_ctx, simple_test_ctx->tctx->dom, params);
++    ret = setup_with_params(simple_test_ctx,
++                            simple_test_ctx->tctx->dom,
++                            params);
+     assert_int_equal(ret, EOK);
+ 
+-    req = simple_access_check_send(simple_test_ctx, simple_test_ctx->tctx->ev,
+-                                   simple_test_ctx->ctx, "u1@simple_test");
++    simple_test_ctx->pd->user = discard_const("u1@simple_test");
++    req = simple_access_handler_send(simple_test_ctx, simple_test_ctx->ctx,
++                                     simple_test_ctx->pd,
++                                     simple_test_ctx->params);
+     assert_non_null(req);
+-    tevent_req_set_callback(req, simple_access_check_done, simple_test_ctx);
++    tevent_req_set_callback(req, simple_access_handler_done, simple_test_ctx);
+ 
+     ret = test_ev_loop(simple_test_ctx->tctx);
+     assert_int_equal(ret, EOK);
+     assert_false(simple_test_ctx->access_granted);
+ 
+     simple_test_ctx->tctx->done = false;
+-    req = simple_access_check_send(simple_test_ctx, simple_test_ctx->tctx->ev,
+-                                   simple_test_ctx->ctx, "u3@simple_test");
++    simple_test_ctx->pd->user = discard_const("u3@simple_test");
++    req = simple_access_handler_send(simple_test_ctx, simple_test_ctx->ctx,
++                                     simple_test_ctx->pd,
++                                     simple_test_ctx->params);
+     assert_non_null(req);
+-    tevent_req_set_callback(req, simple_access_check_done, simple_test_ctx);
++    tevent_req_set_callback(req, simple_access_handler_done, simple_test_ctx);
+ 
+     ret = test_ev_loop(simple_test_ctx->tctx);
+     assert_int_equal(ret, EOK);
+@@ -584,6 +604,118 @@ static void test_group_allow_case_insensitive(void **state)
+     run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, true);
+ }
+ 
++static void test_unparseable_allow_user(void **state)
++{
++    errno_t ret;
++    struct simple_test_ctx *simple_test_ctx = \
++                            talloc_get_type(*state, struct simple_test_ctx);
++    struct sss_test_conf_param params[] = {
++        { "simple_allow_users", "u1, user@no.such.domain" },
++        { NULL, NULL },
++    };
++
++    ret = setup_with_params(simple_test_ctx,
++                            simple_test_ctx->tctx->dom,
++                            params);
++    assert_int_equal(ret, EOK);
++
++    /* Case-sensitive domain, wrong case */
++    simple_test_ctx->tctx->done = false;
++    simple_test_ctx->tctx->dom->case_sensitive = false;
++    /* A user that would normally be denied access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false);
++    /* A user that would normally be allowed access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false);
++}
++
++static void test_unparseable_deny_user(void **state)
++{
++    errno_t ret;
++    struct simple_test_ctx *simple_test_ctx = \
++                            talloc_get_type(*state, struct simple_test_ctx);
++    struct sss_test_conf_param params[] = {
++        { "simple_deny_users", "u2, user@no.such.domain" },
++        { NULL, NULL },
++    };
++
++    ret = setup_with_params(simple_test_ctx,
++                            simple_test_ctx->tctx->dom,
++                            params);
++    assert_int_equal(ret, EOK);
++
++    /* Case-sensitive domain, wrong case */
++    simple_test_ctx->tctx->done = false;
++    simple_test_ctx->tctx->dom->case_sensitive = false;
++    /* A user that would normally be denied access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false);
++    /* A user that would normally be allowed access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false);
++}
++
++static void test_unparseable_allow_group(void **state)
++{
++    errno_t ret;
++    struct simple_test_ctx *simple_test_ctx = \
++                            talloc_get_type(*state, struct simple_test_ctx);
++    struct sss_test_conf_param params[] = {
++        { "simple_allow_groups", "g1, group@no.such.domain" },
++        { NULL, NULL },
++    };
++
++    ret = setup_with_params(simple_test_ctx,
++                            simple_test_ctx->tctx->dom,
++                            params);
++    assert_int_equal(ret, EOK);
++
++    /* Case-sensitive domain, wrong case */
++    simple_test_ctx->tctx->done = false;
++    simple_test_ctx->tctx->dom->case_sensitive = false;
++    /* A group that would normally be denied access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false);
++    /* A group that would normally be allowed access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false);
++}
++
++static void test_unparseable_deny_group(void **state)
++{
++    errno_t ret;
++    struct simple_test_ctx *simple_test_ctx = \
++                            talloc_get_type(*state, struct simple_test_ctx);
++    struct sss_test_conf_param params[] = {
++        { "simple_deny_groups", "g2, group@no.such.domain" },
++        { NULL, NULL },
++    };
++
++    ret = setup_with_params(simple_test_ctx,
++                            simple_test_ctx->tctx->dom,
++                            params);
++    assert_int_equal(ret, EOK);
++
++    /* Case-sensitive domain, wrong case */
++    simple_test_ctx->tctx->done = false;
++    simple_test_ctx->tctx->dom->case_sensitive = false;
++    /* A group that would normally be denied access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false);
++    /* A group that would normally be allowed access will be denied because
++     * the access list can't be parsed
++     */
++    run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false);
++}
++
+ static void test_group_space(void **state)
+ {
+     errno_t ret;
+@@ -659,6 +791,18 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(test_group_space,
+                                         simple_group_test_setup,
+                                         simple_group_test_teardown),
++        cmocka_unit_test_setup_teardown(test_unparseable_allow_user,
++                                        simple_test_setup,
++                                        simple_test_teardown),
++        cmocka_unit_test_setup_teardown(test_unparseable_deny_user,
++                                        simple_test_setup,
++                                        simple_test_teardown),
++        cmocka_unit_test_setup_teardown(test_unparseable_allow_group,
++                                        simple_test_setup,
++                                        simple_test_teardown),
++        cmocka_unit_test_setup_teardown(test_unparseable_deny_group,
++                                        simple_test_setup,
++                                        simple_test_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can decide if -d 0 was used. */
+-- 
+2.4.11
+
diff --git a/SOURCES/0087-DYNDNS-remove-zone-command.patch b/SOURCES/0087-DYNDNS-remove-zone-command.patch
deleted file mode 100644
index db57a1b..0000000
--- a/SOURCES/0087-DYNDNS-remove-zone-command.patch
+++ /dev/null
@@ -1,213 +0,0 @@
-From 17f136d85a5ce0e2a6fa71d32eb2b048853b4800 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Thu, 23 Jul 2015 05:30:34 -0400
-Subject: [PATCH 87/90] DYNDNS: remove zone command
-
-Remove zone command from message to nsupsate. This command is generally
-used to hint nsupdate. In correctly configured environment such
-information should be obtained via DNS.
-
-If DNS does not provide necessary information we give other hints.
-
-For more details see:
-https://fedorahosted.org/sssd/wiki/DesignDocs/DDNSMessagesUpdate
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2495
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 4f2a07c422fa357ef6651bca8c48b8005280fa1d)
----
- src/providers/ad/ad_dyndns.c     |  1 -
- src/providers/dp_dyndns.c        | 12 +-----------
- src/providers/dp_dyndns.h        |  2 +-
- src/providers/ipa/ipa_dyndns.c   | 16 ----------------
- src/providers/ldap/sdap_dyndns.c | 13 +------------
- src/providers/ldap/sdap_dyndns.h |  1 -
- 6 files changed, 3 insertions(+), 42 deletions(-)
-
-diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
-index aac7d8b0a170e07cba0cd150a6f19c538948d657..5f8638128b966f0981c85a44e50e3201c73d561e 100644
---- a/src/providers/ad/ad_dyndns.c
-+++ b/src/providers/ad/ad_dyndns.c
-@@ -233,7 +233,6 @@ ad_dyndns_update_send(struct ad_options *ctx)
-                                                        DP_OPT_DYNDNS_IFACE),
-                                      dp_opt_get_string(ctx->basic,
-                                                        AD_HOSTNAME),
--                                     NULL,
-                                      dp_opt_get_string(ctx->basic,
-                                                        AD_KRB5_REALM),
-                                      state->servername,
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 3171e6909e5f92a98cd506278e6e8c3418b979fe..ae3f913ee392a6513f75aab497e7f2d784784748 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -436,7 +436,7 @@ fail:
- 
- errno_t
- be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
--                           const char *zone, const char *servername,
-+                           const char *servername,
-                            const char *hostname, const unsigned int ttl,
-                            uint8_t remove_af, struct sss_iface_addr *addresses,
-                            char **_update_msg)
-@@ -459,16 +459,6 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
-         goto done;
-     }
- 
--    if (zone) {
--        DEBUG(SSSDBG_FUNC_DATA,
--              "Setting the zone explicitly to [%s].\n", zone);
--        update_msg = talloc_asprintf_append(update_msg, "zone %s.\n", zone);
--        if (update_msg == NULL) {
--            ret = ENOMEM;
--            goto done;
--        }
--    }
--
-     update_msg = nsupdate_msg_add_fwd(update_msg, addresses, hostname,
-                                       ttl, remove_af);
-     if (update_msg == NULL) {
-diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
-index 3cc8d122646590365a3fb6dafa6a0f699b620ad9..9f72331b6fd68e17e9eb91505a13fc839d3f54e1 100644
---- a/src/providers/dp_dyndns.h
-+++ b/src/providers/dp_dyndns.h
-@@ -89,7 +89,7 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
- 
- errno_t
- be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
--                           const char *zone, const char *servername,
-+                           const char *servername,
-                            const char *hostname, const unsigned int ttl,
-                            uint8_t remove_af, struct sss_iface_addr *addresses,
-                            char **_update_msg);
-diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
-index 83009ff2a08cb8e4ae2b7a1e89039539b23b6d79..e7026eb275798f0ed21fb8490295b6e6d419d8ee 100644
---- a/src/providers/ipa/ipa_dyndns.c
-+++ b/src/providers/ipa/ipa_dyndns.c
-@@ -153,9 +153,7 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
-     struct ipa_dyndns_update_state *state;
-     struct tevent_req *req, *subreq;
-     struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
--    char *dns_zone;
-     const char *servername;
--    int i;
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "Performing update\n");
- 
-@@ -175,19 +173,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
-     }
-     state->ipa_ctx->dyndns_ctx->last_refresh = time(NULL);
- 
--    dns_zone = dp_opt_get_string(ctx->basic, IPA_DOMAIN);
--    if (!dns_zone) {
--        ret = EIO;
--        goto done;
--    }
--
--    /* The DNS zone for IPA is the lower-case
--     * version of the IPA domain
--     */
--    for (i = 0; dns_zone[i] != '\0'; i++) {
--        dns_zone[i] = tolower(dns_zone[i]);
--    }
--
-     if (strncmp(ctx->service->sdap->uri,
-                 "ldap://", 7) != 0) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected format of LDAP URI.\n");
-@@ -209,7 +194,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
-                                                        DP_OPT_DYNDNS_IFACE),
-                                      dp_opt_get_string(ctx->basic,
-                                                        IPA_HOSTNAME),
--                                     dns_zone,
-                                      dp_opt_get_string(ctx->basic,
-                                                        IPA_KRB5_REALM),
-                                      servername,
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index 0f0e63ee2259d017c3e94afca5f3148f4fc2ce04..f0e3dd855005d00ea19cb5dc283375f58b0d2cca 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -47,7 +47,6 @@ struct sdap_dyndns_update_state {
-     struct dp_option *opts;
- 
-     const char *hostname;
--    const char *dns_zone;
-     const char *realm;
-     const char *servername;
-     int ttl;
-@@ -61,7 +60,6 @@ struct sdap_dyndns_update_state {
-     enum be_nsupdate_auth auth_type;
-     bool use_server_with_nsupdate;
-     char *update_msg;
--    size_t pass_num;
- };
- 
- static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq);
-@@ -82,7 +80,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-                         enum be_nsupdate_auth auth_type,
-                         const char *ifname,
-                         const char *hostname,
--                        const char *dns_zone,
-                         const char *realm,
-                         const char *servername,
-                         const int ttl,
-@@ -101,7 +98,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     state->check_diff = check_diff;
-     state->update_ptr = dp_opt_get_bool(opts, DP_OPT_DYNDNS_UPDATE_PTR);
-     state->hostname = hostname;
--    state->dns_zone = dns_zone;
-     state->realm = realm;
-     state->servername = servername;
-     state->use_server_with_nsupdate = false;
-@@ -110,7 +106,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     state->ev = ev;
-     state->opts = opts;
-     state->auth_type = auth_type;
--    state->pass_num = 0;
- 
-     /* fallback servername is overriden by user option */
-     conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
-@@ -317,7 +312,6 @@ sdap_dyndns_update_step(struct tevent_req *req)
-     struct sdap_dyndns_update_state *state;
-     const char *servername;
-     struct tevent_req *subreq;
--    const char *dns_zone = NULL;
- 
-     state = tevent_req_data(req, struct sdap_dyndns_update_state);
- 
-@@ -327,11 +321,7 @@ sdap_dyndns_update_step(struct tevent_req *req)
-         servername = state->servername;
-     }
- 
--    if (state->pass_num > 0) {
--        dns_zone = state->dns_zone;
--    }
--
--    ret = be_nsupdate_create_fwd_msg(state, state->realm, dns_zone,
-+    ret = be_nsupdate_create_fwd_msg(state, state->realm,
-                                      servername, state->hostname,
-                                      state->ttl, state->remove_af,
-                                      state->addresses,
-@@ -340,7 +330,6 @@ sdap_dyndns_update_step(struct tevent_req *req)
-         DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
-         return ret;
-     }
--    state->pass_num++;
- 
-     /* Fork a child process to perform the DNS update */
-     subreq = be_nsupdate_send(state, state->ev, state->auth_type,
-diff --git a/src/providers/ldap/sdap_dyndns.h b/src/providers/ldap/sdap_dyndns.h
-index 7aaff5d2c69fbda55fff5208c97b953b970c55cc..a9481b7941be6af0f172afce5f4d54f57ef85e48 100644
---- a/src/providers/ldap/sdap_dyndns.h
-+++ b/src/providers/ldap/sdap_dyndns.h
-@@ -39,7 +39,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-                         enum be_nsupdate_auth auth_type,
-                         const char *ifname,
-                         const char *hostname,
--                        const char *dns_zone,
-                         const char *realm,
-                         const char *servername,
-                         const int ttl,
--- 
-2.4.3
-
diff --git a/SOURCES/0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch b/SOURCES/0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch
new file mode 100644
index 0000000..d36a75a
--- /dev/null
+++ b/SOURCES/0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch
@@ -0,0 +1,91 @@
+From 662af3eaefdb11aff02947c0d34d31ba37c7b09c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Fri, 29 Jul 2016 16:09:16 +0200
+Subject: [PATCH 87/87] gpo: gPCMachineExtensionNames with just whitespaces
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3114
+
+We failed GPO procesing if the gPCMachineExtensionNames
+attribute contained just whitespaces. This coused
+failures in some server settings.
+
+Comment from Alexander Bokovoy quoting:
+
+You should use MS-GPOL spec. 2.2.4 'GPO Search' section says that when
+processing gPCMachineExtensionNames, "Group Policy processing terminates
+at the first <CSE GUIDn> out of sequence."
+Since ' ' (space only) does not fall into defined syntax for
+gPCMachineExtensionNames, this Group Policy processing is stopped and
+its CSE GUIDs are set to 'empty list'.
+
+Because of the 3.2.5.1.10 'Extension Protocol Sequences' language
+------------------------------------------------------------------------
+The Group Policy client MUST evaluate the subset of the abstract element
+Filtered GPO list separately for each Group Policy extension by
+including in the subset only those GPOs whose gPCUserExtensionNames (for
+user policy mode) or gPCMachineExtensionNames (for computer policy mode)
+attributes contain CSE GUID that correspond to the Group Policy
+extension. If the CSE GUID corresponding to the Group Policy extension
+is present in Extension List, it is invoked using the
+Implementation Identifier field. Applicability is determined as
+specified in section 3.2.1.5. The Group Policy Registry Extension MUST
+always execute first. All other applicable Group Policy extensions in
+the Extension List MUST be loaded and executed in Extension List order.
+A failure in any Group Policy extension sequence MUST NOT affect the
+execution of other Group Policy extensions.
+-------------------------------------------------------------------------
+
+I think we can practically treat wrong content of
+gPCMachineExtensionNames (and gPCUserExtensionNames) as inability of the
+GPO to pass through the Filtered GPO list. Thus, the GPO would be
+ignored.
+
+Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ad/ad_gpo.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index f609d28136918adfe6a8d5e95319b27ffcab79c0..63c68ce35922ca0407ae6ea32c0a78100e14504b 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3765,6 +3765,24 @@ done:
+    }
+ }
+ 
++static bool machine_ext_names_is_blank(char *attr_value)
++{
++    char *ptr;
++
++    if (attr_value == NULL) {
++        return true;
++    }
++
++    ptr = attr_value;
++    for (; *ptr != '\0'; ptr++) {
++        if (!isspace(*ptr)) {
++            return false;
++        }
++    }
++
++    return true;
++}
++
+ static errno_t
+ ad_gpo_sd_process_attrs(struct tevent_req *req,
+                         char *smb_host,
+@@ -3880,7 +3898,8 @@ ad_gpo_sd_process_attrs(struct tevent_req *req,
+         goto done;
+     }
+ 
+-    if ((ret == ENOENT) || (el->num_values == 0)) {
++    if ((ret == ENOENT) || (el->num_values == 0)
++            || machine_ext_names_is_blank((char *) el[0].values[0].data)) {
+         /*
+          * if gpo has no machine_ext_names (which is perfectly valid: it could
+          * have only user_ext_names, for example), we continue to next gpo
+-- 
+2.4.11
+
diff --git a/SOURCES/0088-DYNDNS-rename-field-of-sdap_dyndns_update_state.patch b/SOURCES/0088-DYNDNS-rename-field-of-sdap_dyndns_update_state.patch
deleted file mode 100644
index d8bae19..0000000
--- a/SOURCES/0088-DYNDNS-rename-field-of-sdap_dyndns_update_state.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-From 9941803301b127d9326283b7eee9ad29f462574f Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Thu, 23 Jul 2015 09:52:47 -0400
-Subject: [PATCH 88/90] DYNDNS: rename field of sdap_dyndns_update_state
-
-Rename 'use_server_with_nsupdate' to more general name 'fallback_mode'.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2495
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 76604931b11594394a05df10f8370a1b8bb3e54b)
----
- src/providers/ldap/sdap_dyndns.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index f0e3dd855005d00ea19cb5dc283375f58b0d2cca..2a179fd1b5e88bdf2442657ff6fa1dcc55417467 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -58,7 +58,7 @@ struct sdap_dyndns_update_state {
-     bool update_ptr;
-     bool check_diff;
-     enum be_nsupdate_auth auth_type;
--    bool use_server_with_nsupdate;
-+    bool fallback_mode;
-     char *update_msg;
- };
- 
-@@ -100,7 +100,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     state->hostname = hostname;
-     state->realm = realm;
-     state->servername = servername;
--    state->use_server_with_nsupdate = false;
-+    state->fallback_mode = false;
-     state->ttl = ttl;
-     state->be_res = be_ctx->be_res;
-     state->ev = ev;
-@@ -316,7 +316,7 @@ sdap_dyndns_update_step(struct tevent_req *req)
-     state = tevent_req_data(req, struct sdap_dyndns_update_state);
- 
-     servername = NULL;
--    if (state->use_server_with_nsupdate == true &&
-+    if (state->fallback_mode == true &&
-         state->servername) {
-         servername = state->servername;
-     }
-@@ -359,9 +359,9 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         /* If the update didn't succeed, we can retry using the server name */
--        if (state->use_server_with_nsupdate == false && state->servername &&
-+        if (state->fallback_mode == false && state->servername &&
-             WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
--            state->use_server_with_nsupdate = true;
-+            state->fallback_mode = true;
-             DEBUG(SSSDBG_MINOR_FAILURE,
-                    "nsupdate failed, retrying with server name\n");
-             ret = sdap_dyndns_update_step(req);
-@@ -400,7 +400,7 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
-     state = tevent_req_data(req, struct sdap_dyndns_update_state);
- 
-     servername = NULL;
--    if (state->use_server_with_nsupdate == true &&
-+    if (state->fallback_mode == true &&
-         state->servername) {
-         servername = state->servername;
-     }
-@@ -443,9 +443,9 @@ sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         /* If the update didn't succeed, we can retry using the server name */
--        if (state->use_server_with_nsupdate == false && state->servername &&
-+        if (state->fallback_mode == false && state->servername &&
-             WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
--            state->use_server_with_nsupdate = true;
-+            state->fallback_mode = true;
-             DEBUG(SSSDBG_MINOR_FAILURE,
-                    "nsupdate failed, retrying with server name\n");
-             ret = sdap_dyndns_update_ptr_step(req);
--- 
-2.4.3
-
diff --git a/SOURCES/0088-sss_ini-Change-debug-level-of-config-error-msgs.patch b/SOURCES/0088-sss_ini-Change-debug-level-of-config-error-msgs.patch
new file mode 100644
index 0000000..1ed8612
--- /dev/null
+++ b/SOURCES/0088-sss_ini-Change-debug-level-of-config-error-msgs.patch
@@ -0,0 +1,44 @@
+From d049533953665fa3494a4932aeae7705ff84e107 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 27 Jul 2016 14:14:33 +0200
+Subject: [PATCH 088/102] sss_ini: Change debug level of config error msgs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Syntax errors in configuration files
+prevent SSSD or sssctl to start completely.
+It would be good to display these errors
+by default with the highest level.
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+(cherry picked from commit 9dc081500979616f9af623ebe2d52837c211759f)
+---
+ src/util/sss_ini.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
+index d9bc46ad71fa820fd5f462cf71036213171fa92a..e56006c05555d6e0c5e726e83771abce5a72b139 100644
+--- a/src/util/sss_ini.c
++++ b/src/util/sss_ini.c
+@@ -182,7 +182,7 @@ int sss_ini_get_mtime(struct sss_ini_initdata *init_data,
+ 
+ /* Print ini_config errors */
+ 
+-void sss_ini_config_print_errors(char **error_list)
++static void sss_ini_config_print_errors(char **error_list)
+ {
+ #ifdef HAVE_LIBINI_CONFIG_V1
+     unsigned count = 0;
+@@ -192,7 +192,7 @@ void sss_ini_config_print_errors(char **error_list)
+     }
+ 
+     while (error_list[count]) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "%s\n", error_list[count]);
++        DEBUG(SSSDBG_FATAL_FAILURE, "%s\n", error_list[count]);
+         count++;
+     }
+ #endif
+-- 
+2.4.11
+
diff --git a/SOURCES/0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch b/SOURCES/0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch
new file mode 100644
index 0000000..6c52b00
--- /dev/null
+++ b/SOURCES/0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch
@@ -0,0 +1,77 @@
+From c54b38573a93d1176a44935ba310e590904edb92 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 12 Aug 2016 13:23:16 +0200
+Subject: [PATCH 089/102] CONFIG: full_name_format is an allowed option for all
+ domains
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit cc4d1af16820b15595b60c3df15220fb852eb897)
+---
+ src/config/SSSDConfig/__init__.py.in | 1 +
+ src/config/SSSDConfigTest.py         | 2 ++
+ src/config/cfg_rules.ini             | 1 +
+ src/config/etc/sssd.api.conf         | 1 +
+ 4 files changed, 5 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 7856c4c6b2d675b7f7f0f5f2048086044e8fb5ea..3114d1da9fe8e833ae4050ac343ba2763dc56e68 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -163,6 +163,7 @@ option_strings = {
+     'subdomain_refresh_interval' : _('How often should subdomains list be refreshed'),
+     'subdomain_inherit' : _('List of options that should be inherited into a subdomain'),
+     'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'),
++    'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'),
+ 
+     # [provider/ipa]
+     'ipa_domain' : _('IPA domain'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 332d8702d983b6ec8bf12ec781a1bbf296b552e0..bfb247ac45f752397000d43c54a20e57c6fbd9a5 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -560,6 +560,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'realmd_tags',
+             'subdomain_refresh_interval',
+             'subdomain_inherit',
++            'full_name_format',
+             'cached_auth_timeout']
+ 
+         self.assertTrue(type(options) == dict,
+@@ -927,6 +928,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'realmd_tags',
+             'subdomain_refresh_interval',
+             'subdomain_inherit',
++            'full_name_format',
+             'cached_auth_timeout']
+ 
+         self.assertTrue(type(options) == dict,
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 09f53fa41eb2904f11a78af333b6d79619d2759c..febe4289832f3778b7e974ef4e8b3f6d9d8bffd8 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -287,6 +287,7 @@ option = subdomain_refresh_interval
+ option = subdomain_inherit
+ option = cached_auth_timeout
+ option = wildcard_limit
++option = full_name_format
+ 
+ #Entry cache timeouts
+ option = entry_cache_user_timeout
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index 737f0e149d56bd07b078cb83acbc43ea2ed3a057..2a43b8b68051c5133abc65a78f0d4a5561e760bd 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -147,6 +147,7 @@ realmd_tags = str, None, false
+ subdomain_refresh_interval = int, None, false
+ subdomain_inherit = str, None, false
+ cached_auth_timeout = int, None, false
++full_name_format = str, None, false
+ 
+ #Entry cache timeouts
+ entry_cache_user_timeout = int, None, false
+-- 
+2.4.11
+
diff --git a/SOURCES/0089-DYNDNS-remove-code-duplication.patch b/SOURCES/0089-DYNDNS-remove-code-duplication.patch
deleted file mode 100644
index 89270d9..0000000
--- a/SOURCES/0089-DYNDNS-remove-code-duplication.patch
+++ /dev/null
@@ -1,195 +0,0 @@
-From 194e127156332dcd29a7e2aa4a142b574e8b7eac Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Fri, 24 Jul 2015 08:24:48 -0400
-Subject: [PATCH 89/90] DYNDNS: remove code duplication
-
-Move copy pasted code for converting sockaddr_storage to string into
-function.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2495
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit b42bf6c0c01db08208fb81d8295a2909d307284a)
----
- src/providers/dp_dyndns.c | 99 +++++++++++++++++++++--------------------------
- src/util/util_errors.c    |  1 +
- src/util/util_errors.h    |  1 +
- 3 files changed, 46 insertions(+), 55 deletions(-)
-
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index ae3f913ee392a6513f75aab497e7f2d784784748..0577743cb2daca9c0e86b5beb6bf059ee7b5783f 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -58,6 +58,39 @@ void sss_iface_addr_concatenate(struct sss_iface_addr **list,
-     DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
- }
- 
-+static errno_t addr_to_str(struct sockaddr_storage *addr,
-+                           char *dst, size_t size)
-+{
-+    const void *src;
-+    const char *res;
-+    errno_t ret;
-+
-+    switch(addr->ss_family) {
-+    case AF_INET:
-+        src = &(((struct sockaddr_in *)addr)->sin_addr);
-+        break;
-+    case AF_INET6:
-+        src = &(((struct sockaddr_in6 *)addr)->sin6_addr);
-+        break;
-+    default:
-+        ret = ERR_ADDR_FAMILY_NOT_SUPPORTED;
-+        goto done;
-+    }
-+
-+    res = inet_ntop(addr->ss_family, src, dst, size);
-+    if (res == NULL) {
-+        ret = errno;
-+        DEBUG(SSSDBG_OP_FAILURE, "inet_ntop failed [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    return ret;
-+}
-+
- errno_t
- sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
-                                 struct sss_iface_addr *ifaddr_list,
-@@ -67,7 +100,6 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
-     size_t count;
-     int ai;
-     char **straddrs;
--    const char *ip;
-     char ip_addr[INET6_ADDRSTRLEN];
-     errno_t ret;
- 
-@@ -83,35 +115,17 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
- 
-     ai = 0;
-     DLIST_FOR_EACH(ifaddr, ifaddr_list) {
--        switch(ifaddr->addr->ss_family) {
--        case AF_INET:
--            errno = 0;
--            ip = inet_ntop(ifaddr->addr->ss_family,
--                           &(((struct sockaddr_in *)ifaddr->addr)->sin_addr),
--                           ip_addr, INET6_ADDRSTRLEN);
--            if (ip == NULL) {
--                ret = errno;
--                goto fail;
--            }
--            break;
- 
--        case AF_INET6:
--            errno = 0;
--            ip = inet_ntop(ifaddr->addr->ss_family,
--                           &(((struct sockaddr_in6 *)ifaddr->addr)->sin6_addr),
--                           ip_addr, INET6_ADDRSTRLEN);
--            if (ip == NULL) {
--                ret = errno;
--                goto fail;
--            }
--            break;
--
--        default:
--            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
-+        ret = addr_to_str(ifaddr->addr, ip_addr, INET6_ADDRSTRLEN);
-+        if (ret == ERR_ADDR_FAMILY_NOT_SUPPORTED) {
-             continue;
-+        } else if (ret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
-+                  ret, sss_strerror(ret));
-+            goto fail;
-         }
- 
--        straddrs[ai] = talloc_strdup(straddrs, ip);
-+        straddrs[ai] = talloc_strdup(straddrs, ip_addr);
-         if (straddrs[ai] == NULL) {
-             ret = ENOMEM;
-             goto fail;
-@@ -237,7 +251,6 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
- {
-     struct sss_iface_addr *new_record;
-     char ip_addr[INET6_ADDRSTRLEN];
--    const char *ip;
-     errno_t ret;
- 
-     /* Remove existing entries as needed */
-@@ -259,33 +272,10 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
-     }
- 
-     DLIST_FOR_EACH(new_record, addresses) {
--        switch(new_record->addr->ss_family) {
--        case AF_INET:
--            ip = inet_ntop(new_record->addr->ss_family,
--                           &(((struct sockaddr_in *)new_record->addr)->sin_addr),
--                           ip_addr, INET6_ADDRSTRLEN);
--            if (ip == NULL) {
--                ret = errno;
--                DEBUG(SSSDBG_OP_FAILURE,
--                      "inet_ntop failed [%d]: %s\n", ret, strerror(ret));
--                return NULL;
--            }
--            break;
--
--        case AF_INET6:
--            ip = inet_ntop(new_record->addr->ss_family,
--                           &(((struct sockaddr_in6 *)new_record->addr)->sin6_addr),
--                           ip_addr, INET6_ADDRSTRLEN);
--            if (ip == NULL) {
--                ret = errno;
--                DEBUG(SSSDBG_OP_FAILURE,
--                      "inet_ntop failed [%d]: %s\n", ret, strerror(ret));
--                return NULL;
--            }
--            break;
--
--        default:
--            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
-+        ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
-+                  ret, sss_strerror(ret));
-             return NULL;
-         }
- 
-@@ -298,7 +288,6 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
-         if (update_msg == NULL) {
-             return NULL;
-         }
--
-     }
- 
-     return talloc_asprintf_append(update_msg, "send\n");
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 0e288e3908bf03b4906bb449bd0f3445d22a303e..3041a1a28481aa8916bc1f5d972365e3c8007a4a 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -80,6 +80,7 @@ struct err_string error_to_str[] = {
-     { "Trusted forest root unknown" }, /* ERR_TRUST_FOREST_UNKNOWN */
-     { "p11_child failed" }, /* ERR_P11_CHILD */
-     { "Subdomain is inactive" }, /* ERR_SUBDOM_INACTIVE */
-+    { "Address family not supported" }, /* ERR_ADDR_FAMILY_NOT_SUPPORTED */
-     { "ERR_LAST" } /* ERR_LAST */
- };
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index da926db00121f569048ec515e95f0547ae6c4e35..660c370d600f6373d4515181cf88f62b42bcb7d7 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -102,6 +102,7 @@ enum sssd_errors {
-     ERR_TRUST_FOREST_UNKNOWN,
-     ERR_P11_CHILD,
-     ERR_SUBDOM_INACTIVE,
-+    ERR_ADDR_FAMILY_NOT_SUPPORTED,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch b/SOURCES/0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch
new file mode 100644
index 0000000..61b409a
--- /dev/null
+++ b/SOURCES/0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch
@@ -0,0 +1,77 @@
+From 92302f81c25bc2b5ce9dbc2236c671d591fe69e0 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 12 Aug 2016 16:41:21 +0200
+Subject: [PATCH 090/102] CONFIG: re_expression is an allowed option for all
+ domains
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 6d19051c50c10fc4de056ebb385c63ec0ed221cb)
+---
+ src/config/SSSDConfig/__init__.py.in | 1 +
+ src/config/SSSDConfigTest.py         | 2 ++
+ src/config/cfg_rules.ini             | 1 +
+ src/config/etc/sssd.api.conf         | 1 +
+ 4 files changed, 5 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 3114d1da9fe8e833ae4050ac343ba2763dc56e68..ac538788b9878dc2613cb48b7483d392cca41d47 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -164,6 +164,7 @@ option_strings = {
+     'subdomain_inherit' : _('List of options that should be inherited into a subdomain'),
+     'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'),
+     'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'),
++    're_expression' : _('Regex to parse username and domain'),
+ 
+     # [provider/ipa]
+     'ipa_domain' : _('IPA domain'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index bfb247ac45f752397000d43c54a20e57c6fbd9a5..00c688f1e57c5f481d3adba2fe0374145216bc33 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -561,6 +561,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'subdomain_refresh_interval',
+             'subdomain_inherit',
+             'full_name_format',
++            're_expression',
+             'cached_auth_timeout']
+ 
+         self.assertTrue(type(options) == dict,
+@@ -929,6 +930,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'subdomain_refresh_interval',
+             'subdomain_inherit',
+             'full_name_format',
++            're_expression',
+             'cached_auth_timeout']
+ 
+         self.assertTrue(type(options) == dict,
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index febe4289832f3778b7e974ef4e8b3f6d9d8bffd8..bd0116f334e2605e7671a208225761421511a75a 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -288,6 +288,7 @@ option = subdomain_inherit
+ option = cached_auth_timeout
+ option = wildcard_limit
+ option = full_name_format
++option = re_expression
+ 
+ #Entry cache timeouts
+ option = entry_cache_user_timeout
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index 2a43b8b68051c5133abc65a78f0d4a5561e760bd..5ac6f79521f5f776fc17319c3afb87d44961afca 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -148,6 +148,7 @@ subdomain_refresh_interval = int, None, false
+ subdomain_inherit = str, None, false
+ cached_auth_timeout = int, None, false
+ full_name_format = str, None, false
++re_expression = str, None, false
+ 
+ #Entry cache timeouts
+ entry_cache_user_timeout = int, None, false
+-- 
+2.4.11
+
diff --git a/SOURCES/0090-DDNS-execute-nsupdate-for-single-update-of-PTR-rec.patch b/SOURCES/0090-DDNS-execute-nsupdate-for-single-update-of-PTR-rec.patch
deleted file mode 100644
index 7883663..0000000
--- a/SOURCES/0090-DDNS-execute-nsupdate-for-single-update-of-PTR-rec.patch
+++ /dev/null
@@ -1,471 +0,0 @@
-From 514240c29da65f8bbfc6d17e225655a5ac0f1b3c Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Sat, 12 Sep 2015 09:09:35 -0400
-Subject: [PATCH 90/90] DDNS: execute nsupdate for single update of PTR rec
-
-nsupdate fails definitely if any of update request fails when GSSAPI is used.
-
-As tmp solution nsupdate is executed for each update.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2783
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit eeac17ebbe38f16deaa8599231cccfc97aaac85c)
----
- src/providers/dp_dyndns.c        | 128 ++++++++++++++++++++-------------------
- src/providers/dp_dyndns.h        |  13 +++-
- src/providers/ldap/sdap_dyndns.c | 121 ++++++++++++++++++++++++++++++++++--
- src/tests/cmocka/test_dyndns.c   |  29 +++++++++
- 4 files changed, 219 insertions(+), 72 deletions(-)
-
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 0577743cb2daca9c0e86b5beb6bf059ee7b5783f..50b087446f9437466de355e4d72b39a69512da03 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -52,6 +52,25 @@ struct sss_iface_addr {
-     struct sockaddr_storage *addr;
- };
- 
-+struct sockaddr_storage*
-+sss_iface_addr_get_address(struct sss_iface_addr *address)
-+{
-+    if (address == NULL) {
-+        return NULL;
-+    }
-+
-+    return address->addr;
-+}
-+
-+struct sss_iface_addr *sss_iface_addr_get_next(struct sss_iface_addr *address)
-+{
-+    if (address) {
-+        return address->next;
-+    }
-+
-+    return NULL;
-+}
-+
- void sss_iface_addr_concatenate(struct sss_iface_addr **list,
-                                 struct sss_iface_addr *list2)
- {
-@@ -293,80 +312,63 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
-     return talloc_asprintf_append(update_msg, "send\n");
- }
- 
--static char *
--nsupdate_msg_add_ptr(char *update_msg, struct sss_iface_addr *addresses,
--                     const char *hostname, int ttl, uint8_t remove_af,
--                     struct sss_iface_addr *old_addresses)
-+static uint8_t *nsupdate_convert_address(struct sockaddr_storage *add_address)
-+{
-+    uint8_t *addr;
-+
-+    switch(add_address->ss_family) {
-+    case AF_INET:
-+        addr = (uint8_t *) &((struct sockaddr_in *) add_address)->sin_addr;
-+        break;
-+    case AF_INET6:
-+        addr = (uint8_t *) &((struct sockaddr_in6 *) add_address)->sin6_addr;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
-+        addr = NULL;
-+        break;
-+    }
-+
-+    return addr;
-+}
-+
-+static char *nsupdate_msg_add_ptr(char *update_msg,
-+                                  struct sockaddr_storage *address,
-+                                  const char *hostname,
-+                                  int ttl,
-+                                  bool delete)
- {
--    struct sss_iface_addr *new_record, *old_record;
-     char *strptr;
-     uint8_t *addr;
- 
--    DLIST_FOR_EACH(old_record, old_addresses) {
--        switch(old_record->addr->ss_family) {
--        case AF_INET:
--            if (!(remove_af & DYNDNS_REMOVE_A)) {
--                continue;
--            }
--            addr = (uint8_t *) &((struct sockaddr_in *) old_record->addr)->sin_addr;
--            break;
--        case AF_INET6:
--            if (!(remove_af & DYNDNS_REMOVE_AAAA)) {
--                continue;
--            }
--            addr = (uint8_t *) &((struct sockaddr_in6 *) old_record->addr)->sin6_addr;
--            break;
--        default:
--            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
--            return NULL;
--        }
-+    addr = nsupdate_convert_address(address);
-+    if (addr == NULL) {
-+        return NULL;
-+    }
- 
--        strptr = resolv_get_string_ptr_address(update_msg, old_record->addr->ss_family,
--                                               addr);
--        if (strptr == NULL) {
--            return NULL;
--        }
-+    strptr = resolv_get_string_ptr_address(update_msg, address->ss_family,
-+                                           addr);
-+    if (strptr == NULL) {
-+        return NULL;
-+    }
- 
-+    if (delete) {
-         /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
-         update_msg = talloc_asprintf_append(update_msg,
-                                             "update delete %s in PTR\n"
-                                             "send\n",
-                                             strptr);
--        talloc_free(strptr);
--        if (update_msg == NULL) {
--            return NULL;
--        }
--    }
--
--    /* example: update add 11.78.16.10.in-addr.arpa. 85000 in PTR testvm.example.com */
--    DLIST_FOR_EACH(new_record, addresses) {
--        switch(new_record->addr->ss_family) {
--        case AF_INET:
--            addr = (uint8_t *) &((struct sockaddr_in *) new_record->addr)->sin_addr;
--            break;
--        case AF_INET6:
--            addr = (uint8_t *) &((struct sockaddr_in6 *) new_record->addr)->sin6_addr;
--            break;
--        default:
--            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
--            return NULL;
--        }
--
--        strptr = resolv_get_string_ptr_address(update_msg, new_record->addr->ss_family,
--                                               addr);
--        if (strptr == NULL) {
--            return NULL;
--        }
--
-+    } else {
-         /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
-         update_msg = talloc_asprintf_append(update_msg,
-                                             "update add %s %d in PTR %s.\n"
-                                             "send\n",
-                                             strptr, ttl, hostname);
--        talloc_free(strptr);
--        if (update_msg == NULL) {
--            return NULL;
--        }
-+    }
-+
-+    talloc_free(strptr);
-+    if (update_msg == NULL) {
-+        return NULL;
-     }
- 
-     return update_msg;
-@@ -471,9 +473,9 @@ done:
- errno_t
- be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
-                            const char *servername, const char *hostname,
--                           const unsigned int ttl, uint8_t remove_af,
--                           struct sss_iface_addr *addresses,
--                           struct sss_iface_addr *old_addresses,
-+                           const unsigned int ttl,
-+                           struct sockaddr_storage *address,
-+                           bool delete,
-                            char **_update_msg)
- {
-     errno_t ret;
-@@ -490,8 +492,8 @@ be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
-         goto done;
-     }
- 
--    update_msg = nsupdate_msg_add_ptr(update_msg, addresses, hostname,
--                                      ttl, remove_af, old_addresses);
-+    update_msg = nsupdate_msg_add_ptr(update_msg, address, hostname, ttl,
-+                                      delete);
-     if (update_msg == NULL) {
-         ret = ENOMEM;
-         goto done;
-diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
-index 9f72331b6fd68e17e9eb91505a13fc839d3f54e1..9f39e5d48ed46e69d4052f2139ea5f13b9e5d12c 100644
---- a/src/providers/dp_dyndns.h
-+++ b/src/providers/dp_dyndns.h
-@@ -97,9 +97,9 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
- errno_t
- be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
-                            const char *servername, const char *hostname,
--                           const unsigned int ttl, uint8_t remove_af,
--                           struct sss_iface_addr *addresses,
--                           struct sss_iface_addr *old_addresses,
-+                           const unsigned int ttl,
-+                           struct sockaddr_storage *address,
-+                           bool delete,
-                            char **_update_msg);
- 
- /* Returns:
-@@ -133,4 +133,11 @@ errno_t
- sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
-                             struct sockaddr *ss,
-                             struct sss_iface_addr **_iface_addrs);
-+
-+struct sss_iface_addr *
-+sss_iface_addr_get_next(struct sss_iface_addr *address);
-+
-+struct sockaddr_storage*
-+sss_iface_addr_get_address(struct sss_iface_addr *address);
-+
- #endif /* DP_DYNDNS_H_ */
-diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
-index 2a179fd1b5e88bdf2442657ff6fa1dcc55417467..3a52a11d1e1c86ee7b26cf6affd81f7cf1bb7d03 100644
---- a/src/providers/ldap/sdap_dyndns.c
-+++ b/src/providers/ldap/sdap_dyndns.c
-@@ -60,6 +60,8 @@ struct sdap_dyndns_update_state {
-     enum be_nsupdate_auth auth_type;
-     bool fallback_mode;
-     char *update_msg;
-+    struct sss_iface_addr *ptr_addr_iter;
-+    bool del_phase;
- };
- 
- static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq);
-@@ -70,6 +72,12 @@ static errno_t sdap_dyndns_update_step(struct tevent_req *req);
- static errno_t sdap_dyndns_update_ptr_step(struct tevent_req *req);
- static void sdap_dyndns_update_done(struct tevent_req *subreq);
- static void sdap_dyndns_update_ptr_done(struct tevent_req *subreq);
-+static errno_t
-+sdap_dyndns_next_ptr_record(struct sdap_dyndns_update_state *state,
-+                            struct tevent_req *req);
-+static struct sss_iface_addr*
-+sdap_get_address_to_delete(struct sss_iface_addr *address_it,
-+                           uint8_t remove_af);
- 
- struct tevent_req *
- sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-@@ -106,6 +114,8 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
-     state->ev = ev;
-     state->opts = opts;
-     state->auth_type = auth_type;
-+    state->ptr_addr_iter = NULL;
-+    state->del_phase = true;
- 
-     /* fallback servername is overriden by user option */
-     conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
-@@ -381,6 +391,16 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
-     }
- 
-     talloc_free(state->update_msg);
-+
-+    /* init iterator for addresses to be deleted */
-+    state->ptr_addr_iter = sdap_get_address_to_delete(state->dns_addrlist,
-+                                                      state->remove_af);
-+    if (state->ptr_addr_iter == NULL) {
-+        /* init iterator for addresses to be added */
-+        state->del_phase = false;
-+        state->ptr_addr_iter = state->addresses;
-+    }
-+
-     ret = sdap_dyndns_update_ptr_step(req);
-     if (ret != EOK) {
-         tevent_req_error(req, ret);
-@@ -389,6 +409,50 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
-     /* Execution will resume in sdap_dyndns_update_ptr_done */
- }
- 
-+
-+static bool remove_addr(int address_family, uint8_t remove_af)
-+{
-+    bool ret = false;
-+
-+    switch(address_family) {
-+    case AF_INET:
-+        if (remove_af & DYNDNS_REMOVE_A) {
-+            ret = true;
-+        }
-+        break;
-+    case AF_INET6:
-+        if (remove_af & DYNDNS_REMOVE_AAAA) {
-+            ret = true;
-+        }
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
-+        ret = false;
-+    }
-+
-+    return ret;
-+}
-+
-+static struct sss_iface_addr*
-+sdap_get_address_to_delete(struct sss_iface_addr *address_it,
-+                           uint8_t remove_af)
-+{
-+    struct sockaddr_storage* address;
-+
-+    while (address_it != NULL) {
-+        address = sss_iface_addr_get_address(address_it);
-+
-+        /* skip addresses that are not to be deleted */
-+        if (remove_addr(address->ss_family, remove_af)) {
-+            break;
-+        }
-+
-+        address_it = sss_iface_addr_get_next(address_it);
-+    }
-+
-+    return address_it;
-+}
-+
- static errno_t
- sdap_dyndns_update_ptr_step(struct tevent_req *req)
- {
-@@ -396,6 +460,7 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
-     struct sdap_dyndns_update_state *state;
-     const char *servername;
-     struct tevent_req *subreq;
-+    struct sockaddr_storage *address;
- 
-     state = tevent_req_data(req, struct sdap_dyndns_update_state);
- 
-@@ -405,11 +470,14 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
-         servername = state->servername;
-     }
- 
--    ret = be_nsupdate_create_ptr_msg(state, state->realm,
--                                     servername, state->hostname,
--                                     state->ttl, state->remove_af,
--                                     state->addresses, state->dns_addrlist,
--                                     &state->update_msg);
-+    address = sss_iface_addr_get_address(state->ptr_addr_iter);
-+    if (address == NULL) {
-+        return EIO;
-+    }
-+
-+    ret = be_nsupdate_create_ptr_msg(state, state->realm, servername,
-+                                     state->hostname, state->ttl, address,
-+                                     state->del_phase, &state->update_msg);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
-         return ret;
-@@ -454,13 +522,55 @@ sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
-             }
-         }
- 
-+        ret = sdap_dyndns_next_ptr_record(state, req);
-+        if (ret == EAGAIN) {
-+            return;
-+        }
-+
-         tevent_req_error(req, ret);
-         return;
-     }
- 
-+    ret = sdap_dyndns_next_ptr_record(state, req);
-+    if (ret == EAGAIN) {
-+        return;
-+    }
-+
-     tevent_req_done(req);
- }
- 
-+static errno_t
-+sdap_dyndns_next_ptr_record(struct sdap_dyndns_update_state *state,
-+                            struct tevent_req *req)
-+{
-+    errno_t ret;
-+
-+    if (state->del_phase) {
-+        /* iterate to next address to delete */
-+        state->ptr_addr_iter = sdap_get_address_to_delete(
-+            sss_iface_addr_get_next(state->ptr_addr_iter), state->remove_af);
-+        if (state->ptr_addr_iter == NULL) {
-+            /* init iterator for addresses to be added */
-+            state->del_phase = false;
-+            state->ptr_addr_iter = state->addresses;
-+        }
-+    } else {
-+        /* iterate to next address to add */
-+        state->ptr_addr_iter = sss_iface_addr_get_next(state->ptr_addr_iter);
-+    }
-+
-+    if (state->ptr_addr_iter != NULL) {
-+
-+        state->fallback_mode = false;
-+        ret = sdap_dyndns_update_ptr_step(req);
-+        if (ret == EOK) {
-+            return EAGAIN;
-+        }
-+    }
-+
-+    return EOK;
-+}
-+
- errno_t
- sdap_dyndns_update_recv(struct tevent_req *req)
- {
-@@ -755,7 +865,6 @@ fail:
-     return req;
- }
- 
--
- static void
- sdap_dyndns_timer_conn_done(struct tevent_req *subreq)
- {
-diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
-index 8118e9438e89465674155c11f4523d2313f6a59c..0a2fd1227c84c7783207444e21269026d268f993 100644
---- a/src/tests/cmocka/test_dyndns.c
-+++ b/src/tests/cmocka/test_dyndns.c
-@@ -200,6 +200,32 @@ void will_return_getifaddrs(const char *ifname, const char *straddr,
-     }
- }
- 
-+void dyndns_test_sss_iface_addr_get_misc(void **state)
-+{
-+    struct sss_iface_addr addrs[3];
-+    struct sockaddr_storage ss[3];
-+
-+    addrs[0].prev = NULL;
-+    addrs[0].next = &addrs[1];
-+    addrs[0].addr = &ss[0];
-+    addrs[1].prev = &addrs[0];
-+    addrs[1].next = &addrs[2];
-+    addrs[1].addr = &ss[1];
-+    addrs[2].prev = &addrs[1];
-+    addrs[2].next = NULL;
-+    addrs[2].addr = &ss[2];
-+
-+    assert_ptr_equal(sss_iface_addr_get_address(NULL), NULL);
-+    assert_ptr_equal(sss_iface_addr_get_address(&addrs[0]), &ss[0]);
-+    assert_ptr_equal(sss_iface_addr_get_address(&addrs[1]), &ss[1]);
-+    assert_ptr_equal(sss_iface_addr_get_address(&addrs[2]), &ss[2]);
-+
-+    assert_ptr_equal(sss_iface_addr_get_next(NULL), NULL);
-+    assert_ptr_equal(sss_iface_addr_get_next(&addrs[0]), &addrs[1]);
-+    assert_ptr_equal(sss_iface_addr_get_next(&addrs[1]), &addrs[2]);
-+    assert_ptr_equal(sss_iface_addr_get_next(&addrs[2]), NULL);
-+}
-+
- void dyndns_test_get_ifaddr(void **state)
- {
-     errno_t ret;
-@@ -663,6 +689,9 @@ int main(int argc, const char *argv[])
- 
-     const struct CMUnitTest tests[] = {
-         /* Utility functions unit test */
-+        cmocka_unit_test_setup_teardown(dyndns_test_sss_iface_addr_get_misc,
-+                                        dyndns_test_simple_setup,
-+                                        dyndns_test_teardown),
-         cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr,
-                                         dyndns_test_simple_setup,
-                                         dyndns_test_teardown),
--- 
-2.4.3
-
diff --git a/SOURCES/0091-DYNDNS-Return-right-error-code-in-case-of-failure.patch b/SOURCES/0091-DYNDNS-Return-right-error-code-in-case-of-failure.patch
deleted file mode 100644
index a448123..0000000
--- a/SOURCES/0091-DYNDNS-Return-right-error-code-in-case-of-failure.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 02e61ddc6986c6ada9c702bf2dd4ef42d20425c1 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 23 Sep 2015 13:50:22 +0200
-Subject: [PATCH 91/96] DYNDNS: Return right error code in case of failure
-
-The variable will be zero if getifaddrs succeeds
-and therefore wrong error code will be returned
-in case of insufficient memory (talloc_zero failed)
-
-Reviewed-by: Pavel Reichl <preichl@redhat.com>
-(cherry picked from commit 75889713afc99ea52f4ff13b40672a12b28bdd41)
----
- src/providers/dp_dyndns.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
-index 50b087446f9437466de355e4d72b39a69512da03..a5eb383bd4f6c08b846a69f0588b9c25647dc5c8 100644
---- a/src/providers/dp_dyndns.c
-+++ b/src/providers/dp_dyndns.c
-@@ -228,6 +228,7 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
-             /* Add this address to the IP address list */
-             address = talloc_zero(mem_ctx, struct sss_iface_addr);
-             if (!address) {
-+                ret = ENOMEM;
-                 goto done;
-             }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch b/SOURCES/0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch
new file mode 100644
index 0000000..1719c18
--- /dev/null
+++ b/SOURCES/0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch
@@ -0,0 +1,518 @@
+From dc115d8a6aa1a656522c4f11c89e11d61360fd05 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 28 Jun 2016 11:40:16 +0200
+Subject: [PATCH 091/102] rdp: add ability to forward reply to the client
+ request
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In cases where the InfoPipe servers just as a middle-man between
+the DataProvider and a client we can simply forward the reply
+reducing amount of coded needed in the InfoPipe.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit a40d9cc11d17d9c3c22a0462cd8c419d1e79ffb8)
+---
+ src/responder/common/data_provider/rdp.h         |  20 ++
+ src/responder/common/data_provider/rdp_message.c | 260 +++++++++++++++++------
+ src/responder/ifp/ifp_domains.c                  |  78 +------
+ 3 files changed, 220 insertions(+), 138 deletions(-)
+
+diff --git a/src/responder/common/data_provider/rdp.h b/src/responder/common/data_provider/rdp.h
+index 8a3ec803d8ea7914e2a54661e31dec084586582a..f0aed179a3d33de0462591e6c0bcd3c518105707 100644
+--- a/src/responder/common/data_provider/rdp.h
++++ b/src/responder/common/data_provider/rdp.h
+@@ -54,6 +54,26 @@ errno_t _rdp_message_recv(struct tevent_req *req,
+ #define rdp_message_recv(req, ...)                                         \
+     _rdp_message_recv(req, ##__VA_ARGS__, DBUS_TYPE_INVALID)
+ 
++/**
++ * Send D-Bus message to Data Provider but instead of returning the reply
++ * to the caller it forwards the reply to the client request. No further
++ * processing is required by the caller. In case of a failure the client
++ * request is freed since there is nothing we can do.
++ */
++void _rdp_message_send_and_reply(struct sbus_request *sbus_req,
++                                 struct resp_ctx *rctx,
++                                 struct sss_domain_info *domain,
++                                 const char *path,
++                                 const char *iface,
++                                 const char *method,
++                                 int first_arg_type,
++                                 ...);
++
++#define rdp_message_send_and_reply(sbus_req, rctx, domain, path, iface,       \
++                                   method, ...)                               \
++    _rdp_message_send_and_reply(sbus_req, rctx, domain, path, iface, method,  \
++                                ##__VA_ARGS__, DBUS_TYPE_INVALID)
++
+ errno_t rdp_register_client(struct be_conn *be_conn,
+                             const char *client_name);
+ 
+diff --git a/src/responder/common/data_provider/rdp_message.c b/src/responder/common/data_provider/rdp_message.c
+index 78af6f8967b378536b6456274fbcac4b609d1033..e226401567e4a1b2b9784a9aba21540ff5f0bc8d 100644
+--- a/src/responder/common/data_provider/rdp_message.c
++++ b/src/responder/common/data_provider/rdp_message.c
+@@ -53,104 +53,72 @@ static errno_t rdp_error_to_errno(DBusError *error)
+     return EIO;
+ }
+ 
+-struct rdp_message_state {
+-    struct DBusMessage *reply;
+-};
+-
+-static int rdp_message_state_destructor(struct rdp_message_state *state)
++static errno_t
++rdp_message_send_internal(struct resp_ctx *rctx,
++                          struct sss_domain_info *domain,
++                          DBusPendingCallNotifyFunction notify_fn,
++                          void *notify_fn_data,
++                          const char *path,
++                          const char *iface,
++                          const char *method,
++                          int first_arg_type,
++                          va_list va)
+ {
+-    if (state->reply != NULL) {
+-        dbus_message_unref(state->reply);
+-    }
+-
+-    return 0;
+-}
+-
+-static void rdp_message_done(DBusPendingCall *pending, void *ptr);
+-
+-struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx,
+-                                     struct resp_ctx *rctx,
+-                                     struct sss_domain_info *domain,
+-                                     const char *path,
+-                                     const char *iface,
+-                                     const char *method,
+-                                     int first_arg_type,
+-                                     ...)
+-{
+-    struct rdp_message_state *state;
+     struct be_conn *be_conn;
+-    struct tevent_req *req;
+-    DBusMessage *msg;
++    DBusMessage *msg = NULL;
+     dbus_bool_t bret;
+     errno_t ret;
+-    va_list va;
+-
+-    req = tevent_req_create(mem_ctx, &state, struct rdp_message_state);
+-    if (req == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+-        return NULL;
+-    }
+-
+-    talloc_set_destructor(state, rdp_message_state_destructor);
+ 
+     ret = sss_dp_get_domain_conn(rctx, domain->conn_name, &be_conn);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "BUG: The Data Provider connection for "
+               "%s is not available!\n", domain->name);
+-        ret = ERR_INTERNAL;
+-        goto immediately;
++        goto done;
+     }
+ 
+     msg = dbus_message_new_method_call(NULL, path, iface, method);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create message\n");
+         ret = ENOMEM;
+-        goto immediately;
++        goto done;
+     }
+ 
+-    va_start(va, first_arg_type);
+     bret = dbus_message_append_args_valist(msg, first_arg_type, va);
+-    va_end(va);
+     if (!bret) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
+         ret = EIO;
+-        goto immediately;
++        goto done;
+     }
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "DP Request: %s %s.%s\n", path, iface, method);
+ 
+-    ret = sbus_conn_send(be_conn->conn, msg, 30000,
+-                         rdp_message_done, req, NULL);
++    ret = sbus_conn_send(be_conn->conn, msg, 3000,
++                         notify_fn, notify_fn_data, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+-        goto immediately;
++        goto done;
+     }
+ 
+-    return req;
++    ret = EOK;
+ 
+-immediately:
+-    if (ret == EOK) {
+-        tevent_req_done(req);
+-    } else {
+-        tevent_req_error(req, ret);
++done:
++    if (msg != NULL) {
++        dbus_message_unref(msg);
+     }
+-    tevent_req_post(req, rctx->ev);
+ 
+-    return req;
++    return ret;
+ }
+ 
+-static void rdp_message_done(DBusPendingCall *pending, void *ptr)
++static errno_t rdp_process_pending_call(DBusPendingCall *pending,
++                                        DBusMessage **_reply)
+ {
+-    struct rdp_message_state *state;
+-    DBusMessage *reply = NULL;
+-    struct tevent_req *req;
+-    DBusError error;
++    DBusMessage *reply;
+     dbus_bool_t bret;
++    DBusError error;
+     errno_t ret;
+ 
+-    req = talloc_get_type(ptr, struct tevent_req);
+-    state = tevent_req_data(req, struct rdp_message_state);
++    *_reply = NULL;
+ 
+     dbus_error_init(&error);
+ 
+@@ -165,9 +133,8 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr)
+     switch (dbus_message_get_type(reply)) {
+     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+         DEBUG(SSSDBG_TRACE_FUNC, "DP Success\n");
+-        state->reply = reply;
+         ret = EOK;
+-        goto done;
++        break;
+ 
+     case DBUS_MESSAGE_TYPE_ERROR:
+         bret = dbus_set_error_from_message(&error, reply);
+@@ -180,28 +147,105 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr)
+         DEBUG(SSSDBG_CRIT_FAILURE, "DP Error [%s]: %s\n",
+               error.name, (error.message == NULL ? "(null)" : error.message));
+         ret = rdp_error_to_errno(&error);
+-        goto done;
++        break;
+     default:
++        dbus_message_unref(reply);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type?\n");
+         ret = ERR_INTERNAL;
+         goto done;
+     }
+ 
+-    ret = ERR_INTERNAL;
++    *_reply = reply;
+ 
+ done:
+     dbus_pending_call_unref(pending);
+     dbus_error_free(&error);
+ 
++    return ret;
++}
++
++struct rdp_message_state {
++    struct DBusMessage *reply;
++};
++
++static int rdp_message_state_destructor(struct rdp_message_state *state)
++{
++    if (state->reply != NULL) {
++        dbus_message_unref(state->reply);
++    }
++
++    return 0;
++}
++
++static void rdp_message_done(DBusPendingCall *pending, void *ptr);
++
++struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx,
++                                     struct resp_ctx *rctx,
++                                     struct sss_domain_info *domain,
++                                     const char *path,
++                                     const char *iface,
++                                     const char *method,
++                                     int first_arg_type,
++                                     ...)
++{
++    struct rdp_message_state *state;
++    struct tevent_req *req;
++    errno_t ret;
++    va_list va;
++
++    req = tevent_req_create(mem_ctx, &state, struct rdp_message_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    talloc_set_destructor(state, rdp_message_state_destructor);
++
++    va_start(va, first_arg_type);
++    ret = rdp_message_send_internal(rctx, domain, rdp_message_done, req,
++                                    path, iface, method, first_arg_type, va);
++    va_end(va);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        goto immediately;
++    }
++
++    return req;
++
++immediately:
+     if (ret == EOK) {
+         tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, rctx->ev);
++
++    return req;
++}
++
++static void rdp_message_done(DBusPendingCall *pending, void *ptr)
++{
++    struct rdp_message_state *state;
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = talloc_get_type(ptr, struct tevent_req);
++    state = tevent_req_data(req, struct rdp_message_state);
++
++    ret = rdp_process_pending_call(pending, &state->reply);
++    if (ret != EOK) {
++        if (state->reply != NULL) {
++            dbus_message_unref(state->reply);
++        }
++
++        state->reply = NULL;
++
++        tevent_req_error(req, ret);
+         return;
+     }
+ 
+-    if (reply != NULL) {
+-        dbus_message_unref(reply);
+-    }
+-    tevent_req_error(req, ret);
++    tevent_req_done(req);
+ }
+ 
+ errno_t _rdp_message_recv(struct tevent_req *req,
+@@ -241,3 +285,85 @@ done:
+     return ret;
+ }
+ 
++static void rdp_message_send_and_reply_done(DBusPendingCall *pending,
++                                            void *ptr);
++
++void _rdp_message_send_and_reply(struct sbus_request *sbus_req,
++                                 struct resp_ctx *rctx,
++                                 struct sss_domain_info *domain,
++                                 const char *path,
++                                 const char *iface,
++                                 const char *method,
++                                 int first_arg_type,
++                                 ...)
++{
++    errno_t ret;
++    va_list va;
++
++    va_start(va, first_arg_type);
++    ret = rdp_message_send_internal(rctx, domain,
++                                    rdp_message_send_and_reply_done, sbus_req,
++                                    path, iface, method, first_arg_type, va);
++    va_end(va);
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        talloc_free(sbus_req);
++    }
++}
++
++static void rdp_message_send_and_reply_done(DBusPendingCall *pending,
++                                            void *ptr)
++{
++    struct sbus_request *sbus_req;
++    DBusMessage *reply = NULL;
++    dbus_uint32_t serial;
++    const char *sender;
++    dbus_bool_t dbret;
++    errno_t ret;
++
++    sbus_req = talloc_get_type(ptr, struct sbus_request);
++
++    ret = rdp_process_pending_call(pending, &reply);
++    if (reply == NULL) {
++        /* Something bad happened. Just kill the request. */
++        ret = EIO;
++        goto done;
++    }
++
++    /* Otherwise we have a valid reply and we do not care about returned
++     * value. We set destination and serial in reply to point to the original
++     * client request. */
++
++    sender = dbus_message_get_sender(sbus_req->message);
++    serial = dbus_message_get_serial(sbus_req->message);
++
++    dbret = dbus_message_set_destination(reply, sender);
++    if (dbret == false) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set reply sender!\n");
++        ret = EIO;
++        goto done;
++    }
++
++    dbret = dbus_message_set_reply_serial(reply, serial);
++    if (dbret == false) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set reply serial!\n");
++        ret = EIO;
++        goto done;
++    }
++
++    sbus_request_finish(sbus_req, reply);
++
++    ret = EOK;
++
++done:
++    if (reply != NULL) {
++        dbus_message_unref(reply);
++    }
++
++    if (ret != EOK) {
++        /* Something bad happend, just kill the request. */
++        talloc_free(sbus_req);
++    }
++}
+diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
+index 5333b25275e0847015f9cdd294eab5dbdda32f6c..8bfd39feb39822921ea703d8a89ac372e0ad5410 100644
+--- a/src/responder/ifp/ifp_domains.c
++++ b/src/responder/ifp/ifp_domains.c
+@@ -538,14 +538,11 @@ void ifp_dom_get_parent_domain(struct sbus_request *dbus_req,
+                                dom->parent->name);
+ }
+ 
+-static void ifp_domains_domain_is_online_done(struct tevent_req *req);
+-
+ int ifp_domains_domain_is_online(struct sbus_request *sbus_req,
+                                  void *data)
+ {
+     struct ifp_ctx *ifp_ctx;
+     struct sss_domain_info *dom;
+-    struct tevent_req *req;
+     DBusError *error;
+ 
+     ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+@@ -558,49 +555,18 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req,
+         return EOK;
+     }
+ 
+-    req = rdp_message_send(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
+-                           IFACE_DP_BACKEND, IFACE_DP_BACKEND_ISONLINE,
+-                           DBUS_TYPE_STRING, &dom->name);
+-    if (req == NULL) {
+-        return ENOMEM;
+-    }
+-
+-    tevent_req_set_callback(req, ifp_domains_domain_is_online_done, sbus_req);
++    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
++                               IFACE_DP_BACKEND, IFACE_DP_BACKEND_ISONLINE,
++                               DBUS_TYPE_STRING, &dom->name);
+ 
+     return EOK;
+ }
+ 
+-static void ifp_domains_domain_is_online_done(struct tevent_req *req)
+-{
+-    struct sbus_request *sbus_req;
+-    DBusError *error;
+-    bool is_online;
+-    errno_t ret;
+-
+-    sbus_req = tevent_req_callback_data(req, struct sbus_request);
+-
+-    ret = rdp_message_recv(req, DBUS_TYPE_BOOLEAN, &is_online);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Unable to get online status [%d]: %s\n",
+-              ret, sss_strerror(ret));
+-        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
+-                               "Unable to get online status [%d]: %s",
+-                               ret, sss_strerror(ret));
+-        sbus_request_fail_and_finish(sbus_req, error);
+-        return;
+-    }
+-
+-    iface_ifp_domains_domain_IsOnline_finish(sbus_req, is_online);
+-}
+-
+-static void ifp_domains_domain_list_services_done(struct tevent_req *req);
+-
+ int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
+                                      void *data)
+ {
+     struct ifp_ctx *ifp_ctx;
+     struct sss_domain_info *dom;
+-    struct tevent_req *req;
+     DBusError *error;
+ 
+     ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+@@ -613,40 +579,10 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
+         return EOK;
+     }
+ 
+-    req = rdp_message_send(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
+-                           IFACE_DP_FAILOVER, IFACE_DP_FAILOVER_LISTSERVICES,
+-                           DBUS_TYPE_STRING, &dom->name);
+-    if (req == NULL) {
+-        return ENOMEM;
+-    }
+-
+-    tevent_req_set_callback(req, ifp_domains_domain_list_services_done, sbus_req);
++    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
++                               IFACE_DP_FAILOVER,
++                               IFACE_DP_FAILOVER_LISTSERVICES,
++                               DBUS_TYPE_STRING, &dom->name);
+ 
+     return EOK;
+ }
+-
+-static void ifp_domains_domain_list_services_done(struct tevent_req *req)
+-{
+-    struct sbus_request *sbus_req;
+-    DBusError *error;
+-    int num_services;
+-    const char **services;
+-    errno_t ret;
+-
+-    sbus_req = tevent_req_callback_data(req, struct sbus_request);
+-
+-    ret = rdp_message_recv(req, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+-                           &services, &num_services);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Unable to get failover services [%d]: %s\n",
+-              ret, sss_strerror(ret));
+-        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
+-                               "Unable to get failover services [%d]: %s",
+-                               ret, sss_strerror(ret));
+-        sbus_request_fail_and_finish(sbus_req, error);
+-        return;
+-    }
+-
+-    iface_ifp_domains_domain_ListServices_finish(sbus_req, services,
+-                                                 num_services);
+-}
+-- 
+2.4.11
+
diff --git a/SOURCES/0092-IPA-Change-ipa_server_trust_add_send-request-to-be-r.patch b/SOURCES/0092-IPA-Change-ipa_server_trust_add_send-request-to-be-r.patch
deleted file mode 100644
index 797fd6a..0000000
--- a/SOURCES/0092-IPA-Change-ipa_server_trust_add_send-request-to-be-r.patch
+++ /dev/null
@@ -1,270 +0,0 @@
-From ce69c907f04214e16c07c5a05fb8dac12b271aba Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 17 Sep 2015 17:09:24 +0200
-Subject: [PATCH 92/96] IPA: Change ipa_server_trust_add_send request to be
- reusable from ID code
-
-Required for:
-    https://fedorahosted.org/sssd/ticket/2639
-
-Expose a request ipa_server_trusted_dom_setup_send that sets up a
-trusted domain. The setup might include actions like retrieving a keytab
-for one-way trusts.
-
-Creating the AD ID context for the trused domain is now done in the
-caller of this new request.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 1ccfd8e2e5cf4cdb6807d9809c150b7f6ba3e0eb)
----
- src/providers/ipa/ipa_subdomains.h        |  11 +++
- src/providers/ipa/ipa_subdomains_server.c | 122 ++++++++++++++++--------------
- 2 files changed, 75 insertions(+), 58 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h
-index 2302c5f03e80de2ea1efad424769e777cd6dd8d5..0c13f8ed2eeda87237dfb097f532c7137095ddf1 100644
---- a/src/providers/ipa/ipa_subdomains.h
-+++ b/src/providers/ipa/ipa_subdomains.h
-@@ -52,6 +52,17 @@ struct ipa_ad_server_ctx {
-     struct ipa_ad_server_ctx *next, *prev;
- };
- 
-+/* Can be used to set up trusted subdomain, for example fetch
-+ * keytab in server mode
-+ */
-+struct tevent_req *
-+ipa_server_trusted_dom_setup_send(TALLOC_CTX *mem_ctx,
-+                                  struct tevent_context *ev,
-+                                  struct be_ctx *be_ctx,
-+                                  struct ipa_id_ctx *id_ctx,
-+                                  struct sss_domain_info *subdom);
-+errno_t ipa_server_trusted_dom_setup_recv(struct tevent_req *req);
-+
- /* To be used by ipa_subdomains.c only */
- struct tevent_req *
- ipa_server_create_trusts_send(TALLOC_CTX *mem_ctx,
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index dfecab1bc362b5772379bae6d51f9cef8443f225..c561118946e2ba76b2b4076e5057b1b5c0075a41 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -563,7 +563,7 @@ done:
-     return ret;
- }
- 
--struct ipa_server_trust_add_state {
-+struct ipa_server_trusted_dom_setup_state {
-     struct tevent_context *ev;
-     struct be_ctx *be_ctx;
-     struct ipa_id_ctx *id_ctx;
-@@ -578,22 +578,22 @@ struct ipa_server_trust_add_state {
-     const char *ccache;
- };
- 
--static errno_t ipa_server_trust_add_1way(struct tevent_req *req);
-+static errno_t ipa_server_trusted_dom_setup_1way(struct tevent_req *req);
- static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq);
--static errno_t ipa_server_trust_add_step(struct tevent_req *req);
- 
--static struct tevent_req *
--ipa_server_trust_add_send(TALLOC_CTX *mem_ctx,
--                          struct tevent_context *ev,
--                          struct be_ctx *be_ctx,
--                          struct ipa_id_ctx *id_ctx,
--                          struct sss_domain_info *subdom)
-+struct tevent_req *
-+ipa_server_trusted_dom_setup_send(TALLOC_CTX *mem_ctx,
-+                                  struct tevent_context *ev,
-+                                  struct be_ctx *be_ctx,
-+                                  struct ipa_id_ctx *id_ctx,
-+                                  struct sss_domain_info *subdom)
- {
-     struct tevent_req *req = NULL;
--    struct ipa_server_trust_add_state *state = NULL;
-+    struct ipa_server_trusted_dom_setup_state *state = NULL;
-     errno_t ret;
- 
--    req = tevent_req_create(mem_ctx, &state, struct ipa_server_trust_add_state);
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct ipa_server_trusted_dom_setup_state);
-     if (req == NULL) {
-         return NULL;
-     }
-@@ -626,16 +626,19 @@ ipa_server_trust_add_send(TALLOC_CTX *mem_ctx,
-           ipa_trust_dir2str(state->direction));
- 
-     if (state->direction & LSA_TRUST_DIRECTION_OUTBOUND) {
--        /* Use system keytab */
--        ret = ipa_server_trust_add_step(req);
-+        /* Use system keytab, nothing to do here */
-+        ret = EOK;
-+        goto immediate;
-     } else if (state->direction & LSA_TRUST_DIRECTION_INBOUND) {
-         /* Need special keytab */
--        ret = ipa_server_trust_add_1way(req);
-+        ret = ipa_server_trusted_dom_setup_1way(req);
-         if (ret == EAGAIN) {
-             /* In progress.. */
-             return req;
-         } else if (ret == EOK) {
--            ret = ipa_server_trust_add_step(req);
-+            /* Keytab available, shortcut */
-+            ret = EOK;
-+            goto immediate;
-         }
-     } else {
-         /* Even unset is an error at this point */
-@@ -658,12 +661,12 @@ immediate:
-     return req;
- }
- 
--static errno_t ipa_server_trust_add_1way(struct tevent_req *req)
-+static errno_t ipa_server_trusted_dom_setup_1way(struct tevent_req *req)
- {
-     errno_t ret;
-     struct tevent_req *subreq = NULL;
--    struct ipa_server_trust_add_state *state =
--            tevent_req_data(req, struct ipa_server_trust_add_state);
-+    struct ipa_server_trusted_dom_setup_state *state =
-+            tevent_req_data(req, struct ipa_server_trusted_dom_setup_state);
-     const char *hostname;
- 
-     state->keytab = forest_keytab(state, state->forest);
-@@ -715,8 +718,8 @@ static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq)
-     errno_t ret;
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct ipa_server_trust_add_state *state =
--            tevent_req_data(req, struct ipa_server_trust_add_state);
-+    struct ipa_server_trusted_dom_setup_state *state =
-+            tevent_req_data(req, struct ipa_server_trusted_dom_setup_state);
- 
-     ret = ipa_getkeytab_recv(subreq, NULL);
-     talloc_zfree(subreq);
-@@ -764,46 +767,12 @@ static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq)
-     DEBUG(SSSDBG_TRACE_FUNC,
-           "Keytab %s contains the expected principals\n", state->new_keytab);
- 
--    ret = ipa_server_trust_add_step(req);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "ipa_server_trust_add_step failed: %d\n", ret);
--        tevent_req_error(req, ret);
--        return;
--    }
--
-     DEBUG(SSSDBG_TRACE_FUNC,
-           "Established trust context for %s\n", state->subdom->name);
-     tevent_req_done(req);
- }
- 
--static errno_t ipa_server_trust_add_step(struct tevent_req *req)
--{
--    struct ipa_ad_server_ctx *trust_ctx;
--    struct ad_id_ctx *ad_id_ctx;
--    errno_t ret;
--    struct ipa_server_trust_add_state *state =
--            tevent_req_data(req, struct ipa_server_trust_add_state);
--
--    ret = ipa_ad_ctx_new(state->be_ctx, state->id_ctx, state->subdom, &ad_id_ctx);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Cannot create ad_id_ctx for subdomain %s\n", state->subdom->name);
--        return ret;
--    }
--
--    trust_ctx = talloc(state->id_ctx->server_mode, struct ipa_ad_server_ctx);
--    if (trust_ctx == NULL) {
--        return ENOMEM;
--    }
--    trust_ctx->dom = state->subdom;
--    trust_ctx->ad_id_ctx = ad_id_ctx;
--
--    DLIST_ADD(state->id_ctx->server_mode->trusts, trust_ctx);
--    return EOK;
--}
--
--static errno_t ipa_server_trust_add_recv(struct tevent_req *req)
-+errno_t ipa_server_trusted_dom_setup_recv(struct tevent_req *req)
- {
-     TEVENT_REQ_RETURN_ON_ERROR(req);
-     return EOK;
-@@ -817,6 +786,7 @@ struct ipa_server_create_trusts_state {
- };
- 
- static errno_t ipa_server_create_trusts_step(struct tevent_req *req);
-+static errno_t ipa_server_create_trusts_ctx(struct tevent_req *req);
- static void ipa_server_create_trusts_done(struct tevent_req *subreq);
- 
- struct tevent_req *
-@@ -879,8 +849,11 @@ static errno_t ipa_server_create_trusts_step(struct tevent_req *req)
- 
-         /* Newly detected trust */
-         if (trust_iter == NULL) {
--            subreq = ipa_server_trust_add_send(state, state->ev, state->be_ctx,
--                                               state->id_ctx, state->domiter);
-+            subreq = ipa_server_trusted_dom_setup_send(state,
-+                                                       state->ev,
-+                                                       state->be_ctx,
-+                                                       state->id_ctx,
-+                                                       state->domiter);
-             if (subreq == NULL) {
-                 return ENOMEM;
-             }
-@@ -898,13 +871,19 @@ static void ipa_server_create_trusts_done(struct tevent_req *subreq)
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
- 
--    ret = ipa_server_trust_add_recv(subreq);
-+    ret = ipa_server_trusted_dom_setup_recv(subreq);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         tevent_req_error(req, ret);
-         return;
-     }
- 
-+    ret = ipa_server_create_trusts_ctx(req);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-     ret = ipa_server_create_trusts_step(req);
-     if (ret == EOK) {
-         tevent_req_done(req);
-@@ -917,6 +896,33 @@ static void ipa_server_create_trusts_done(struct tevent_req *subreq)
-     /* Will cycle back */
- }
- 
-+static errno_t ipa_server_create_trusts_ctx(struct tevent_req *req)
-+{
-+    struct ipa_ad_server_ctx *trust_ctx;
-+    struct ad_id_ctx *ad_id_ctx;
-+    errno_t ret;
-+    struct ipa_server_create_trusts_state *state = NULL;
-+
-+    state = tevent_req_data(req, struct ipa_server_create_trusts_state);
-+
-+    ret = ipa_ad_ctx_new(state->be_ctx, state->id_ctx, state->domiter, &ad_id_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Cannot create ad_id_ctx for subdomain %s\n", state->domiter->name);
-+        return ret;
-+    }
-+
-+    trust_ctx = talloc(state->id_ctx->server_mode, struct ipa_ad_server_ctx);
-+    if (trust_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+    trust_ctx->dom = state->domiter;
-+    trust_ctx->ad_id_ctx = ad_id_ctx;
-+
-+    DLIST_ADD(state->id_ctx->server_mode->trusts, trust_ctx);
-+    return EOK;
-+}
-+
- errno_t ipa_server_create_trusts_recv(struct tevent_req *req)
- {
-     TEVENT_REQ_RETURN_ON_ERROR(req);
--- 
-2.4.3
-
diff --git a/SOURCES/0092-sbus-add-sbus_request_reply_error.patch b/SOURCES/0092-sbus-add-sbus_request_reply_error.patch
new file mode 100644
index 0000000..623cc9c
--- /dev/null
+++ b/SOURCES/0092-sbus-add-sbus_request_reply_error.patch
@@ -0,0 +1,218 @@
+From 9b0cda6876a5407b152bdeb51bb312aa52916172 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 28 Jun 2016 15:29:39 +0200
+Subject: [PATCH 092/102] sbus: add sbus_request_reply_error()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This simplifies error handling in sbus requests since we avoid
+creating DBusError and checking for NULL manually. It removes
+few lines of code.
+
+This patch does not replace all calls to sbus_request_fail_and_finish
+since sometimes it is desirable to create the error manualy. But
+it replaces it in most recent places.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit a06e23c0bcf0c8669a29b801876aca8aac422931)
+---
+ src/providers/data_provider/dp_iface_backend.c | 11 ++--
+ src/responder/ifp/ifp_domains.c                | 12 ++---
+ src/sbus/sssd_dbus.h                           |  9 +++-
+ src/sbus/sssd_dbus_request.c                   | 73 ++++++++++++++++++++------
+ 4 files changed, 70 insertions(+), 35 deletions(-)
+
+diff --git a/src/providers/data_provider/dp_iface_backend.c b/src/providers/data_provider/dp_iface_backend.c
+index f4af35ed6ec3858b7fff80cf2933926a653ba6f5..d9a84bfee4c5c11e46e0e8f7021f829825ad95c1 100644
+--- a/src/providers/data_provider/dp_iface_backend.c
++++ b/src/providers/data_provider/dp_iface_backend.c
+@@ -34,7 +34,6 @@ errno_t dp_backend_is_online(struct sbus_request *sbus_req,
+ {
+     struct be_ctx *be_ctx;
+     struct sss_domain_info *domain;
+-    DBusError *error;
+     bool online;
+ 
+     be_ctx = dp_client_be(dp_cli);
+@@ -44,13 +43,9 @@ errno_t dp_backend_is_online(struct sbus_request *sbus_req,
+     } else {
+         domain = find_domain_by_name(be_ctx->domain, domname, false);
+         if (domain == NULL) {
+-            error = sbus_error_new(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
+-                                   "Unknown domain %s", domname);
+-            if (error == NULL) {
+-                return ENOMEM;
+-            }
+-
+-            return sbus_request_fail_and_finish(sbus_req, error);
++            sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
++                                     "Unknown domain %s", domname);
++            return EOK;
+         }
+     }
+ 
+diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
+index 8bfd39feb39822921ea703d8a89ac372e0ad5410..ff690ed6a7d5519979d242a4d5dadd08aff50347 100644
+--- a/src/responder/ifp/ifp_domains.c
++++ b/src/responder/ifp/ifp_domains.c
+@@ -543,15 +543,13 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req,
+ {
+     struct ifp_ctx *ifp_ctx;
+     struct sss_domain_info *dom;
+-    DBusError *error;
+ 
+     ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+ 
+     dom = get_domain_info_from_req(sbus_req, data);
+     if (dom == NULL) {
+-        error = sbus_error_new(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
+-                               "Unknown domain");
+-        sbus_request_fail_and_finish(sbus_req, error);
++        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
++                                 "Unknown domain");
+         return EOK;
+     }
+ 
+@@ -567,15 +565,13 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
+ {
+     struct ifp_ctx *ifp_ctx;
+     struct sss_domain_info *dom;
+-    DBusError *error;
+ 
+     ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+ 
+     dom = get_domain_info_from_req(sbus_req, data);
+     if (dom == NULL) {
+-        error = sbus_error_new(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
+-                               "Unknown domain");
+-        sbus_request_fail_and_finish(sbus_req, error);
++        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
++                                 "Unknown domain");
+         return EOK;
+     }
+ 
+diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
+index fe1c4a7e1730e088647744d9b49a68c3c71db57f..c0aedf36b496bfda05dcde921ea7060efb4cc91f 100644
+--- a/src/sbus/sssd_dbus.h
++++ b/src/sbus/sssd_dbus.h
+@@ -357,6 +357,11 @@ int sbus_request_return_and_finish(struct sbus_request *dbus_req,
+ int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
+                                  const DBusError *error);
+ 
++void sbus_request_reply_error(struct sbus_request *sbus_req,
++                              const char *error_name,
++                              const char *fmt,
++                              ...) SSS_ATTRIBUTE_PRINTF(3, 4);
++
+ /*
+  * Construct a new DBusError instance which can be consumed by functions such
+  * as @sbus_request_fail_and_finish().
+@@ -368,9 +373,9 @@ int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
+  * is duplicated using the returned DBusError instance as a talloc parent.
+  */
+ DBusError *sbus_error_new(TALLOC_CTX *mem_ctx,
+-                          const char *dbus_err_name,
++                          const char *dbus_error_name,
+                           const char *fmt,
+-                          ...) SSS_ATTRIBUTE_PRINTF(3,4);
++                          ...) SSS_ATTRIBUTE_PRINTF(3, 4);
+ 
+ /*
+  * Parse a DBus method call request.
+diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
+index f8647b5ecfb4a49d45a15733b22c6014f4bd084c..c5b08539ff85b5427e41f6e03991b40a0a43a7e3 100644
+--- a/src/sbus/sssd_dbus_request.c
++++ b/src/sbus/sssd_dbus_request.c
+@@ -199,31 +199,70 @@ int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
+     return ret;
+ }
+ 
++static DBusError *sbus_error_new_va(TALLOC_CTX *mem_ctx,
++                                    const char *error_name,
++                                    const char *fmt,
++                                    va_list ap)
++{
++    DBusError *error;
++    const char *error_msg;
++
++    error = talloc_zero(mem_ctx, DBusError);
++    if (error == NULL) {
++        return NULL;
++    }
++
++    if (fmt != NULL) {
++        error_msg = talloc_vasprintf(error, fmt, ap);
++        if (error_msg == NULL) {
++            talloc_free(error);
++            return NULL;
++        }
++    } else {
++        error_msg = NULL;
++    }
++
++    dbus_error_init(error);
++    dbus_set_error_const(error, error_name, error_msg);
++
++    return error;
++}
++
+ DBusError *sbus_error_new(TALLOC_CTX *mem_ctx,
+-                          const char *dbus_err_name,
++                          const char *dbus_error_name,
+                           const char *fmt,
+                           ...)
+ {
+-    DBusError *dberr;
+-    const char *err_msg_dup = NULL;
++    DBusError *error;
+     va_list ap;
+ 
+-    dberr = talloc(mem_ctx, DBusError);
+-    if (dberr == NULL) return NULL;
+-
+-    if (fmt) {
+-        va_start(ap, fmt);
+-        err_msg_dup = talloc_vasprintf(dberr, fmt, ap);
+-        va_end(ap);
+-        if (err_msg_dup == NULL) {
+-            talloc_free(dberr);
+-            return NULL;
+-        }
++    va_start(ap, fmt);
++    error = sbus_error_new_va(mem_ctx, dbus_error_name, fmt, ap);
++    va_end(ap);
++
++    return error;
++}
++
++void sbus_request_reply_error(struct sbus_request *sbus_req,
++                              const char *error_name,
++                              const char *fmt,
++                              ...)
++{
++    DBusError *error;
++    va_list ap;
++
++    va_start(ap, fmt);
++    error = sbus_error_new_va(sbus_req, error_name, fmt, ap);
++    va_end(ap);
++
++    if (error == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Unable to create D-Bus error, killing request!\n");
++        talloc_free(sbus_req);
++        return;
+     }
+ 
+-    dbus_error_init(dberr);
+-    dbus_set_error_const(dberr, dbus_err_name, err_msg_dup);
+-    return dberr;
++    sbus_request_fail_and_finish(sbus_req, error);
+ }
+ 
+ struct array_arg {
+-- 
+2.4.11
+
diff --git a/SOURCES/0093-DEBUG-Add-new-debug-category-for-fail-over.patch b/SOURCES/0093-DEBUG-Add-new-debug-category-for-fail-over.patch
deleted file mode 100644
index 6e4651f..0000000
--- a/SOURCES/0093-DEBUG-Add-new-debug-category-for-fail-over.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-From ac77db34a46e36f42e917f1b6d66fee39234d5f8 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Mon, 10 Aug 2015 18:35:16 +0200
-Subject: [PATCH 93/96] DEBUG: Add new debug category for fail over.
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit c4fb8f55f2894de431478ccfec63f9a97e090d0e)
----
- src/providers/data_provider_fo.c | 30 ++++++++++++++++++++++++++----
- src/providers/dp_backend.h       | 15 +++++++++++----
- src/tests/debug-tests.c          |  2 +-
- src/util/debug.c                 |  2 +-
- src/util/util.h                  |  1 +
- 5 files changed, 40 insertions(+), 10 deletions(-)
-
-diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
-index dab796d4647a552c2fd1c626c490278de91c2e81..41d70de065260f31dcea4c2b664a1f436823ccc1 100644
---- a/src/providers/data_provider_fo.c
-+++ b/src/providers/data_provider_fo.c
-@@ -743,13 +743,35 @@ void reset_fo(struct be_ctx *be_ctx)
-     fo_reset_services(be_ctx->be_fo->fo_ctx);
- }
- 
--void be_fo_set_port_status(struct be_ctx *ctx,
--                           const char *service_name,
--                           struct fo_server *server,
--                           enum port_status status)
-+void _be_fo_set_port_status(struct be_ctx *ctx,
-+                            const char *service_name,
-+                            struct fo_server *server,
-+                            enum port_status status,
-+                            int line,
-+                            const char *file,
-+                            const char *function)
- {
-     struct be_svc_data *be_svc;
- 
-+    /* Print debug info */
-+    switch (status) {
-+    case PORT_NEUTRAL:
-+        DEBUG(SSSDBG_BE_FO,
-+              "Setting status: PORT_NEUTRAL. Called from: %s: %s: %d\n",
-+              file, function, line);
-+        break;
-+    case PORT_WORKING:
-+        DEBUG(SSSDBG_BE_FO,
-+              "Setting status: PORT_WORKING. Called from: %s: %s: %d\n",
-+              file, function, line);
-+        break;
-+    case PORT_NOT_WORKING:
-+        DEBUG(SSSDBG_BE_FO,
-+              "Setting status: PORT_NOT_WORKING. Called from: %s: %s: %d\n",
-+              file, function, line);
-+        break;
-+    }
-+
-     be_svc = be_fo_find_svc_data(ctx, service_name);
-     if (be_svc == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE,
-diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
-index 4d54bf547682379bcb8cf855b8fae39214495728..4bffcee9e8739302343b7813d3540eb43e966581 100644
---- a/src/providers/dp_backend.h
-+++ b/src/providers/dp_backend.h
-@@ -260,10 +260,17 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
-                                           bool first_try);
- int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv);
- 
--void be_fo_set_port_status(struct be_ctx *ctx,
--                           const char *service_name,
--                           struct fo_server *server,
--                           enum port_status status);
-+#define be_fo_set_port_status(ctx, service_name, server, status) \
-+    _be_fo_set_port_status(ctx, service_name, server, status, \
-+                           __LINE__, __FILE__, __FUNCTION__)
-+
-+void _be_fo_set_port_status(struct be_ctx *ctx,
-+                            const char *service_name,
-+                            struct fo_server *server,
-+                            enum port_status status,
-+                            int line,
-+                            const char *file,
-+                            const char *function);
- 
- /*
-  * Instruct fail-over to try next server on the next connect attempt.
-diff --git a/src/tests/debug-tests.c b/src/tests/debug-tests.c
-index 2b91c149d79483316794240498e7fe33545dede0..067209b1dda1c445b971bcec7108d0b886d55e53 100644
---- a/src/tests/debug-tests.c
-+++ b/src/tests/debug-tests.c
-@@ -48,7 +48,7 @@ START_TEST(test_debug_convert_old_level_old_format)
-         SSSDBG_TRACE_FUNC,
-         SSSDBG_TRACE_LIBS,
-         SSSDBG_TRACE_INTERNAL,
--        SSSDBG_TRACE_ALL
-+        SSSDBG_TRACE_ALL | SSSDBG_BE_FO
-     };
- 
-     for (old_level = 0; old_level <= 9; old_level++) {
-diff --git a/src/util/debug.c b/src/util/debug.c
-index bf83624c98769c4c53d9c25522712a9705b26ed2..69df54386101973548108c3194a1bfd111f046f0 100644
---- a/src/util/debug.c
-+++ b/src/util/debug.c
-@@ -114,7 +114,7 @@ int debug_convert_old_level(int old_level)
-         new_level |= SSSDBG_TRACE_INTERNAL;
- 
-     if (old_level >= 9)
--        new_level |= SSSDBG_TRACE_ALL;
-+        new_level |= SSSDBG_TRACE_ALL | SSSDBG_BE_FO;
- 
-     return new_level;
- }
-diff --git a/src/util/util.h b/src/util/util.h
-index 4655e90a89b0ff3c457b80c943aefc4d6cf8e21f..f9fe1ca7189c6b2cdcb29f143005b20a2d969fee 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -92,6 +92,7 @@ int get_fd_from_debug_file(void);
- #define SSSDBG_TRACE_LIBS     0x1000   /* level 7 */
- #define SSSDBG_TRACE_INTERNAL 0x2000   /* level 8 */
- #define SSSDBG_TRACE_ALL      0x4000   /* level 9 */
-+#define SSSDBG_BE_FO          0x8000   /* level 9 */
- #define SSSDBG_IMPORTANT_INFO SSSDBG_OP_FAILURE
- 
- #define SSSDBG_INVALID        -1
--- 
-2.4.3
-
diff --git a/SOURCES/0093-sbus-add-utility-function-to-simplify-message-and-re.patch b/SOURCES/0093-sbus-add-utility-function-to-simplify-message-and-re.patch
new file mode 100644
index 0000000..561fd47
--- /dev/null
+++ b/SOURCES/0093-sbus-add-utility-function-to-simplify-message-and-re.patch
@@ -0,0 +1,624 @@
+From 420e47f6a0e173e774faa426d172c6e2160b8302 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 29 Jun 2016 12:35:59 +0200
+Subject: [PATCH 093/102] sbus: add utility function to simplify message and
+ reply handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch adds the ability to hook DBusMessage to a talloc context
+to remove the need of calling dbus_message_unref(). It also provides
+an automatical way to detect error in a reply so the caller does
+not need to parse it manually and the whole code around DBusError
+can be avoided.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 439e08cdc5c83b3e5835cb0435983f1da2ffbaf1)
+---
+ Makefile.am                                      |   2 +
+ src/responder/common/data_provider/rdp_message.c |  85 ++-------
+ src/sbus/sssd_dbus.h                             |   2 +
+ src/sbus/sssd_dbus_utils.c                       | 226 +++++++++++++++++++++++
+ src/sbus/sssd_dbus_utils.h                       |  64 +++++++
+ src/tools/sssctl/sssctl_domains.c                |  32 +---
+ 6 files changed, 313 insertions(+), 98 deletions(-)
+ create mode 100644 src/sbus/sssd_dbus_utils.c
+ create mode 100644 src/sbus/sssd_dbus_utils.h
+
+diff --git a/Makefile.am b/Makefile.am
+index ee9b48c666a44781b582ba5d83102b705e898f29..1837e36da7302cb51c0b90e51b762ce0a87cd65f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -634,6 +634,7 @@ dist_noinst_HEADERS = \
+     src/sbus/sssd_dbus_private.h \
+     src/sbus/sssd_dbus_invokers.h \
+     src/sbus/sssd_dbus_errors.h \
++    src/sbus/sssd_dbus_utils.h \
+     src/db/sysdb.h \
+     src/db/sysdb_sudo.h \
+     src/db/sysdb_autofs.h \
+@@ -915,6 +916,7 @@ libsss_util_la_SOURCES = \
+     src/sbus/sssd_dbus_server.c \
+     src/sbus/sssd_dbus_signals.c \
+     src/sbus/sssd_dbus_common_signals.c \
++    src/sbus/sssd_dbus_utils.c \
+     src/util/util.c \
+     src/util/memory.c \
+     src/util/safe-format-string.c \
+diff --git a/src/responder/common/data_provider/rdp_message.c b/src/responder/common/data_provider/rdp_message.c
+index e226401567e4a1b2b9784a9aba21540ff5f0bc8d..6ad2ba056e992cd89b87b478d422d1a4259a12d9 100644
+--- a/src/responder/common/data_provider/rdp_message.c
++++ b/src/responder/common/data_provider/rdp_message.c
+@@ -26,33 +26,6 @@
+ #include "sbus/sssd_dbus_errors.h"
+ #include "util/util.h"
+ 
+-static errno_t rdp_error_to_errno(DBusError *error)
+-{
+-    static struct {
+-        const char *name;
+-        errno_t ret;
+-    } list[] = {{SBUS_ERROR_INTERNAL, ERR_INTERNAL},
+-                {SBUS_ERROR_NOT_FOUND, ENOENT},
+-                {SBUS_ERROR_DP_FATAL, ERR_TERMINATED},
+-                {SBUS_ERROR_DP_OFFLINE, ERR_OFFLINE},
+-                {SBUS_ERROR_DP_NOTSUP, ENOTSUP},
+-                {NULL, ERR_INTERNAL}
+-    };
+-    int i;
+-
+-    if (!dbus_error_is_set(error)) {
+-        return EOK;
+-    }
+-
+-    for (i = 0; list[i].name != NULL; i ++) {
+-        if (dbus_error_has_name(error, list[i].name)) {
+-            return list[i].ret;
+-        }
+-    }
+-
+-    return EIO;
+-}
+-
+ static errno_t
+ rdp_message_send_internal(struct resp_ctx *rctx,
+                           struct sss_domain_info *domain,
+@@ -110,7 +83,8 @@ done:
+     return ret;
+ }
+ 
+-static errno_t rdp_process_pending_call(DBusPendingCall *pending,
++static errno_t rdp_process_pending_call(TALLOC_CTX *mem_ctx,
++                                        DBusPendingCall *pending,
+                                         DBusMessage **_reply)
+ {
+     DBusMessage *reply;
+@@ -130,6 +104,11 @@ static errno_t rdp_process_pending_call(DBusPendingCall *pending,
+         goto done;
+     }
+ 
++    ret = sbus_talloc_bound_message(mem_ctx, reply);
++    if (ret != EOK) {
++        return ret;
++    }
++
+     switch (dbus_message_get_type(reply)) {
+     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+         DEBUG(SSSDBG_TRACE_FUNC, "DP Success\n");
+@@ -146,10 +125,9 @@ static errno_t rdp_process_pending_call(DBusPendingCall *pending,
+ 
+         DEBUG(SSSDBG_CRIT_FAILURE, "DP Error [%s]: %s\n",
+               error.name, (error.message == NULL ? "(null)" : error.message));
+-        ret = rdp_error_to_errno(&error);
++        ret = sbus_error_to_errno(&error);
+         break;
+     default:
+-        dbus_message_unref(reply);
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type?\n");
+         ret = ERR_INTERNAL;
+         goto done;
+@@ -168,15 +146,6 @@ struct rdp_message_state {
+     struct DBusMessage *reply;
+ };
+ 
+-static int rdp_message_state_destructor(struct rdp_message_state *state)
+-{
+-    if (state->reply != NULL) {
+-        dbus_message_unref(state->reply);
+-    }
+-
+-    return 0;
+-}
+-
+ static void rdp_message_done(DBusPendingCall *pending, void *ptr);
+ 
+ struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx,
+@@ -199,8 +168,6 @@ struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx,
+         return NULL;
+     }
+ 
+-    talloc_set_destructor(state, rdp_message_state_destructor);
+-
+     va_start(va, first_arg_type);
+     ret = rdp_message_send_internal(rctx, domain, rdp_message_done, req,
+                                     path, iface, method, first_arg_type, va);
+@@ -233,14 +200,8 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr)
+     req = talloc_get_type(ptr, struct tevent_req);
+     state = tevent_req_data(req, struct rdp_message_state);
+ 
+-    ret = rdp_process_pending_call(pending, &state->reply);
++    ret = rdp_process_pending_call(state, pending, &state->reply);
+     if (ret != EOK) {
+-        if (state->reply != NULL) {
+-            dbus_message_unref(state->reply);
+-        }
+-
+-        state->reply = NULL;
+-
+         tevent_req_error(req, ret);
+         return;
+     }
+@@ -253,35 +214,17 @@ errno_t _rdp_message_recv(struct tevent_req *req,
+                           ...)
+ {
+     struct rdp_message_state *state;
+-    DBusError error;
+-    dbus_bool_t bret;
+     errno_t ret;
+     va_list va;
+ 
+     TEVENT_REQ_RETURN_ON_ERROR(req);
+ 
+     state = tevent_req_data(req, struct rdp_message_state);
+-    dbus_error_init(&error);
+ 
+     va_start(va, first_arg_type);
+-    bret = dbus_message_get_args_valist(state->reply, &error, first_arg_type, va);
++    ret = sbus_parse_message_valist(state->reply, false, first_arg_type, va);
+     va_end(va);
+ 
+-    if (bret == false) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse reply\n");
+-        ret = EIO;
+-        goto done;
+-    }
+-
+-    ret = rdp_error_to_errno(&error);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse message [%s]: %s\n",
+-              error.name, error.message);
+-        goto done;
+-    }
+-
+-done:
+-    dbus_error_free(&error);
+     return ret;
+ }
+ 
+@@ -317,7 +260,7 @@ static void rdp_message_send_and_reply_done(DBusPendingCall *pending,
+                                             void *ptr)
+ {
+     struct sbus_request *sbus_req;
+-    DBusMessage *reply = NULL;
++    DBusMessage *reply;
+     dbus_uint32_t serial;
+     const char *sender;
+     dbus_bool_t dbret;
+@@ -325,7 +268,7 @@ static void rdp_message_send_and_reply_done(DBusPendingCall *pending,
+ 
+     sbus_req = talloc_get_type(ptr, struct sbus_request);
+ 
+-    ret = rdp_process_pending_call(pending, &reply);
++    ret = rdp_process_pending_call(sbus_req, pending, &reply);
+     if (reply == NULL) {
+         /* Something bad happened. Just kill the request. */
+         ret = EIO;
+@@ -358,10 +301,6 @@ static void rdp_message_send_and_reply_done(DBusPendingCall *pending,
+     ret = EOK;
+ 
+ done:
+-    if (reply != NULL) {
+-        dbus_message_unref(reply);
+-    }
+-
+     if (ret != EOK) {
+         /* Something bad happend, just kill the request. */
+         talloc_free(sbus_req);
+diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
+index c0aedf36b496bfda05dcde921ea7060efb4cc91f..15e3b117e1a467f4e250cdf4ba8fd0326e4d380e 100644
+--- a/src/sbus/sssd_dbus.h
++++ b/src/sbus/sssd_dbus.h
+@@ -29,6 +29,8 @@ struct sbus_request;
+ #include <dbus/dbus.h>
+ #include <sys/types.h>
+ #include "util/util.h"
++#include "sbus/sssd_dbus_errors.h"
++#include "sbus/sssd_dbus_utils.h"
+ 
+ /* Older platforms (such as RHEL-6) might not have these error constants
+  * defined */
+diff --git a/src/sbus/sssd_dbus_utils.c b/src/sbus/sssd_dbus_utils.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..4c33f9fd75cac2d4a56a5638982f8ecb73da8e2e
+--- /dev/null
++++ b/src/sbus/sssd_dbus_utils.c
+@@ -0,0 +1,226 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2016 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 <talloc.h>
++
++#include "sbus/sssd_dbus.h"
++#include "util/util.h"
++
++struct sbus_talloc_msg {
++    DBusMessage *msg;
++};
++
++static int sbus_talloc_msg_destructor(struct sbus_talloc_msg *talloc_msg)
++{
++    if (talloc_msg->msg == NULL) {
++        return 0;
++    }
++
++    dbus_message_unref(talloc_msg->msg);
++    return 0;
++}
++
++errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg)
++{
++    struct sbus_talloc_msg *talloc_msg;
++
++    talloc_msg = talloc(mem_ctx, struct sbus_talloc_msg);
++    if (talloc_msg == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Unable to bound D-Bus message with talloc context!\n");
++        return ENOMEM;
++    }
++
++    talloc_msg->msg = msg;
++
++    talloc_set_destructor(talloc_msg, sbus_talloc_msg_destructor);
++
++    return EOK;
++}
++
++errno_t sbus_error_to_errno(DBusError *error)
++{
++    static struct {
++        const char *name;
++        errno_t ret;
++    } list[] = { { SBUS_ERROR_INTERNAL, ERR_INTERNAL },
++                 { SBUS_ERROR_NOT_FOUND, ENOENT },
++                 { SBUS_ERROR_UNKNOWN_DOMAIN, ERR_DOMAIN_NOT_FOUND },
++                 { SBUS_ERROR_DP_FATAL, ERR_TERMINATED },
++                 { SBUS_ERROR_DP_OFFLINE, ERR_OFFLINE },
++                 { SBUS_ERROR_DP_NOTSUP, ENOTSUP },
++                 { NULL, ERR_INTERNAL } };
++    int i;
++
++    if (!dbus_error_is_set(error)) {
++        return EOK;
++    }
++
++    for (i = 0; list[i].name != NULL; i++) {
++        if (dbus_error_has_name(error, list[i].name)) {
++            return list[i].ret;
++        }
++    }
++
++    return EIO;
++}
++
++errno_t sbus_check_reply(DBusMessage *reply)
++{
++    dbus_bool_t bret;
++    DBusError error;
++    errno_t ret;
++
++    dbus_error_init(&error);
++
++    switch (dbus_message_get_type(reply)) {
++    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
++        ret = EOK;
++        goto done;
++
++    case DBUS_MESSAGE_TYPE_ERROR:
++        bret = dbus_set_error_from_message(&error, reply);
++        if (bret == false) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read error from message\n");
++            ret = EIO;
++            goto done;
++        }
++
++        DEBUG(SSSDBG_CRIT_FAILURE, "D-Bus error [%s]: %s\n",
++              error.name, (error.message == NULL ? "(null)" : error.message));
++        ret = sbus_error_to_errno(&error);
++        goto done;
++    default:
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected D-Bus message type?\n");
++        ret = ERR_INTERNAL;
++        goto done;
++    }
++
++done:
++    dbus_error_free(&error);
++
++    return ret;
++}
++
++DBusMessage *sbus_create_message_valist(TALLOC_CTX *mem_ctx,
++                                        const char *bus,
++                                        const char *path,
++                                        const char *iface,
++                                        const char *method,
++                                        int first_arg_type,
++                                        va_list va)
++{
++    DBusMessage *msg;
++    dbus_bool_t bret;
++    errno_t ret;
++
++    msg = dbus_message_new_method_call(bus, path, iface, method);
++    if (msg == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create message\n");
++        return NULL;
++    }
++
++    bret = dbus_message_append_args_valist(msg, first_arg_type, va);
++    if (!bret) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
++        ret = EIO;
++        goto done;
++    }
++
++    ret = sbus_talloc_bound_message(mem_ctx, msg);
++
++done:
++    if (ret != EOK) {
++        dbus_message_unref(msg);
++    }
++
++    return msg;
++}
++
++DBusMessage *_sbus_create_message(TALLOC_CTX *mem_ctx,
++                                  const char *bus,
++                                  const char *path,
++                                  const char *iface,
++                                  const char *method,
++                                  int first_arg_type,
++                                  ...)
++{
++    DBusMessage *msg;
++    va_list va;
++
++    va_start(va, first_arg_type);
++    msg = sbus_create_message_valist(mem_ctx, bus, path, iface, method,
++                                     first_arg_type, va);
++    va_end(va);
++
++    return msg;
++}
++
++errno_t sbus_parse_message_valist(DBusMessage *msg,
++                                  bool check_reply,
++                                  int first_arg_type,
++                                  va_list va)
++{
++    DBusError error;
++    dbus_bool_t bret;
++    errno_t ret;
++
++    if (check_reply) {
++        ret = sbus_check_reply(msg);
++        if (ret != EOK) {
++            return ret;
++        }
++    }
++
++    dbus_error_init(&error);
++
++    bret = dbus_message_get_args_valist(msg, &error, first_arg_type, va);
++    if (bret == false) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus message\n");
++        ret = EIO;
++        goto done;
++    }
++
++    ret = sbus_error_to_errno(&error);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus message [%s]: %s\n",
++              error.name, error.message);
++        goto done;
++    }
++
++done:
++    dbus_error_free(&error);
++    return ret;
++}
++
++errno_t _sbus_parse_message(DBusMessage *msg,
++                            bool check_reply,
++                            int first_arg_type,
++                            ...)
++{
++    errno_t ret;
++    va_list va;
++
++    va_start(va, first_arg_type);
++    ret = sbus_parse_message_valist(msg, check_reply, first_arg_type, va);
++    va_end(va);
++
++    return ret;
++}
+diff --git a/src/sbus/sssd_dbus_utils.h b/src/sbus/sssd_dbus_utils.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..74c21fb7930c7f5f5417b6a2587cf691b1bc0b19
+--- /dev/null
++++ b/src/sbus/sssd_dbus_utils.h
+@@ -0,0 +1,64 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2016 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/>.
++*/
++
++#ifndef SSSD_DBUS_UTILS_H_
++#define SSSD_DBUS_UTILS_H_
++
++errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg);
++errno_t sbus_error_to_errno(DBusError *error);
++errno_t sbus_check_reply(DBusMessage *reply);
++
++DBusMessage *sbus_create_message_valist(TALLOC_CTX *mem_ctx,
++                                        const char *bus,
++                                        const char *path,
++                                        const char *iface,
++                                        const char *method,
++                                        int first_arg_type,
++                                        va_list va);
++
++DBusMessage *_sbus_create_message(TALLOC_CTX *mem_ctx,
++                                  const char *bus,
++                                  const char *path,
++                                  const char *iface,
++                                  const char *method,
++                                  int first_arg_type,
++                                  ...);
++
++#define sbus_create_message(mem_ctx, bus, path, iface, method, ...) \
++    _sbus_create_message(mem_ctx, bus, path, iface, method,         \
++                         ##__VA_ARGS__, DBUS_TYPE_INVALID)
++
++errno_t sbus_parse_message_valist(DBusMessage *msg,
++                                  bool check_reply,
++                                  int first_arg_type,
++                                  va_list va);
++
++errno_t _sbus_parse_message(DBusMessage *msg,
++                            bool check_reply,
++                            int first_arg_type,
++                            ...);
++
++#define sbus_parse_message(msg, ...) \
++    _sbus_parse_message(msg, false, ##__VA_ARGS__, DBUS_TYPE_INVALID)
++
++#define sbus_parse_reply(msg, ...) \
++    _sbus_parse_message(msg, true, ##__VA_ARGS__, DBUS_TYPE_INVALID)
++
++#endif /* SSSD_DBUS_UTILS_H_ */
+diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c
+index cfc4e56133213e27496350033d4d28c3f5b5c63d..17ad670f39dfc045ba090210ffcfa77df713c306 100644
+--- a/src/tools/sssctl/sssctl_domains.c
++++ b/src/tools/sssctl/sssctl_domains.c
+@@ -79,15 +79,11 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx,
+ {
+     sss_sifp_ctx *sifp;
+     sss_sifp_error sifp_error;
+-    DBusError dbus_error;
+     DBusMessage *reply = NULL;
+-    DBusMessage *msg = NULL;
++    DBusMessage *msg;
+     bool is_online;
+-    dbus_bool_t dbret;
+     errno_t ret;
+ 
+-    dbus_error_init(&dbus_error);
+-
+     if (!sssctl_start_sssd(force_start)) {
+         ret = ERR_SSSD_NOT_RUNNING;
+         goto done;
+@@ -100,16 +96,15 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx,
+         goto done;
+     }
+ 
+-
+-    msg = sss_sifp_create_message(domain_path, IFACE_IFP_DOMAINS_DOMAIN,
+-                                  IFACE_IFP_DOMAINS_DOMAIN_ISONLINE);
++    msg = sbus_create_message(tool_ctx, SSS_SIFP_ADDRESS, domain_path,
++                              IFACE_IFP_DOMAINS_DOMAIN,
++                              IFACE_IFP_DOMAINS_DOMAIN_ISONLINE);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n");
+         ret = ENOMEM;
+         goto done;
+     }
+ 
+-
+     sifp_error = sss_sifp_send_message(sifp, msg, &reply);
+     if (sifp_error != SSS_SIFP_OK) {
+         sssctl_sifp_error(sifp, sifp_error, "Unable to get online status");
+@@ -117,16 +112,9 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx,
+         goto done;
+     }
+ 
+-    dbret = dbus_message_get_args(reply, &dbus_error,
+-                                  DBUS_TYPE_BOOLEAN, &is_online,
+-                                  DBUS_TYPE_INVALID);
+-    if (!dbret) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus reply\n");
+-        if (dbus_error_is_set(&dbus_error)) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "%s: %s\n",
+-                  dbus_error.name, dbus_error.message);
+-        }
+-        ret = EIO;
++    ret = sbus_parse_reply(reply, DBUS_TYPE_BOOLEAN, &is_online);
++    if (ret != EOK) {
++        fprintf(stderr, _("Unable to get information from SSSD\n"));
+         goto done;
+     }
+ 
+@@ -135,16 +123,10 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx,
+     ret = EOK;
+ 
+ done:
+-    if (msg != NULL) {
+-        dbus_message_unref(msg);
+-    }
+-
+     if (reply != NULL) {
+         dbus_message_unref(reply);
+     }
+ 
+-    dbus_error_free(&dbus_error);
+-
+     return ret;
+ }
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0094-FO-Add-an-API-to-reset-all-servers-in-a-single-servi.patch b/SOURCES/0094-FO-Add-an-API-to-reset-all-servers-in-a-single-servi.patch
deleted file mode 100644
index dfe3da8..0000000
--- a/SOURCES/0094-FO-Add-an-API-to-reset-all-servers-in-a-single-servi.patch
+++ /dev/null
@@ -1,128 +0,0 @@
-From 3551dd5c2c2c75ce68ef95b91fc2420f17c92b92 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 21 Sep 2015 12:31:18 +0200
-Subject: [PATCH 94/96] FO: Add an API to reset all servers in a single service
-
-Required for:
-    https://fedorahosted.org/sssd/ticket/2639
-
-Previously, we had a function that allowed the caller to reset the
-status of all services in the global fail over context. This patch adds
-a new function that allows the caller to reset a single service instead.
-
-The main user would be IPA subdomain provider that might need to reset
-the status of an AD trusted domain on demand.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 3ac3b5746f08970c109664b95340c556057e3c6a)
----
- src/providers/data_provider_fo.c | 19 +++++++++++++++++++
- src/providers/dp_backend.h       |  1 +
- src/providers/fail_over.c        | 30 ++++++++++++++++++++----------
- src/providers/fail_over.h        |  2 ++
- 4 files changed, 42 insertions(+), 10 deletions(-)
-
-diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
-index 41d70de065260f31dcea4c2b664a1f436823ccc1..cd57340a0ba0ac7e474dc502bf1f1b4de0e1f778 100644
---- a/src/providers/data_provider_fo.c
-+++ b/src/providers/data_provider_fo.c
-@@ -743,6 +743,25 @@ void reset_fo(struct be_ctx *be_ctx)
-     fo_reset_services(be_ctx->be_fo->fo_ctx);
- }
- 
-+void be_fo_reset_svc(struct be_ctx *be_ctx,
-+                     const char *svc_name)
-+{
-+    struct fo_service *service;
-+    int ret;
-+
-+    DEBUG(SSSDBG_TRACE_LIBS,
-+          "Resetting all servers in service %s\n", svc_name);
-+
-+    ret = fo_get_service(be_ctx->be_fo->fo_ctx, svc_name, &service);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot retrieve service [%s]\n", svc_name);
-+        return;
-+    }
-+
-+    fo_reset_servers(service);
-+}
-+
- void _be_fo_set_port_status(struct be_ctx *ctx,
-                             const char *service_name,
-                             struct fo_server *server,
-diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
-index 4bffcee9e8739302343b7813d3540eb43e966581..0ced851be8468ce21a9d283e26461fc47194557e 100644
---- a/src/providers/dp_backend.h
-+++ b/src/providers/dp_backend.h
-@@ -283,6 +283,7 @@ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
-                                         const char *service_name);
- 
- void reset_fo(struct be_ctx *be_ctx);
-+void be_fo_reset_svc(struct be_ctx *be_ctx, const char *svc_name);
- 
- errno_t be_res_init(struct be_ctx *ctx);
- 
-diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
-index 6d835ae0efdfdf96532e8458e12238ba17910a4f..562f0b3fd7870387a80c889b245cda0d39dea509 100644
---- a/src/providers/fail_over.c
-+++ b/src/providers/fail_over.c
-@@ -1547,21 +1547,31 @@ time_t fo_get_service_retry_timeout(struct fo_service *svc)
-     return svc->ctx->opts->retry_timeout;
- }
- 
-+void fo_reset_servers(struct fo_service *service)
-+{
-+    struct fo_server *server;
-+
-+    DLIST_FOR_EACH(server, service->server_list) {
-+        if (server->srv_data != NULL) {
-+            set_srv_data_status(server->srv_data, SRV_NEUTRAL);
-+        } else {
-+            fo_set_server_status(server, SERVER_NAME_NOT_RESOLVED);
-+        }
-+
-+        fo_set_port_status(server, PORT_NEUTRAL);
-+    }
-+}
-+
-+
- void fo_reset_services(struct fo_ctx *fo_ctx)
- {
-     struct fo_service *service;
--    struct fo_server *server;
-+
-+    DEBUG(SSSDBG_TRACE_LIBS,
-+          "Resetting all servers in all services\n");
- 
-     DLIST_FOR_EACH(service, fo_ctx->service_list) {
--        DLIST_FOR_EACH(server, service->server_list) {
--            if (server->srv_data != NULL) {
--                set_srv_data_status(server->srv_data, SRV_NEUTRAL);
--            } else {
--                fo_set_server_status(server, SERVER_NAME_NOT_RESOLVED);
--            }
--
--            fo_set_port_status(server, PORT_NEUTRAL);
--        }
-+        fo_reset_servers(service);
-     }
- }
- 
-diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
-index d44ad2ff145dc6b3617e6f2ea665c7d82d923ddb..e49c6414a14eb6ca2cad333f8efbb58576811345 100644
---- a/src/providers/fail_over.h
-+++ b/src/providers/fail_over.h
-@@ -198,6 +198,8 @@ time_t fo_get_service_retry_timeout(struct fo_service *svc);
- 
- void fo_reset_services(struct fo_ctx *fo_ctx);
- 
-+void fo_reset_servers(struct fo_service *svc);
-+
- bool fo_svc_has_server(struct fo_service *service, struct fo_server *server);
- 
- /*
--- 
-2.4.3
-
diff --git a/SOURCES/0094-sssctl-use-talloc-with-sifp.patch b/SOURCES/0094-sssctl-use-talloc-with-sifp.patch
new file mode 100644
index 0000000..4417086
--- /dev/null
+++ b/SOURCES/0094-sssctl-use-talloc-with-sifp.patch
@@ -0,0 +1,215 @@
+From bb8653ba6ba4eddb7faeddd9ceb3349107f77fd9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 29 Jun 2016 14:03:38 +0200
+Subject: [PATCH 094/102] sssctl: use talloc with sifp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This way we completely move D-Bus memory management to talloc and
+we reduce number of code lines needed to send and receive reply.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 9b74009c1260e6f3b1031a6ae110bf1d957cba81)
+---
+ src/tools/sssctl/sssctl.h         | 14 +++++++++
+ src/tools/sssctl/sssctl_domains.c | 62 ++++++++++++++++++---------------------
+ src/tools/sssctl/sssctl_sifp.c    | 46 +++++++++++++++++++++++++++++
+ 3 files changed, 88 insertions(+), 34 deletions(-)
+
+diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
+index 72930ee5c3a1195e90c6e35768f715cbf6a1c4e1..d4e3359b0b160d12a0c2699f754989a24b2b336a 100644
+--- a/src/tools/sssctl/sssctl.h
++++ b/src/tools/sssctl/sssctl.h
+@@ -24,6 +24,7 @@
+ #include "lib/sifp/sss_sifp.h"
+ #include "lib/sifp/sss_sifp_dbus.h"
+ #include "tools/common/sss_tools.h"
++#include "sbus/sssd_dbus.h"
+ 
+ enum sssctl_prompt_result {
+     SSSCTL_PROMPT_YES,
+@@ -56,6 +57,19 @@ void _sssctl_sifp_error(sss_sifp_ctx *sifp,
+ #define sssctl_sifp_error(sifp, error, message) \
+     _sssctl_sifp_error(sifp, error, _(message))
+ 
++sss_sifp_error _sssctl_sifp_send(TALLOC_CTX *mem_ctx,
++                                 sss_sifp_ctx *sifp,
++                                 DBusMessage **_reply,
++                                 const char *path,
++                                 const char *iface,
++                                 const char *method,
++                                 int first_arg_type,
++                                 ...);
++
++#define sssctl_sifp_send(mem_ctx, sifp, reply, path, iface, method, ...) \
++    _sssctl_sifp_send(mem_ctx, sifp, reply, path, iface, method,         \
++                      ##__VA_ARGS__, DBUS_TYPE_INVALID);
++
+ errno_t sssctl_domain_list(struct sss_cmdline *cmdline,
+                            struct sss_tool_ctx *tool_ctx,
+                            void *pvt);
+diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c
+index 17ad670f39dfc045ba090210ffcfa77df713c306..40962792b84eabeb2c142f158184b17180a01669 100644
+--- a/src/tools/sssctl/sssctl_domains.c
++++ b/src/tools/sssctl/sssctl_domains.c
+@@ -74,47 +74,32 @@ errno_t sssctl_domain_list(struct sss_cmdline *cmdline,
+ }
+ 
+ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx,
+-                                           const char *domain_path,
+-                                           bool force_start)
++                                           sss_sifp_ctx *sifp,
++                                           const char *domain_path)
+ {
+-    sss_sifp_ctx *sifp;
+-    sss_sifp_error sifp_error;
+-    DBusMessage *reply = NULL;
+-    DBusMessage *msg;
++    TALLOC_CTX *tmp_ctx;
++    sss_sifp_error error;
++    DBusMessage *reply;
+     bool is_online;
+     errno_t ret;
+ 
+-    if (!sssctl_start_sssd(force_start)) {
+-        ret = ERR_SSSD_NOT_RUNNING;
+-        goto done;
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
++        return ENOMEM;
+     }
+ 
+-    sifp_error = sssctl_sifp_init(tool_ctx, &sifp);
+-    if (sifp_error != SSS_SIFP_OK) {
+-        sssctl_sifp_error(sifp, sifp_error, "Unable to connect to the InfoPipe");
+-        ret = EFAULT;
+-        goto done;
+-    }
+-
+-    msg = sbus_create_message(tool_ctx, SSS_SIFP_ADDRESS, domain_path,
+-                              IFACE_IFP_DOMAINS_DOMAIN,
+-                              IFACE_IFP_DOMAINS_DOMAIN_ISONLINE);
+-    if (msg == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    sifp_error = sss_sifp_send_message(sifp, msg, &reply);
+-    if (sifp_error != SSS_SIFP_OK) {
+-        sssctl_sifp_error(sifp, sifp_error, "Unable to get online status");
++    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
++                             IFACE_IFP_DOMAINS_DOMAIN,
++                             IFACE_IFP_DOMAINS_DOMAIN_ISONLINE);
++    if (error != SSS_SIFP_OK) {
++        sssctl_sifp_error(sifp, error, "Unable to get online status");
+         ret = EIO;
+         goto done;
+     }
+ 
+     ret = sbus_parse_reply(reply, DBUS_TYPE_BOOLEAN, &is_online);
+     if (ret != EOK) {
+-        fprintf(stderr, _("Unable to get information from SSSD\n"));
+         goto done;
+     }
+ 
+@@ -123,10 +108,7 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx,
+     ret = EOK;
+ 
+ done:
+-    if (reply != NULL) {
+-        dbus_message_unref(reply);
+-    }
+-
++    talloc_free(tmp_ctx);
+     return ret;
+ }
+ 
+@@ -144,6 +126,8 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
+                              void *pvt)
+ {
+     struct sssctl_domain_status_opts opts = {0};
++    sss_sifp_ctx *sifp;
++    sss_sifp_error error;
+     const char *path;
+     bool opt_set;
+     errno_t ret;
+@@ -181,7 +165,17 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
+         return ENOMEM;
+     }
+ 
+-    ret = sssctl_domain_status_online(tool_ctx, path, opts.force_start);
++    if (!sssctl_start_sssd(opts.force_start)) {
++        return ERR_SSSD_NOT_RUNNING;
++    }
++
++    error = sssctl_sifp_init(tool_ctx, &sifp);
++    if (error != SSS_SIFP_OK) {
++        sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe");
++        return EFAULT;
++    }
++
++    ret = sssctl_domain_status_online(tool_ctx, sifp, path);
+     if (ret != EOK) {
+         fprintf(stderr, _("Unable to get online status\n"));
+         return ret;
+diff --git a/src/tools/sssctl/sssctl_sifp.c b/src/tools/sssctl/sssctl_sifp.c
+index e541c4b27ba38e50b209b0957c8b38f03afc891a..782a72d7ce8bbf1080c6d6ac988ffac2f432955f 100644
+--- a/src/tools/sssctl/sssctl_sifp.c
++++ b/src/tools/sssctl/sssctl_sifp.c
+@@ -116,3 +116,49 @@ void _sssctl_sifp_error(sss_sifp_ctx *sifp,
+         break;
+     }
+ }
++
++sss_sifp_error _sssctl_sifp_send(TALLOC_CTX *mem_ctx,
++                                 sss_sifp_ctx *sifp,
++                                 DBusMessage **_reply,
++                                 const char *path,
++                                 const char *iface,
++                                 const char *method,
++                                 int first_arg_type,
++                                 ...)
++{
++    sss_sifp_error error;
++    DBusMessage *msg;
++    dbus_bool_t bret;
++    errno_t ret;
++    va_list va;
++
++    msg = sss_sifp_create_message(path, iface, method);
++    if (msg == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n");
++        return SSS_SIFP_OUT_OF_MEMORY;
++    }
++
++    va_start(va, first_arg_type);
++    bret = dbus_message_append_args_valist(msg, first_arg_type, va);
++    va_end(va);
++    if (!bret) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
++        error = SSS_SIFP_OUT_OF_MEMORY;
++        goto done;
++    }
++
++    error = sss_sifp_send_message(sifp, msg, _reply);
++    if (error != SSS_SIFP_OK) {
++        goto done;
++    }
++
++    ret = sbus_talloc_bound_message(mem_ctx, *_reply);
++    if (ret != EOK) {
++        error = SSS_SIFP_OUT_OF_MEMORY;
++        goto done;
++    }
++
++done:
++    dbus_message_unref(msg);
++    return error;
++}
+-- 
+2.4.11
+
diff --git a/SOURCES/0095-FO-Also-reset-the-server-common-data-in-addition-to-.patch b/SOURCES/0095-FO-Also-reset-the-server-common-data-in-addition-to-.patch
deleted file mode 100644
index ea5b245..0000000
--- a/SOURCES/0095-FO-Also-reset-the-server-common-data-in-addition-to-.patch
+++ /dev/null
@@ -1,426 +0,0 @@
-From 1f861441042380362345d8ce3f9e81151664c6c0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 21 Sep 2015 12:31:38 +0200
-Subject: [PATCH 95/96] FO: Also reset the server common data in addition to
- SRV
-
-In a server that is expanded from a SRV query was reset, only it's
-'meta-server' status was set to neutral, but the server->common
-structure still retained its not_working status.
-
-This patch also resets the status of the common structure so that both
-the SRV query and resolving the server are retried next time.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 6ac6e8f83da241458742b7f8a3406ed66bded292)
----
- src/providers/fail_over.c      |   4 +-
- src/tests/cmocka/test_fo_srv.c | 188 ++++++++++++++++++++++++++++++-----------
- 2 files changed, 142 insertions(+), 50 deletions(-)
-
-diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
-index 562f0b3fd7870387a80c889b245cda0d39dea509..b076687ac6e571f7e27402fd11ac60183ea46951 100644
---- a/src/providers/fail_over.c
-+++ b/src/providers/fail_over.c
-@@ -1554,7 +1554,9 @@ void fo_reset_servers(struct fo_service *service)
-     DLIST_FOR_EACH(server, service->server_list) {
-         if (server->srv_data != NULL) {
-             set_srv_data_status(server->srv_data, SRV_NEUTRAL);
--        } else {
-+        }
-+
-+        if (server->common) {
-             fo_set_server_status(server, SERVER_NAME_NOT_RESOLVED);
-         }
- 
-diff --git a/src/tests/cmocka/test_fo_srv.c b/src/tests/cmocka/test_fo_srv.c
-index e5c5e4fe3b818ca2df0ab7bcd1a83719fefba191..e892bab0a261779363ea78a10038b15acefc49b7 100644
---- a/src/tests/cmocka/test_fo_srv.c
-+++ b/src/tests/cmocka/test_fo_srv.c
-@@ -194,7 +194,7 @@ errno_t resolv_get_domain_recv(TALLOC_CTX *mem_ctx,
- }
- 
- /* The unit test */
--struct test_fo_srv_ctx {
-+struct test_fo_ctx {
-     struct resolv_ctx *resolv;
-     struct fo_ctx *fo_ctx;
-     struct fo_resolve_srv_dns_ctx *srv_ctx;
-@@ -208,19 +208,18 @@ int test_fo_srv_data_cmp(void *ud1, void *ud2)
-     return strcasecmp((char*) ud1, (char*) ud2);
- }
- 
--static int test_fo_srv_setup(void **state)
-+static int test_fo_setup(void **state)
- {
--    struct test_fo_srv_ctx *test_ctx;
-+    struct test_fo_ctx *test_ctx;
-     errno_t ret;
-     struct fo_options fopts;
--    bool ok;
- 
-     assert_true(leak_check_setup());
-     global_mock_context = talloc_new(global_talloc_context);
-     assert_non_null(global_mock_context);
- 
-     test_ctx = talloc_zero(global_mock_context,
--                           struct test_fo_srv_ctx);
-+                           struct test_fo_ctx);
-     assert_non_null(test_ctx);
- 
-     test_ctx->ctx = create_ev_test_ctx(test_ctx);
-@@ -237,6 +236,34 @@ static int test_fo_srv_setup(void **state)
-     test_ctx->fo_ctx = fo_context_init(test_ctx, &fopts);
-     assert_non_null(test_ctx->fo_ctx);
- 
-+    ret = fo_new_service(test_ctx->fo_ctx, "ldap",
-+                         test_fo_srv_data_cmp,
-+                         &test_ctx->fo_svc);
-+    assert_int_equal(ret, ERR_OK);
-+
-+    *state = test_ctx;
-+    return 0;
-+}
-+
-+static int test_fo_teardown(void **state)
-+{
-+    struct test_fo_ctx *test_ctx =
-+        talloc_get_type(*state, struct test_fo_ctx);
-+
-+    talloc_free(test_ctx);
-+    talloc_free(global_mock_context);
-+    assert_true(leak_check_teardown());
-+    return 0;
-+}
-+
-+static int test_fo_srv_setup(void **state)
-+{
-+    struct test_fo_ctx *test_ctx;
-+    bool ok;
-+
-+    test_fo_setup(state);
-+    test_ctx = *state;
-+
-     test_ctx->srv_ctx = fo_resolve_srv_dns_ctx_init(test_ctx, test_ctx->resolv,
-                                                     IPV4_FIRST, default_host_dbs,
-                                                     "client.sssd.com", "sssd.local");
-@@ -248,23 +275,13 @@ static int test_fo_srv_setup(void **state)
-                                   test_ctx->srv_ctx);
-     assert_true(ok);
- 
--    ret = fo_new_service(test_ctx->fo_ctx, "ldap",
--                         test_fo_srv_data_cmp,
--                         &test_ctx->fo_svc);
--    assert_int_equal(ret, ERR_OK);
--
-     *state = test_ctx;
-     return 0;
- }
- 
- static int test_fo_srv_teardown(void **state)
- {
--    struct test_fo_srv_ctx *test_ctx =
--        talloc_get_type(*state, struct test_fo_srv_ctx);
--
--    talloc_free(test_ctx);
--    talloc_free(global_mock_context);
--    assert_true(leak_check_teardown());
-+    test_fo_teardown(state);
-     return 0;
- }
- 
-@@ -280,25 +297,30 @@ static void mock_srv_results(struct ares_srv_reply *reply_list,
-     will_return(resolv_discover_srv_recv, dns_domain);
- }
- 
--static void check_server(struct fo_server *srv, int port, const char *name)
-+static void check_server(struct test_fo_ctx *ctx,
-+                         struct fo_server *srv,
-+                         int port,
-+                         const char *name)
- {
-     assert_non_null(srv);
--    assert_true(fo_is_srv_lookup(srv));
-     assert_int_equal(fo_get_server_port(srv), port);
-     assert_string_equal(fo_get_server_name(srv), name);
-+
-+
-+    if (ctx->srv_ctx) {
-+        assert_true(fo_is_srv_lookup(srv));
-+    }
- }
- 
-+static void test_fo_srv_step1(struct test_fo_ctx *test_ctx);
- static void test_fo_srv_done1(struct tevent_req *req);
- static void test_fo_srv_done2(struct tevent_req *req);
- static void test_fo_srv_done3(struct tevent_req *req);
- static void test_fo_srv_done4(struct tevent_req *req);
-+static void test_fo_srv_done5(struct tevent_req *req);
- 
--void test_fo_srv(void **state)
-+static void test_fo_srv_mock_dns(struct test_fo_ctx *test_ctx)
- {
--    errno_t ret;
--    struct tevent_req *req;
--    struct test_fo_srv_ctx *test_ctx =
--        talloc_get_type(*state, struct test_fo_srv_ctx);
-     struct ares_srv_reply *s1;
-     struct ares_srv_reply *s2;
-     char *dns_domain;
-@@ -325,25 +347,41 @@ void test_fo_srv(void **state)
-     assert_non_null(dns_domain);
- 
-     mock_srv_results(s1, TEST_SRV_TTL, dns_domain);
-+}
-+
-+static void test_fo_srv(void **state)
-+{
-+    errno_t ret;
-+    struct test_fo_ctx *test_ctx =
-+        talloc_get_type(*state, struct test_fo_ctx);
-+
-+    test_fo_srv_mock_dns(test_ctx);
- 
-     ret = fo_add_srv_server(test_ctx->fo_svc, "_ldap", "sssd.com",
-                             "sssd.local", "tcp", test_ctx);
-     assert_int_equal(ret, ERR_OK);
- 
-+    test_fo_srv_step1(test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->ctx);
-+    assert_int_equal(ret, ERR_OK);
-+}
-+
-+static void test_fo_srv_step1(struct test_fo_ctx *test_ctx)
-+{
-+    struct tevent_req *req;
-+
-     req = fo_resolve_service_send(test_ctx, test_ctx->ctx->ev,
-                                   test_ctx->resolv, test_ctx->fo_ctx,
-                                   test_ctx->fo_svc);
-     assert_non_null(req);
-     tevent_req_set_callback(req, test_fo_srv_done1, test_ctx);
--
--    ret = test_ev_loop(test_ctx->ctx);
--    assert_int_equal(ret, ERR_OK);
- }
- 
- static void test_fo_srv_done1(struct tevent_req *req)
- {
--    struct test_fo_srv_ctx *test_ctx = \
--        tevent_req_callback_data(req, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-     struct fo_server *srv;
-     errno_t ret;
- 
-@@ -352,7 +390,7 @@ static void test_fo_srv_done1(struct tevent_req *req)
-     assert_int_equal(ret, ERR_OK);
- 
-     /* ldap1.sssd.com has lower priority, it must always be first */
--    check_server(srv, 389, "ldap1.sssd.com");
-+    check_server(test_ctx, srv, 389, "ldap1.sssd.com");
- 
-     /* Mark the server as working and request the service again. The same server
-      * must be returned */
-@@ -367,8 +405,8 @@ static void test_fo_srv_done1(struct tevent_req *req)
- 
- static void test_fo_srv_done2(struct tevent_req *req)
- {
--    struct test_fo_srv_ctx *test_ctx = \
--        tevent_req_callback_data(req, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-     struct fo_server *srv;
-     errno_t ret;
- 
-@@ -377,7 +415,7 @@ static void test_fo_srv_done2(struct tevent_req *req)
-     assert_int_equal(ret, ERR_OK);
- 
-     /* Must be ldap1 again */
--    check_server(srv, 389, "ldap1.sssd.com");
-+    check_server(test_ctx, srv, 389, "ldap1.sssd.com");
- 
-     /* Mark it at wrong, next lookup should yield ldap2 */
-     fo_set_server_status(srv, SERVER_NOT_WORKING);
-@@ -391,8 +429,8 @@ static void test_fo_srv_done2(struct tevent_req *req)
- 
- static void test_fo_srv_done3(struct tevent_req *req)
- {
--    struct test_fo_srv_ctx *test_ctx = \
--        tevent_req_callback_data(req, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-     struct fo_server *srv;
-     errno_t ret;
- 
-@@ -401,7 +439,7 @@ static void test_fo_srv_done3(struct tevent_req *req)
-     assert_int_equal(ret, ERR_OK);
- 
-     /* Must be ldap2 now */
--    check_server(srv, 389, "ldap2.sssd.com");
-+    check_server(test_ctx, srv, 389, "ldap2.sssd.com");
- 
-     /* Mark is at wrong, next lookup must reach the end of the server list */
-     fo_set_server_status(srv, SERVER_NOT_WORKING);
-@@ -415,8 +453,8 @@ static void test_fo_srv_done3(struct tevent_req *req)
- 
- static void test_fo_srv_done4(struct tevent_req *req)
- {
--    struct test_fo_srv_ctx *test_ctx = \
--        tevent_req_callback_data(req, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-     struct fo_server *srv;
-     errno_t ret;
- 
-@@ -425,6 +463,35 @@ static void test_fo_srv_done4(struct tevent_req *req)
-     /* No servers are left..*/
-     assert_int_equal(ret, ENOENT);
- 
-+    /* reset the server status and try again.. */
-+    fo_reset_servers(test_ctx->fo_svc);
-+    if (test_ctx->srv_ctx) {
-+        test_fo_srv_mock_dns(test_ctx);
-+    }
-+
-+    req = fo_resolve_service_send(test_ctx, test_ctx->ctx->ev,
-+                                  test_ctx->resolv, test_ctx->fo_ctx,
-+                                  test_ctx->fo_svc);
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, test_fo_srv_done5, test_ctx);
-+}
-+
-+static void test_fo_srv_done5(struct tevent_req *req)
-+{
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-+    struct fo_server *srv;
-+    errno_t ret;
-+
-+    ret = fo_resolve_service_recv(req, &srv);
-+    talloc_zfree(req);
-+
-+    assert_int_equal(ret, ERR_OK);
-+
-+    /* ldap1.sssd.com has lower priority, it must always be first */
-+    check_server(test_ctx, srv, 389, "ldap1.sssd.com");
-+
-+    /* OK, we made a full circle with the test, done */
-     test_ctx->ctx->error = ERR_OK;
-     test_ctx->ctx->done = true;
- }
-@@ -432,20 +499,20 @@ static void test_fo_srv_done4(struct tevent_req *req)
- /* Make sure that two queries more than TTL seconds apart resolve
-  * into two different lists
-  */
--static void test_fo_srv_ttl_change_step(struct test_fo_srv_ctx *test_ctx);
-+static void test_fo_srv_ttl_change_step(struct test_fo_ctx *test_ctx);
- static void test_fo_srv_before(struct tevent_req *req);
- static void test_fo_srv_after(struct tevent_req *req);
- 
- void test_fo_srv_ttl_change(void **state)
- {
--    struct test_fo_srv_ctx *test_ctx =
--        talloc_get_type(*state, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx =
-+        talloc_get_type(*state, struct test_fo_ctx);
- 
-     test_ctx->ttl = TEST_SRV_SHORT_TTL;
-     test_fo_srv_ttl_change_step(test_ctx);
- }
- 
--static void test_fo_srv_ttl_change_step(struct test_fo_srv_ctx *test_ctx)
-+static void test_fo_srv_ttl_change_step(struct test_fo_ctx *test_ctx)
- {
-     errno_t ret;
-     struct tevent_req *req;
-@@ -497,8 +564,8 @@ static void test_fo_srv_ttl_change_step(struct test_fo_srv_ctx *test_ctx)
- 
- static void test_fo_srv_before(struct tevent_req *req)
- {
--    struct test_fo_srv_ctx *test_ctx = \
--        tevent_req_callback_data(req, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-     struct fo_server *srv;
-     struct ares_srv_reply *s1;
-     struct ares_srv_reply *s2;
-@@ -511,7 +578,7 @@ static void test_fo_srv_before(struct tevent_req *req)
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "Before TTL change\n");
- 
--    check_server(srv, 389, "ldap1.sssd.com");
-+    check_server(test_ctx, srv, 389, "ldap1.sssd.com");
-     fo_set_server_status(srv, SERVER_WORKING);
- 
-     /* Simulate changing the DNS environment. Change the host names */
-@@ -548,8 +615,8 @@ static void test_fo_srv_before(struct tevent_req *req)
- 
- static void test_fo_srv_after(struct tevent_req *req)
- {
--    struct test_fo_srv_ctx *test_ctx = \
--        tevent_req_callback_data(req, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx = \
-+        tevent_req_callback_data(req, struct test_fo_ctx);
-     struct fo_server *srv;
-     errno_t ret;
- 
-@@ -558,7 +625,7 @@ static void test_fo_srv_after(struct tevent_req *req)
-     assert_int_equal(ret, ERR_OK);
- 
-     /* Must be a different server now */
--    check_server(srv, 389, "ldap3.sssd.com");
-+    check_server(test_ctx, srv, 389, "ldap3.sssd.com");
- 
-     test_ctx->ctx->error = ERR_OK;
-     test_ctx->ctx->done = true;
-@@ -566,13 +633,33 @@ static void test_fo_srv_after(struct tevent_req *req)
- 
- void test_fo_srv_ttl_zero(void **state)
- {
--    struct test_fo_srv_ctx *test_ctx =
--        talloc_get_type(*state, struct test_fo_srv_ctx);
-+    struct test_fo_ctx *test_ctx =
-+        talloc_get_type(*state, struct test_fo_ctx);
- 
-     test_ctx->ttl = 0;
-     test_fo_srv_ttl_change_step(test_ctx);
- }
- 
-+static void test_fo_hostlist(void **state)
-+{
-+    errno_t ret;
-+    struct test_fo_ctx *test_ctx =
-+        talloc_get_type(*state, struct test_fo_ctx);
-+
-+    ret = fo_add_server(test_ctx->fo_svc,
-+                        "ldap1.sssd.com", 389, test_ctx, true);
-+    assert_int_equal(ret, ERR_OK);
-+
-+    ret = fo_add_server(test_ctx->fo_svc,
-+                        "ldap2.sssd.com", 389, test_ctx, true);
-+    assert_int_equal(ret, ERR_OK);
-+
-+    test_fo_srv_step1(test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->ctx);
-+    assert_int_equal(ret, ERR_OK);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     int rv;
-@@ -585,6 +672,9 @@ int main(int argc, const char *argv[])
-     };
- 
-     const struct CMUnitTest tests[] = {
-+        cmocka_unit_test_setup_teardown(test_fo_hostlist,
-+                                        test_fo_setup,
-+                                        test_fo_teardown),
-         cmocka_unit_test_setup_teardown(test_fo_srv,
-                                         test_fo_srv_setup,
-                                         test_fo_srv_teardown),
--- 
-2.4.3
-
diff --git a/SOURCES/0095-failover-mark-subdomain-service-with-sd_-prefix.patch b/SOURCES/0095-failover-mark-subdomain-service-with-sd_-prefix.patch
new file mode 100644
index 0000000..4d9a1bf
--- /dev/null
+++ b/SOURCES/0095-failover-mark-subdomain-service-with-sd_-prefix.patch
@@ -0,0 +1,92 @@
+From a3b502fa85d493795c963e4298aeec3dc5806fcf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 29 Jun 2016 14:58:37 +0200
+Subject: [PATCH 095/102] failover: mark subdomain service with sd_ prefix
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 778f241e78241b0d6b8734148175f8dee804f494)
+---
+ src/providers/ad/ad_subdomains.c          | 11 +++++++++--
+ src/providers/ipa/ipa_subdomains_server.c | 11 +++++++++--
+ 2 files changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index e9da04e384e598927f9c8c203a751bcccd29e895..a0d5c2e544fc62fda64771dce59b3b7ab8ecd8b6 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -66,6 +66,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+     struct ad_options *ad_options;
+     struct ad_id_ctx *ad_id_ctx;
+     const char *gc_service_name;
++    const char *service_name;
+     struct ad_srv_plugin_ctx *srv_ctx;
+     char *ad_domain;
+     char *ad_site_override;
+@@ -94,14 +95,20 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+ 
+     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
+ 
+-    gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
++    gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->name);
+     if (gc_service_name == NULL) {
+         talloc_free(ad_options);
+         return ENOMEM;
+     }
+ 
++    service_name = talloc_asprintf(ad_options, "sd_%s", subdom->name);
++    if (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,
++                           service_name, gc_service_name,
+                            subdom->name, &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
+diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
+index 43636098f6928006db0e0a9c05f2e39f8427d705..13640b04d66a1cdbbf0c8eab7648f7ebe921884b 100644
+--- a/src/providers/ipa/ipa_subdomains_server.c
++++ b/src/providers/ipa/ipa_subdomains_server.c
+@@ -203,6 +203,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+     struct ad_options *ad_options;
+     struct ad_id_ctx *ad_id_ctx;
+     const char *gc_service_name;
++    const char *service_name;
+     struct ad_srv_plugin_ctx *srv_ctx;
+     const char *ad_domain;
+     const char *ad_site_override;
+@@ -250,17 +251,23 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+         DEBUG(SSSDBG_TRACE_ALL, "No extra attrs set.\n");
+     }
+ 
+-    gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->forest);
++    gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->forest);
+     if (gc_service_name == NULL) {
+         talloc_free(ad_options);
+         return ENOMEM;
+     }
+ 
++    service_name = talloc_asprintf(ad_options, "sd_%s", subdom->name);
++    if (service_name == NULL) {
++        talloc_free(ad_options);
++        return ENOMEM;
++    }
++
+     /* Set KRB5 realm to same as the one of IPA when IPA
+      * is able to attach PAC. For testing, use hardcoded. */
+     ret = ad_failover_init(ad_options, be_ctx, NULL, NULL,
+                            id_ctx->server_mode->realm,
+-                           subdom->name, gc_service_name,
++                           service_name, gc_service_name,
+                            subdom->name, &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
+-- 
+2.4.11
+
diff --git a/SOURCES/0096-IPA-Retry-fetching-keytab-if-IPA-user-lookup-fails.patch b/SOURCES/0096-IPA-Retry-fetching-keytab-if-IPA-user-lookup-fails.patch
deleted file mode 100644
index f5b2c27..0000000
--- a/SOURCES/0096-IPA-Retry-fetching-keytab-if-IPA-user-lookup-fails.patch
+++ /dev/null
@@ -1,296 +0,0 @@
-From 569233a9db93bfd2926bb1ecf73d9b67a634e840 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 17 Sep 2015 17:11:34 +0200
-Subject: [PATCH 96/96] IPA: Retry fetching keytab if IPA user lookup fails
-
-Required for:
-    https://fedorahosted.org/sssd/ticket/2639
-
-Instead of calling ipa_get_ad_acct_send directly, call a new request
-ipa_srv_ad_acct_send. The new request wraps ipa_get_ad_acct_send and
-either tries to request a new keytab every time the lookup fails but the
-domain is online.
-
-be_mark_dom_offline() is called when the retry fails with the new code.
-
-The retry tries to re-setup the trusted domain. With two-way setups, the
-request is a no-op. With one-way trust setups, the request re-fetches
-new keytab unconditionally.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 0aff5b651a414a1fd58ab3eb2f029399c0278a18)
----
- src/providers/ipa/ipa_id.h            |   9 --
- src/providers/ipa/ipa_subdomains_id.c | 190 +++++++++++++++++++++++++++++++++-
- 2 files changed, 185 insertions(+), 14 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
-index c03ca037a2850478a8f4933bac4fcf8bd70ada04..91a94115386955f63eca706bf6f4ac41884445eb 100644
---- a/src/providers/ipa/ipa_id.h
-+++ b/src/providers/ipa/ipa_id.h
-@@ -70,15 +70,6 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
-                                             struct be_acct_req *ar);
- int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out);
- 
--struct tevent_req *ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
--                                        struct tevent_context *ev,
--                                        struct ipa_id_ctx *ipa_ctx,
--                                        struct be_req *be_req,
--                                        struct sysdb_attrs *override_attrs,
--                                        struct be_acct_req *ar);
--
--errno_t ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out);
--
- errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
-                                 const char *domain_name,
-                                 struct be_acct_req **_ar);
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index ff14b4a4c68cb5c6e9865a66931ee4ecd6e49211..86dd71f3cc09f11de88c4269d49552718c5ba027 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -34,6 +34,16 @@
- #include "providers/ad/ad_id.h"
- #include "providers/ipa/ipa_subdomains.h"
- 
-+static struct tevent_req *
-+ipa_srv_ad_acct_send(TALLOC_CTX *mem_ctx,
-+                     struct tevent_context *ev,
-+                     struct ipa_id_ctx *ipa_ctx,
-+                     struct be_req *be_req,
-+                     struct sysdb_attrs *override_attrs,
-+                     struct be_acct_req *ar);
-+static errno_t
-+ipa_srv_ad_acct_recv(struct tevent_req *req, int *dp_error_out);
-+
- struct ipa_subdomain_account_state {
-     struct tevent_context *ev;
-     struct ipa_id_ctx *ipa_ctx;
-@@ -45,6 +55,7 @@ struct ipa_subdomain_account_state {
-     struct be_acct_req *ar;
- 
-     bool ipa_server_mode;
-+    bool server_retry;
-     int entry_type;
-     const char *filter;
-     int filter_type;
-@@ -263,7 +274,7 @@ static errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
-     struct tevent_req *subreq;
- 
-     if (state->ipa_server_mode) {
--        subreq = ipa_get_ad_acct_send(state, state->ev, state->ipa_ctx,
-+        subreq = ipa_srv_ad_acct_send(state, state->ev, state->ipa_ctx,
-                                       state->be_req, state->override_attrs, ar);
-     } else {
-         subreq = ipa_get_subdom_acct_send(state, state->ev, state->ipa_ctx,
-@@ -291,7 +302,7 @@ static void ipa_subdomain_account_done(struct tevent_req *subreq)
-     int ret;
- 
-     if (state->ipa_server_mode) {
--        ret = ipa_get_ad_acct_recv(subreq, &dp_error);
-+        ret = ipa_srv_ad_acct_recv(subreq, &dp_error);
-     } else {
-         ret = ipa_get_subdom_acct_recv(subreq, &dp_error);
-     }
-@@ -575,7 +586,7 @@ static void ipa_get_ad_acct_done(struct tevent_req *subreq);
- static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
-                                            struct sss_domain_info *dom);
- 
--struct tevent_req *
-+static struct tevent_req *
- ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-                      struct tevent_context *ev,
-                      struct ipa_id_ctx *ipa_ctx,
-@@ -1039,7 +1050,6 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
-     ret = ad_handle_acct_info_recv(subreq, &state->dp_error, NULL);
-     talloc_zfree(subreq);
-     if (ret == ERR_SUBDOM_INACTIVE) {
--        be_mark_dom_offline(state->obj_dom, be_req_get_be_ctx(state->be_req));
-         tevent_req_error(req, ret);
-         return;
-     } else if (ret != EOK) {
-@@ -1324,7 +1334,7 @@ ipa_get_ad_acct_done(struct tevent_req *subreq)
-     tevent_req_done(req);
- }
- 
--errno_t
-+static errno_t
- ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out)
- {
-     struct ipa_get_ad_acct_state *state = tevent_req_data(req,
-@@ -1338,3 +1348,173 @@ ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out)
- 
-     return EOK;
- }
-+
-+struct ipa_srv_ad_acct_state {
-+    struct tevent_context *ev;
-+    struct ipa_id_ctx *ipa_ctx;
-+    struct be_req *be_req;
-+    struct sysdb_attrs *override_attrs;
-+    struct be_acct_req *ar;
-+
-+    struct sss_domain_info *obj_dom;
-+    struct be_ctx *be_ctx;
-+    bool retry;
-+
-+    int dp_error;
-+};
-+
-+static int ipa_srv_ad_acct_lookup_step(struct tevent_req *req);
-+static void ipa_srv_ad_acct_lookup_done(struct tevent_req *subreq);
-+static void ipa_srv_ad_acct_retried(struct tevent_req *subreq);
-+
-+static struct tevent_req *
-+ipa_srv_ad_acct_send(TALLOC_CTX *mem_ctx,
-+                     struct tevent_context *ev,
-+                     struct ipa_id_ctx *ipa_ctx,
-+                     struct be_req *be_req,
-+                     struct sysdb_attrs *override_attrs,
-+                     struct be_acct_req *ar)
-+{
-+    errno_t ret;
-+    struct tevent_req *req;
-+    struct ipa_srv_ad_acct_state *state;
-+
-+    req = tevent_req_create(mem_ctx, &state, struct ipa_srv_ad_acct_state);
-+    if (req == NULL) {
-+        return NULL;
-+    }
-+
-+    state->ev = ev;
-+    state->ipa_ctx = ipa_ctx;
-+    state->be_req = be_req;
-+    state->override_attrs = override_attrs;
-+    state->ar = ar;
-+    state->retry = true;
-+    state->dp_error = DP_ERR_FATAL;
-+    state->be_ctx = be_req_get_be_ctx(state->be_req);
-+
-+    state->obj_dom = find_domain_by_name(
-+                                  state->ipa_ctx->sdap_id_ctx->be->domain,
-+                                  state->ar->domain, true);
-+    if (state->obj_dom == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Domain not found\n");
-+        ret = ERR_DOMAIN_NOT_FOUND;
-+        goto fail;
-+    }
-+
-+    ret = ipa_srv_ad_acct_lookup_step(req);
-+    if (ret != EOK) {
-+        goto fail;
-+    }
-+
-+    return req;
-+
-+fail:
-+    tevent_req_error(req, ret);
-+    tevent_req_post(req, ev);
-+    return req;
-+}
-+
-+static int ipa_srv_ad_acct_lookup_step(struct tevent_req *req)
-+{
-+    struct tevent_req *subreq;
-+    struct ipa_srv_ad_acct_state *state = tevent_req_data(req,
-+                                            struct ipa_srv_ad_acct_state);
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Looking up AD account\n");
-+    subreq = ipa_get_ad_acct_send(state, state->ev, state->ipa_ctx,
-+                                  state->be_req, state->override_attrs,
-+                                  state->ar);
-+    if (subreq == NULL) {
-+        return ENOMEM;
-+    }
-+    tevent_req_set_callback(subreq, ipa_srv_ad_acct_lookup_done, req);
-+
-+    return EOK;
-+}
-+
-+static void ipa_srv_ad_acct_lookup_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 ipa_srv_ad_acct_state *state = tevent_req_data(req,
-+                                            struct ipa_srv_ad_acct_state);
-+
-+    ret = ipa_get_ad_acct_recv(subreq, &dp_error);
-+    talloc_free(subreq);
-+    if (ret == ERR_SUBDOM_INACTIVE && state->retry == true) {
-+
-+        state->retry = false;
-+
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Sudomain lookup failed, will try to reset sudomain..\n");
-+        subreq = ipa_server_trusted_dom_setup_send(state, state->ev,
-+                                                   state->be_ctx,
-+                                                   state->ipa_ctx,
-+                                                   state->obj_dom);
-+        if (subreq == NULL) {
-+            goto fail;
-+        }
-+        tevent_req_set_callback(subreq, ipa_srv_ad_acct_retried, req);
-+        return;
-+    } else if (ret != EOK) {
-+        be_mark_dom_offline(state->obj_dom, state->be_ctx);
-+
-+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_*_acct request failed: [%d]: %s.\n",
-+              ret, sss_strerror(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);
-+}
-+
-+static void ipa_srv_ad_acct_retried(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                struct tevent_req);
-+    struct ipa_srv_ad_acct_state *state = tevent_req_data(req,
-+                                            struct ipa_srv_ad_acct_state);
-+
-+    ret = ipa_server_trusted_dom_setup_recv(subreq);
-+    talloc_free(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Failed to re-set subdomain [%d]: %s\n", ret, sss_strerror(ret));
-+        state->dp_error = DP_ERR_FATAL;
-+        tevent_req_error(req, ret);
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Sudomain re-set, will retry lookup\n");
-+    be_fo_reset_svc(state->be_ctx, state->obj_dom->name);
-+
-+    ret = ipa_srv_ad_acct_lookup_step(req);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Failed to look up AD acct [%d]: %s\n", ret, sss_strerror(ret));
-+        state->dp_error = DP_ERR_FATAL;
-+        tevent_req_error(req, ret);
-+    }
-+}
-+
-+static errno_t
-+ipa_srv_ad_acct_recv(struct tevent_req *req, int *dp_error_out)
-+{
-+    struct ipa_srv_ad_acct_state *state = tevent_req_data(req,
-+                                                struct ipa_srv_ad_acct_state);
-+
-+    if (dp_error_out) {
-+        *dp_error_out = state->dp_error;
-+    }
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+    return EOK;
-+}
--- 
-2.4.3
-
diff --git a/SOURCES/0096-sssctl-print-active-server-and-server-list.patch b/SOURCES/0096-sssctl-print-active-server-and-server-list.patch
new file mode 100644
index 0000000..8bb1918
--- /dev/null
+++ b/SOURCES/0096-sssctl-print-active-server-and-server-list.patch
@@ -0,0 +1,1013 @@
+From 7f4199c2d4dc9147be436005d75e03fc468f5349 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 27 Jun 2016 13:56:13 +0200
+Subject: [PATCH 096/102] sssctl: print active server and server list
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3069
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit bd4c2ed5aec7f57ea04500f0e43f151eedfdde45)
+---
+ src/providers/data_provider/dp_iface.c           |   6 +-
+ src/providers/data_provider/dp_iface.h           |   8 +
+ src/providers/data_provider/dp_iface.xml         |   8 +
+ src/providers/data_provider/dp_iface_failover.c  | 297 ++++++++++++++++++++++-
+ src/providers/data_provider/dp_iface_generated.c |  52 ++++
+ src/providers/data_provider/dp_iface_generated.h |  10 +
+ src/providers/fail_over.c                        |  42 ++++
+ src/providers/fail_over.h                        |   4 +
+ src/responder/ifp/ifp_domains.c                  |  48 ++++
+ src/responder/ifp/ifp_domains.h                  |   8 +
+ src/responder/ifp/ifp_iface.c                    |   4 +-
+ src/responder/ifp/ifp_iface.xml                  |  10 +
+ src/responder/ifp/ifp_iface_generated.c          |  52 ++++
+ src/responder/ifp/ifp_iface_generated.h          |  10 +
+ src/tools/sssctl/sssctl_domains.c                | 182 +++++++++++++-
+ 15 files changed, 722 insertions(+), 19 deletions(-)
+
+diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
+index 8ed7274f0dd7b59598e2cf21e0dd59d16666df0b..4b2b0ddca68be8899f7285b4d881a91444b99362 100644
+--- a/src/providers/data_provider/dp_iface.c
++++ b/src/providers/data_provider/dp_iface.c
+@@ -42,8 +42,10 @@ struct iface_dp_backend iface_dp_backend = {
+ };
+ 
+ struct iface_dp_failover iface_dp_failover = {
+-    {&iface_dp_failover_meta, 0},
+-    .ListServices = dp_failover_list_services
++    { &iface_dp_failover_meta, 0 },
++    .ListServices = dp_failover_list_services,
++    .ActiveServer = dp_failover_active_server,
++    .ListServers = dp_failover_list_servers
+ };
+ 
+ static struct sbus_iface_map dp_map[] = {
+diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
+index 76e623d21c413fd68f8f3c9a91ea32fd707dc54d..5c6f0eb2f5dd68b63bda389e6fdd2446ca9efb21 100644
+--- a/src/providers/data_provider/dp_iface.h
++++ b/src/providers/data_provider/dp_iface.h
+@@ -69,4 +69,12 @@ errno_t dp_failover_list_services(struct sbus_request *sbus_req,
+                                   void *dp_cli,
+                                   const char *domname);
+ 
++errno_t dp_failover_active_server(struct sbus_request *sbus_req,
++                                  void *dp_cli,
++                                  const char *service_name);
++
++errno_t dp_failover_list_servers(struct sbus_request *sbus_req,
++                                 void *dp_cli,
++                                 const char *service_name);
++
+ #endif /* DP_IFACE_H_ */
+diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
+index eab7fc0f1500bf8890030352421da62c134115b9..992848a048ef9fe813d6ae05bbcabd0913ecb277 100644
+--- a/src/providers/data_provider/dp_iface.xml
++++ b/src/providers/data_provider/dp_iface.xml
+@@ -22,6 +22,14 @@
+             <arg name="domain_name" type="s" direction="in" />
+             <arg name="services" type="as" direction="out" />
+         </method>
++        <method name="ActiveServer">
++            <arg name="service_name" type="s" direction="in" />
++            <arg name="server" type="s" direction="out" />
++        </method>
++        <method name="ListServers">
++            <arg name="service_name" type="s" direction="in" />
++            <arg name="servers" type="as" direction="out" />
++        </method>
+     </interface>
+ 
+     <interface name="org.freedesktop.sssd.dataprovider">
+diff --git a/src/providers/data_provider/dp_iface_failover.c b/src/providers/data_provider/dp_iface_failover.c
+index 038791088eeab7e9c5923996db77d2a107ff067d..7d95ffdd627604eb8c7e1b2882bf1665f792b660 100644
+--- a/src/providers/data_provider/dp_iface_failover.c
++++ b/src/providers/data_provider/dp_iface_failover.c
+@@ -28,20 +28,208 @@
+ #include "providers/backend.h"
+ #include "util/util.h"
+ 
++static errno_t
++dp_failover_list_services_ldap(struct be_ctx *be_ctx,
++                               const char **services,
++                               int *_count)
++{
++    struct be_svc_data *svc;
++    int count;
++
++    count = 0;
++    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
++        services[count] = talloc_strdup(services, svc->name);
++        if (services[count] == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
++            return ENOMEM;
++        }
++        count++;
++    }
++
++    *_count = count;
++
++    return EOK;
++}
++
++static errno_t
++dp_failover_list_services_ad(struct be_ctx *be_ctx,
++                             struct sss_domain_info *domain,
++                             const char **services,
++                             int *_count)
++{
++    char *fo_svc_name = NULL;
++    struct be_svc_data *svc;
++    errno_t ret;
++    int count;
++
++    fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name);
++    if (fo_svc_name == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    count = 0;
++    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
++        /* Drop each sd_gc_* since this service is not used with AD at all,
++         * we only connect to AD_GC for global catalog. */
++        if (strncasecmp(svc->name, "sd_gc_", strlen("sd_gc_")) == 0) {
++            continue;
++        }
++
++        /* Drop all subdomain services for different domain. */
++        if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) {
++            if (!IS_SUBDOMAIN(domain)) {
++                continue;
++            }
++
++            if (strcasecmp(svc->name, fo_svc_name) != 0) {
++                continue;
++            }
++        }
++
++        if (IS_SUBDOMAIN(domain)) {
++            /* Drop AD since we connect to subdomain.com for LDAP. */
++            if (strcasecmp(svc->name, "AD") == 0) {
++                continue;
++            }
++        }
++
++        services[count] = talloc_strdup(services, svc->name);
++        if (services[count] == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
++            ret = ENOMEM;
++            goto done;
++        }
++        count++;
++    }
++
++    *_count = count;
++
++    ret = EOK;
++
++done:
++    talloc_free(fo_svc_name);
++    return ret;
++}
++
++static errno_t
++dp_failover_list_services_ipa(struct be_ctx *be_ctx,
++                              struct sss_domain_info *domain,
++                              const char **services,
++                              int *_count)
++{
++    struct be_svc_data *svc;
++    char *fo_svc_name = NULL;
++    char *fo_gc_name = NULL;
++    errno_t ret;
++    int count;
++
++    fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name);
++    if (fo_svc_name == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    fo_gc_name = talloc_asprintf(services, "sd_gc_%s", domain->name);
++    if (fo_gc_name == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    count = 0;
++    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
++        /* Drop all subdomain services for different domain. */
++        if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) {
++            if (!IS_SUBDOMAIN(domain)) {
++                continue;
++            }
++
++            if (strcasecmp(svc->name, fo_svc_name) != 0
++                    && strcasecmp(svc->name, fo_gc_name) != 0) {
++                continue;
++            }
++        }
++
++        services[count] = talloc_strdup(services, svc->name);
++        if (services[count] == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
++            return ENOMEM;
++        }
++        count++;
++    }
++
++    *_count = count;
++
++    ret = EOK;
++
++done:
++    talloc_free(fo_svc_name);
++    talloc_free(fo_gc_name);
++
++    return ret;
++}
++
++enum dp_fo_svc_type {
++    DP_FO_SVC_LDAP = 0,
++    DP_FO_SVC_AD = 1,
++    DP_FO_SVC_IPA = 1 << 1,
++    DP_FO_SVC_MIXED = DP_FO_SVC_AD | DP_FO_SVC_IPA
++};
++
+ errno_t dp_failover_list_services(struct sbus_request *sbus_req,
+                                   void *dp_cli,
+                                   const char *domname)
+ {
++    enum dp_fo_svc_type svc_type = DP_FO_SVC_LDAP;
++    struct sss_domain_info *domain;
+     struct be_ctx *be_ctx;
+     struct be_svc_data *svc;
+     const char **services;
+     int num_services;
++    errno_t ret;
+ 
+     be_ctx = dp_client_be(dp_cli);
+ 
++    if (SBUS_IS_STRING_EMPTY(domname)) {
++        domain = be_ctx->domain;
++    } else {
++        domain = find_domain_by_name(be_ctx->domain, domname, false);
++        if (domain == NULL) {
++            sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
++                                     "Unknown domain %s", domname);
++            return EOK;
++        }
++    }
++
++    /**
++     * Returning list of failover services is currently rather difficult
++     * since there is only one failover context for the whole backend.
++     *
++     * The list of services for the given domain depends on whether it is
++     * a master domain or a subdomain and whether we are using IPA, AD or
++     * LDAP backend.
++     *
++     * For LDAP we just return everything we have.
++     * For AD master domain we return AD, AD_GC.
++     * For AD subdomain we return subdomain.com, AD_GC.
++     * For IPA in client mode we return IPA.
++     * For IPA in server mode we return IPA for master domain and
++     * subdomain.com, gc_subdomain.com for subdomain.
++     *
++     * We also return everything else for all cases if any other service
++     * such as kerberos is configured separately.
++     */
++
++    /* Allocate enough space. */
+     num_services = 0;
+     DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+         num_services++;
++
++        if (strcasecmp(svc->name, "AD") == 0) {
++            svc_type |= DP_FO_SVC_AD;
++        } else if (strcasecmp(svc->name, "IPA") == 0) {
++            svc_type |= DP_FO_SVC_IPA;
++        }
+     }
+ 
+     services = talloc_zero_array(sbus_req, const char *, num_services);
+@@ -50,17 +238,108 @@ errno_t dp_failover_list_services(struct sbus_request *sbus_req,
+         return ENOMEM;
+     }
+ 
+-    num_services = 0;
+-    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+-        services[num_services] = talloc_strdup(services, svc->name);
+-        if (services[num_services] == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+-            talloc_free(services);
+-            return ENOMEM;
+-        }
+-        num_services++;
++    /* Fill the list. */
++    switch (svc_type) {
++    case DP_FO_SVC_LDAP:
++    case DP_FO_SVC_MIXED:
++        ret = dp_failover_list_services_ldap(be_ctx, services, &num_services);
++        break;
++    case DP_FO_SVC_AD:
++        ret = dp_failover_list_services_ad(be_ctx, domain,
++                                           services, &num_services);
++        break;
++    case DP_FO_SVC_IPA:
++        ret = dp_failover_list_services_ipa(be_ctx, domain,
++                                            services, &num_services);
++        break;
++    default:
++        ret = ERR_INTERNAL;
++        break;
++    }
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create service list [%d]: %s\n",
++              ret, sss_strerror(ret));
++        talloc_free(services);
++        return ret;
+     }
+ 
+     iface_dp_failover_ListServices_finish(sbus_req, services, num_services);
+     return EOK;
+ }
++
++errno_t dp_failover_active_server(struct sbus_request *sbus_req,
++                                  void *dp_cli,
++                                  const char *service_name)
++{
++    struct be_ctx *be_ctx;
++    struct be_svc_data *svc;
++    const char *server;
++    bool found = false;
++
++    be_ctx = dp_client_be(dp_cli);
++
++    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
++        if (strcmp(svc->name, service_name) == 0) {
++            found = true;
++            break;
++        }
++    }
++
++    if (!found) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n");
++        sbus_request_reply_error(sbus_req, SBUS_ERROR_NOT_FOUND,
++                                 "Unknown service name");
++        return EOK;
++    }
++
++    if (svc->last_good_srv == NULL) {
++        server = "";
++    } else {
++        server = fo_get_server_name(svc->last_good_srv);
++        if (server == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n");
++            sbus_request_reply_error(sbus_req, SBUS_ERROR_INTERNAL,
++                                     "Unable to get server name");
++            return EOK;
++        }
++    }
++
++    iface_dp_failover_ActiveServer_finish(sbus_req, server);
++    return EOK;
++}
++
++errno_t dp_failover_list_servers(struct sbus_request *sbus_req,
++                                 void *dp_cli,
++                                 const char *service_name)
++{
++    struct be_ctx *be_ctx;
++    struct be_svc_data *svc;
++    const char **servers;
++    bool found = false;
++    size_t count;
++
++    be_ctx = dp_client_be(dp_cli);
++
++    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
++        if (strcmp(svc->name, service_name) == 0) {
++            found = true;
++            break;
++        }
++    }
++
++    if (!found) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server list\n");
++        sbus_request_reply_error(sbus_req, SBUS_ERROR_NOT_FOUND,
++                                 "Unknown service name");
++        return EOK;
++    }
++
++    servers = fo_svc_server_list(sbus_req, svc->fo_service, &count);
++    if (servers == NULL) {
++        return ENOMEM;
++    }
++
++    iface_dp_failover_ListServers_finish(sbus_req, servers, (int)count);
++    return EOK;
++}
+diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
+index 7b36fd8aaeebb976a511c5592b1dd0ae28e9bb8a..fd2acb4f4bd8cf1dcbe8842cccc6dc2077fc83a2 100644
+--- a/src/providers/data_provider/dp_iface_generated.c
++++ b/src/providers/data_provider/dp_iface_generated.c
+@@ -111,6 +111,44 @@ int iface_dp_failover_ListServices_finish(struct sbus_request *req, const char *
+                                          DBUS_TYPE_INVALID);
+ }
+ 
++/* arguments for org.freedesktop.sssd.DataProvider.Failover.ActiveServer */
++const struct sbus_arg_meta iface_dp_failover_ActiveServer__in[] = {
++    { "service_name", "s" },
++    { NULL, }
++};
++
++/* arguments for org.freedesktop.sssd.DataProvider.Failover.ActiveServer */
++const struct sbus_arg_meta iface_dp_failover_ActiveServer__out[] = {
++    { "server", "s" },
++    { NULL, }
++};
++
++int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *arg_server)
++{
++   return sbus_request_return_and_finish(req,
++                                         DBUS_TYPE_STRING, &arg_server,
++                                         DBUS_TYPE_INVALID);
++}
++
++/* arguments for org.freedesktop.sssd.DataProvider.Failover.ListServers */
++const struct sbus_arg_meta iface_dp_failover_ListServers__in[] = {
++    { "service_name", "s" },
++    { NULL, }
++};
++
++/* arguments for org.freedesktop.sssd.DataProvider.Failover.ListServers */
++const struct sbus_arg_meta iface_dp_failover_ListServers__out[] = {
++    { "servers", "as" },
++    { NULL, }
++};
++
++int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers)
++{
++   return sbus_request_return_and_finish(req,
++                                         DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_servers, len_servers,
++                                         DBUS_TYPE_INVALID);
++}
++
+ /* methods for org.freedesktop.sssd.DataProvider.Failover */
+ const struct sbus_method_meta iface_dp_failover__methods[] = {
+     {
+@@ -120,6 +158,20 @@ const struct sbus_method_meta iface_dp_failover__methods[] = {
+         offsetof(struct iface_dp_failover, ListServices),
+         invoke_s_method,
+     },
++    {
++        "ActiveServer", /* name */
++        iface_dp_failover_ActiveServer__in,
++        iface_dp_failover_ActiveServer__out,
++        offsetof(struct iface_dp_failover, ActiveServer),
++        invoke_s_method,
++    },
++    {
++        "ListServers", /* name */
++        iface_dp_failover_ListServers__in,
++        iface_dp_failover_ListServers__out,
++        offsetof(struct iface_dp_failover, ListServers),
++        invoke_s_method,
++    },
+     { NULL, }
+ };
+ 
+diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
+index 977ab3bae803ca002162b02d0c3d9677779983f4..7c2216aa27022769c707d80b59e9b436e72d1739 100644
+--- a/src/providers/data_provider/dp_iface_generated.h
++++ b/src/providers/data_provider/dp_iface_generated.h
+@@ -22,6 +22,8 @@
+ /* constants for org.freedesktop.sssd.DataProvider.Failover */
+ #define IFACE_DP_FAILOVER "org.freedesktop.sssd.DataProvider.Failover"
+ #define IFACE_DP_FAILOVER_LISTSERVICES "ListServices"
++#define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer"
++#define IFACE_DP_FAILOVER_LISTSERVERS "ListServers"
+ 
+ /* constants for org.freedesktop.sssd.dataprovider */
+ #define IFACE_DP "org.freedesktop.sssd.dataprovider"
+@@ -72,11 +74,19 @@ int iface_dp_backend_IsOnline_finish(struct sbus_request *req, bool arg_status);
+ struct iface_dp_failover {
+     struct sbus_vtable vtable; /* derive from sbus_vtable */
+     int (*ListServices)(struct sbus_request *req, void *data, const char *arg_domain_name);
++    int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service_name);
++    int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name);
+ };
+ 
+ /* finish function for ListServices */
+ int iface_dp_failover_ListServices_finish(struct sbus_request *req, const char *arg_services[], int len_services);
+ 
++/* finish function for ActiveServer */
++int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *arg_server);
++
++/* finish function for ListServers */
++int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
++
+ /* vtable for org.freedesktop.sssd.dataprovider */
+ struct iface_dp {
+     struct sbus_vtable vtable; /* derive from sbus_vtable */
+diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
+index 1d88d2aa54bfdebd4b648e2b13fa8d03e2be3973..8ab39f27f77e19e601855632196006a8dbbdf136 100644
+--- a/src/providers/fail_over.c
++++ b/src/providers/fail_over.c
+@@ -1660,6 +1660,48 @@ bool fo_svc_has_server(struct fo_service *service, struct fo_server *server)
+     return false;
+ }
+ 
++const char **fo_svc_server_list(TALLOC_CTX *mem_ctx,
++                                struct fo_service *service,
++                                size_t *_count)
++{
++    const char **list;
++    const char *server;
++    struct fo_server *srv;
++    size_t count;
++
++    count = 0;
++    DLIST_FOR_EACH(srv, service->server_list) {
++        count++;
++    }
++
++    list = talloc_zero_array(mem_ctx, const char *, count + 1);
++    if (list == NULL) {
++        return NULL;
++    }
++
++    count = 0;
++    DLIST_FOR_EACH(srv, service->server_list) {
++        server = fo_get_server_name(srv);
++        if (server == NULL) {
++            /* _srv_ */
++            continue;
++        }
++
++        list[count] = talloc_strdup(list, server);
++        if (list[count] == NULL) {
++            talloc_free(list);
++            return NULL;
++        }
++        count++;
++    }
++
++    if (_count != NULL) {
++        *_count = count;
++    }
++
++    return list;
++}
++
+ bool fo_set_srv_lookup_plugin(struct fo_ctx *ctx,
+                               fo_srv_lookup_plugin_send_t send_fn,
+                               fo_srv_lookup_plugin_recv_t recv_fn,
+diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
+index f24b5715f13931965400c20562a1578aaf756908..d70212fb7ea569b9c47bba36704aa8ae18754cbb 100644
+--- a/src/providers/fail_over.h
++++ b/src/providers/fail_over.h
+@@ -212,6 +212,10 @@ struct fo_server *fo_get_active_server(struct fo_service *service);
+ 
+ bool fo_svc_has_server(struct fo_service *service, struct fo_server *server);
+ 
++const char **fo_svc_server_list(TALLOC_CTX *mem_ctx,
++                                struct fo_service *service,
++                                size_t *_count);
++
+ /*
+  * pvt will be talloc_stealed to ctx
+  */
+diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
+index ff690ed6a7d5519979d242a4d5dadd08aff50347..977bbfcbe818f08873ce072d34fdcf900cabf52f 100644
+--- a/src/responder/ifp/ifp_domains.c
++++ b/src/responder/ifp/ifp_domains.c
+@@ -582,3 +582,51 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
+ 
+     return EOK;
+ }
++
++int ifp_domains_domain_active_server(struct sbus_request *sbus_req,
++                                     void *data,
++                                     const char *service)
++{
++    struct ifp_ctx *ifp_ctx;
++    struct sss_domain_info *dom;
++
++    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
++
++    dom = get_domain_info_from_req(sbus_req, data);
++    if (dom == NULL) {
++        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
++                                 "Unknown domain");
++        return EOK;
++    }
++
++    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
++                               IFACE_DP_FAILOVER,
++                               IFACE_DP_FAILOVER_ACTIVESERVER,
++                               DBUS_TYPE_STRING, &service);
++
++    return EOK;
++}
++
++int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
++                                    void *data,
++                                    const char *service)
++{
++    struct ifp_ctx *ifp_ctx;
++    struct sss_domain_info *dom;
++
++    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
++
++    dom = get_domain_info_from_req(sbus_req, data);
++    if (dom == NULL) {
++        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
++                                 "Unknown domain");
++        return EOK;
++    }
++
++    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
++                               IFACE_DP_FAILOVER,
++                               IFACE_DP_FAILOVER_LISTSERVERS,
++                               DBUS_TYPE_STRING, &service);
++
++    return EOK;
++}
+diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h
+index 91645e60701f8f75e89a42e93e2c066def67b018..621ba6158e285911cb8298cef212219dfd3afec8 100644
+--- a/src/responder/ifp/ifp_domains.h
++++ b/src/responder/ifp/ifp_domains.h
+@@ -100,4 +100,12 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req,
+ int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
+                                      void *data);
+ 
++int ifp_domains_domain_active_server(struct sbus_request *sbus_req,
++                                     void *data,
++                                     const char *service);
++
++int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
++                                    void *data,
++                                    const char *service);
++
+ #endif /* IFP_DOMAINS_H_ */
+diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c
+index 90bb52b2ccf5207034abbe12bddbfa1eeaf875f7..e6ddc687ba9db878ee39fee5868d1f924d58482d 100644
+--- a/src/responder/ifp/ifp_iface.c
++++ b/src/responder/ifp/ifp_iface.c
+@@ -81,7 +81,9 @@ struct iface_ifp_domains iface_ifp_domains = {
+ struct iface_ifp_domains_domain iface_ifp_domains_domain = {
+     { &iface_ifp_domains_domain_meta, 0 },
+     .IsOnline = ifp_domains_domain_is_online,
+-    .ListServices = ifp_domains_domain_list_services
++    .ListServices = ifp_domains_domain_list_services,
++    .ActiveServer = ifp_domains_domain_active_server,
++    .ListServers = ifp_domains_domain_list_servers
+ };
+ 
+ struct iface_ifp_users iface_ifp_users = {
+diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
+index 7f6f47299deeba4b1baa23d1e63ee7bb17304a59..25b104ad70c0fd84b6c0fe9dbb0dc6e6439c1376 100644
+--- a/src/responder/ifp/ifp_iface.xml
++++ b/src/responder/ifp/ifp_iface.xml
+@@ -112,6 +112,16 @@
+         <method name="ListServices">
+             <arg name="services" type="as" direction="out" />
+         </method>
++
++        <method name="ActiveServer">
++            <arg name="service" type="s" direction="in" />
++            <arg name="server" type="s" direction="out" />
++        </method>
++
++        <method name="ListServers">
++            <arg name="service_name" type="s" direction="in" />
++            <arg name="servers" type="as" direction="out" />
++        </method>
+     </interface>
+ 
+     <interface name="org.freedesktop.sssd.infopipe.Cache">
+diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
+index 4d3bb5727b03ae64adad14fcdbb3eb5366edb406..6156ca2947434f301d206232f83cfc0647007707 100644
+--- a/src/responder/ifp/ifp_iface_generated.c
++++ b/src/responder/ifp/ifp_iface_generated.c
+@@ -558,6 +558,44 @@ int iface_ifp_domains_domain_ListServices_finish(struct sbus_request *req, const
+                                          DBUS_TYPE_INVALID);
+ }
+ 
++/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ActiveServer */
++const struct sbus_arg_meta iface_ifp_domains_domain_ActiveServer__in[] = {
++    { "service", "s" },
++    { NULL, }
++};
++
++/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ActiveServer */
++const struct sbus_arg_meta iface_ifp_domains_domain_ActiveServer__out[] = {
++    { "server", "s" },
++    { NULL, }
++};
++
++int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const char *arg_server)
++{
++   return sbus_request_return_and_finish(req,
++                                         DBUS_TYPE_STRING, &arg_server,
++                                         DBUS_TYPE_INVALID);
++}
++
++/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ListServers */
++const struct sbus_arg_meta iface_ifp_domains_domain_ListServers__in[] = {
++    { "service_name", "s" },
++    { NULL, }
++};
++
++/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ListServers */
++const struct sbus_arg_meta iface_ifp_domains_domain_ListServers__out[] = {
++    { "servers", "as" },
++    { NULL, }
++};
++
++int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers)
++{
++   return sbus_request_return_and_finish(req,
++                                         DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_servers, len_servers,
++                                         DBUS_TYPE_INVALID);
++}
++
+ /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */
+ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
+     {
+@@ -574,6 +612,20 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
+         offsetof(struct iface_ifp_domains_domain, ListServices),
+         NULL, /* no invoker */
+     },
++    {
++        "ActiveServer", /* name */
++        iface_ifp_domains_domain_ActiveServer__in,
++        iface_ifp_domains_domain_ActiveServer__out,
++        offsetof(struct iface_ifp_domains_domain, ActiveServer),
++        invoke_s_method,
++    },
++    {
++        "ListServers", /* name */
++        iface_ifp_domains_domain_ListServers__in,
++        iface_ifp_domains_domain_ListServers__out,
++        offsetof(struct iface_ifp_domains_domain, ListServers),
++        invoke_s_method,
++    },
+     { NULL, }
+ };
+ 
+diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
+index 2eff57410e5292a05818050b96eb85aa3a4f2e16..141348249d2da5447fa04495564a8c6a55d67a1b 100644
+--- a/src/responder/ifp/ifp_iface_generated.h
++++ b/src/responder/ifp/ifp_iface_generated.h
+@@ -58,6 +58,8 @@
+ #define IFACE_IFP_DOMAINS_DOMAIN "org.freedesktop.sssd.infopipe.Domains.Domain"
+ #define IFACE_IFP_DOMAINS_DOMAIN_ISONLINE "IsOnline"
+ #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices"
++#define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer"
++#define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers"
+ 
+ /* constants for org.freedesktop.sssd.infopipe.Cache */
+ #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache"
+@@ -215,6 +217,8 @@ struct iface_ifp_domains_domain {
+     struct sbus_vtable vtable; /* derive from sbus_vtable */
+     int (*IsOnline)(struct sbus_request *req, void *data);
+     int (*ListServices)(struct sbus_request *req, void *data);
++    int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service);
++    int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name);
+ };
+ 
+ /* finish function for IsOnline */
+@@ -223,6 +227,12 @@ int iface_ifp_domains_domain_IsOnline_finish(struct sbus_request *req, bool arg_
+ /* finish function for ListServices */
+ int iface_ifp_domains_domain_ListServices_finish(struct sbus_request *req, const char *arg_services[], int len_services);
+ 
++/* finish function for ActiveServer */
++int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const char *arg_server);
++
++/* finish function for ListServers */
++int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
++
+ /* vtable for org.freedesktop.sssd.infopipe.Cache */
+ struct iface_ifp_cache {
+     struct sbus_vtable vtable; /* derive from sbus_vtable */
+diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c
+index 40962792b84eabeb2c142f158184b17180a01669..545ed95f4415da597b191146409ea6ba028f36f8 100644
+--- a/src/tools/sssctl/sssctl_domains.c
++++ b/src/tools/sssctl/sssctl_domains.c
+@@ -112,6 +112,155 @@ done:
+     return ret;
+ }
+ 
++static const char *proper_service_name(const char *service)
++{
++    if (strcasecmp(service, "AD_GC") == 0) {
++        return "AD Global Catalog";
++    } else if (strcasecmp(service, "AD") == 0) {
++        return "AD Domain Controller";
++    } else if (strncasecmp(service, "sd_gc_", strlen("sd_gc_")) == 0) {
++        return "AD Global Catalog";
++    } else if (strncasecmp(service, "sd_", strlen("sd_")) == 0) {
++        return "AD Domain Controller";
++    }
++
++    return service;
++}
++
++static errno_t sssctl_domain_status_active_server(struct sss_tool_ctx *tool_ctx,
++                                                  sss_sifp_ctx *sifp,
++                                                  const char *domain_path)
++{
++    TALLOC_CTX *tmp_ctx;
++    sss_sifp_error error;
++    DBusMessage *reply;
++    const char *server;
++    const char **services;
++    int num_services;
++    errno_t ret;
++    int i;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
++        return ENOMEM;
++    }
++
++    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
++                             IFACE_IFP_DOMAINS_DOMAIN,
++                             IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES);
++    if (error != SSS_SIFP_OK) {
++        sssctl_sifp_error(sifp, error, "Unable to list services");
++        ret = EIO;
++        goto done;
++    }
++
++    ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
++                           &services, &num_services);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    printf(_("Active servers:\n"));
++    for (i = 0; i < num_services; i++) {
++        error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
++                                 IFACE_IFP_DOMAINS_DOMAIN,
++                                 IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER,
++                                 DBUS_TYPE_STRING, &services[i]);
++        if (error != SSS_SIFP_OK) {
++            sssctl_sifp_error(sifp, error, "Unable to get active server");
++            ret = EIO;
++            goto done;
++        }
++
++        ret = sbus_parse_reply(reply, DBUS_TYPE_STRING, &server);
++        if (ret != EOK) {
++            goto done;
++        }
++
++        server = SBUS_IS_STRING_EMPTY(server) ? _("not connected") : server;
++        printf("%s: %s\n", proper_service_name(services[i]), server);
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
++static errno_t sssctl_domain_status_server_list(struct sss_tool_ctx *tool_ctx,
++                                                sss_sifp_ctx *sifp,
++                                                const char *domain_path)
++{
++    TALLOC_CTX *tmp_ctx;
++    sss_sifp_error error;
++    DBusMessage *reply;
++    const char **servers;
++    int num_servers;
++    const char **services;
++    int num_services;
++    errno_t ret;
++    int i, j;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
++        return ENOMEM;
++    }
++
++    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
++                             IFACE_IFP_DOMAINS_DOMAIN,
++                             IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES);
++    if (error != SSS_SIFP_OK) {
++        sssctl_sifp_error(sifp, error, "Unable to list services");
++        ret = EIO;
++        goto done;
++    }
++
++    ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
++                           &services, &num_services);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    for (i = 0; i < num_services; i++) {
++        printf(_("Discovered %s servers:\n"), proper_service_name(services[i]));
++        error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
++                                 IFACE_IFP_DOMAINS_DOMAIN,
++                                 IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS,
++                                 DBUS_TYPE_STRING, &services[i]);
++        if (error != SSS_SIFP_OK) {
++            sssctl_sifp_error(sifp, error, "Unable to get active server");
++            ret = EIO;
++            goto done;
++        }
++
++        ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
++                               &servers, &num_servers);
++        if (ret != EOK) {
++            goto done;
++        }
++
++        if (num_servers == 0) {
++            puts(_("None so far.\n"));
++            continue;
++        }
++
++        for (j = 0; j < num_servers; j++) {
++            printf("- %s\n", servers[j]);
++        }
++
++        printf("\n");
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ struct sssctl_domain_status_opts {
+     const char *domain;
+     int online;
+@@ -135,11 +284,8 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
+     /* Parse command line. */
+     struct poptOption options[] = {
+         {"online", 'o', POPT_ARG_NONE , &opts.online, 0, _("Show online status"), NULL },
+-        /*
+-        {"last-requests", 'l', POPT_ARG_NONE, &opts.last, 0, _("Show last requests that went to data provider"), NULL },
+         {"active-server", 'a', POPT_ARG_NONE, &opts.active, 0, _("Show information about active server"), NULL },
+         {"servers", 'r', POPT_ARG_NONE, &opts.servers, 0, _("Show list of discovered servers"), NULL },
+-        */
+         {"start", 's', POPT_ARG_NONE, &opts.force_start, 0, _("Start SSSD if it is not running"), NULL },
+         POPT_TABLEEND
+     };
+@@ -175,10 +321,32 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
+         return EFAULT;
+     }
+ 
+-    ret = sssctl_domain_status_online(tool_ctx, sifp, path);
+-    if (ret != EOK) {
+-        fprintf(stderr, _("Unable to get online status\n"));
+-        return ret;
++    if (opts.online) {
++        ret = sssctl_domain_status_online(tool_ctx, sifp, path);
++        if (ret != EOK) {
++            fprintf(stderr, _("Unable to get online status\n"));
++            return ret;
++        }
++
++        printf("\n");
++    }
++
++    if (opts.active) {
++        ret = sssctl_domain_status_active_server(tool_ctx, sifp, path);
++        if (ret != EOK) {
++            fprintf(stderr, _("Unable to get online status\n"));
++            return ret;
++        }
++
++        printf("\n");
++    }
++
++    if (opts.servers) {
++        ret = sssctl_domain_status_server_list(tool_ctx, sifp, path);
++        if (ret != EOK) {
++            fprintf(stderr, _("Unable to get server list\n"));
++            return ret;
++        }
+     }
+ 
+     return EOK;
+-- 
+2.4.11
+
diff --git a/SOURCES/0097-AD-inicialize-root_domain_attrs-field.patch b/SOURCES/0097-AD-inicialize-root_domain_attrs-field.patch
deleted file mode 100644
index 2537ab2..0000000
--- a/SOURCES/0097-AD-inicialize-root_domain_attrs-field.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From d97d6d3acc32d0e4914a1d2c39bfb7fa8ecc7197 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Thu, 24 Sep 2015 11:03:12 -0400
-Subject: [PATCH 97/97] AD: inicialize root_domain_attrs field
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2805
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 101628a48d25ffae3b13c75d0b0b01577188c803)
----
- 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 8ed3dab0995f78a16f4a7df2e729ea88a39a782c..c2a6544fb7f146058acee9baca9b0cc6ee50aa3f 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -505,7 +505,7 @@ static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
-     int dp_error = DP_ERR_FATAL;
-     int ret;
- 
--    req_ctx = talloc(be_req, struct ad_subdomains_req_ctx);
-+    req_ctx = talloc_zero(be_req, struct ad_subdomains_req_ctx);
-     if (req_ctx == NULL) {
-         ret = ENOMEM;
-         goto done;
-@@ -519,6 +519,7 @@ static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
-     req_ctx->root_id_ctx = NULL;
-     req_ctx->root_op = NULL;
-     req_ctx->root_domain = NULL;
-+    req_ctx->root_domain_attrs = NULL;
-     req_ctx->reply_count = 0;
-     req_ctx->reply = NULL;
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0097-sifp-fix-coverity-warning.patch b/SOURCES/0097-sifp-fix-coverity-warning.patch
new file mode 100644
index 0000000..6a761a7
--- /dev/null
+++ b/SOURCES/0097-sifp-fix-coverity-warning.patch
@@ -0,0 +1,47 @@
+From 87f7c2f1f44085963b41eb78e337840ddbc7be76 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 14 Jul 2016 10:49:37 +0200
+Subject: [PATCH 097/102] sifp: fix coverity warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sssd-1.14.1/src/lib/sifp/sss_sifp_dbus.c:51: check_return:
+  Calling "dbus_message_append_args_valist" without checking return value
+  (as is done elsewhere 4 out of 5 times).
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit de5160e354c02020f0593c7cabdb811107d5d8e2)
+---
+ src/lib/sifp/sss_sifp_dbus.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/lib/sifp/sss_sifp_dbus.c b/src/lib/sifp/sss_sifp_dbus.c
+index 7c72c52f0d226ccdfaf7b8ffaed7776647a7771c..2906c5ac383c412231127f6ffa8081d47eb2bced 100644
+--- a/src/lib/sifp/sss_sifp_dbus.c
++++ b/src/lib/sifp/sss_sifp_dbus.c
+@@ -36,6 +36,7 @@ static sss_sifp_error sss_sifp_ifp_call(sss_sifp_ctx *ctx,
+ {
+    DBusMessage *msg = NULL;
+    sss_sifp_error ret;
++   dbus_bool_t bret;
+ 
+    if (object_path == NULL || interface == NULL || method == NULL) {
+        return SSS_SIFP_INVALID_ARGUMENT;
+@@ -48,7 +49,11 @@ static sss_sifp_error sss_sifp_ifp_call(sss_sifp_ctx *ctx,
+    }
+ 
+    if (first_arg_type != DBUS_TYPE_INVALID) {
+-       dbus_message_append_args_valist(msg, first_arg_type, ap);
++       bret = dbus_message_append_args_valist(msg, first_arg_type, ap);
++       if (!bret) {
++           ret = SSS_SIFP_IO_ERROR;
++           goto done;
++       }
+    }
+ 
+    ret = sss_sifp_send_message(ctx, msg, _reply);
+-- 
+2.4.11
+
diff --git a/SOURCES/0098-PAM-only-allow-missing-user-name-for-certificate-aut.patch b/SOURCES/0098-PAM-only-allow-missing-user-name-for-certificate-aut.patch
deleted file mode 100644
index 2168ab2..0000000
--- a/SOURCES/0098-PAM-only-allow-missing-user-name-for-certificate-aut.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-From 63c52299e122a05e7b25b5ee94b528fe64a6c6ef Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 1 Oct 2015 10:10:22 +0200
-Subject: [PATCH 98/99] PAM: only allow missing user name for certificate
- authentication
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2811
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit 2e76b32e74abedb23665808bacc73cafd1097c37)
-(cherry picked from commit ba9d5c0456a2fbb9adf9b4b4dffbfb190628a273)
----
- src/responder/pam/pamsrv_cmd.c  | 12 +++++++++---
- src/tests/cmocka/test_pam_srv.c | 41 +++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 50 insertions(+), 3 deletions(-)
-
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index aa5c20906a36351e425304122517c81676e730b7..ae14b9287268ffb36500b0cfdb38e69adb0ecce9 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -962,11 +962,13 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p
-     } else {
-         /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
-          * name is determined with the help of a certificate */
--        if (pd->cmd == SSS_PAM_PREAUTH) {
-+        if (pd->cmd == SSS_PAM_PREAUTH
-+                && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
-+                                                    struct pam_ctx), pd)) {
-             ret = EOK;
-         } else {
-             DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
--            ret = EINVAL;
-+            ret = ERR_NO_CREDS;
-             goto done;
-         }
-     }
-@@ -1076,7 +1078,6 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
-         }
-         goto done;
-     } else if (ret != EOK) {
--        ret = EINVAL;
-         goto done;
-     }
- 
-@@ -1597,6 +1598,11 @@ static int pam_check_user_done(struct pam_auth_req *preq, int ret)
-         pam_reply(preq);
-         break;
- 
-+    case ERR_NO_CREDS:
-+        preq->pd->pam_status = PAM_CRED_INSUFFICIENT;
-+        pam_reply(preq);
-+        break;
-+
-     default:
-         preq->pd->pam_status = PAM_SYSTEM_ERR;
-         pam_reply(preq);
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 3c70c599060e09125ab5b73ce3d2698eaa3006bd..0ae2554032d28329ebb1d6ad09cfd859cf9b4260 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -596,6 +596,23 @@ static int test_pam_wrong_pw_offline_auth_check(uint32_t status,
-     return test_pam_simple_check(status, body, blen);
- }
- 
-+static int test_pam_creds_insufficient_check(uint32_t status,
-+                                             uint8_t *body, size_t blen)
-+{
-+    size_t rp = 0;
-+    uint32_t val;
-+
-+    assert_int_equal(status, 0);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, PAM_CRED_INSUFFICIENT);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, 0);
-+
-+    return EOK;
-+}
-+
- static int test_pam_user_unknown_check(uint32_t status,
-                                        uint8_t *body, size_t blen)
- {
-@@ -1100,6 +1117,25 @@ void test_pam_offline_chauthtok(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+void test_pam_preauth_no_logon_name(void **state)
-+{
-+    int ret;
-+
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_pam_creds_insufficient_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
- static void set_cert_auth_param(struct pam_ctx *pctx, const char *dbpath)
- {
-     pam_test_ctx->pctx->cert_auth = true;
-@@ -1405,6 +1441,8 @@ int main(int argc, const char *argv[])
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_offline_chauthtok,
-                                         pam_test_setup, pam_test_teardown),
-+/* p11_child is not built without NSS */
-+#ifdef HAVE_NSS
-         cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nocert,
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nomatch,
-@@ -1422,6 +1460,9 @@ int main(int argc, const char *argv[])
-                                    pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_auth,
-                                         pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_preauth_no_logon_name,
-+                                        pam_test_setup, pam_test_teardown),
-+#endif
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.4.3
-
diff --git a/SOURCES/0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch b/SOURCES/0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch
new file mode 100644
index 0000000..37be3b9
--- /dev/null
+++ b/SOURCES/0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch
@@ -0,0 +1,112 @@
+From efb18a2688546db9c6fe7ba75b595a2fc54dff41 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Fri, 15 Jul 2016 14:50:41 +0200
+Subject: [PATCH 098/102] sbus: allow freeing msg through dbus api when using
+ talloc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When a talloc-bound message was freed by removing all references
+to it with dbus_message_unref we failed to free the talloc context
+and thus leaking memory or unreferencing invalid message when
+the parent context is freed.
+
+This patch allows to bound dbus message to talloc in the way that
+allows us to free the message by both talloc and dbus api.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 5d556f70f00c43864d8495d7caacfadf962799df)
+---
+ src/sbus/sssd_dbus_utils.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 51 insertions(+)
+
+diff --git a/src/sbus/sssd_dbus_utils.c b/src/sbus/sssd_dbus_utils.c
+index 4c33f9fd75cac2d4a56a5638982f8ecb73da8e2e..b0150e2fe7f829013677e0a4a894d1468e5b9128 100644
+--- a/src/sbus/sssd_dbus_utils.c
++++ b/src/sbus/sssd_dbus_utils.c
+@@ -25,22 +25,52 @@
+ 
+ struct sbus_talloc_msg {
+     DBusMessage *msg;
++    dbus_int32_t data_slot;
++    bool in_talloc_destructor;
+ };
+ 
+ static int sbus_talloc_msg_destructor(struct sbus_talloc_msg *talloc_msg)
+ {
++    talloc_msg->in_talloc_destructor = true;
++
+     if (talloc_msg->msg == NULL) {
+         return 0;
+     }
+ 
++    /* There may exist more references to this message but this talloc
++     * context is no longer valid. We remove dbus message data to invoke
++     * dbus destructor now. */
++    dbus_message_set_data(talloc_msg->msg, talloc_msg->data_slot, NULL, NULL);
+     dbus_message_unref(talloc_msg->msg);
+     return 0;
+ }
+ 
++static void sbus_msg_data_destructor(void *ctx)
++{
++    struct sbus_talloc_msg *talloc_msg;
++
++    talloc_msg = talloc_get_type(ctx, struct sbus_talloc_msg);
++
++    dbus_message_free_data_slot(&talloc_msg->data_slot);
++
++    if (!talloc_msg->in_talloc_destructor) {
++        /* References to this message dropped to zero but through
++         * dbus_message_unref(), not by calling talloc_free(). We need to free
++         * the talloc context and avoid running talloc desctuctor. */
++        talloc_set_destructor(talloc_msg, NULL);
++        talloc_free(talloc_msg);
++    }
++}
++
+ errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg)
+ {
+     struct sbus_talloc_msg *talloc_msg;
++    dbus_int32_t data_slot = -1;
++    DBusFreeFunction free_fn;
++    dbus_bool_t bret;
+ 
++    /* Create a talloc context that will unreference this message when
++     * the parent context is freed. */
+     talloc_msg = talloc(mem_ctx, struct sbus_talloc_msg);
+     if (talloc_msg == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+@@ -48,7 +78,28 @@ errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg)
+         return ENOMEM;
+     }
+ 
++    /* Allocate a dbus message data slot that will contain point to the
++     * talloc context so we can pick up cases when the dbus message is
++     * freed through dbus api. */
++    bret = dbus_message_allocate_data_slot(&data_slot);
++    if (!bret) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to allocate data slot!\n");
++        talloc_free(talloc_msg);
++        return ENOMEM;
++    }
++
++    free_fn = sbus_msg_data_destructor;
++    bret = dbus_message_set_data(msg, data_slot, talloc_msg, free_fn);
++    if (!bret) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set message data!\n");
++        talloc_free(talloc_msg);
++        dbus_message_free_data_slot(&data_slot);
++        return ENOMEM;
++    }
++
+     talloc_msg->msg = msg;
++    talloc_msg->data_slot = data_slot;
++    talloc_msg->in_talloc_destructor = false;
+ 
+     talloc_set_destructor(talloc_msg, sbus_talloc_msg_destructor);
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0099-Fix-memory-leak-in-sssdpac_verify.patch b/SOURCES/0099-Fix-memory-leak-in-sssdpac_verify.patch
deleted file mode 100644
index 3324d44..0000000
--- a/SOURCES/0099-Fix-memory-leak-in-sssdpac_verify.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From d600e8bedf05d447ba84d9a89be7d46ba34f1b5d Mon Sep 17 00:00:00 2001
-From: Thomas Oulevey <thomas.oulevey@cern.ch>
-Date: Wed, 23 Sep 2015 10:55:59 +0200
-Subject: [PATCH 99/99] Fix memory leak in sssdpac_verify()
-
-Resolves https://fedorahosted.org/sssd/ticket/2803
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit b4c44ebb8997d3debb33607c123ccfd9926e0cba)
----
- src/sss_client/sssd_pac.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/sss_client/sssd_pac.c b/src/sss_client/sssd_pac.c
-index 1939f61b18398f62a3e3d6b29cc4fef151b1c3b7..1d98e38826b36aed199b32880a7e27de905a4592 100644
---- a/src/sss_client/sssd_pac.c
-+++ b/src/sss_client/sssd_pac.c
-@@ -150,6 +150,9 @@ static krb5_error_code sssdpac_verify(krb5_context kcontext,
-     kerr = krb5_pac_verify(kcontext, pac,
-                            req->ticket->enc_part2->times.authtime,
-                            req->ticket->enc_part2->client, key, NULL);
-+    /* deallocate pac */
-+    krb5_pac_free(kcontext, pac);
-+    pac = NULL;
-     if (kerr != 0) {
-         /* The krb5 documentation says:
-          * A checksum mismatch can occur if the PAC was copied from a
--- 
-2.4.3
-
diff --git a/SOURCES/0099-PROXY-Do-not-abuse-data-provider-interface.patch b/SOURCES/0099-PROXY-Do-not-abuse-data-provider-interface.patch
new file mode 100644
index 0000000..df4370b
--- /dev/null
+++ b/SOURCES/0099-PROXY-Do-not-abuse-data-provider-interface.patch
@@ -0,0 +1,730 @@
+From 4b23c3128726fe59e02d28352e37bb0ff7f97640 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Fri, 15 Jul 2016 14:20:32 +0200
+Subject: [PATCH 099/102] PROXY: Do not abuse data provider interface
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We want to use custom interface for proxy provider so we do not
+abuse the data provider one. This way we gain more control over
+it and we can remove the old interface entirely.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit e07d700ed9daf0cf96607fa2d72978cb2431b794)
+---
+ Makefile.am                                 |   6 +-
+ src/providers/dp_auth_util.c                |  64 ---------------
+ src/providers/proxy/proxy.h                 |   2 +
+ src/providers/proxy/proxy_auth.c            |   8 +-
+ src/providers/proxy/proxy_child.c           | 119 +++++++++++++++-------------
+ src/providers/proxy/proxy_client.c          | 108 +++++++++++--------------
+ src/providers/proxy/proxy_iface.xml         |  17 ++++
+ src/providers/proxy/proxy_iface_generated.c |  80 +++++++++++++++++++
+ src/providers/proxy/proxy_iface_generated.h |  71 +++++++++++++++++
+ 9 files changed, 288 insertions(+), 187 deletions(-)
+ create mode 100644 src/providers/proxy/proxy_iface.xml
+ create mode 100644 src/providers/proxy/proxy_iface_generated.c
+ create mode 100644 src/providers/proxy/proxy_iface_generated.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 1837e36da7302cb51c0b90e51b762ce0a87cd65f..5d54838659e44fa446fc921d014e48ac91469b25 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -715,6 +715,7 @@ dist_noinst_HEADERS = \
+     src/providers/ad/ad_domain_info.h \
+     src/providers/ad/ad_subdomains.h \
+     src/providers/proxy/proxy.h \
++    src/providers/proxy/proxy_iface_generated.h \
+     src/tools/tools_util.h \
+     src/tools/sss_sync_ops.h \
+     src/resolv/async_resolv.h \
+@@ -1197,6 +1198,7 @@ CODEGEN_XML = \
+     $(srcdir)/src/monitor/monitor_iface.xml \
+     $(srcdir)/src/providers/data_provider_iface.xml \
+     $(srcdir)/src/providers/data_provider/dp_iface.xml \
++    $(srcdir)/src/providers/proxy/proxy_iface.xml \
+     $(srcdir)/src/responder/ifp/ifp_iface.xml
+ 
+ SBUS_CODEGEN = src/sbus/sbus_codegen
+@@ -3337,7 +3339,7 @@ libsss_proxy_la_SOURCES = \
+     src/providers/proxy/proxy_netgroup.c \
+     src/providers/proxy/proxy_services.c \
+     src/providers/proxy/proxy_auth.c \
+-    src/providers/data_provider_iface_generated.c \
++    src/providers/proxy/proxy_iface_generated.c \
+     $(NULL)
+ libsss_proxy_la_CFLAGS = \
+     $(AM_CFLAGS)
+@@ -3606,7 +3608,7 @@ gpo_child_LDADD = \
+ 
+ proxy_child_SOURCES = \
+     src/providers/proxy/proxy_child.c \
+-    src/providers/data_provider_iface_generated.c \
++    src/providers/proxy/proxy_iface_generated.c \
+     $(NULL)
+ proxy_child_CFLAGS = \
+     $(AM_CFLAGS) \
+diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c
+index 8c09299b12c703ed703a025d1e8cfe5df2088eb2..35d22ab5f24ba2300889256f477a9ed856b69cb9 100644
+--- a/src/providers/dp_auth_util.c
++++ b/src/providers/dp_auth_util.c
+@@ -321,67 +321,3 @@ bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd, DBusError *db
+ 
+     return true;
+ }
+-
+-void dp_id_callback(DBusPendingCall *pending, void *ptr)
+-{
+-    DBusMessage *reply;
+-    DBusError dbus_error;
+-    dbus_bool_t ret;
+-    dbus_uint16_t dp_ver;
+-    int type;
+-
+-    dbus_error_init(&dbus_error);
+-
+-    reply = dbus_pending_call_steal_reply(pending);
+-    if (!reply) {
+-        /* reply should never be null. This function shouldn't be called
+-         * until reply is valid or timeout has occurred. If reply is NULL
+-         * here, something is seriously wrong and we should bail out.
+-         */
+-        DEBUG(SSSDBG_FATAL_FAILURE,
+-              "Severe error. A reply callback was called but no"
+-                  " reply was received and no timeout occurred\n");
+-
+-        /* FIXME: Destroy this connection ? */
+-        goto done;
+-    }
+-
+-    type = dbus_message_get_type(reply);
+-    switch (type) {
+-    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+-        ret = dbus_message_get_args(reply, &dbus_error,
+-                                    DBUS_TYPE_UINT16, &dp_ver,
+-                                    DBUS_TYPE_INVALID);
+-        if (!ret) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse message\n");
+-            if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+-            /* FIXME: Destroy this connection ? */
+-            goto done;
+-        }
+-
+-        DEBUG(SSSDBG_CONF_SETTINGS,
+-              "Got id ack and version (%d) from DP\n", dp_ver);
+-
+-        break;
+-
+-    case DBUS_MESSAGE_TYPE_ERROR:
+-        DEBUG(SSSDBG_FATAL_FAILURE,"The Monitor returned an error [%s]\n",
+-                 dbus_message_get_error_name(reply));
+-        /* Falling through to default intentionally*/
+-    default:
+-        /*
+-         * Timeout or other error occurred or something
+-         * unexpected happened.
+-         * It doesn't matter which, because either way we
+-         * know that this connection isn't trustworthy.
+-         * We'll destroy it now.
+-         */
+-
+-        /* FIXME: Destroy this connection ? */
+-        break;
+-    }
+-
+-done:
+-    dbus_pending_call_unref(pending);
+-    dbus_message_unref(reply);
+-}
+diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h
+index 11c85c54ea64db7ad9feb163bd5a86f65ac0ea90..6f91782bb06ea8bbf3ac35052b840dd21300b96e 100644
+--- a/src/providers/proxy/proxy.h
++++ b/src/providers/proxy/proxy.h
+@@ -42,6 +42,8 @@
+ #include "sss_client/nss_compat.h"
+ #include <dhash.h>
+ 
++#define PROXY_CHILD_PATH "/org/freedesktop/sssd/proxychild"
++
+ struct proxy_nss_ops {
+     enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
+                                   char *buffer, size_t buflen, int *errnop);
+diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c
+index 6e7139aaa5d45631fa08f265c54b66ab97555a64..2b3510c38b1cb265e3042425c373f39e524a71eb 100644
+--- a/src/providers/proxy/proxy_auth.c
++++ b/src/providers/proxy/proxy_auth.c
+@@ -23,6 +23,7 @@
+ */
+ 
+ #include "providers/proxy/proxy.h"
++#include "providers/proxy/proxy_iface_generated.h"
+ 
+ struct pc_init_ctx;
+ 
+@@ -531,9 +532,9 @@ static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
+     state->pid = pid;
+ 
+     msg = dbus_message_new_method_call(NULL,
+-                                       DP_PATH,
+-                                       DATA_PROVIDER_IFACE,
+-                                       DATA_PROVIDER_IFACE_PAMHANDLER);
++                                       PROXY_CHILD_PATH,
++                                       IFACE_PROXY_AUTH,
++                                       IFACE_PROXY_AUTH_PAM);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "dbus_message_new_method_call failed.\n");
+         talloc_zfree(req);
+@@ -847,4 +848,3 @@ proxy_pam_handler_recv(TALLOC_CTX *mem_ctx,
+ 
+     return EOK;
+ }
+-
+diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c
+index efd304d5aafd5e53792ef96b75d8aa0c908bbe13..b492adcb3b5efefc08e6eb9e069035aeff8d34df 100644
+--- a/src/providers/proxy/proxy_child.c
++++ b/src/providers/proxy/proxy_child.c
+@@ -44,22 +44,10 @@
+ #include "confdb/confdb.h"
+ #include "sbus/sssd_dbus.h"
+ #include "providers/proxy/proxy.h"
++#include "providers/proxy/proxy_iface_generated.h"
+ 
+ #include "providers/backend.h"
+ 
+-static int pc_pam_handler(struct sbus_request *dbus_req, void *user_data);
+-
+-struct data_provider_iface pc_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = pc_pam_handler,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ struct pc_ctx {
+     struct tevent_context *ev;
+     struct confdb_ctx *cdb;
+@@ -382,17 +370,71 @@ done:
+     exit(ret);
+ }
+ 
+-int proxy_child_send_id(struct sbus_connection *conn,
+-                        uint16_t version,
+-                        uint32_t id);
++static void proxy_child_id_callback(DBusPendingCall *pending, void *ptr)
++{
++    DBusMessage *reply;
++    errno_t ret;
++
++    reply = dbus_pending_call_steal_reply(pending);
++    if (reply == NULL) {
++        /* reply should never be null. This function shouldn't be called
++         * until reply is valid or timeout has occurred. If reply is NULL
++         * here, something is seriously wrong and we should bail out.
++         */
++        DEBUG(SSSDBG_FATAL_FAILURE, "Severe error. A reply callback was "
++              "called but no reply was received and no timeout occurred\n");
++        goto done;
++    }
++
++    ret = sbus_parse_reply(reply);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get ID ack [%d]: %s\n",
++              ret, sss_strerror(ret));
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Got id ack from proxy child\n");
++
++done:
++    dbus_pending_call_unref(pending);
++    dbus_message_unref(reply);
++}
++
++static errno_t proxy_child_send_id(struct sbus_connection *conn, uint32_t id)
++{
++    DBusMessage *msg;
++    errno_t ret;
++
++    msg = sbus_create_message(NULL, NULL, PROXY_CHILD_PATH, IFACE_PROXY_CLIENT,
++                              IFACE_PROXY_CLIENT_REGISTER,
++                              DBUS_TYPE_UINT32, &id);
++    if (msg == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?!\n");
++        return ENOMEM;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Sending ID to Proxy Backend: (%"PRIu32")\n", id);
++
++    ret = sbus_conn_send(conn, msg, 30000, proxy_child_id_callback, NULL, NULL);
++
++    dbus_message_unref(msg);
++
++    return ret;
++}
++
+ static int proxy_cli_init(struct pc_ctx *ctx)
+ {
+     char *sbus_address;
+     int ret;
+ 
++    static struct iface_proxy_auth iface_proxy_auth = {
++        { &iface_proxy_auth_meta, 0 },
++
++        .PAM = pc_pam_handler,
++    };
++
+     sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s",
+-                                      PIPE_PATH, PROXY_CHILD_PIPE,
+-                                      ctx->domain->name);
++                                   PIPE_PATH, PROXY_CHILD_PIPE,
++                                   ctx->domain->name);
+     if (sbus_address == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
+         return ENOMEM;
+@@ -404,13 +446,14 @@ static int proxy_cli_init(struct pc_ctx *ctx)
+         return ret;
+     }
+ 
+-    ret = sbus_conn_register_iface(ctx->conn, &pc_methods.vtable, DP_PATH, ctx);
++    ret = sbus_conn_register_iface(ctx->conn, &iface_proxy_auth.vtable,
++                                   PROXY_CHILD_PATH, ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export proxy.\n");
+         return ret;
+     }
+ 
+-    ret = proxy_child_send_id(ctx->conn, DATA_PROVIDER_VERSION, ctx->id);
++    ret = proxy_child_send_id(ctx->conn, ctx->id);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "dp_common_send_id failed.\n");
+         return ret;
+@@ -419,42 +462,6 @@ static int proxy_cli_init(struct pc_ctx *ctx)
+     return EOK;
+ }
+ 
+-int proxy_child_send_id(struct sbus_connection *conn,
+-                        uint16_t version,
+-                        uint32_t id)
+-{
+-    DBusMessage *msg;
+-    dbus_bool_t ret;
+-    int retval;
+-
+-    /* create the message */
+-    msg = dbus_message_new_method_call(NULL,
+-                                       DP_PATH,
+-                                       DATA_PROVIDER_IFACE,
+-                                       DATA_PROVIDER_IFACE_REGISTERSERVICE);
+-    if (msg == NULL) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?!\n");
+-        return ENOMEM;
+-    }
+-
+-    DEBUG(SSSDBG_FUNC_DATA, "Sending ID to Proxy Backend: (%d,%"PRIu32")\n",
+-                             version, id);
+-
+-    ret = dbus_message_append_args(msg,
+-                                   DBUS_TYPE_UINT16, &version,
+-                                   DBUS_TYPE_UINT32, &id,
+-                                   DBUS_TYPE_INVALID);
+-    if (!ret) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
+-        return EIO;
+-    }
+-
+-    retval = sbus_conn_send(conn, msg, 30000, dp_id_callback, NULL, NULL);
+-
+-    dbus_message_unref(msg);
+-    return retval;
+-}
+-
+ int proxy_child_process_init(TALLOC_CTX *mem_ctx, const char *domain,
+                              struct tevent_context *ev, struct confdb_ctx *cdb,
+                              const char *pam_target, uint32_t id)
+diff --git a/src/providers/proxy/proxy_client.c b/src/providers/proxy/proxy_client.c
+index fc1735f2a101528a1edeaf3cf9c1118e4a21e937..74957caeec5bf50b5cb959d6f5b8ec1ca9ecba37 100644
+--- a/src/providers/proxy/proxy_client.c
++++ b/src/providers/proxy/proxy_client.c
+@@ -22,24 +22,10 @@
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+ 
+-#include "config.h"
+-
+-#include "util/sss_format.h"
++#include "util/util.h"
++#include "providers/proxy/proxy_iface_generated.h"
+ #include "providers/proxy/proxy.h"
+ 
+-static int client_registration(struct sbus_request *dbus_req, void *data);
+-
+-static struct data_provider_iface proxy_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = client_registration,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ struct proxy_client {
+     struct proxy_auth_ctx *proxy_auth_ctx;
+     struct sbus_connection *conn;
+@@ -47,24 +33,22 @@ struct proxy_client {
+     bool initialized;
+ };
+ 
+-static int client_registration(struct sbus_request *dbus_req, void *data)
++static int proxy_client_register(struct sbus_request *sbus_req,
++                                 void *data,
++                                 uint32_t cli_id)
+ {
+-    dbus_uint16_t version = DATA_PROVIDER_VERSION;
+     struct sbus_connection *conn;
+     struct proxy_client *proxy_cli;
+-    dbus_uint16_t cli_ver;
+-    uint32_t cli_id;
+     int hret;
+     hash_key_t key;
+     hash_value_t value;
+     struct tevent_req *req;
+     struct proxy_child_ctx *child_ctx;
+     struct pc_init_ctx *init_ctx;
+-    int ret;
+ 
+-    conn = dbus_req->conn;
++    conn = sbus_req->conn;
+     proxy_cli = talloc_get_type(data, struct proxy_client);
+-    if (!proxy_cli) {
++    if (proxy_cli == NULL) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
+         return EINVAL;
+     }
+@@ -74,14 +58,6 @@ static int client_registration(struct sbus_request *dbus_req, void *data)
+           "Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout);
+     talloc_zfree(proxy_cli->timeout);
+ 
+-    if (!sbus_request_parse_or_finish(dbus_req,
+-                                      DBUS_TYPE_UINT16, &cli_ver,
+-                                      DBUS_TYPE_UINT32, &cli_id,
+-                                      DBUS_TYPE_INVALID)) {
+-        sbus_disconnect(conn);
+-        return EOK; /* handled */
+-    }
+-
+     DEBUG(SSSDBG_FUNC_DATA, "Proxy client [%"PRIu32"] connected\n", cli_id);
+ 
+     /* Check the hash table */
+@@ -94,20 +70,14 @@ static int client_registration(struct sbus_request *dbus_req, void *data)
+         return EIO;
+     }
+ 
+-    /* reply that all is ok */
+-    ret = sbus_request_return_and_finish(dbus_req,
+-                                         DBUS_TYPE_UINT16, &version,
+-                                         DBUS_TYPE_INVALID);
+-    if (ret != EOK) {
+-        sbus_disconnect(conn);
+-        return ret;
+-    }
++    iface_proxy_client_Register_finish(sbus_req);
+ 
+     hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);
+     if (hret != HASH_SUCCESS) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Hash error [%d][%s]\n", hret, hash_error_string(hret));
++              "Hash error [%d]: %s\n", hret, hash_error_string(hret));
+         sbus_disconnect(conn);
++        return EIO;
+     }
+ 
+     /* Signal that the child is up and ready to receive the request */
+@@ -121,7 +91,7 @@ static int client_registration(struct sbus_request *dbus_req, void *data)
+          * break.
+          */
+         DEBUG(SSSDBG_CRIT_FAILURE, "Client connection from a request "
+-                  "that's not marked as running\n");
++              "that's not marked as running\n");
+         return EIO;
+     }
+ 
+@@ -133,9 +103,10 @@ static int client_registration(struct sbus_request *dbus_req, void *data)
+     return EOK;
+ }
+ 
+-static void init_timeout(struct tevent_context *ev,
+-                         struct tevent_timer *te,
+-                         struct timeval t, void *ptr)
++static void proxy_client_timeout(struct tevent_context *ev,
++                                 struct tevent_timer *te,
++                                 struct timeval t,
++                                 void *ptr)
+ {
+     struct proxy_client *proxy_cli;
+ 
+@@ -155,38 +126,53 @@ static void init_timeout(struct tevent_context *ev,
+ 
+ int proxy_client_init(struct sbus_connection *conn, void *data)
+ {
+-    struct proxy_auth_ctx *proxy_auth_ctx;
++    struct proxy_auth_ctx *auth_ctx;
+     struct proxy_client *proxy_cli;
+     struct timeval tv;
++    errno_t ret;
+ 
+-    proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
++    static struct iface_proxy_client iface_proxy_client = {
++        { &iface_proxy_client_meta, 0 },
+ 
+-    /* hang off this memory to the connection so that when the connection
+-     * is freed we can potentially call a destructor */
++        .Register = proxy_client_register,
++    };
+ 
++    auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
++
++    /* When connection is lost we also free the client. */
+     proxy_cli = talloc_zero(conn, struct proxy_client);
+-    if (!proxy_cli) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
+-        talloc_zfree(conn);
++    if (proxy_cli == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, killing connection.\n");
++        talloc_free(conn);
+         return ENOMEM;
+     }
+-    proxy_cli->proxy_auth_ctx = proxy_auth_ctx;
++
++    proxy_cli->proxy_auth_ctx = auth_ctx;
+     proxy_cli->conn = conn;
+     proxy_cli->initialized = false;
+ 
+-    /* 5 seconds should be plenty */
++    /* Setup timeout in case client fails to register himself in time. */
+     tv = tevent_timeval_current_ofs(5, 0);
+-
+-    proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli,
+-                                          tv, init_timeout, proxy_cli);
+-    if (!proxy_cli->timeout) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
+-        talloc_zfree(conn);
++    proxy_cli->timeout = tevent_add_timer(auth_ctx->be->ev, proxy_cli, tv,
++                                          proxy_client_timeout, proxy_cli);
++    if (proxy_cli->timeout == NULL) {
++        /* Connection is closed in the caller. */
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, killing connection\n");
+         return ENOMEM;
+     }
++
+     DEBUG(SSSDBG_CONF_SETTINGS,
+           "Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout);
+ 
+-    return sbus_conn_register_iface(conn, &proxy_methods.vtable,
+-                                    DP_PATH, proxy_cli);
++    /* Setup D-Bus interfaces and methods. */
++    ret = sbus_conn_register_iface(conn, &iface_proxy_client.vtable,
++                                   PROXY_CHILD_PATH, proxy_cli);
++    if (ret != EOK) {
++        /* Connection is closed in the caller. */
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register D-Bus interface, "
++              "killing connection [%d]: %s\n", ret, sss_strerror(ret));
++        return ret;
++    }
++
++    return ret;
+ }
+diff --git a/src/providers/proxy/proxy_iface.xml b/src/providers/proxy/proxy_iface.xml
+new file mode 100644
+index 0000000000000000000000000000000000000000..39b0b03928661a1851fd739598b0194547441c2c
+--- /dev/null
++++ b/src/providers/proxy/proxy_iface.xml
+@@ -0,0 +1,17 @@
++<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
++ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
++<node>
++    <interface name="org.freedesktop.sssd.ProxyChild.Client">
++        <annotation value="iface_proxy_client" name="org.freedesktop.DBus.GLib.CSymbol"/>
++        <method name="Register">
++            <arg name="ID" type="u" direction="in" />
++        </method>
++    </interface>
++
++    <interface name="org.freedesktop.sssd.ProxyChild.Auth">
++        <annotation value="iface_proxy_auth" name="org.freedesktop.DBus.GLib.CSymbol"/>
++        <method name="PAM">
++            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
++        </method>
++    </interface>
++</node>
+diff --git a/src/providers/proxy/proxy_iface_generated.c b/src/providers/proxy/proxy_iface_generated.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..425727d1496b537eb25b002815d14e1f57b8f00d
+--- /dev/null
++++ b/src/providers/proxy/proxy_iface_generated.c
+@@ -0,0 +1,80 @@
++/* The following definitions are auto-generated from proxy_iface.xml */
++
++#include "util/util.h"
++#include "sbus/sssd_dbus.h"
++#include "sbus/sssd_dbus_meta.h"
++#include "sbus/sssd_dbus_invokers.h"
++#include "proxy_iface_generated.h"
++
++/* invokes a handler with a 'u' DBus signature */
++static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr);
++
++/* arguments for org.freedesktop.sssd.ProxyChild.Client.Register */
++const struct sbus_arg_meta iface_proxy_client_Register__in[] = {
++    { "ID", "u" },
++    { NULL, }
++};
++
++int iface_proxy_client_Register_finish(struct sbus_request *req)
++{
++   return sbus_request_return_and_finish(req,
++                                         DBUS_TYPE_INVALID);
++}
++
++/* methods for org.freedesktop.sssd.ProxyChild.Client */
++const struct sbus_method_meta iface_proxy_client__methods[] = {
++    {
++        "Register", /* name */
++        iface_proxy_client_Register__in,
++        NULL, /* no out_args */
++        offsetof(struct iface_proxy_client, Register),
++        invoke_u_method,
++    },
++    { NULL, }
++};
++
++/* interface info for org.freedesktop.sssd.ProxyChild.Client */
++const struct sbus_interface_meta iface_proxy_client_meta = {
++    "org.freedesktop.sssd.ProxyChild.Client", /* name */
++    iface_proxy_client__methods,
++    NULL, /* no signals */
++    NULL, /* no properties */
++    sbus_invoke_get_all, /* GetAll invoker */
++};
++
++/* methods for org.freedesktop.sssd.ProxyChild.Auth */
++const struct sbus_method_meta iface_proxy_auth__methods[] = {
++    {
++        "PAM", /* name */
++        NULL, /* no in_args */
++        NULL, /* no out_args */
++        offsetof(struct iface_proxy_auth, PAM),
++        NULL, /* no invoker */
++    },
++    { NULL, }
++};
++
++/* interface info for org.freedesktop.sssd.ProxyChild.Auth */
++const struct sbus_interface_meta iface_proxy_auth_meta = {
++    "org.freedesktop.sssd.ProxyChild.Auth", /* name */
++    iface_proxy_auth__methods,
++    NULL, /* no signals */
++    NULL, /* no properties */
++    sbus_invoke_get_all, /* GetAll invoker */
++};
++
++/* invokes a handler with a 'u' DBus signature */
++static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr)
++{
++    uint32_t arg_0;
++    int (*handler)(struct sbus_request *, void *, uint32_t) = function_ptr;
++
++    if (!sbus_request_parse_or_finish(dbus_req,
++                               DBUS_TYPE_UINT32, &arg_0,
++                               DBUS_TYPE_INVALID)) {
++         return EOK; /* request handled */
++    }
++
++    return (handler)(dbus_req, dbus_req->intf->handler_data,
++                     arg_0);
++}
+diff --git a/src/providers/proxy/proxy_iface_generated.h b/src/providers/proxy/proxy_iface_generated.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..7af074fa3d839263318ceac7ea34f62dcde64563
+--- /dev/null
++++ b/src/providers/proxy/proxy_iface_generated.h
+@@ -0,0 +1,71 @@
++/* The following declarations are auto-generated from proxy_iface.xml */
++
++#ifndef __PROXY_IFACE_XML__
++#define __PROXY_IFACE_XML__
++
++#include "sbus/sssd_dbus.h"
++
++/* ------------------------------------------------------------------------
++ * DBus Constants
++ *
++ * Various constants of interface and method names mostly for use by clients
++ */
++
++/* constants for org.freedesktop.sssd.ProxyChild.Client */
++#define IFACE_PROXY_CLIENT "org.freedesktop.sssd.ProxyChild.Client"
++#define IFACE_PROXY_CLIENT_REGISTER "Register"
++
++/* constants for org.freedesktop.sssd.ProxyChild.Auth */
++#define IFACE_PROXY_AUTH "org.freedesktop.sssd.ProxyChild.Auth"
++#define IFACE_PROXY_AUTH_PAM "PAM"
++
++/* ------------------------------------------------------------------------
++ * DBus handlers
++ *
++ * These structures are filled in by implementors of the different
++ * dbus interfaces to handle method calls.
++ *
++ * Handler functions of type sbus_msg_handler_fn accept raw messages,
++ * other handlers are typed appropriately. If a handler that is
++ * set to NULL is invoked it will result in a
++ * org.freedesktop.DBus.Error.NotSupported error for the caller.
++ *
++ * Handlers have a matching xxx_finish() function (unless the method has
++ * accepts raw messages). These finish functions the
++ * sbus_request_return_and_finish() with the appropriate arguments to
++ * construct a valid reply. Once a finish function has been called, the
++ * @dbus_req it was called with is freed and no longer valid.
++ */
++
++/* vtable for org.freedesktop.sssd.ProxyChild.Client */
++struct iface_proxy_client {
++    struct sbus_vtable vtable; /* derive from sbus_vtable */
++    int (*Register)(struct sbus_request *req, void *data, uint32_t arg_ID);
++};
++
++/* finish function for Register */
++int iface_proxy_client_Register_finish(struct sbus_request *req);
++
++/* vtable for org.freedesktop.sssd.ProxyChild.Auth */
++struct iface_proxy_auth {
++    struct sbus_vtable vtable; /* derive from sbus_vtable */
++    sbus_msg_handler_fn PAM;
++};
++
++/* ------------------------------------------------------------------------
++ * DBus Interface Metadata
++ *
++ * These structure definitions are filled in with the information about
++ * the interfaces, methods, properties and so on.
++ *
++ * The actual definitions are found in the accompanying C file next
++ * to this header.
++ */
++
++/* interface info for org.freedesktop.sssd.ProxyChild.Client */
++extern const struct sbus_interface_meta iface_proxy_client_meta;
++
++/* interface info for org.freedesktop.sssd.ProxyChild.Auth */
++extern const struct sbus_interface_meta iface_proxy_auth_meta;
++
++#endif /* __PROXY_IFACE_XML__ */
+-- 
+2.4.11
+
diff --git a/SOURCES/0100-AD-Provide-common-connection-list-construction-funct.patch b/SOURCES/0100-AD-Provide-common-connection-list-construction-funct.patch
deleted file mode 100644
index 33f2ef6..0000000
--- a/SOURCES/0100-AD-Provide-common-connection-list-construction-funct.patch
+++ /dev/null
@@ -1,241 +0,0 @@
-From 809f139ac4c23dd9db20ea6068e18682f32eb1db Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 1 Oct 2015 13:13:05 +0200
-Subject: [PATCH 100/101] AD: Provide common connection list construction
- functions
-
-https://fedorahosted.org/sssd/ticket/2810
-
-Provides a new AD common function ad_ldap_conn_list() that creates a
-list of AD connection to use along with properties to avoid mistakes
-when manually constructing these lists.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 309aa83d16b5919f727af04850bcd0799ba0962f)
-(cherry picked from commit 15a4b34ccfcfbcec2c9ba529d0113adf251abc16)
----
- src/providers/ad/ad_common.c          | 26 +++++++++++++++++++
- src/providers/ad/ad_common.h          |  5 ++++
- src/providers/ad/ad_id.c              | 17 +------------
- src/providers/ipa/ipa_subdomains_id.c | 21 ++++++----------
- src/tests/cmocka/test_ad_common.c     | 47 ++++++++++++++++++++++++++++++-----
- 5 files changed, 81 insertions(+), 35 deletions(-)
-
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index 130cdeb613aae3843f7453a478815daaae6aab77..df277e55e234d4d4efe34d5f5d8efdfe7267fb60 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1236,6 +1236,14 @@ ad_get_dom_ldap_conn(struct ad_id_ctx *ad_ctx, struct sss_domain_info *dom)
-     subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
-     conn = subdom_id_ctx->ldap_ctx;
- 
-+    if (IS_SUBDOMAIN(sdom->dom) == true && conn != NULL) {
-+        /* Regardless of connection types, a subdomain error must not be
-+         * allowed to set the whole back end offline, rather report an error
-+         * and let the caller deal with it (normally disable the subdomain
-+         */
-+        conn->ignore_mark_offline = true;
-+    }
-+
-     return conn;
- }
- 
-@@ -1260,3 +1268,21 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
- 
-     return clist;
- }
-+
-+struct sdap_id_conn_ctx **
-+ad_ldap_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 *, 2);
-+    if (clist == NULL) {
-+        return NULL;
-+    }
-+
-+    clist[0] = ad_get_dom_ldap_conn(ad_ctx, dom);
-+
-+    clist[1] = NULL;
-+    return clist;
-+}
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index 817f5b42cad7cad6a88244fd43bd91a4358d56c0..701e461987cb286ca7add2766ffb4dc496bde01e 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -148,6 +148,11 @@ 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_ldap_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);
- 
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index ecaf6c993bf7ddb7ba565d40ef0ad250114f5536..be0cb3b12f2e3a2b53d740ecf3befc07fd853f8b 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -269,29 +269,14 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-     case BE_REQ_GROUP: /* group */
-     case BE_REQ_INITGROUPS: /* init groups for user */
-         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;
-+        clist = ad_ldap_conn_list(breq, ad_ctx, dom);
-         break;
-     }
- 
--    /* Regardless of connection types, a subdomain error must not be allowed
--     * to set the whole back end offline, rather report an error and let the
--     * caller deal with it (normally disable the subdomain
--     */
--    if (IS_SUBDOMAIN(dom)) {
--        for (cindex = 0; clist[cindex] != NULL; cindex++) {
--            clist[cindex]->ignore_mark_offline = true;
--        }
--    }
--
-     return clist;
- }
- 
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 86dd71f3cc09f11de88c4269d49552718c5ba027..7acbb38e66c2c36ff230ae35b236544195a8104b 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -640,21 +640,16 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-     case BE_REQ_BY_SECID:
-     case BE_REQ_GROUP:
-         clist = ad_gc_conn_list(req, ad_id_ctx, state->obj_dom);
--        if (clist == NULL) {
--            ret = ENOMEM;
--            goto fail;
--        }
--        clist[1]->ignore_mark_offline = true;
-         break;
-     default:
--        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[0]->ignore_mark_offline = true;
--        clist[1] = NULL;
-+        clist = ad_ldap_conn_list(req, ad_id_ctx, state->obj_dom);
-+        break;
-+    }
-+
-+    if (clist == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Cannot generate AD connection list!\n");
-+        ret = ENOMEM;
-+        goto fail;
-     }
- 
-     /* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-index 985a05fae5a4d09ab102ed611c7d03ca8e4d955b..c7bcc0f7cfde7164672123a35940327ee3ca4aba 100644
---- a/src/tests/cmocka/test_ad_common.c
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -337,7 +337,7 @@ __wrap_sdap_set_sasl_options(struct sdap_options *id_opts,
-     return EOK;
- }
- 
--void test_ldap_conn_list(void **state)
-+void test_ad_get_dom_ldap_conn(void **state)
- {
-     struct sdap_id_conn_ctx *conn;
- 
-@@ -352,7 +352,7 @@ void test_ldap_conn_list(void **state)
-     assert_true(conn == test_ctx->subdom_ad_ctx->ldap_ctx);
- }
- 
--void test_conn_list(void **state)
-+void test_gc_conn_list(void **state)
- {
-     struct sdap_id_conn_ctx **conn_list;
- 
-@@ -379,7 +379,8 @@ void test_conn_list(void **state)
-     assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx);
-     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);
-+    /* Subdomain error should not set the backend offline! */
-+    assert_true(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);
-@@ -398,6 +399,37 @@ void test_conn_list(void **state)
-     assert_non_null(conn_list);
- 
-     assert_true(conn_list[0] == test_ctx->subdom_ad_ctx->ldap_ctx);
-+    assert_true(conn_list[0]->ignore_mark_offline);
-+    assert_null(conn_list[1]);
-+    talloc_free(conn_list);
-+}
-+
-+void test_ldap_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_ldap_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_ldap_conn_list(test_ctx,
-+                                  test_ctx->ad_ctx,
-+                                  test_ctx->subdom);
-+    assert_non_null(conn_list);
-+
-+    assert_true(conn_list[0] == test_ctx->subdom_ad_ctx->ldap_ctx);
-+    assert_true(conn_list[0]->ignore_mark_offline);
-+    assert_null(conn_list[1]);
-     talloc_free(conn_list);
- }
- 
-@@ -419,12 +451,15 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_ad_create_2way_trust_options,
-                                         test_ad_common_setup,
-                                         test_ad_common_teardown),
-+        cmocka_unit_test_setup_teardown(test_ad_get_dom_ldap_conn,
-+                                        test_ldap_conn_setup,
-+                                        test_ldap_conn_teardown),
-+        cmocka_unit_test_setup_teardown(test_gc_conn_list,
-+                                        test_ldap_conn_setup,
-+                                        test_ldap_conn_teardown),
-         cmocka_unit_test_setup_teardown(test_ldap_conn_list,
-                                         test_ldap_conn_setup,
-                                         test_ldap_conn_teardown),
--        cmocka_unit_test_setup_teardown(test_conn_list,
--                                        test_ldap_conn_setup,
--                                        test_ldap_conn_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.4.3
-
diff --git a/SOURCES/0100-DP-Remove-old-data-provider-interface.patch b/SOURCES/0100-DP-Remove-old-data-provider-interface.patch
new file mode 100644
index 0000000..db73927
--- /dev/null
+++ b/SOURCES/0100-DP-Remove-old-data-provider-interface.patch
@@ -0,0 +1,1034 @@
+From c2fe5c54faa92c670161d65fe5a1ff62acd4ac91 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 19 Jul 2016 14:24:16 +0200
+Subject: [PATCH 100/102] DP: Remove old data provider interface
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reverse data provider interface is moved to a better location in
+NSS responder. All responders now can have an sbus interface
+defined per data provider connection. The unused old data provider
+interface is removed.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 04e870d99e72aa3160bdb6ab05d986fb4005c3ed)
+---
+ Makefile.am                                   | 11 +--
+ src/providers/data_provider.h                 |  1 -
+ src/providers/data_provider/dp_target_id.c    |  7 +-
+ src/providers/data_provider_iface.xml         | 53 ---------------
+ src/providers/data_provider_iface_generated.c | 98 ---------------------------
+ src/providers/data_provider_iface_generated.h | 82 ----------------------
+ src/responder/autofs/autofssrv.c              | 13 +---
+ src/responder/common/responder.h              |  8 +--
+ src/responder/common/responder_common.c       | 16 +++--
+ src/responder/common/responder_get_domains.c  |  4 +-
+ src/responder/ifp/ifpsrv.c                    | 13 +---
+ src/responder/nss/nss_iface.c                 | 38 +++++++++++
+ src/responder/nss/nss_iface.h                 | 30 ++++++++
+ src/responder/nss/nss_iface.xml               | 12 ++++
+ src/responder/nss/nss_iface_generated.c       | 69 +++++++++++++++++++
+ src/responder/nss/nss_iface_generated.h       | 58 ++++++++++++++++
+ src/responder/nss/nsssrv.c                    | 39 ++++-------
+ src/responder/nss/nsssrv.h                    |  7 ++
+ src/responder/pac/pacsrv.c                    | 13 +---
+ src/responder/pam/pamsrv.c                    | 13 +---
+ src/responder/pam/pamsrv_dp.c                 |  4 +-
+ src/responder/ssh/sshsrv.c                    | 13 +---
+ src/responder/sudo/sudosrv.c                  | 13 +---
+ src/tests/cwrap/Makefile.am                   |  1 -
+ 24 files changed, 259 insertions(+), 357 deletions(-)
+ delete mode 100644 src/providers/data_provider_iface.xml
+ delete mode 100644 src/providers/data_provider_iface_generated.c
+ delete mode 100644 src/providers/data_provider_iface_generated.h
+ create mode 100644 src/responder/nss/nss_iface.c
+ create mode 100644 src/responder/nss/nss_iface.h
+ create mode 100644 src/responder/nss/nss_iface.xml
+ create mode 100644 src/responder/nss/nss_iface_generated.c
+ create mode 100644 src/responder/nss/nss_iface_generated.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 5d54838659e44fa446fc921d014e48ac91469b25..e2e4c4c08f66ef15684e1b3b1fe17bfae4e4131b 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -492,7 +492,6 @@ SSSD_RESPONDER_OBJ = \
+     src/responder/common/data_provider/rdp_message.c \
+     src/responder/common/data_provider/rdp_client.c \
+     src/monitor/monitor_iface_generated.c \
+-    src/providers/data_provider_iface_generated.c \
+     src/providers/data_provider_req.c
+ 
+ SSSD_TOOLS_OBJ = \
+@@ -610,6 +609,8 @@ dist_noinst_HEADERS = \
+     src/responder/nss/nsssrv_netgroup.h \
+     src/responder/nss/nsssrv_services.h \
+     src/responder/nss/nsssrv_mmap_cache.h \
++    src/responder/nss/nss_iface_generated.h \
++    src/responder/nss/nss_iface.h \
+     src/responder/pac/pacsrv.h \
+     src/responder/common/negcache_files.h \
+     src/responder/common/negcache.h \
+@@ -647,7 +648,6 @@ dist_noinst_HEADERS = \
+     src/confdb/confdb_setup.h \
+     src/providers/data_provider.h \
+     src/providers/data_provider_req.h \
+-    src/providers/data_provider_iface_generated.h \
+     src/providers/data_provider/dp.h \
+     src/providers/data_provider/dp_flags.h \
+     src/providers/data_provider/dp_responder_iface.h \
+@@ -1196,10 +1196,10 @@ endif
+ CODEGEN_XML = \
+     $(srcdir)/src/tests/sbus_codegen_tests.xml \
+     $(srcdir)/src/monitor/monitor_iface.xml \
+-    $(srcdir)/src/providers/data_provider_iface.xml \
+     $(srcdir)/src/providers/data_provider/dp_iface.xml \
+     $(srcdir)/src/providers/proxy/proxy_iface.xml \
+-    $(srcdir)/src/responder/ifp/ifp_iface.xml
++    $(srcdir)/src/responder/ifp/ifp_iface.xml \
++    $(srcdir)/src/responder/nss/nss_iface.xml
+ 
+ SBUS_CODEGEN = src/sbus/sbus_codegen
+ 
+@@ -1248,6 +1248,8 @@ sssd_nss_SOURCES = \
+     src/responder/nss/nsssrv_netgroup.c \
+     src/responder/nss/nsssrv_services.c \
+     src/responder/nss/nsssrv_mmap_cache.c \
++    src/responder/nss/nss_iface_generated.c \
++    src/responder/nss/nss_iface.c \
+     $(SSSD_RESPONDER_OBJ)
+ sssd_nss_LDADD = \
+     $(TDB_LIBS) \
+@@ -1411,7 +1413,6 @@ sssd_be_SOURCES = \
+     src/providers/be_ptask.c \
+     src/providers/be_refresh.c \
+     src/monitor/monitor_iface_generated.c \
+-    src/providers/data_provider_iface_generated.c \
+     src/providers/data_provider/dp.c \
+     src/providers/data_provider/dp_modules.c \
+     src/providers/data_provider/dp_targets.c \
+diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
+index b0b6876d984d7c6574baaa8d130e374ba2e6f0c4..14a0902c265850d91fa7d29cc2708e70b060ec18 100644
+--- a/src/providers/data_provider.h
++++ b/src/providers/data_provider.h
+@@ -44,7 +44,6 @@
+ #include "sss_client/sss_cli.h"
+ #include "util/authtok.h"
+ #include "providers/data_provider_req.h"
+-#include "providers/data_provider_iface_generated.h"
+ 
+ #define DATA_PROVIDER_VERSION 0x0001
+ #define DATA_PROVIDER_PIPE "private/sbus-dp"
+diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
+index 1b06cbe5b96f56c33dd048cf6211b7c97819db8c..938651545ea995091d0aaf29da12bbb8110c9add 100644
+--- a/src/providers/data_provider/dp_target_id.c
++++ b/src/providers/data_provider/dp_target_id.c
+@@ -25,6 +25,7 @@
+ #include "providers/data_provider/dp_private.h"
+ #include "providers/data_provider/dp_iface.h"
+ #include "providers/backend.h"
++#include "responder/nss/nss_iface.h"
+ #include "util/util.h"
+ 
+ #define FILTER_TYPE(str, type) {str "=", sizeof(str "=") - 1, type}
+@@ -168,9 +169,9 @@ static void dp_req_initgr_pp(const char *req_name,
+     }
+ 
+     msg = dbus_message_new_method_call(NULL,
+-                                       DP_PATH,
+-                                       DATA_PROVIDER_REV_IFACE,
+-                                       DATA_PROVIDER_REV_IFACE_INITGRCHECK);
++                                       NSS_MEMORYCACHE_PATH,
++                                       IFACE_NSS_MEMORYCACHE,
++                                       IFACE_NSS_MEMORYCACHE_UPDATEINITGROUPS);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
+         return;
+diff --git a/src/providers/data_provider_iface.xml b/src/providers/data_provider_iface.xml
+deleted file mode 100644
+index 143975633081ce2ae5690c4036e7169e41d776fc..0000000000000000000000000000000000000000
+--- a/src/providers/data_provider_iface.xml
++++ /dev/null
+@@ -1,53 +0,0 @@
+-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+- "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+-<node>
+-    <interface name="org.freedesktop.sssd.dataprovider">
+-        <annotation value="data_provider_iface" name="org.freedesktop.DBus.GLib.CSymbol"/>
+-        <method name="RegisterService">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="pamHandler">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="sudoHandler">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="autofsHandler">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="hostHandler">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="getDomains">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="getAccountInfo">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-    </interface>
+-
+-    <!--
+-      this is a reverse method sent from providers to
+-      the nss responder to tell it to update the mmap
+-      cache
+-    -->
+-
+-    <interface name="org.freedesktop.sssd.dataprovider_rev">
+-        <annotation value="data_provider_rev_iface" name="org.freedesktop.DBus.GLib.CSymbol"/>
+-        <method name="updateCache">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-        <method name="initgrCheck">
+-            <!-- arguments parsed manually, raw handler -->
+-            <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
+-        </method>
+-    </interface>
+-</node>
+diff --git a/src/providers/data_provider_iface_generated.c b/src/providers/data_provider_iface_generated.c
+deleted file mode 100644
+index bdd6a4d76d18bbb44530d816fce14009736b6f6d..0000000000000000000000000000000000000000
+--- a/src/providers/data_provider_iface_generated.c
++++ /dev/null
+@@ -1,98 +0,0 @@
+-/* The following definitions are auto-generated from data_provider_iface.xml */
+-
+-#include "util/util.h"
+-#include "sbus/sssd_dbus.h"
+-#include "sbus/sssd_dbus_meta.h"
+-#include "sbus/sssd_dbus_invokers.h"
+-#include "data_provider_iface_generated.h"
+-
+-/* methods for org.freedesktop.sssd.dataprovider */
+-const struct sbus_method_meta data_provider_iface__methods[] = {
+-    {
+-        "RegisterService", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, RegisterService),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "pamHandler", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, pamHandler),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "sudoHandler", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, sudoHandler),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "autofsHandler", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, autofsHandler),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "hostHandler", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, hostHandler),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "getDomains", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, getDomains),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "getAccountInfo", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_iface, getAccountInfo),
+-        NULL, /* no invoker */
+-    },
+-    { NULL, }
+-};
+-
+-/* interface info for org.freedesktop.sssd.dataprovider */
+-const struct sbus_interface_meta data_provider_iface_meta = {
+-    "org.freedesktop.sssd.dataprovider", /* name */
+-    data_provider_iface__methods,
+-    NULL, /* no signals */
+-    NULL, /* no properties */
+-    sbus_invoke_get_all, /* GetAll invoker */
+-};
+-
+-/* methods for org.freedesktop.sssd.dataprovider_rev */
+-const struct sbus_method_meta data_provider_rev_iface__methods[] = {
+-    {
+-        "updateCache", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_rev_iface, updateCache),
+-        NULL, /* no invoker */
+-    },
+-    {
+-        "initgrCheck", /* name */
+-        NULL, /* no in_args */
+-        NULL, /* no out_args */
+-        offsetof(struct data_provider_rev_iface, initgrCheck),
+-        NULL, /* no invoker */
+-    },
+-    { NULL, }
+-};
+-
+-/* interface info for org.freedesktop.sssd.dataprovider_rev */
+-const struct sbus_interface_meta data_provider_rev_iface_meta = {
+-    "org.freedesktop.sssd.dataprovider_rev", /* name */
+-    data_provider_rev_iface__methods,
+-    NULL, /* no signals */
+-    NULL, /* no properties */
+-    sbus_invoke_get_all, /* GetAll invoker */
+-};
+diff --git a/src/providers/data_provider_iface_generated.h b/src/providers/data_provider_iface_generated.h
+deleted file mode 100644
+index 976e42b89c6aaf9523b16999b8f5103a1e6f8e66..0000000000000000000000000000000000000000
+--- a/src/providers/data_provider_iface_generated.h
++++ /dev/null
+@@ -1,82 +0,0 @@
+-/* The following declarations are auto-generated from data_provider_iface.xml */
+-
+-#ifndef __DATA_PROVIDER_IFACE_XML__
+-#define __DATA_PROVIDER_IFACE_XML__
+-
+-#include "sbus/sssd_dbus.h"
+-
+-/* ------------------------------------------------------------------------
+- * DBus Constants
+- *
+- * Various constants of interface and method names mostly for use by clients
+- */
+-
+-/* constants for org.freedesktop.sssd.dataprovider */
+-#define DATA_PROVIDER_IFACE "org.freedesktop.sssd.dataprovider"
+-#define DATA_PROVIDER_IFACE_REGISTERSERVICE "RegisterService"
+-#define DATA_PROVIDER_IFACE_PAMHANDLER "pamHandler"
+-#define DATA_PROVIDER_IFACE_SUDOHANDLER "sudoHandler"
+-#define DATA_PROVIDER_IFACE_AUTOFSHANDLER "autofsHandler"
+-#define DATA_PROVIDER_IFACE_HOSTHANDLER "hostHandler"
+-#define DATA_PROVIDER_IFACE_GETDOMAINS "getDomains"
+-#define DATA_PROVIDER_IFACE_GETACCOUNTINFO "getAccountInfo"
+-
+-/* constants for org.freedesktop.sssd.dataprovider_rev */
+-#define DATA_PROVIDER_REV_IFACE "org.freedesktop.sssd.dataprovider_rev"
+-#define DATA_PROVIDER_REV_IFACE_UPDATECACHE "updateCache"
+-#define DATA_PROVIDER_REV_IFACE_INITGRCHECK "initgrCheck"
+-
+-/* ------------------------------------------------------------------------
+- * DBus handlers
+- *
+- * These structures are filled in by implementors of the different
+- * dbus interfaces to handle method calls.
+- *
+- * Handler functions of type sbus_msg_handler_fn accept raw messages,
+- * other handlers are typed appropriately. If a handler that is
+- * set to NULL is invoked it will result in a
+- * org.freedesktop.DBus.Error.NotSupported error for the caller.
+- *
+- * Handlers have a matching xxx_finish() function (unless the method has
+- * accepts raw messages). These finish functions the
+- * sbus_request_return_and_finish() with the appropriate arguments to
+- * construct a valid reply. Once a finish function has been called, the
+- * @dbus_req it was called with is freed and no longer valid.
+- */
+-
+-/* vtable for org.freedesktop.sssd.dataprovider */
+-struct data_provider_iface {
+-    struct sbus_vtable vtable; /* derive from sbus_vtable */
+-    sbus_msg_handler_fn RegisterService;
+-    sbus_msg_handler_fn pamHandler;
+-    sbus_msg_handler_fn sudoHandler;
+-    sbus_msg_handler_fn autofsHandler;
+-    sbus_msg_handler_fn hostHandler;
+-    sbus_msg_handler_fn getDomains;
+-    sbus_msg_handler_fn getAccountInfo;
+-};
+-
+-/* vtable for org.freedesktop.sssd.dataprovider_rev */
+-struct data_provider_rev_iface {
+-    struct sbus_vtable vtable; /* derive from sbus_vtable */
+-    sbus_msg_handler_fn updateCache;
+-    sbus_msg_handler_fn initgrCheck;
+-};
+-
+-/* ------------------------------------------------------------------------
+- * DBus Interface Metadata
+- *
+- * These structure definitions are filled in with the information about
+- * the interfaces, methods, properties and so on.
+- *
+- * The actual definitions are found in the accompanying C file next
+- * to this header.
+- */
+-
+-/* interface info for org.freedesktop.sssd.dataprovider */
+-extern const struct sbus_interface_meta data_provider_iface_meta;
+-
+-/* interface info for org.freedesktop.sssd.dataprovider_rev */
+-extern const struct sbus_interface_meta data_provider_rev_iface_meta;
+-
+-#endif /* __DATA_PROVIDER_IFACE_XML__ */
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index c72f3c1f7aee81a9986076975086cdd88e968edb..826a36e9bc0e2afedfda17104d15b86c5fc1b7e1 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -44,17 +44,6 @@ struct mon_cli_iface monitor_autofs_methods = {
+     .sysbusReconnect = NULL,
+ };
+ 
+-static struct data_provider_iface autofs_dp_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ static errno_t
+ autofs_get_config(struct autofs_ctx *actx,
+                   struct confdb_ctx *cdb)
+@@ -130,7 +119,7 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
+                            SSS_AUTOFS_SBUS_SERVICE_VERSION,
+                            &monitor_autofs_methods,
+                            "autofs",
+-                           &autofs_dp_methods.vtable,
++                           NULL,
+                            autofs_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index 335b313ce1a6bc7c0e0ba332786e2e9f39a04ff1..9e3b2fdbda4e30b859df597374fc7d490b1720e5 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -163,11 +163,7 @@ struct mon_cli_iface;
+ typedef int (*connection_setup_t)(struct cli_ctx *cctx);
+ 
+ int sss_connection_setup(struct cli_ctx *cctx);
+-/*
+- * NOTE: We would like to use more strong typing for the @dp_vtable argument
+- * but can't since it accepts either a struct data_provider_iface
+- * or struct data_provider_rev_iface. So pass the base struct: sbus_vtable
+- */
++
+ int sss_process_init(TALLOC_CTX *mem_ctx,
+                      struct tevent_context *ev,
+                      struct confdb_ctx *cdb,
+@@ -181,7 +177,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
+                      uint16_t svc_version,
+                      struct mon_cli_iface *monitor_intf,
+                      const char *cli_name,
+-                     struct sbus_vtable *dp_intf,
++                     struct sbus_iface_map *sbus_iface,
+                      connection_setup_t conn_setup,
+                      struct resp_ctx **responder_ctx);
+ 
+diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
+index 7f6264ae70e5073063b5cfcd73098eefad2ce653..c604c64a652221521ec7114b8588186f087eb11a 100644
+--- a/src/responder/common/responder_common.c
++++ b/src/responder/common/responder_common.c
+@@ -549,7 +549,7 @@ void idle_handler(struct tevent_context *ev,
+ }
+ 
+ static int sss_dp_init(struct resp_ctx *rctx,
+-                       struct sbus_vtable *dp_intf,
++                       struct sbus_iface_map *sbus_iface,
+                        const char *cli_name,
+                        struct sss_domain_info *domain)
+ {
+@@ -577,10 +577,12 @@ static int sss_dp_init(struct resp_ctx *rctx,
+         return ret;
+     }
+ 
+-    ret = sbus_conn_register_iface(be_conn->conn, dp_intf, DP_PATH, rctx);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export data provider.\n");
+-        return ret;
++    if (sbus_iface != NULL) {
++        ret = sbus_conn_register_iface_map(be_conn->conn, sbus_iface, rctx);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_FATAL_FAILURE, "Failed to register D-Bus interface.\n");
++            return ret;
++        }
+     }
+ 
+     DLIST_ADD_END(rctx->be_conns, be_conn, struct be_conn *);
+@@ -925,7 +927,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
+                      uint16_t svc_version,
+                      struct mon_cli_iface *monitor_intf,
+                      const char *cli_name,
+-                     struct sbus_vtable *dp_intf,
++                     struct sbus_iface_map *sbus_iface,
+                      connection_setup_t conn_setup,
+                      struct resp_ctx **responder_ctx)
+ {
+@@ -1040,7 +1042,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
+             continue;
+         }
+ 
+-        ret = sss_dp_init(rctx, dp_intf, cli_name, dom);
++        ret = sss_dp_init(rctx, sbus_iface, cli_name, dom);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+                   "fatal error setting up backend connector\n");
+diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
+index 6b354d8b2251f3a5cf576a58ae191fd99f307dd7..cc7b99f30046569547a08f83e46cbbe9d6c19897 100644
+--- a/src/responder/common/responder_get_domains.c
++++ b/src/responder/common/responder_get_domains.c
+@@ -88,8 +88,8 @@ sss_dp_get_domains_msg(void *pvt)
+ 
+     msg = dbus_message_new_method_call(NULL,
+                                        DP_PATH,
+-                                       DATA_PROVIDER_IFACE,
+-                                       DATA_PROVIDER_IFACE_GETDOMAINS);
++                                       IFACE_DP,
++                                       IFACE_DP_GETDOMAINS);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
+         return NULL;
+diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
+index a2137ecb218824909325df6c7052dbbbcb144679..0555c00167045707b7d455d28df368749b9b84f6 100644
+--- a/src/responder/ifp/ifpsrv.c
++++ b/src/responder/ifp/ifpsrv.c
+@@ -58,17 +58,6 @@ struct mon_cli_iface monitor_ifp_methods = {
+     .sysbusReconnect = ifp_sysbus_reconnect,
+ };
+ 
+-static struct data_provider_iface ifp_dp_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ struct sss_cmd_table *get_ifp_cmds(void)
+ {
+     static struct sss_cmd_table ifp_cmds[] = {
+@@ -238,7 +227,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
+                            SSS_IFP_SBUS_SERVICE_VERSION,
+                            &monitor_ifp_methods,
+                            "InfoPipe",
+-                           &ifp_dp_methods.vtable,
++                           NULL,
+                            sss_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/responder/nss/nss_iface.c b/src/responder/nss/nss_iface.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..b01732e086c5fc5c7018ec84c3438e19ed812fef
+--- /dev/null
++++ b/src/responder/nss/nss_iface.c
+@@ -0,0 +1,38 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2016 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 "sbus/sssd_dbus.h"
++#include "responder/nss/nss_iface.h"
++#include "responder/nss/nsssrv.h"
++
++struct iface_nss_memorycache iface_nss_memorycache = {
++    { &iface_nss_memorycache_meta, 0 },
++    .UpdateInitgroups = nss_memorycache_update_initgroups
++};
++
++static struct sbus_iface_map iface_map[] = {
++    { NSS_MEMORYCACHE_PATH, &iface_nss_memorycache.vtable },
++    { NULL, NULL }
++};
++
++struct sbus_iface_map *nss_get_sbus_interface()
++{
++    return iface_map;
++}
+diff --git a/src/responder/nss/nss_iface.h b/src/responder/nss/nss_iface.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..ab59928c3e2dac62cea6f793ff774d9e0f8da6db
+--- /dev/null
++++ b/src/responder/nss/nss_iface.h
+@@ -0,0 +1,30 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2016 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/>.
++*/
++
++#ifndef _NSS_IFACE_H_
++#define _NSS_IFACE_H_
++
++#include "responder/nss/nss_iface_generated.h"
++
++#define NSS_MEMORYCACHE_PATH "/org/freedesktop/sssd/nss/memcache"
++
++struct sbus_iface_map *nss_get_sbus_interface(void);
++
++#endif /* _NSS_IFACE_H_ */
+diff --git a/src/responder/nss/nss_iface.xml b/src/responder/nss/nss_iface.xml
+new file mode 100644
+index 0000000000000000000000000000000000000000..b7cc4deb77135a592bad2ca62570f206231129b7
+--- /dev/null
++++ b/src/responder/nss/nss_iface.xml
+@@ -0,0 +1,12 @@
++<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
++ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
++<node>
++    <interface name="org.freedesktop.sssd.nss.MemoryCache">
++        <annotation value="iface_nss_memorycache" name="org.freedesktop.DBus.GLib.CSymbol"/>
++        <method name="UpdateInitgroups">
++            <arg name="user" type="s" direction="in" />
++            <arg name="domain" type="s" direction="in" />
++            <arg name="groups" type="au" direction="in" />
++        </method>
++    </interface>
++</node>
+diff --git a/src/responder/nss/nss_iface_generated.c b/src/responder/nss/nss_iface_generated.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..2d0031090e33df9c9e9d9fbf1a18825026509803
+--- /dev/null
++++ b/src/responder/nss/nss_iface_generated.c
+@@ -0,0 +1,69 @@
++/* The following definitions are auto-generated from nss_iface.xml */
++
++#include "util/util.h"
++#include "sbus/sssd_dbus.h"
++#include "sbus/sssd_dbus_meta.h"
++#include "sbus/sssd_dbus_invokers.h"
++#include "nss_iface_generated.h"
++
++/* invokes a handler with a 'ssau' DBus signature */
++static int invoke_ssau_method(struct sbus_request *dbus_req, void *function_ptr);
++
++/* arguments for org.freedesktop.sssd.nss.MemoryCache.UpdateInitgroups */
++const struct sbus_arg_meta iface_nss_memorycache_UpdateInitgroups__in[] = {
++    { "user", "s" },
++    { "domain", "s" },
++    { "groups", "au" },
++    { NULL, }
++};
++
++int iface_nss_memorycache_UpdateInitgroups_finish(struct sbus_request *req)
++{
++   return sbus_request_return_and_finish(req,
++                                         DBUS_TYPE_INVALID);
++}
++
++/* methods for org.freedesktop.sssd.nss.MemoryCache */
++const struct sbus_method_meta iface_nss_memorycache__methods[] = {
++    {
++        "UpdateInitgroups", /* name */
++        iface_nss_memorycache_UpdateInitgroups__in,
++        NULL, /* no out_args */
++        offsetof(struct iface_nss_memorycache, UpdateInitgroups),
++        invoke_ssau_method,
++    },
++    { NULL, }
++};
++
++/* interface info for org.freedesktop.sssd.nss.MemoryCache */
++const struct sbus_interface_meta iface_nss_memorycache_meta = {
++    "org.freedesktop.sssd.nss.MemoryCache", /* name */
++    iface_nss_memorycache__methods,
++    NULL, /* no signals */
++    NULL, /* no properties */
++    sbus_invoke_get_all, /* GetAll invoker */
++};
++
++/* invokes a handler with a 'ssau' DBus signature */
++static int invoke_ssau_method(struct sbus_request *dbus_req, void *function_ptr)
++{
++    const char * arg_0;
++    const char * arg_1;
++    uint32_t *arg_2;
++    int len_2;
++    int (*handler)(struct sbus_request *, void *, const char *, const char *, uint32_t[], int) = function_ptr;
++
++    if (!sbus_request_parse_or_finish(dbus_req,
++                               DBUS_TYPE_STRING, &arg_0,
++                               DBUS_TYPE_STRING, &arg_1,
++                               DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &arg_2, &len_2,
++                               DBUS_TYPE_INVALID)) {
++         return EOK; /* request handled */
++    }
++
++    return (handler)(dbus_req, dbus_req->intf->handler_data,
++                     arg_0,
++                     arg_1,
++                     arg_2,
++                     len_2);
++}
+diff --git a/src/responder/nss/nss_iface_generated.h b/src/responder/nss/nss_iface_generated.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..ad902482a9be03a60cbf3663b6f771d0a2020b88
+--- /dev/null
++++ b/src/responder/nss/nss_iface_generated.h
+@@ -0,0 +1,58 @@
++/* The following declarations are auto-generated from nss_iface.xml */
++
++#ifndef __NSS_IFACE_XML__
++#define __NSS_IFACE_XML__
++
++#include "sbus/sssd_dbus.h"
++
++/* ------------------------------------------------------------------------
++ * DBus Constants
++ *
++ * Various constants of interface and method names mostly for use by clients
++ */
++
++/* constants for org.freedesktop.sssd.nss.MemoryCache */
++#define IFACE_NSS_MEMORYCACHE "org.freedesktop.sssd.nss.MemoryCache"
++#define IFACE_NSS_MEMORYCACHE_UPDATEINITGROUPS "UpdateInitgroups"
++
++/* ------------------------------------------------------------------------
++ * DBus handlers
++ *
++ * These structures are filled in by implementors of the different
++ * dbus interfaces to handle method calls.
++ *
++ * Handler functions of type sbus_msg_handler_fn accept raw messages,
++ * other handlers are typed appropriately. If a handler that is
++ * set to NULL is invoked it will result in a
++ * org.freedesktop.DBus.Error.NotSupported error for the caller.
++ *
++ * Handlers have a matching xxx_finish() function (unless the method has
++ * accepts raw messages). These finish functions the
++ * sbus_request_return_and_finish() with the appropriate arguments to
++ * construct a valid reply. Once a finish function has been called, the
++ * @dbus_req it was called with is freed and no longer valid.
++ */
++
++/* vtable for org.freedesktop.sssd.nss.MemoryCache */
++struct iface_nss_memorycache {
++    struct sbus_vtable vtable; /* derive from sbus_vtable */
++    int (*UpdateInitgroups)(struct sbus_request *req, void *data, const char *arg_user, const char *arg_domain, uint32_t arg_groups[], int len_groups);
++};
++
++/* finish function for UpdateInitgroups */
++int iface_nss_memorycache_UpdateInitgroups_finish(struct sbus_request *req);
++
++/* ------------------------------------------------------------------------
++ * DBus Interface Metadata
++ *
++ * These structure definitions are filled in with the information about
++ * the interfaces, methods, properties and so on.
++ *
++ * The actual definitions are found in the accompanying C file next
++ * to this header.
++ */
++
++/* interface info for org.freedesktop.sssd.nss.MemoryCache */
++extern const struct sbus_interface_meta iface_nss_memorycache_meta;
++
++#endif /* __NSS_IFACE_XML__ */
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index 8be3455e57e07481e7cf7d4d0f525dad5b8601fc..05b51ecdf2e17e20af2ee3ee48377cbe1bf19a24 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -37,6 +37,7 @@
+ #include "responder/nss/nsssrv_private.h"
+ #include "responder/nss/nsssrv_mmap_cache.h"
+ #include "responder/nss/nsssrv_netgroup.h"
++#include "responder/nss/nss_iface.h"
+ #include "responder/common/negcache.h"
+ #include "db/sysdb.h"
+ #include "confdb/confdb.h"
+@@ -327,7 +328,7 @@ done:
+     return ret;
+ }
+ 
+-static int nss_update_memcache(struct sbus_request *dbus_req, void *data)
++int nss_update_memcache(struct sbus_request *dbus_req, void *data)
+ {
+     struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
+     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
+@@ -338,37 +339,24 @@ static int nss_update_memcache(struct sbus_request *dbus_req, void *data)
+     return EOK;
+ }
+ 
+-static int nss_memcache_initgr_check(struct sbus_request *dbus_req, void *data)
++int nss_memorycache_update_initgroups(struct sbus_request *sbus_req,
++                                      void *data,
++                                      const char *user,
++                                      const char *domain,
++                                      uint32_t *groups,
++                                      int num_groups)
+ {
+     struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
+     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
+-    char *user;
+-    char *domain;
+-    uint32_t *groups;
+-    int gnum;
+ 
+-    if (!sbus_request_parse_or_finish(dbus_req,
+-                                      DBUS_TYPE_STRING, &user,
+-                                      DBUS_TYPE_STRING, &domain,
+-                                      DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &groups, &gnum,
+-                                      DBUS_TYPE_INVALID)) {
+-        return EOK; /* handled */
+-    }
++    DEBUG(SSSDBG_TRACE_LIBS, "Updating inigroups memory cache of [%s@%s]\n",
++          user, domain);
+ 
+-    DEBUG(SSSDBG_TRACE_LIBS,
+-          "Got request for [%s@%s]\n", user, domain);
++    nss_update_initgr_memcache(nctx, user, domain, num_groups, groups);
+ 
+-    nss_update_initgr_memcache(nctx, user, domain, gnum, groups);
+-
+-    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
++    return iface_nss_memorycache_UpdateInitgroups_finish(sbus_req);
+ }
+ 
+-static struct data_provider_rev_iface nss_dp_methods = {
+-    { &data_provider_rev_iface_meta, 0 },
+-    .updateCache = nss_update_memcache,
+-    .initgrCheck = nss_memcache_initgr_check
+-};
+-
+ static void nss_dp_reconnect_init(struct sbus_connection *conn,
+                                   int status, void *pvt)
+ {
+@@ -419,7 +407,8 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
+                            NSS_SBUS_SERVICE_NAME,
+                            NSS_SBUS_SERVICE_VERSION,
+                            &monitor_nss_methods,
+-                           "NSS", &nss_dp_methods.vtable,
++                           "NSS",
++                           nss_get_sbus_interface(),
+                            nss_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/responder/nss/nsssrv.h b/src/responder/nss/nsssrv.h
+index 2977479aa52082480f92eab94f7833e2e696a9ac..d4a80f76df236f40d872c701687bf453255d9890 100644
+--- a/src/responder/nss/nsssrv.h
++++ b/src/responder/nss/nsssrv.h
+@@ -81,4 +81,11 @@ struct nss_packet;
+ 
+ struct sss_cmd_table *get_nss_cmds(void);
+ 
++int nss_memorycache_update_initgroups(struct sbus_request *sbus_req,
++                                      void *data,
++                                      const char *user,
++                                      const char *domain,
++                                      uint32_t *groups,
++                                      int num_groups);
++
+ #endif /* __NSSSRV_H__ */
+diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
+index 15d1986f842ac8397cf509ca8ef44728d6ddc5f1..852deb10eff014189d35a2769d895a901d8296e1 100644
+--- a/src/responder/pac/pacsrv.c
++++ b/src/responder/pac/pacsrv.c
+@@ -61,17 +61,6 @@ struct mon_cli_iface monitor_pac_methods = {
+     .sysbusReconnect = NULL,
+ };
+ 
+-static struct data_provider_iface pac_dp_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ /* TODO: check if this can be made generic for all responders */
+ static void pac_dp_reconnect_init(struct sbus_connection *conn,
+                                   int status, void *pvt)
+@@ -122,7 +111,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
+                            PAC_SBUS_SERVICE_NAME,
+                            PAC_SBUS_SERVICE_VERSION,
+                            &monitor_pac_methods,
+-                           "PAC", &pac_dp_methods.vtable,
++                           "PAC", NULL,
+                            sss_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index efd1e5c7527decda5de7304b54919846fa2ee0db..9374de4d63b2886262ca1541daff581603d7c838 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -66,17 +66,6 @@ struct mon_cli_iface monitor_pam_methods = {
+     .sysbusReconnect = NULL,
+ };
+ 
+-static struct data_provider_iface pam_dp_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void *pvt)
+ {
+     struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
+@@ -201,7 +190,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
+                            SSS_PAM_SBUS_SERVICE_NAME,
+                            SSS_PAM_SBUS_SERVICE_VERSION,
+                            &monitor_pam_methods,
+-                           "PAM", &pam_dp_methods.vtable,
++                           "PAM", NULL,
+                            sss_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/responder/pam/pamsrv_dp.c b/src/responder/pam/pamsrv_dp.c
+index 826146350670d67f897ee7eec2cf6ca607b96435..aa3fdc3c32d234ed54a9f5202886157601ee3846 100644
+--- a/src/responder/pam/pamsrv_dp.c
++++ b/src/responder/pam/pamsrv_dp.c
+@@ -130,8 +130,8 @@ int pam_dp_send_req(struct pam_auth_req *preq, int timeout)
+ 
+     msg = dbus_message_new_method_call(NULL,
+                                        DP_PATH,
+-                                       DATA_PROVIDER_IFACE,
+-                                       DATA_PROVIDER_IFACE_PAMHANDLER);
++                                       IFACE_DP,
++                                       IFACE_DP_PAMHANDLER);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
+         return ENOMEM;
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index f763e3b00d20527225046a85609e7ff56861f682..88938215b542b5748721cfecc59ca4141010fb88 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -41,17 +41,6 @@ struct mon_cli_iface monitor_ssh_methods = {
+     .sysbusReconnect = NULL,
+ };
+ 
+-static struct data_provider_iface ssh_dp_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ static void ssh_dp_reconnect_init(struct sbus_connection *conn,
+                                   int status, void *pvt)
+ {
+@@ -96,7 +85,7 @@ int ssh_process_init(TALLOC_CTX *mem_ctx,
+                            SSS_SSH_SBUS_SERVICE_VERSION,
+                            &monitor_ssh_methods,
+                            "SSH",
+-                           &ssh_dp_methods.vtable,
++                           NULL,
+                            sss_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index e0346033e38f1e39e621e131c3265a583b91a5c3..d832686a8572f3729a0477cdca2f77ebcb19fbc0 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -42,17 +42,6 @@ struct mon_cli_iface monitor_sudo_methods = {
+     .sysbusReconnect = NULL,
+ };
+ 
+-static struct data_provider_iface sudo_dp_methods = {
+-    { &data_provider_iface_meta, 0 },
+-    .RegisterService = NULL,
+-    .pamHandler = NULL,
+-    .sudoHandler = NULL,
+-    .autofsHandler = NULL,
+-    .hostHandler = NULL,
+-    .getDomains = NULL,
+-    .getAccountInfo = NULL,
+-};
+-
+ static void sudo_dp_reconnect_init(struct sbus_connection *conn,
+                                    int status,
+                                    void *pvt)
+@@ -98,7 +87,7 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
+                            SSS_SUDO_SBUS_SERVICE_VERSION,
+                            &monitor_sudo_methods,
+                            "SUDO",
+-                           &sudo_dp_methods.vtable,
++                           NULL,
+                            sss_connection_setup,
+                            &rctx);
+     if (ret != EOK) {
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index d8a49f1434cefc02bc7fce505d1b4e07fc74ec5f..3e40cba52e927730483b14cc7e56687b250de646 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -49,7 +49,6 @@ SSSD_RESPONDER_OBJ = \
+     ../../../src/responder/common/data_provider/rdp_message.c \
+     ../../../src/responder/common/data_provider/rdp_client.c \
+     ../../../src/monitor/monitor_iface_generated.c \
+-    ../../../src/providers/data_provider_iface_generated.c \
+     ../../../src/providers/data_provider_req.c
+ 
+ dist_noinst_DATA = \
+-- 
+2.4.11
+
diff --git a/SOURCES/0101-AD-Consolidate-connection-list-construction-on-ad_co.patch b/SOURCES/0101-AD-Consolidate-connection-list-construction-on-ad_co.patch
deleted file mode 100644
index 9e4fbf4..0000000
--- a/SOURCES/0101-AD-Consolidate-connection-list-construction-on-ad_co.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-From 64b1b88acacf4004acdfca1a6cda9763e017dfbf Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 5 Oct 2015 16:11:14 +0200
-Subject: [PATCH 101/101] AD: Consolidate connection list construction on
- ad_common.c
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit afb21fd06690a0bec288a7970abf74ed2ea7dfdc)
-(cherry picked from commit f1742784d9b1cffd74f67beeb26375124183428a)
----
- src/providers/ad/ad_common.c      | 31 +++++++++++++++++++++++++++++++
- src/providers/ad/ad_common.h      |  5 +++++
- src/providers/ad/ad_id.c          | 18 +-----------------
- src/tests/cmocka/test_ad_common.c | 34 ++++++++++++++++++++++++++++++++++
- 4 files changed, 71 insertions(+), 17 deletions(-)
-
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index df277e55e234d4d4efe34d5f5d8efdfe7267fb60..650ec41578297f7b3a59df118b71a6bb8bc6d6ed 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1286,3 +1286,34 @@ ad_ldap_conn_list(TALLOC_CTX *mem_ctx,
-     clist[1] = NULL;
-     return clist;
- }
-+
-+struct sdap_id_conn_ctx **
-+ad_user_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(ad_ctx, struct sdap_id_conn_ctx *, 3);
-+    if (clist == NULL) {
-+        return NULL;
-+    }
-+
-+    /* Try GC first for users from trusted domains, but go to LDAP
-+     * for users from non-trusted domains to get all POSIX attrs
-+     */
-+    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);
-+
-+    return clist;
-+}
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index 701e461987cb286ca7add2766ffb4dc496bde01e..0cefa1859aaa75731267917e66ab9a1905528e91 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -153,6 +153,11 @@ ad_ldap_conn_list(TALLOC_CTX *mem_ctx,
-                   struct ad_id_ctx *ad_ctx,
-                   struct sss_domain_info *dom);
- 
-+struct sdap_id_conn_ctx **
-+ad_user_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);
- 
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index be0cb3b12f2e3a2b53d740ecf3befc07fd853f8b..51d378863a5c7394ca3a2b8bd72f8c131a2b02b1 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -244,25 +244,10 @@ 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);
-+        clist = ad_user_conn_list(breq, ad_ctx, dom);
-         break;
-     case BE_REQ_BY_SECID:   /* by SID */
-     case BE_REQ_USER_AND_GROUP: /* get SID */
-@@ -270,7 +255,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
-     case BE_REQ_INITGROUPS: /* init groups for user */
-         clist = ad_gc_conn_list(breq, ad_ctx, dom);
-         break;
--
-     default:
-         /* Requests for other object should only contact LDAP by default */
-         clist = ad_ldap_conn_list(breq, ad_ctx, dom);
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-index c7bcc0f7cfde7164672123a35940327ee3ca4aba..f6a4c0db413bbe9c79e6d41f3de5ac75d080c225 100644
---- a/src/tests/cmocka/test_ad_common.c
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -433,6 +433,37 @@ void test_ldap_conn_list(void **state)
-     talloc_free(conn_list);
- }
- 
-+void test_user_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_user_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_user_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_true(conn_list[0]->ignore_mark_offline);
-+    assert_true(conn_list[1] == test_ctx->subdom_ad_ctx->ldap_ctx);
-+    /* Subdomain error should not set the backend offline! */
-+    assert_true(conn_list[1]->ignore_mark_offline);
-+    talloc_free(conn_list);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -460,6 +491,9 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_ldap_conn_list,
-                                         test_ldap_conn_setup,
-                                         test_ldap_conn_teardown),
-+        cmocka_unit_test_setup_teardown(test_user_conn_list,
-+                                        test_ldap_conn_setup,
-+                                        test_ldap_conn_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.4.3
-
diff --git a/SOURCES/0101-NSS-Remove-unused-functions.patch b/SOURCES/0101-NSS-Remove-unused-functions.patch
new file mode 100644
index 0000000..f7b683f
--- /dev/null
+++ b/SOURCES/0101-NSS-Remove-unused-functions.patch
@@ -0,0 +1,187 @@
+From 684ab7416ea1311a98516faddcc975a9731b2a0f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 19 Jul 2016 14:42:26 +0200
+Subject: [PATCH 101/102] NSS: Remove unused functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When removing the old data provider I noticed that those functions
+are not used at all.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit f31610a9ba26b46de9eeab2b0719ff6ad8961104)
+---
+ src/responder/nss/nsssrv.c         |  11 ----
+ src/responder/nss/nsssrv_cmd.c     | 112 -------------------------------------
+ src/responder/nss/nsssrv_private.h |   2 -
+ 3 files changed, 125 deletions(-)
+
+diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
+index 05b51ecdf2e17e20af2ee3ee48377cbe1bf19a24..06d58f21b00b73c6c7a4b7583e10b4b61a627d75 100644
+--- a/src/responder/nss/nsssrv.c
++++ b/src/responder/nss/nsssrv.c
+@@ -328,17 +328,6 @@ done:
+     return ret;
+ }
+ 
+-int nss_update_memcache(struct sbus_request *dbus_req, void *data)
+-{
+-    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
+-    struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
+-
+-    nss_update_pw_memcache(nctx);
+-    nss_update_gr_memcache(nctx);
+-
+-    return EOK;
+-}
+-
+ int nss_memorycache_update_initgroups(struct sbus_request *sbus_req,
+                                       void *data,
+                                       const char *user,
+diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
+index 573959ea76fc1277fe84f40b88dcd34093da468d..b64cea2a53ec6032904237b0afc1377022c2c804 100644
+--- a/src/responder/nss/nsssrv_cmd.c
++++ b/src/responder/nss/nsssrv_cmd.c
+@@ -118,66 +118,6 @@ static int nss_reset_negcache(struct resp_ctx *rctx)
+  * PASSWD db related functions
+  ***************************************************************************/
+ 
+-void nss_update_pw_memcache(struct nss_ctx *nctx)
+-{
+-    struct sss_domain_info *dom;
+-    struct ldb_result *res;
+-    uint64_t exp;
+-    struct sized_string key;
+-    const char *id;
+-    time_t now;
+-    int ret;
+-    int i;
+-
+-    now = time(NULL);
+-
+-    for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) {
+-        ret = sysdb_enumpwent_with_views(nctx, dom, &res);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Failed to enumerate users for domain [%s]\n", dom->name);
+-            continue;
+-        }
+-
+-        for (i = 0; i < res->count; i++) {
+-            exp = ldb_msg_find_attr_as_uint64(res->msgs[i],
+-                                              SYSDB_CACHE_EXPIRE, 0);
+-            if (exp >= now) {
+-                continue;
+-            }
+-
+-            /* names require more manipulation (build up fqname conditionally),
+-             * but uidNumber is unique and always resolvable too, so we use
+-             * that to update the cache, as it points to the same entry */
+-            id = sss_view_ldb_msg_find_attr_as_string(dom, res->msgs[i],
+-                                                      SYSDB_UIDNUM, NULL);
+-            if (!id) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Failed to find uidNumber in %s.\n",
+-                       ldb_dn_get_linearized(res->msgs[i]->dn));
+-                continue;
+-            }
+-            to_sized_string(&key, id);
+-
+-            ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &key);
+-            if (ret != EOK && ret != ENOENT) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Internal failure in memory cache code: %d [%s]\n",
+-                       ret, strerror(ret));
+-            }
+-
+-            ret = sss_mmap_cache_pw_invalidate(nctx->initgr_mc_ctx, &key);
+-            if (ret != EOK && ret != ENOENT) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Internal failure in memory cache code: %d [%s]\n",
+-                      ret, strerror(ret));
+-            }
+-        }
+-
+-        talloc_zfree(res);
+-    }
+-}
+-
+ static gid_t get_gid_override(struct ldb_message *msg,
+                               struct sss_domain_info *dom)
+ {
+@@ -2743,58 +2683,6 @@ done:
+  * GROUP db related functions
+  ***************************************************************************/
+ 
+-void nss_update_gr_memcache(struct nss_ctx *nctx)
+-{
+-    struct sss_domain_info *dom;
+-    struct ldb_result *res;
+-    uint64_t exp;
+-    struct sized_string key;
+-    const char *id;
+-    time_t now;
+-    int ret;
+-    int i;
+-
+-    now = time(NULL);
+-
+-    for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) {
+-        ret = sysdb_enumgrent_with_views(nctx, dom, &res);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE,
+-                  "Failed to enumerate users for domain [%s]\n", dom->name);
+-            continue;
+-        }
+-
+-        for (i = 0; i < res->count; i++) {
+-            exp = ldb_msg_find_attr_as_uint64(res->msgs[i],
+-                                              SYSDB_CACHE_EXPIRE, 0);
+-            if (exp >= now) {
+-                continue;
+-            }
+-
+-            /* names require more manipulation (build up fqname conditionally),
+-             * but uidNumber is unique and always resolvable too, so we use
+-             * that to update the cache, as it points to the same entry */
+-            id = sss_view_ldb_msg_find_attr_as_string(dom, res->msgs[i],
+-                                                      SYSDB_GIDNUM, NULL);
+-            if (!id) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Failed to find gidNumber in %s.\n",
+-                       ldb_dn_get_linearized(res->msgs[i]->dn));
+-                continue;
+-            }
+-            to_sized_string(&key, id);
+-
+-            ret = sss_mmap_cache_gr_invalidate(nctx->grp_mc_ctx, &key);
+-            if (ret != EOK && ret != ENOENT) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Internal failure in memory cache code: %d [%s]\n",
+-                       ret, strerror(ret));
+-            }
+-        }
+-        talloc_zfree(res);
+-    }
+-}
+-
+ #define GID_ROFFSET 0
+ #define MNUM_ROFFSET sizeof(uint32_t)
+ #define STRS_ROFFSET 2*sizeof(uint32_t)
+diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h
+index 391eaaf40f84a7436bee63fd699241e4957fdbeb..472022235adab2c2d2547ee2706ef23fa91b1f8d 100644
+--- a/src/responder/nss/nsssrv_private.h
++++ b/src/responder/nss/nsssrv_private.h
+@@ -143,8 +143,6 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
+                     sss_dp_callback_t callback,
+                     void *pvt);
+ 
+-void nss_update_pw_memcache(struct nss_ctx *nctx);
+-void nss_update_gr_memcache(struct nss_ctx *nctx);
+ void nss_update_initgr_memcache(struct nss_ctx *nctx,
+                                 const char *fq_name, const char *domain,
+                                 int gnum, uint32_t *groups);
+-- 
+2.4.11
+
diff --git a/SOURCES/0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch b/SOURCES/0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch
new file mode 100644
index 0000000..2932c7e
--- /dev/null
+++ b/SOURCES/0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch
@@ -0,0 +1,75 @@
+From c0dedeccc42fa7cc14e207182d54595926dfd700 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Fri, 22 Jul 2016 14:28:54 +0200
+Subject: [PATCH 102/102] LDAP: Fixing of removing netgroup from cache
+
+There were problem with local key which wasn't properly removed.
+This patch fixes it.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2841
+---
+ src/providers/ldap/sdap_async_netgroups.c | 40 +++++++++++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+diff --git a/src/providers/ldap/sdap_async_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c
+index df233d956df70cfcb5f68bd2afc9e2a23c50c3bb..cf7d7b12361f8cc578b891961c0c5566442f1b4e 100644
+--- a/src/providers/ldap/sdap_async_netgroups.c
++++ b/src/providers/ldap/sdap_async_netgroups.c
+@@ -38,6 +38,35 @@ bool is_dn(const char *str)
+     return (ret == LDAP_SUCCESS ? true : false);
+ }
+ 
++static errno_t add_to_missing_attrs(TALLOC_CTX * mem_ctx,
++                                    struct sysdb_attrs *attrs,
++                                    const char *ext_key,
++                                    char ***_missing)
++{
++    bool is_present = false;
++    size_t size = 0;
++    size_t ret;
++
++    for (int i = 0; i < attrs->num; i++) {
++        if (strcmp(ext_key, attrs->a[i].name) == 0) {
++            is_present = true;
++        }
++        size++;
++    }
++
++    if (is_present == false) {
++        ret = add_string_to_list(attrs, ext_key, _missing);
++        if (ret != EOK) {
++            goto done;
++        }
++    }
++
++    ret = EOK;
++
++done:
++    return ret;
++}
++
+ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
+                                   struct sss_domain_info *dom,
+                                   struct sdap_options *opts,
+@@ -138,6 +167,17 @@ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
+         goto fail;
+     }
+ 
++    /* Prepare SYSDB_NETGROUP_MEMBER removing
++     * if not present in netgroup_attrs
++     */
++    ret = add_to_missing_attrs(attrs, netgroup_attrs, SYSDB_NETGROUP_MEMBER,
++                               &missing);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add [%s] to missing attributes\n",
++              SYSDB_NETGROUP_MEMBER);
++        goto fail;
++    }
++
+     ret = sysdb_add_netgroup(dom, name, NULL, netgroup_attrs, missing,
+                              dom->netgroup_timeout, now);
+     if (ret) goto fail;
+-- 
+2.4.11
+
diff --git a/SOURCES/0102-nss-send-original-name-and-id-with-local-views-if-po.patch b/SOURCES/0102-nss-send-original-name-and-id-with-local-views-if-po.patch
deleted file mode 100644
index 475bf31..0000000
--- a/SOURCES/0102-nss-send-original-name-and-id-with-local-views-if-po.patch
+++ /dev/null
@@ -1,191 +0,0 @@
-From c12a2635adacbb321c4c2208160f2eb306333e71 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Sun, 11 Oct 2015 16:45:19 +0200
-Subject: [PATCH 102/104] nss: send original name and id with local views if
- possible
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2833
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2f793681b4debbe015815f908dc12c0463711609)
----
- src/responder/nss/nsssrv_cmd.c | 131 ++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 128 insertions(+), 3 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
-index d177135db00369c2af69eb62f6a4a4aaf54ba510..39fd5b41a31796a05a1790e78cb6c425b39c47cb 100644
---- a/src/responder/nss/nsssrv_cmd.c
-+++ b/src/responder/nss/nsssrv_cmd.c
-@@ -599,6 +599,124 @@ is_refreshed_on_bg(enum sss_dp_acct_type req_type,
- 
- static void nsssrv_dp_send_acct_req_done(struct tevent_req *req);
- 
-+static void get_dp_name_and_id(TALLOC_CTX *mem_ctx,
-+                              struct sss_domain_info *dom,
-+                              enum sss_dp_acct_type req_type,
-+                              const char *opt_name,
-+                              uint32_t opt_id,
-+                              const char **_name,
-+                              uint32_t *_id)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_result *res = NULL;
-+    const char *attr;
-+    const char *name;
-+    uint32_t id;
-+    errno_t ret;
-+
-+    /* First set the same values to make things easier. */
-+    *_name = opt_name;
-+    *_id = opt_id;
-+
-+    if (!DOM_HAS_VIEWS(dom) || !is_local_view(dom->view_name)) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "Not a LOCAL view, continuing with "
-+              "provided values.\n");
-+        return;
-+    }
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-+        return;
-+    }
-+
-+    if (opt_name != NULL) {
-+        switch (req_type) {
-+        case SSS_DP_USER:
-+        case SSS_DP_INITGROUPS:
-+            ret = sysdb_getpwnam_with_views(tmp_ctx, dom, opt_name, &res);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CONF_SETTINGS,
-+                      "sysdb_getpwnam_with_views() failed [%d]: %s\n",
-+                      ret, sss_strerror(ret));
-+                goto done;
-+            }
-+            break;
-+        case SSS_DP_GROUP:
-+            ret = sysdb_getgrnam_with_views(tmp_ctx, dom, opt_name, &res);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CONF_SETTINGS,
-+                      "sysdb_getgrnam_with_views() failed [%d]: %s\n",
-+                      ret, sss_strerror(ret));
-+                goto done;
-+            }
-+            break;
-+        default:
-+            goto done;
-+        }
-+
-+        if (res == NULL || res->count != 1) {
-+            /* This should not happen with LOCAL view and overridden value. */
-+            DEBUG(SSSDBG_TRACE_FUNC, "Entry is missing?! Continuing with "
-+                  "provided values.\n");
-+            goto done;
-+        }
-+
-+        name = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
-+        if (name == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
-+            goto done;
-+        }
-+
-+        *_name = talloc_steal(mem_ctx, name);
-+    } else if (opt_id != 0) {
-+        switch (req_type) {
-+        case SSS_DP_USER:
-+            ret = sysdb_getpwuid_with_views(tmp_ctx, dom, opt_id, &res);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CONF_SETTINGS,
-+                      "sysdb_getpwuid_with_views() failed [%d]: %s\n",
-+                      ret, sss_strerror(ret));
-+                goto done;
-+            }
-+
-+            attr = SYSDB_UIDNUM;
-+            break;
-+        case SSS_DP_GROUP:
-+            ret = sysdb_getgrgid_with_views(tmp_ctx, dom, opt_id, &res);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CONF_SETTINGS,
-+                      "sysdb_getgrgid_with_views() failed [%d]: %s\n",
-+                      ret, sss_strerror(ret));
-+                goto done;
-+            }
-+
-+            attr = SYSDB_GIDNUM;
-+            break;
-+        default:
-+            goto done;
-+        }
-+
-+        if (res == NULL || res->count != 1) {
-+            /* This should not happen with LOCAL view and overridden value. */
-+            DEBUG(SSSDBG_TRACE_FUNC, "Entry is missing?! Continuing with "
-+                  "provided values.\n");
-+            goto done;
-+        }
-+
-+        id = ldb_msg_find_attr_as_uint64(res->msgs[0], attr, 0);
-+        if (id == 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0\n");
-+            goto done;
-+        }
-+
-+        *_id = id;
-+    }
-+
-+done:
-+    talloc_free(tmp_ctx);
-+}
-+
- /* FIXME: do not check res->count, but get in a msgs and check in parent */
- errno_t check_cache(struct nss_dom_ctx *dctx,
-                     struct nss_ctx *nctx,
-@@ -616,6 +734,8 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
-     struct tevent_req *req = NULL;
-     struct dp_callback_ctx *cb_ctx = NULL;
-     uint64_t cacheExpire = 0;
-+    const char *name = opt_name;
-+    uint32_t id = opt_id;
- 
-     /* when searching for a user or netgroup, more than one reply is a
-      * db error
-@@ -627,6 +747,11 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
-         return ENOENT;
-     }
- 
-+    /* In case of local view we have to always contant DP with the original
-+     * name or id. */
-+    get_dp_name_and_id(dctx->cmdctx, dctx->domain, req_type, opt_name, opt_id,
-+                       &name, &id);
-+
-     /* 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)
-@@ -671,10 +796,10 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
-          * immediately.
-          */
-         DEBUG(SSSDBG_TRACE_FUNC,
--             "Performing midpoint cache update on [%s]\n", opt_name);
-+             "Performing midpoint cache update on [%s]\n", name);
- 
-         req = sss_dp_get_account_send(cctx, cctx->rctx, dctx->domain, true,
--                                      req_type, opt_name, opt_id, extra);
-+                                      req_type, name, id, extra);
-         if (!req) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Out of memory sending out-of-band data provider "
-@@ -703,7 +828,7 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
-         }
- 
-         req = sss_dp_get_account_send(cctx, cctx->rctx, dctx->domain, true,
--                                      req_type, opt_name, opt_id, extra);
-+                                      req_type, name, id, extra);
-         if (!req) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Out of memory sending data provider request\n");
--- 
-2.4.3
-
diff --git a/SOURCES/0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch b/SOURCES/0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch
new file mode 100644
index 0000000..d31b96f
--- /dev/null
+++ b/SOURCES/0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch
@@ -0,0 +1,122 @@
+From 5377817417b800335c5ae21f7e6b301ddbcbe1d1 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Fri, 13 May 2016 05:21:07 -0400
+Subject: [PATCH 103/108] AD_PROVIDER: Add ad_enabled_domains option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2828
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/config/SSSDConfig/__init__.py.in   |  1 +
+ src/config/cfg_rules.ini               |  1 +
+ src/config/etc/sssd.api.d/sssd-ad.conf |  1 +
+ src/man/sssd-ad.5.xml                  | 27 +++++++++++++++++++++++++++
+ src/providers/ad/ad_common.h           |  1 +
+ src/providers/ad/ad_opts.c             |  1 +
+ 6 files changed, 32 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index ac538788b9878dc2613cb48b7483d392cca41d47..1718a9babf390b95710ec356f25f09ea679bdd73 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -192,6 +192,7 @@ option_strings = {
+ 
+     # [provider/ad]
+     'ad_domain' : _('Active Directory domain'),
++    'ad_enabled_domains' : _('Enabled Active Directory domains'),
+     'ad_server' : _('Active Directory server address'),
+     'ad_backup_server' : _('Active Directory backup server address'),
+     'ad_hostname' : _('Active Directory client hostname'),
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index bd0116f334e2605e7671a208225761421511a75a..ef6435b08aee416e377fe854e6768f3fa4fd9650 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -335,6 +335,7 @@ option = ad_access_filter
+ option = ad_backup_server
+ option = ad_domain
+ option = ad_enable_dns_sites
++option = ad_enabled_domains
+ option = ad_enable_gc
+ option = ad_gpo_access_control
+ option = ad_gpo_cache_timeout
+diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
+index 87a74f4af0770874c71baaea02d2313721db78bf..8d97a416c8c97bff096042b0b70a3b2c18183710 100644
+--- a/src/config/etc/sssd.api.d/sssd-ad.conf
++++ b/src/config/etc/sssd.api.d/sssd-ad.conf
+@@ -1,5 +1,6 @@
+ [provider/ad]
+ ad_domain = str, None, false
++ad_enabled_domains = str, None, false
+ ad_server = str, None, false
+ ad_backup_server = str, None, false
+ ad_hostname = str, None, false
+diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
+index ef27976dd62e164cfb91359efc69bd54e1aa9711..8a2f4ade9387f0d5723b7056bdce9e83363cf035 100644
+--- a/src/man/sssd-ad.5.xml
++++ b/src/man/sssd-ad.5.xml
+@@ -114,6 +114,33 @@ ldap_id_mapping = False
+                 </varlistentry>
+ 
+                 <varlistentry>
++                    <term>ad_enabled_domains (string)</term>
++                    <listitem>
++                        <para>
++                            A comma-separated list of enabled Active Directory domains.
++                            If provided, SSSD will ignore any domains not listed in this
++                            option. If left unset, all domains from the AD forest will
++                            be available.
++                        </para>
++                        <para>
++                            For proper operation, this option must be specified in all
++                            lower-case and as the fully qualified domain name of the
++                            Active Directory domain. For example:
++                            <programlisting>
++ad_enabled_domains = sales.example.com, eng.example.com
++                            </programlisting>
++                        </para>
++                        <para>
++                            The short domain name (also known as the NetBIOS or the flat
++                            name) will be autodetected by SSSD.
++                        </para>
++                        <para>
++                            Default: Not set
++                        </para>
++                    </listitem>
++                </varlistentry>
++
++                <varlistentry>
+                     <term>ad_server, ad_backup_server (string)</term>
+                     <listitem>
+                         <para>
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index 7e86faf1142d7be49eef01e1ddd7bfafea2fcedc..23351e328968918aa9ca9009c052e670a7d55258 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -42,6 +42,7 @@ struct ad_options;
+ 
+ enum ad_basic_opt {
+     AD_DOMAIN = 0,
++    AD_ENABLED_DOMAINS,
+     AD_SERVER,
+     AD_BACKUP_SERVER,
+     AD_HOSTNAME,
+diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
+index 829f9d9556bc3fa74a95eb76db0e31b19befe8fe..fc1dc67337845754eba8c879c78e08c1777a4abc 100644
+--- a/src/providers/ad/ad_opts.c
++++ b/src/providers/ad/ad_opts.c
+@@ -28,6 +28,7 @@
+ 
+ struct dp_option ad_basic_opts[] = {
+     { "ad_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
++    { "ad_enabled_domains", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ad_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ad_backup_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ad_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+-- 
+2.4.11
+
diff --git a/SOURCES/0103-sudo-search-with-view-even-if-user-is-found.patch b/SOURCES/0103-sudo-search-with-view-even-if-user-is-found.patch
deleted file mode 100644
index fe9f9bf..0000000
--- a/SOURCES/0103-sudo-search-with-view-even-if-user-is-found.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From f69e9a566540896682c1021de92e5eec6a95dd9d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Sun, 11 Oct 2015 17:38:34 +0200
-Subject: [PATCH 103/104] sudo: search with view even if user is found
-
-If an overriden name is provided and the user is already cache we fail
-to refresh it since we won't search with VIEW flag. This patch fix
-it.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 51a0e3a2ef9186d19cbc28d87fe6fc5d5998a0a7)
----
- src/responder/sudo/sudosrv_get_sudorules.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
-index a0b09e69b71f963c353c9c6331c0708cc364924c..cc06977d97e3319584251bdab26e85855d275e8a 100644
---- a/src/responder/sudo/sudosrv_get_sudorules.c
-+++ b/src/responder/sudo/sudosrv_get_sudorules.c
-@@ -160,7 +160,10 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
-         if ((user->count == 0 || cache_expire < time(NULL))
-             && dctx->check_provider) {
- 
--            if (DOM_HAS_VIEWS(dom) && user->count == 0) {
-+            if (DOM_HAS_VIEWS(dom) && (user->count == 0
-+                    || ldb_msg_find_attr_as_string(user->msgs[0],
-+                                                   OVERRIDE_PREFIX SYSDB_NAME,
-+                                                   NULL) != NULL)) {
-                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
-             }
- 
--- 
-2.4.3
-
diff --git a/SOURCES/0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch b/SOURCES/0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch
new file mode 100644
index 0000000..9fa1c6c
--- /dev/null
+++ b/SOURCES/0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch
@@ -0,0 +1,143 @@
+From 7e8b6166086cf04c5b1290c3dffd268438ef9c2c Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 21 Jun 2016 08:34:15 +0200
+Subject: [PATCH 104/108] AD_PROVIDER: Initializing of ad_enabled_domains
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We add ad_enabled_domains into ad_subdomains_ctx.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2828
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ad/ad_subdomains.c | 82 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 82 insertions(+)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index a0d5c2e544fc62fda64771dce59b3b7ab8ecd8b6..6e44760330275f7e4262e6863f180747f659edb5 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -57,6 +57,79 @@
+ /* do not refresh more often than every 5 seconds for now */
+ #define AD_SUBDOMAIN_REFRESH_LIMIT 5
+ 
++static errno_t ad_get_enabled_domains(TALLOC_CTX *mem_ctx,
++                                      struct ad_id_ctx *ad_id_ctx,
++                                      const char *ad_domain,
++                                      const char ***_ad_enabled_domains)
++{
++    int ret;
++    const char *str;
++    const char *option_name;
++    const char **domains = NULL;
++    int count;
++    bool is_ad_in_domains;
++    TALLOC_CTX *tmp_ctx = NULL;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    str = dp_opt_get_cstring(ad_id_ctx->ad_options->basic, AD_ENABLED_DOMAINS);
++    if (str == NULL) {
++        *_ad_enabled_domains = NULL;
++        ret = EOK;
++        goto done;
++    }
++
++    count = 0;
++    ret = split_on_separator(tmp_ctx, str, ',', true, true,
++                             discard_const_p(char **, &domains), &count);
++    if (ret != EOK) {
++        option_name = ad_id_ctx->ad_options->basic[AD_ENABLED_DOMAINS].opt_name;
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse option [%s], [%i] [%s]!\n",
++                                   option_name, ret, sss_strerror(ret));
++        ret = EINVAL;
++        goto done;
++    }
++
++    is_ad_in_domains = false;
++    for (int i = 0; i < count; i++) {
++        is_ad_in_domains += strcmp(ad_domain, domains[i]) == 0 ? true : false;
++    }
++
++    if (is_ad_in_domains == false) {
++        domains = talloc_realloc(tmp_ctx, domains, const char*, count + 2);
++        if (domains == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++
++        domains[count] = talloc_strdup(domains, ad_domain);
++        if (domains[count] == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++
++        domains[count + 1] = NULL;
++    } else {
++        domains = talloc_realloc(tmp_ctx, domains, const char*, count + 1);
++        if (domains == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++
++        domains[count] = NULL;
++    }
++
++    *_ad_enabled_domains = talloc_steal(mem_ctx, domains);
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ static errno_t
+ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+                      struct ad_id_ctx *id_ctx,
+@@ -171,6 +244,7 @@ struct ad_subdomains_ctx {
+ 
+     struct sdap_domain *sdom;
+     char *domain_name;
++    const char **ad_enabled_domains;
+ 
+     time_t last_refreshed;
+ };
+@@ -1357,6 +1431,7 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+ {
+     struct ad_subdomains_ctx *sd_ctx;
+     const char *ad_domain;
++    const char **ad_enabled_domains = NULL;
+     time_t period;
+     errno_t ret;
+ 
+@@ -1368,6 +1443,12 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+         return ENOMEM;
+     }
+ 
++    ret = ad_get_enabled_domains(sd_ctx, ad_id_ctx, ad_domain,
++                                 &ad_enabled_domains);
++    if (ret != EOK) {
++        return EINVAL;
++    }
++
+     sd_ctx->be_ctx = be_ctx;
+     sd_ctx->sdom = ad_id_ctx->sdap_id_ctx->opts->sdom;
+     sd_ctx->sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
+@@ -1376,6 +1457,7 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+         return ENOMEM;
+     }
++    sd_ctx->ad_enabled_domains = ad_enabled_domains;
+     sd_ctx->ad_id_ctx = ad_id_ctx;
+ 
+     dp_set_method(dp_methods, DPM_DOMAINS_HANDLER,
+-- 
+2.4.11
+
diff --git a/SOURCES/0104-sudo-send-original-name-and-id-with-local-views-if-p.patch b/SOURCES/0104-sudo-send-original-name-and-id-with-local-views-if-p.patch
deleted file mode 100644
index 241248c..0000000
--- a/SOURCES/0104-sudo-send-original-name-and-id-with-local-views-if-p.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From ea4b1387c604093036559a1bfc0368c70d73fc4f Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Sun, 11 Oct 2015 17:53:28 +0200
-Subject: [PATCH 104/104] sudo: send original name and id with local views if
- possible
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2833
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit fb8985a3a3a267940760967beaf8af3979ce91ea)
----
- src/responder/sudo/sudosrv_get_sudorules.c | 18 +++++++++++++-----
- 1 file changed, 13 insertions(+), 5 deletions(-)
-
-diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
-index cc06977d97e3319584251bdab26e85855d275e8a..c3336960eeac18ee63167de81891984aa764540c 100644
---- a/src/responder/sudo/sudosrv_get_sudorules.c
-+++ b/src/responder/sudo/sudosrv_get_sudorules.c
-@@ -79,6 +79,7 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
-     struct dp_callback_ctx *cb_ctx;
-     const char *original_name = NULL;
-     const char *extra_flag = NULL;
-+    const char *search_name = NULL;
-     char *name = NULL;
-     uid_t uid = 0;
-     errno_t ret;
-@@ -160,16 +161,23 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
-         if ((user->count == 0 || cache_expire < time(NULL))
-             && dctx->check_provider) {
- 
--            if (DOM_HAS_VIEWS(dom) && (user->count == 0
--                    || ldb_msg_find_attr_as_string(user->msgs[0],
--                                                   OVERRIDE_PREFIX SYSDB_NAME,
--                                                   NULL) != NULL)) {
-+            search_name = cmd_ctx->username;
-+            if (is_local_view(dom->view_name)) {
-+                /* Search with original name in case of local view. */
-+                if (user->count != 0) {
-+                    search_name = ldb_msg_find_attr_as_string(user->msgs[0],
-+                                                              SYSDB_NAME, NULL);
-+                }
-+            } else if (DOM_HAS_VIEWS(dom) && (user->count == 0
-+                || ldb_msg_find_attr_as_string(user->msgs[0],
-+                                               OVERRIDE_PREFIX SYSDB_NAME,
-+                                               NULL) != NULL)) {
-                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
-             }
- 
-             dpreq = sss_dp_get_account_send(cli_ctx, cli_ctx->rctx,
-                                             dom, false, SSS_DP_INITGROUPS,
--                                            cmd_ctx->username, 0, extra_flag);
-+                                            search_name, 0, extra_flag);
-             if (!dpreq) {
-                 DEBUG(SSSDBG_CRIT_FAILURE,
-                       "Out of memory sending data provider request\n");
--- 
-2.4.3
-
diff --git a/SOURCES/0105-AD_PROVIDER-ad_enabled_domains-only-master.patch b/SOURCES/0105-AD_PROVIDER-ad_enabled_domains-only-master.patch
new file mode 100644
index 0000000..81520da
--- /dev/null
+++ b/SOURCES/0105-AD_PROVIDER-ad_enabled_domains-only-master.patch
@@ -0,0 +1,57 @@
+From a0009ecf7cfaaa14eb5b041b9e1d8247d18c61cb Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Tue, 21 Jun 2016 09:48:52 +0200
+Subject: [PATCH 105/108] AD_PROVIDER: ad_enabled_domains - only master
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We can skip looking up other domains if option ad_enabled_domains
+contains only master domain.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2828
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ad/ad_subdomains.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 6e44760330275f7e4262e6863f180747f659edb5..5fdfc63886457db02ea4edc430341b31c3e545ce 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -1170,6 +1170,7 @@ static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq)
+         return;
+     }
+ 
++    /* connect to the DC we are a member of */
+     subreq = ad_master_domain_send(state, state->ev, state->id_ctx->conn,
+                                    state->sdap_op, state->sd_ctx->domain_name);
+     if (subreq == NULL) {
+@@ -1218,6 +1219,21 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
++    /*
++     * If ad_enabled_domains contains only master domain
++     * we shouldn't lookup other domains.
++     */
++    if (state->sd_ctx->ad_enabled_domains != NULL) {
++        if (talloc_array_length(state->sd_ctx->ad_enabled_domains) == 2) {
++            if (strcasecmp(state->sd_ctx->ad_enabled_domains[0],
++                           state->be_ctx->domain->name) == 0) {
++                DEBUG(SSSDBG_TRACE_FUNC,
++                      "No other enabled domain than master.\n");
++                goto done;
++            }
++        }
++    }
++
+     subreq = ad_get_root_domain_send(state, state->ev, forest,
+                                      sdap_id_op_handle(state->sdap_op),
+                                      state->sd_ctx);
+-- 
+2.4.11
+
diff --git a/SOURCES/0105-IPA-fix-override-with-the-same-name.patch b/SOURCES/0105-IPA-fix-override-with-the-same-name.patch
deleted file mode 100644
index 1709e1c..0000000
--- a/SOURCES/0105-IPA-fix-override-with-the-same-name.patch
+++ /dev/null
@@ -1,238 +0,0 @@
-From 6f25f357e3d000f6ad750bc336d24f8402e896af Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 19 Nov 2015 11:42:39 +0100
-Subject: [PATCH] IPA: fix override with the same name
-
-If the user name of a AD user is overridden with the name itself in an
-IPA override object SSSD adds this name twice to the alias list causing
-an ldb error when trying to write the user object to the cache. As a
-result the user is not available.
-
-This patch makes sure that there are no duplicated alias names.
-
-Resolves https://fedorahosted.org/sssd/ticket/2874
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit aedc71fe8360a51785933523f14bb5c4e7e2c38b)
----
- src/db/sysdb.c                   | 18 ++++++++--
- src/db/sysdb.h                   |  4 ++-
- src/providers/ipa/ipa_s2n_exop.c | 13 +++----
- src/tests/sysdb-tests.c          | 78 ++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 103 insertions(+), 10 deletions(-)
-
-diff --git a/src/db/sysdb.c b/src/db/sysdb.c
-index 07a83a8a8e30df1b8e461a8d04866f2dbc53baf8..a71364d7c4b600eafd10fafa6641eac7b2292764 100644
---- a/src/db/sysdb.c
-+++ b/src/db/sysdb.c
-@@ -598,7 +598,7 @@ int sysdb_attrs_add_string(struct sysdb_attrs *attrs,
-     return sysdb_attrs_add_val(attrs, name, &v);
- }
- 
--int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs,
-+int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs, bool safe,
-                                       const char *name, const char *str)
- {
-     char *lc_str;
-@@ -614,7 +614,11 @@ int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs,
-         return ENOMEM;
-     }
- 
--    ret = sysdb_attrs_add_string(attrs, name, lc_str);
-+    if (safe) {
-+        ret = sysdb_attrs_add_string_safe(attrs, name, lc_str);
-+    } else {
-+        ret = sysdb_attrs_add_string(attrs, name, lc_str);
-+    }
-     talloc_free(lc_str);
- 
-     return ret;
-@@ -729,7 +733,15 @@ int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs,
- int sysdb_attrs_add_lc_name_alias(struct sysdb_attrs *attrs,
-                                   const char *value)
- {
--    return sysdb_attrs_add_lower_case_string(attrs, SYSDB_NAME_ALIAS, value);
-+    return sysdb_attrs_add_lower_case_string(attrs, false, SYSDB_NAME_ALIAS,
-+                                             value);
-+}
-+
-+int sysdb_attrs_add_lc_name_alias_safe(struct sysdb_attrs *attrs,
-+                                       const char *value)
-+{
-+    return sysdb_attrs_add_lower_case_string(attrs, true, SYSDB_NAME_ALIAS,
-+                                             value);
- }
- 
- int sysdb_attrs_copy_values(struct sysdb_attrs *src,
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 9e28b5c6691f3710e3051d9746ac5fa47aff8424..3fa3f040708a4984158206d66a1d28a079091cf7 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -315,7 +315,7 @@ int sysdb_attrs_add_string_safe(struct sysdb_attrs *attrs,
-                                 const char *name, const char *str);
- int sysdb_attrs_add_string(struct sysdb_attrs *attrs,
-                            const char *name, const char *str);
--int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs,
-+int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs, bool safe,
-                                       const char *name, const char *str);
- int sysdb_attrs_add_mem(struct sysdb_attrs *attrs, const char *name,
-                         const void *mem, size_t size);
-@@ -329,6 +329,8 @@ 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_add_lc_name_alias_safe(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/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index 1e6368dc7ef1a6f60b541409f7f6740d602f0d43..bcd11749fbde4cae2a47b9b2182138ae04f2d6bc 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -1804,10 +1804,11 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-         ret = sysdb_attrs_get_string(attrs->sysdb_attrs,
-                                      SYSDB_DEFAULT_OVERRIDE_NAME, &tmp_str);
-         if (ret == EOK) {
--            ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, tmp_str);
-+            ret = sysdb_attrs_add_lc_name_alias_safe(attrs->sysdb_attrs,
-+                                                     tmp_str);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "sysdb_attrs_add_lc_name_alias failed.\n");
-+                      "sysdb_attrs_add_lc_name_alias_safe failed.\n");
-                 goto done;
-             }
-         } else if (ret != ENOENT) {
-@@ -1876,10 +1877,10 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-                 }
-             }
- 
--            ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
-+            ret = sysdb_attrs_add_lc_name_alias_safe(attrs->sysdb_attrs, name);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "sysdb_attrs_add_lc_name_alias failed.\n");
-+                      "sysdb_attrs_add_lc_name_alias_safe failed.\n");
-                 goto done;
-             }
- 
-@@ -2133,10 +2134,10 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-             }
-             DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", name);
- 
--            ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
-+            ret = sysdb_attrs_add_lc_name_alias_safe(attrs->sysdb_attrs, name);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "sysdb_attrs_add_lc_name_alias failed.\n");
-+                      "sysdb_attrs_add_lc_name_alias_safe failed.\n");
-                 goto done;
-             }
- 
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index 522a44aa4d5c0da6d10bba10d960fff9426200c1..0b091f741ce158713ed383ad3d98dfea25f388ed 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -4690,6 +4690,7 @@ START_TEST(test_sysdb_attrs_add_lc_name_alias)
-     int ret;
-     struct sysdb_attrs *attrs;
-     const char *str;
-+    char **list = NULL;
- 
-     ret = sysdb_attrs_add_lc_name_alias(NULL, NULL);
-     fail_unless(ret == EINVAL, "EINVAL not returned for NULL input");
-@@ -4706,6 +4707,82 @@ START_TEST(test_sysdb_attrs_add_lc_name_alias)
-                 "Unexpected value, expected [%s], got [%s]",
-                 LC_NAME_ALIAS_CHECK_VAL, str);
- 
-+    /* Add the same value a second time, it is not recommended to do this on
-+     * purpose but the test should illustrate the different to
-+     * sysdb_attrs_add_lc_name_alias_safe(). */
-+    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_array(attrs, SYSDB_NAME_ALIAS, attrs, &list);
-+    fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed");
-+    fail_unless(list != NULL, "No list returned");
-+    fail_unless(list[0] != NULL, "Missing first list element");
-+    fail_unless(strcmp(list[0], LC_NAME_ALIAS_CHECK_VAL) == 0,
-+                "Unexpected value, expected [%s], got [%s]",
-+                LC_NAME_ALIAS_CHECK_VAL, list[0]);
-+    fail_unless(list[1] != NULL, "Missing second list element");
-+    fail_unless(strcmp(list[1], LC_NAME_ALIAS_CHECK_VAL) == 0,
-+                "Unexpected value, expected [%s], got [%s]",
-+                LC_NAME_ALIAS_CHECK_VAL, list[1]);
-+    fail_unless(list[2] == NULL, "Missing list terminator");
-+
-+    talloc_free(attrs);
-+}
-+END_TEST
-+
-+START_TEST(test_sysdb_attrs_add_lc_name_alias_safe)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    const char *str;
-+    char **list = NULL;
-+
-+    ret = sysdb_attrs_add_lc_name_alias_safe(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_safe(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);
-+
-+    /* Adding the same value a second time should be ignored */
-+    ret = sysdb_attrs_add_lc_name_alias_safe(attrs, LC_NAME_ALIAS_TEST_VAL);
-+    fail_unless(ret == EOK, "sysdb_attrs_add_lc_name_alias failed");
-+
-+    ret = sysdb_attrs_get_string_array(attrs, SYSDB_NAME_ALIAS, attrs, &list);
-+    fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed");
-+    fail_unless(list != NULL, "No list returned");
-+    fail_unless(list[0] != NULL, "Missing first list element");
-+    fail_unless(strcmp(list[0], LC_NAME_ALIAS_CHECK_VAL) == 0,
-+                "Unexpected value, expected [%s], got [%s]",
-+                LC_NAME_ALIAS_CHECK_VAL, list[0]);
-+    fail_unless(list[1] == NULL, "Missing list terminator");
-+
-+    /* Adding different value */
-+    ret = sysdb_attrs_add_lc_name_alias_safe(attrs,
-+                                             "2nd_" LC_NAME_ALIAS_TEST_VAL);
-+    fail_unless(ret == EOK, "sysdb_attrs_add_lc_name_alias failed");
-+
-+    ret = sysdb_attrs_get_string_array(attrs, SYSDB_NAME_ALIAS, attrs, &list);
-+    fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed");
-+    fail_unless(list != NULL, "No list returned");
-+    fail_unless(list[0] != NULL, "Missing first list element");
-+    fail_unless(strcmp(list[0], LC_NAME_ALIAS_CHECK_VAL) == 0,
-+                "Unexpected value, expected [%s], got [%s]",
-+                LC_NAME_ALIAS_CHECK_VAL, list[0]);
-+    fail_unless(list[1] != NULL, "Missing first list element");
-+    fail_unless(strcmp(list[1], "2nd_" LC_NAME_ALIAS_CHECK_VAL) == 0,
-+                "Unexpected value, expected [%s], got [%s]",
-+                "2nd_" LC_NAME_ALIAS_CHECK_VAL, list[1]);
-+    fail_unless(list[2] == NULL, "Missing list terminator");
-+
-     talloc_free(attrs);
- }
- END_TEST
-@@ -6412,6 +6489,7 @@ Suite *create_sysdb_suite(void)
-     tcase_add_test(tc_sysdb, test_sysdb_svc_remove_alias);
- 
-     tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias);
-+    tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias_safe);
- 
- /* ===== UTIL TESTS ===== */
-     tcase_add_test(tc_sysdb, test_sysdb_attrs_get_string_array);
--- 
-2.4.3
-
diff --git a/SOURCES/0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch b/SOURCES/0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch
new file mode 100644
index 0000000..6946373
--- /dev/null
+++ b/SOURCES/0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch
@@ -0,0 +1,112 @@
+From 9438cd7b8c8cca1e919afec6c5aa3a3233a31f8c Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Mon, 27 Jun 2016 11:51:30 +0200
+Subject: [PATCH 106/108] AD_PROVIDER: ad_enabled_domains - other then master
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We can skip looking up other domains if
+option ad_enabled_domains doesn't contain them.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2828
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/ad/ad_subdomains.c | 40 +++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 37 insertions(+), 3 deletions(-)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 5fdfc63886457db02ea4edc430341b31c3e545ce..52bf5361fa8de02c7165cbc3513a923ec018fc15 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -130,6 +130,16 @@ done:
+     return ret;
+ }
+ 
++static bool is_domain_enabled(const char *domain,
++                              const char **enabled_doms)
++{
++    if (enabled_doms == NULL) {
++        return true;
++    }
++
++    return string_in_list(domain, discard_const_p(char *, enabled_doms), false);
++}
++
+ static errno_t
+ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+                      struct ad_id_ctx *id_ctx,
+@@ -492,6 +502,7 @@ done:
+ 
+ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+                                      struct sss_domain_info *domain,
++                                     const char **enabled_domains_list,
+                                      size_t nsd, struct sysdb_attrs **sd,
+                                      struct sysdb_attrs *root,
+                                      size_t *_nsd_out,
+@@ -500,9 +511,10 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+     size_t i, sdi;
+     struct sysdb_attrs **sd_out;
+     const char *sd_name;
++    const char *root_name;
+     errno_t ret;
+ 
+-    if (root == NULL) {
++    if (root == NULL && enabled_domains_list == NULL) {
+         /* We are connected directly to the root domain. The 'sd'
+          * list is complete and we can just use it
+          */
+@@ -529,6 +541,13 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+             goto fail;
+         }
+ 
++        if (is_domain_enabled(sd_name, enabled_domains_list) == false) {
++            DEBUG(SSSDBG_TRACE_FUNC, "Disabling subdomain %s\n", sd_name);
++            continue;
++        } else {
++            DEBUG(SSSDBG_TRACE_FUNC, "Enabling subdomain %s\n", sd_name);
++        }
++
+         if (strcasecmp(sd_name, domain->name) == 0) {
+             DEBUG(SSSDBG_TRACE_INTERNAL,
+                   "Not including primary domain %s in the subdomain list\n",
+@@ -541,9 +560,23 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+     }
+ 
+     /* Now include the root */
+-    sd_out[sdi] = talloc_steal(sd_out, root);
++    if (root != NULL) {
++        ret = sysdb_attrs_get_string(root, AD_AT_TRUST_PARTNER, &root_name);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
++            goto fail;
++        }
+ 
+-    *_nsd_out = sdi+1;
++        if (is_domain_enabled(root_name, enabled_domains_list) == true) {
++            sd_out[sdi] = talloc_steal(sd_out, root);
++            sdi++;
++        } else {
++            DEBUG(SSSDBG_TRACE_FUNC, "Disabling forest root domain %s\n",
++                                     root_name);
++        }
++    }
++
++    *_nsd_out = sdi;
+     *_sd_out = sd_out;
+     return EOK;
+ 
+@@ -789,6 +822,7 @@ static void ad_get_slave_domain_done(struct tevent_req *subreq)
+      * subdomains.
+      */
+     ret = ad_subdomains_process(state, state->be_ctx->domain,
++                                state->sd_ctx->ad_enabled_domains,
+                                 reply_count, reply, state->root_attrs,
+                                 &nsubdoms, &subdoms);
+     if (ret != EOK) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0106-Add-a-new-option-ldap_group_external_member.patch b/SOURCES/0106-Add-a-new-option-ldap_group_external_member.patch
deleted file mode 100644
index a17aa8a..0000000
--- a/SOURCES/0106-Add-a-new-option-ldap_group_external_member.patch
+++ /dev/null
@@ -1,178 +0,0 @@
-From b842e04a1e73dd9af3096b065fcf5b2a7fe55b51 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 25 Jan 2016 16:03:23 +0100
-Subject: [PATCH 106/108] Add a new option ldap_group_external_member
-
-Required for:
-    https://fedorahosted.org/sssd/ticket/2522
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 3cf7fdfcaedb986f42a6640e26aa057007b64045)
-(cherry picked from commit 7db3bdfd6b1b845866c1ff062d25de5804141e89)
----
- 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                  | 16 ++++++++++++++++
- 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, 27 insertions(+)
-
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index a7cd1dd243a53e7038dc69628475c76ccdd93260..7ec28d1d4a121cef0f7a8f3122c95bd396f773a7 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -328,6 +328,7 @@ option_strings = {
-     'ldap_group_objectsid' : _("objectSID attribute"),
-     'ldap_group_modify_timestamp' : _('Modification time attribute for groups'),
-     'ldap_group_type' : _('Type of the group and other flags'),
-+    'ldap_group_external_member' : _('The LDAP group external member attribute'),
-     #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 b636d93108ef0a3831970d7827895c14b0f3571c..e1083aa2a6d9a0ebf61a6029af05aea62ec7b217 100644
---- a/src/config/etc/sssd.api.d/sssd-ad.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
-@@ -108,6 +108,7 @@ 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_external_member = str, 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 ab712fe55cdac6d247a085aeca5cc82d65966623..3cbfb2ee5e06f2ef731e8f9eb79be374351d7281 100644
---- a/src/config/etc/sssd.api.d/sssd-ipa.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
-@@ -104,6 +104,7 @@ 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_external_member = str, 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 8fd45fd4093714f458161eb352157c845d926f06..21a38b9581ea35f78618a272bc3a943f6968d37e 100644
---- a/src/config/etc/sssd.api.d/sssd-ldap.conf
-+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
-@@ -98,6 +98,7 @@ 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_external_member = str, 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 3fa3f040708a4984158206d66a1d28a079091cf7..817ecd2764c3fac3ca3e38ba78f9e8ef2afab51b 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -81,6 +81,7 @@
- #define SYSDB_USER_CATEGORY "userCategory"
- #define SYSDB_HOST_CATEGORY "hostCategory"
- #define SYSDB_GROUP_TYPE "groupType"
-+#define SYSDB_EXTERNAL_MEMBER "externalMember"
- 
- #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 49e84560f825b1bff255c1ad131487ba3243300d..cc1b17108500c5d241008f683d14ab32cefab396 100644
---- a/src/man/sssd-ldap.5.xml
-+++ b/src/man/sssd-ldap.5.xml
-@@ -942,6 +942,22 @@
-                 </varlistentry>
- 
-                 <varlistentry>
-+                    <term>ldap_group_external_member (string)</term>
-+                    <listitem>
-+                        <para>
-+                            The LDAP attribute that references group
-+                            members that are defined in an external
-+                            domain. At the moment, only IPA's external
-+                            members are supported.
-+                        </para>
-+                        <para>
-+                            Default: ipaExternalMember in the IPA provider,
-+                            otherwise unset.
-+                        </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 00586a7ada63ad4c89630e9589d3ff75d1726703..b2133db1859914d54d2db2a871d7fbae7aeff268 100644
---- a/src/providers/ad/ad_opts.h
-+++ b/src/providers/ad/ad_opts.h
-@@ -233,6 +233,7 @@ struct sdap_attr_map ad_2008r2_group_map[] = {
-     { "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 },
-+    { "ldap_group_external_member", NULL, SYSDB_EXTERNAL_MEMBER, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
-index 78949e3ddec95f7f4303eab905bbbf6ec14ed6ae..81ccc42fc0c9f21c8ef16e2d1735bc06199ba747 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -221,6 +221,7 @@ struct sdap_attr_map ipa_group_map[] = {
-     { "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 },
-+    { "ldap_group_external_member", NULL, SYSDB_EXTERNAL_MEMBER, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
-index 9f58db5bd9eef1391e97c1890cbff94c2a5406d6..bda2e79e849ab9e4e3e91407faafc0d8b06df899 100644
---- a/src/providers/ldap/ldap_opts.h
-+++ b/src/providers/ldap/ldap_opts.h
-@@ -197,6 +197,7 @@ struct sdap_attr_map rfc2307_group_map[] = {
-     { "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 },
-+    { "ldap_group_external_member", NULL, SYSDB_EXTERNAL_MEMBER, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-@@ -253,6 +254,7 @@ struct sdap_attr_map rfc2307bis_group_map[] = {
-     { "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 },
-+    { "ldap_group_external_member", NULL, SYSDB_EXTERNAL_MEMBER, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-@@ -309,6 +311,7 @@ struct sdap_attr_map gen_ad2008r2_group_map[] = {
-     { "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 },
-+    { "ldap_group_external_member", NULL, SYSDB_EXTERNAL_MEMBER, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index 444502bf7159edcf4cebe530cce8b216c737ec30..d7053949f5804b637c27bb2d8e34991653770639 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -303,6 +303,7 @@ enum sdap_group_attrs {
-     SDAP_AT_GROUP_MODSTAMP,
-     SDAP_AT_GROUP_USN,
-     SDAP_AT_GROUP_TYPE,
-+    SDAP_AT_GROUP_EXT_MEMBER,
- 
-     SDAP_OPTS_GROUP /* attrs counter */
- };
--- 
-2.4.3
-
diff --git a/SOURCES/0107-IPA-Add-interface-to-call-into-IPA-provider-from-LDA.patch b/SOURCES/0107-IPA-Add-interface-to-call-into-IPA-provider-from-LDA.patch
deleted file mode 100644
index 9c83b71..0000000
--- a/SOURCES/0107-IPA-Add-interface-to-call-into-IPA-provider-from-LDA.patch
+++ /dev/null
@@ -1,446 +0,0 @@
-From 2515f7d9a19c2634baf1cd2f008a2148b5300db0 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 25 Jan 2016 16:11:59 +0100
-Subject: [PATCH 107/108] IPA: Add interface to call into IPA provider from
- LDAP provider
-
-https://fedorahosted.org/sssd/ticket/2522
-
-Adds a pluggable interface that is able to resolve the IPA group's
-external members. At the moment, the request calls the full be_
-interface to make sure all corner cases like id-views are handled
-internally.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit e2d96566aeb881bd89e5c9236d663f6a9a88019a)
-(cherry picked from commit 00ee45423f0712b83926c6f8b354a1a18ff741c8)
----
- src/providers/ipa/ipa_id.c                    |   5 +-
- src/providers/ipa/ipa_init.c                  |  28 +++
- src/providers/ipa/ipa_subdomains.h            |  11 ++
- src/providers/ipa/ipa_subdomains_ext_groups.c | 275 ++++++++++++++++++++++++++
- src/providers/ipa/ipa_subdomains_id.c         |   1 +
- src/providers/ldap/sdap.h                     |  23 +++
- 6 files changed, 342 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
-index e81ccb34dd6eb44618538593f5473fbe5e89d896..8782a81247f7ca7ba6d2aa55f8d01897a0b38523 100644
---- a/src/providers/ipa/ipa_id.c
-+++ b/src/providers/ipa/ipa_id.c
-@@ -384,7 +384,10 @@ static int ipa_initgr_get_overrides_step(struct tevent_req *req)
-         /* 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");
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "The group %s has no UUID attribute %s, error!\n",
-+              ldb_dn_get_linearized(state->groups[state->group_idx]->dn),
-+              state->groups_id_attr);
-         return EINVAL;
-     }
- 
-diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
-index 0e16dd97c78a087256fb77be500c9741484867c5..453e2b25673ac709c9fa3809d35b7885630c8b24 100644
---- a/src/providers/ipa/ipa_init.c
-+++ b/src/providers/ipa/ipa_init.c
-@@ -139,6 +139,24 @@ int common_ipa_init(struct be_ctx *bectx)
-     return EOK;
- }
- 
-+static struct sdap_ext_member_ctx *
-+ipa_create_ext_members_ctx(TALLOC_CTX *mem_ctx,
-+                           struct ipa_id_ctx *id_ctx)
-+{
-+    struct sdap_ext_member_ctx *ext_ctx = NULL;
-+
-+    ext_ctx = talloc_zero(mem_ctx, struct sdap_ext_member_ctx);
-+    if (ext_ctx == NULL) {
-+        return NULL;
-+    }
-+
-+    ext_ctx->pvt = id_ctx;
-+    ext_ctx->ext_member_resolve_send = ipa_ext_group_member_send;
-+    ext_ctx->ext_member_resolve_recv = ipa_ext_group_member_recv;
-+
-+    return ext_ctx;
-+}
-+
- int sssm_ipa_id_init(struct be_ctx *bectx,
-                      struct bet_ops **ops,
-                      void **pvt_data)
-@@ -360,6 +378,16 @@ int sssm_ipa_id_init(struct be_ctx *bectx,
-               "will not work [%d]: %s\n", ret, strerror(ret));
-     }
- 
-+    ipa_ctx->sdap_id_ctx->opts->ext_ctx = ipa_create_ext_members_ctx(
-+                                                    ipa_ctx->sdap_id_ctx->opts,
-+                                                    ipa_ctx);
-+    if (ipa_ctx->sdap_id_ctx->opts->ext_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Unable to set SRV the extrernal group ctx\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     *ops = &ipa_id_ops;
-     *pvt_data = ipa_ctx;
-     ret = EOK;
-diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h
-index 0c13f8ed2eeda87237dfb097f532c7137095ddf1..23c3b7e3cd3ee1e0ac1dbcf98dc71a6c2337b835 100644
---- a/src/providers/ipa/ipa_subdomains.h
-+++ b/src/providers/ipa/ipa_subdomains.h
-@@ -137,4 +137,15 @@ struct tevent_req *ipa_get_ad_memberships_send(TALLOC_CTX *mem_ctx,
-                                         const char *domain);
- 
- errno_t ipa_get_ad_memberships_recv(struct tevent_req *req, int *dp_error_out);
-+
-+struct tevent_req *ipa_ext_group_member_send(TALLOC_CTX *mem_ctx,
-+                                             struct tevent_context *ev,
-+                                             const char *ext_member,
-+                                             void *pvt);
-+errno_t ipa_ext_group_member_recv(TALLOC_CTX *mem_ctx,
-+                                  struct tevent_req *req,
-+                                  enum sysdb_member_type *_member_type,
-+                                  struct sss_domain_info **_dom,
-+                                  struct sysdb_attrs **_member);
-+
- #endif /* _IPA_SUBDOMAINS_H_ */
-diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
-index d487a58b8adffabe09ff50e31cb750b800b1d252..5dc6d0d6417ec3fb5e7865e4cbaf3c07f4afbd07 100644
---- a/src/providers/ipa/ipa_subdomains_ext_groups.c
-+++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
-@@ -923,3 +923,278 @@ static errno_t ipa_add_ad_memberships_recv(struct tevent_req *req,
- 
-     return EOK;
- }
-+
-+static errno_t
-+search_user_or_group_by_sid_str(TALLOC_CTX *mem_ctx,
-+                                struct sss_domain_info *domain,
-+                                const char *sid_str,
-+                                enum sysdb_member_type *_member_type,
-+                                struct ldb_message **_msg)
-+{
-+    errno_t ret;
-+    struct ldb_message *msg = NULL;
-+    const char *attrs[] = { SYSDB_NAME,
-+                            SYSDB_SID_STR,
-+                            SYSDB_ORIG_DN,
-+                            SYSDB_OBJECTCLASS,
-+                            SYSDB_CACHE_EXPIRE,
-+                            NULL };
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    char *sanitized_sid = NULL;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-+        return ENOMEM;
-+    }
-+
-+    /* In theory SID shouldn't contain any special LDAP characters, but let's
-+     * be paranoid
-+     */
-+    ret = sss_filter_sanitize(tmp_ctx, sid_str, &sanitized_sid);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_user_by_sid_str(tmp_ctx, domain,
-+                                       sid_str, attrs, &msg);
-+    if (ret == EOK) {
-+        *_member_type = SYSDB_MEMBER_USER;
-+    } else if (ret == ENOENT) {
-+        ret = sysdb_search_group_by_sid_str(tmp_ctx, domain,
-+                                            sid_str, attrs, &msg);
-+        if (ret == EOK) {
-+            *_member_type = SYSDB_MEMBER_GROUP;
-+        }
-+    }
-+
-+    switch (ret) {
-+    case EOK:
-+        DEBUG(SSSDBG_TRACE_FUNC, "Found %s in sysdb\n", sid_str);
-+        *_msg = talloc_steal(mem_ctx, msg);
-+        break;
-+    case ENOENT:
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "Could not find %s in sysdb", sid_str);
-+        break;
-+    default:
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Error looking for %s in sysdb [%d]: %s\n",
-+              sid_str, ret, sss_strerror(ret));
-+        break;
-+    }
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+ipa_ext_group_member_check(TALLOC_CTX *mem_ctx,
-+                           struct ipa_id_ctx *ipa_ctx,
-+                           struct sss_domain_info *member_dom,
-+                           const char *ext_member,
-+                           enum sysdb_member_type *_member_type,
-+                           struct sysdb_attrs **_member)
-+{
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    errno_t ret;
-+    uint64_t expire;
-+    time_t now = time(NULL);
-+    struct ldb_message *msg;
-+    struct sysdb_attrs **members;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = search_user_or_group_by_sid_str(tmp_ctx, member_dom, ext_member,
-+                                          _member_type, &msg);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Error looking up sid %s: [%d]: %s\n",
-+               ext_member, ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = sysdb_msg2attrs(tmp_ctx, 1, &msg, &members);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not convert result to sysdb_attrs [%d]: %s\n",
-+               ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    /* Return the member both expired and valid */
-+    *_member = talloc_steal(mem_ctx, members[0]);
-+
-+    expire = ldb_msg_find_attr_as_uint64(msg, SYSDB_CACHE_EXPIRE, 0);
-+    if (expire != 0 && expire <= now) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "%s is expired", ext_member);
-+        ret = EAGAIN;
-+        goto done;
-+    }
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+/* For the IPA external member resolution, we expect a SID as the input.
-+ * The _recv() function output is the member and a type (user/group)
-+ * since nothing else can be a group member.
-+ */
-+struct ipa_ext_member_state {
-+    const char *ext_member;
-+    struct sss_domain_info *dom;
-+
-+    enum sysdb_member_type member_type;
-+    struct sysdb_attrs *member;
-+};
-+
-+static void ipa_ext_group_member_done(struct tevent_req *subreq);
-+
-+struct tevent_req *ipa_ext_group_member_send(TALLOC_CTX *mem_ctx,
-+                                             struct tevent_context *ev,
-+                                             const char *ext_member,
-+                                             void *pvt)
-+{
-+    struct ipa_id_ctx *ipa_ctx;
-+    struct ipa_ext_member_state *state;
-+    struct tevent_req *req;
-+    struct tevent_req *subreq;
-+    struct be_acct_req *ar;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state, struct ipa_ext_member_state);
-+    if (req == NULL) {
-+        return NULL;
-+    }
-+    state->ext_member = ext_member;
-+
-+    ipa_ctx = talloc_get_type(pvt, struct ipa_id_ctx);
-+    if (ipa_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Wrong private context!\n");
-+        ret = EINVAL;
-+        goto immediate;
-+    }
-+
-+    state->dom = find_domain_by_sid(ipa_ctx->sdap_id_ctx->be->domain,
-+                                    ext_member);
-+    if (state->dom == NULL) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot find domain of SID [%s]\n", ext_member);
-+        ret = ENOENT;
-+        goto immediate;
-+    }
-+
-+    ret = ipa_ext_group_member_check(state, ipa_ctx, state->dom, ext_member,
-+                                     &state->member_type, &state->member);
-+    if (ret == EOK) {
-+        DEBUG(SSSDBG_TRACE_INTERNAL,
-+              "external member %s already cached\n", ext_member);
-+        goto immediate;
-+    }
-+
-+    ret = get_be_acct_req_for_sid(state, ext_member, state->dom->name, &ar);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot create the account request for [%s]\n", ext_member);
-+        goto immediate;
-+    }
-+
-+    subreq = be_get_account_info_send(state, ev, NULL,
-+                                      ipa_ctx->sdap_id_ctx->be, ar);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediate;
-+    }
-+    tevent_req_set_callback(subreq, ipa_ext_group_member_done, req);
-+
-+    return req;
-+
-+immediate:
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+    } else {
-+        tevent_req_done(req);
-+    }
-+    tevent_req_post(req, ev);
-+    return req;
-+}
-+
-+static void ipa_ext_group_member_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct ipa_ext_member_state *state = tevent_req_data(req,
-+                                                struct ipa_ext_member_state);
-+    errno_t ret;
-+    int err_maj;
-+    int err_min;
-+    const char *err_msg;
-+    struct ldb_message *msg;
-+    struct sysdb_attrs **members;
-+
-+    ret = be_get_account_info_recv(subreq, state,
-+                                   &err_maj, &err_min, &err_msg);
-+    talloc_free(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "be request failed %d:%d: %s\n", err_maj, err_min, err_msg);
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    ret = search_user_or_group_by_sid_str(state,
-+                                          state->dom,
-+                                          state->ext_member,
-+                                          &state->member_type,
-+                                          &msg);
-+    if (ret != EOK) {
-+        DEBUG(ret == ENOENT ? SSSDBG_TRACE_FUNC : SSSDBG_OP_FAILURE,
-+              "Could not find %s in sysdb [%d]: %s\n",
-+              state->ext_member, ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    ret = sysdb_msg2attrs(state, 1, &msg, &members);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not convert result to sysdb_attrs [%d]: %s\n",
-+               ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    state->member = members[0];
-+    tevent_req_done(req);
-+}
-+
-+errno_t ipa_ext_group_member_recv(TALLOC_CTX *mem_ctx,
-+                                  struct tevent_req *req,
-+                                  enum sysdb_member_type *_member_type,
-+                                  struct sss_domain_info **_dom,
-+                                  struct sysdb_attrs **_member)
-+{
-+    struct ipa_ext_member_state *state = tevent_req_data(req,
-+                                                struct ipa_ext_member_state);
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    if (_member_type != NULL) {
-+        *_member_type = state->member_type;
-+    }
-+
-+    if (_dom) {
-+        *_dom = state->dom;
-+    }
-+
-+    if (_member != NULL) {
-+        *_member = talloc_steal(mem_ctx, state->member);
-+    }
-+
-+    return EOK;
-+}
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 7acbb38e66c2c36ff230ae35b236544195a8104b..ebbf3be71d7488c0e5138183925668fc6187df97 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -1229,6 +1229,7 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
-      * attributes set, i.e. where overrides might not have been applied. */
-     ret = sysdb_asq_search(state, state->obj_dom, state->obj_msg->dn,
-                           "(&("SYSDB_GC")("SYSDB_GIDNUM"=*)" \
-+                            "("SYSDB_POSIX"=TRUE)" \
-                             "(!("ORIGINALAD_PREFIX SYSDB_GIDNUM"=*))" \
-                             "(!("ORIGINALAD_PREFIX SYSDB_NAME"=*)))",
-                           SYSDB_INITGR_ATTR,
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index d7053949f5804b637c27bb2d8e34991653770639..312789411fa273dd263bd6319f7a5ff45437d8d0 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -415,6 +415,26 @@ struct sdap_domain {
-     void *pvt;
- };
- 
-+typedef struct tevent_req *
-+(*ext_member_send_fn_t)(TALLOC_CTX *mem_ctx,
-+                        struct tevent_context *ev,
-+                        const char *ext_member,
-+                        void *pvt);
-+typedef errno_t
-+(*ext_member_recv_fn_t)(TALLOC_CTX *mem_ctx,
-+                        struct tevent_req *req,
-+                        enum sysdb_member_type *member_type,
-+                        struct sss_domain_info **_dom,
-+                        struct sysdb_attrs **_member);
-+
-+struct sdap_ext_member_ctx {
-+    /* Typically ID context of the external ID provider */
-+    void *pvt;
-+
-+    ext_member_send_fn_t ext_member_resolve_send;
-+    ext_member_recv_fn_t ext_member_resolve_recv;
-+};
-+
- struct sdap_options {
-     struct dp_option *basic;
-     struct sdap_attr_map *gen_map;
-@@ -427,6 +447,9 @@ struct sdap_options {
-     /* ID-mapping support */
-     struct sdap_idmap_ctx *idmap_ctx;
- 
-+    /* Resolving external members */
-+    struct sdap_ext_member_ctx *ext_ctx;
-+
-     /* FIXME - should this go to a special struct to avoid mixing with name-service-switch maps? */
-     struct sdap_attr_map *sudorule_map;
-     struct sdap_attr_map *autofs_mobject_map;
--- 
-2.4.3
-
diff --git a/SOURCES/0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch b/SOURCES/0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch
new file mode 100644
index 0000000..96cddc6
--- /dev/null
+++ b/SOURCES/0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch
@@ -0,0 +1,398 @@
+From 70c1809c7ad309d87fba7570cff5c5e9f10d17f1 Mon Sep 17 00:00:00 2001
+From: Petr Cech <pcech@redhat.com>
+Date: Mon, 27 Jun 2016 11:53:19 +0200
+Subject: [PATCH 107/108] TESTS: Adding tests for ad_enabled_domains option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is special logic around ad_enabled_domains option:
+ * option is disabled by default
+ * master domain is always added to enabled domains
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2828
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am                           |  20 +++
+ src/tests/cmocka/test_ad_subdomains.c | 328 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 348 insertions(+)
+ create mode 100644 src/tests/cmocka/test_ad_subdomains.c
+
+diff --git a/Makefile.am b/Makefile.am
+index e2e4c4c08f66ef15684e1b3b1fe17bfae4e4131b..4d90c7a46e2ee0fe652aa392cf647d056e06c7fc 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -257,6 +257,7 @@ if HAVE_CMOCKA
+         test_sbus_opath \
+         test_fo_srv \
+         pam-srv-tests \
++        test_ad_subdom \
+         test_ipa_subdom_util \
+         test_tools_colondb \
+         test_krb5_wait_queue \
+@@ -2817,6 +2818,25 @@ test_fo_srv_LDADD = \
+     libsss_test_common.la \
+     $(NULL)
+ 
++test_ad_subdom_SOURCES = \
++    src/tests/cmocka/test_ad_subdomains.c \
++    $(NULL)
++test_ad_subdom_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NDR_NBT_CFLAGS) \
++    $(NULL)
++test_ad_subdom_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(POPT_LIBS) \
++    $(TALLOC_LIBS) \
++    $(SSSD_INTERNAL_LTLIBS) \
++    libsss_ldap_common.la \
++    libsss_ad_tests.la \
++    libsss_idmap.la \
++    libsss_test_common.la \
++    libdlopen_test_providers.la \
++    $(NULL)
++
+ test_ipa_subdom_util_SOURCES = \
+     src/tests/cmocka/test_ipa_subdomains_utils.c \
+     src/providers/ipa/ipa_subdomains_utils.c \
+diff --git a/src/tests/cmocka/test_ad_subdomains.c b/src/tests/cmocka/test_ad_subdomains.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..99908b5f8f0b89c2cc391b5496e24a247bfd7448
+--- /dev/null
++++ b/src/tests/cmocka/test_ad_subdomains.c
+@@ -0,0 +1,328 @@
++/*
++    Authors:
++        Petr Čech <pcech@redhat.com>
++
++    Copyright (C) 2016 Red Hat
++
++    SSSD tests: AD subdomain 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 <arpa/inet.h>
++#include <netinet/in.h>
++#include <sys/types.h>
++#include <stdarg.h>
++#include <stdlib.h>
++
++#include "tests/cmocka/common_mock.h"
++#include "tests/cmocka/common_mock_resp.h"
++#include "providers/ad/ad_common.h"
++
++#include "providers/ad/ad_subdomains.c"
++#include "providers/ad/ad_opts.c"
++
++#define AD_DOMAIN "ad_domain.domain.test"
++#define DOMAIN_1 "one.domain.test"
++#define DOMAIN_2 "two.domain.test"
++
++struct test_ad_subdom_ctx {
++    struct ad_id_ctx *ad_id_ctx;
++};
++
++static struct ad_id_ctx *
++test_ad_subdom_init_ad_id_ctx(TALLOC_CTX *mem_ctx)
++{
++    struct ad_id_ctx *ad_id_ctx;
++    struct ad_options *ad_options;
++    errno_t ret;
++
++    ad_id_ctx = talloc_zero(mem_ctx, struct ad_id_ctx);
++    assert_non_null(ad_id_ctx);
++
++    ad_options = talloc_zero(ad_id_ctx, struct ad_options);
++    assert_non_null(ad_options);
++
++    ret = dp_copy_defaults(ad_options,
++                           ad_basic_opts,
++                           AD_OPTS_BASIC,
++                           &ad_options->basic);
++    assert_int_equal(ret, EOK);
++
++    ad_id_ctx->ad_options = ad_options;
++
++    return ad_id_ctx;
++}
++
++static int test_ad_subdom_setup(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++
++    assert_true(leak_check_setup());
++
++    test_ctx = talloc_zero(global_talloc_context, struct test_ad_subdom_ctx);
++    assert_non_null(test_ctx);
++
++    test_ctx->ad_id_ctx = NULL;
++
++    check_leaks_push(test_ctx);
++    *state = test_ctx;
++    return 0;
++}
++
++static int test_ad_subdom_teardown(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++
++    test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx);
++    assert_non_null(test_ctx);
++
++    assert_true(check_leaks_pop(test_ctx) == true);
++    talloc_free(test_ctx);
++    assert_true(leak_check_teardown());
++    return 0;
++}
++
++static void test_ad_subdom_default(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++    const char **ad_enabled_domains = NULL;
++    errno_t ret;
++
++    test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx);
++    test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx);
++    assert_non_null(test_ctx->ad_id_ctx);
++
++    ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx,
++                                 AD_DOMAIN,
++                                 &ad_enabled_domains);
++    assert_int_equal(ret, EOK);
++    assert_null(ad_enabled_domains);
++
++    talloc_zfree(test_ctx->ad_id_ctx);
++}
++
++static void test_ad_subdom_add_one(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++    const char **ad_enabled_domains = NULL;
++    int enabled_domains_count;
++    int domain_count = 2;
++    const char *domains[domain_count];
++    errno_t ret;
++
++    test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx);
++    test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx);
++    assert_non_null(test_ctx->ad_id_ctx);
++
++    ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic,
++                            AD_ENABLED_DOMAINS, DOMAIN_1);
++    assert_int_equal(ret, EOK);
++
++    ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx,
++                                 AD_DOMAIN,
++                                 &ad_enabled_domains);
++    assert_int_equal(ret, EOK);
++    assert_non_null(ad_enabled_domains);
++
++    for (enabled_domains_count = 0;
++         ad_enabled_domains[enabled_domains_count] != NULL;
++         enabled_domains_count++) {
++    }
++    assert_int_equal(domain_count, enabled_domains_count);
++
++    domains[0] = AD_DOMAIN;
++    domains[1] = DOMAIN_1;
++    assert_true(are_values_in_array(domains, domain_count,
++                                    ad_enabled_domains, enabled_domains_count));
++
++    talloc_zfree(test_ctx->ad_id_ctx);
++    talloc_zfree(ad_enabled_domains);
++}
++
++static void test_ad_subdom_add_two(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++    const char **ad_enabled_domains = NULL;
++    int enabled_domains_count;
++    int domain_count = 3;
++    const char *domains[domain_count];
++    errno_t ret;
++
++    test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx);
++    test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx);
++    assert_non_null(test_ctx->ad_id_ctx);
++
++    ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic,
++                            AD_ENABLED_DOMAINS, DOMAIN_1","DOMAIN_2);
++    assert_int_equal(ret, EOK);
++
++    ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx,
++                                 AD_DOMAIN,
++                                 &ad_enabled_domains);
++    assert_int_equal(ret, EOK);
++    assert_non_null(ad_enabled_domains);
++
++    for (enabled_domains_count = 0;
++         ad_enabled_domains[enabled_domains_count] != NULL;
++         enabled_domains_count++) {
++    }
++    assert_int_equal(domain_count, enabled_domains_count);
++
++    domains[0] = AD_DOMAIN;
++    domains[1] = DOMAIN_1;
++    domains[2] = DOMAIN_2;
++    assert_true(are_values_in_array(domains, domain_count,
++                                    ad_enabled_domains, enabled_domains_count));
++
++    talloc_zfree(test_ctx->ad_id_ctx);
++    talloc_zfree(ad_enabled_domains);
++}
++
++static void test_ad_subdom_add_master(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++    const char **ad_enabled_domains = NULL;
++    int enabled_domains_count;
++    int domain_count = 1;
++    const char *domains[domain_count];
++    errno_t ret;
++
++    test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx);
++    test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx);
++    assert_non_null(test_ctx->ad_id_ctx);
++
++    ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic,
++                            AD_ENABLED_DOMAINS, AD_DOMAIN);
++    assert_int_equal(ret, EOK);
++
++    ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx,
++                                 AD_DOMAIN,
++                                 &ad_enabled_domains);
++    assert_int_equal(ret, EOK);
++    assert_non_null(ad_enabled_domains);
++
++    for (enabled_domains_count = 0;
++         ad_enabled_domains[enabled_domains_count] != NULL;
++         enabled_domains_count++) {
++    }
++    assert_int_equal(domain_count, enabled_domains_count);
++
++    domains[0] = AD_DOMAIN;
++    assert_true(are_values_in_array(domains, domain_count,
++                                    ad_enabled_domains, enabled_domains_count));
++
++    talloc_zfree(test_ctx->ad_id_ctx);
++    talloc_zfree(ad_enabled_domains);
++}
++
++static void test_ad_subdom_add_two_with_master(void **state)
++{
++    struct test_ad_subdom_ctx *test_ctx;
++    const char **ad_enabled_domains = NULL;
++    int enabled_domains_count;
++    int domain_count = 3;
++    const char *domains[domain_count];
++    errno_t ret;
++
++    test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx);
++    test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx);
++    assert_non_null(test_ctx->ad_id_ctx);
++
++    ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic,
++                            AD_ENABLED_DOMAINS,
++                            DOMAIN_1","AD_DOMAIN","DOMAIN_2);
++    assert_int_equal(ret, EOK);
++
++    ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx,
++                                 AD_DOMAIN,
++                                 &ad_enabled_domains);
++    assert_int_equal(ret, EOK);
++    assert_non_null(ad_enabled_domains);
++
++    for (enabled_domains_count = 0;
++         ad_enabled_domains[enabled_domains_count] != NULL;
++         enabled_domains_count++) {
++    }
++    assert_int_equal(domain_count, enabled_domains_count);
++
++    domains[0] = AD_DOMAIN;
++    domains[1] = DOMAIN_1;
++    domains[2] = DOMAIN_2;
++    assert_true(are_values_in_array(domains, domain_count,
++                                    ad_enabled_domains, enabled_domains_count));
++
++    talloc_zfree(test_ctx->ad_id_ctx);
++    talloc_zfree(ad_enabled_domains);
++}
++
++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 struct CMUnitTest tests[] = {
++        cmocka_unit_test_setup_teardown(test_ad_subdom_default,
++                                        test_ad_subdom_setup,
++                                        test_ad_subdom_teardown),
++        cmocka_unit_test_setup_teardown(test_ad_subdom_add_one,
++                                        test_ad_subdom_setup,
++                                        test_ad_subdom_teardown),
++        cmocka_unit_test_setup_teardown(test_ad_subdom_add_two,
++                                        test_ad_subdom_setup,
++                                        test_ad_subdom_teardown),
++        cmocka_unit_test_setup_teardown(test_ad_subdom_add_master,
++                                        test_ad_subdom_setup,
++                                        test_ad_subdom_teardown),
++        cmocka_unit_test_setup_teardown(test_ad_subdom_add_two_with_master,
++                                        test_ad_subdom_setup,
++                                        test_ad_subdom_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);
++
++    /* 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 = cmocka_run_group_tests(tests, NULL, NULL);
++    return rv;
++}
+-- 
+2.4.11
+
diff --git a/SOURCES/0108-LDAP-Use-the-IPA-provider-interface-to-resolve-exter.patch b/SOURCES/0108-LDAP-Use-the-IPA-provider-interface-to-resolve-exter.patch
deleted file mode 100644
index 845a2c8..0000000
--- a/SOURCES/0108-LDAP-Use-the-IPA-provider-interface-to-resolve-exter.patch
+++ /dev/null
@@ -1,916 +0,0 @@
-From 3af57ba315eb5268c56919297e3a688c3f2f5b05 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 25 Jan 2016 16:13:03 +0100
-Subject: [PATCH 108/108] LDAP: Use the IPA provider interface to resolve
- external group members
-
-Resolves:
-    https://fedorahosted.org/sssd/ticket/2522
-
-Currently the approach is not optimized for performance, because each
-external member is resolved in a full transaction to make sure even ID
-views and similar information is processed.
-
-In future, we should implement https://fedorahosted.org/sssd/ticket/2943
-we will again be able to process all the data in a single transaction.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit c32266e79f9d4bebd0c31eaa8d6fa26050e7fb3e)
-(cherry picked from commit 19194cb18a1cc20f02423861dd831aa5bc3a1003)
----
- src/providers/ldap/sdap_async_groups.c        |  49 +-
- src/providers/ldap/sdap_async_nested_groups.c | 618 +++++++++++++++++++++++++-
- src/providers/ldap/sdap_async_private.h       |  16 +-
- src/tests/cmocka/test_nested_groups.c         |   4 +-
- 4 files changed, 659 insertions(+), 28 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 57a53af3f4eb46e6f31af9ee7c4d4625239d2a54..485f79d2fb2e7e34f1420b43baadb40ab3f96d17 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -1728,6 +1728,7 @@ struct sdap_get_groups_state {
-     struct sysdb_attrs **groups;
-     size_t count;
-     size_t check_count;
-+    hash_table_t *missing_external;
- 
-     hash_table_t *user_hash;
-     hash_table_t *group_hash;
-@@ -2289,6 +2290,8 @@ int sdap_get_groups_recv(struct tevent_req *req,
-     return EOK;
- }
- 
-+static void sdap_nested_ext_done(struct tevent_req *subreq);
-+
- static void sdap_nested_done(struct tevent_req *subreq)
- {
-     errno_t ret, tret;
-@@ -2304,7 +2307,8 @@ static void sdap_nested_done(struct tevent_req *subreq)
-                                             struct sdap_get_groups_state);
- 
-     ret = sdap_nested_group_recv(state, subreq, &user_count, &users,
--                                 &group_count, &groups);
-+                                 &group_count, &groups,
-+                                 &state->missing_external);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Nested group processing failed: [%d][%s]\n",
-@@ -2343,8 +2347,25 @@ static void sdap_nested_done(struct tevent_req *subreq)
-     }
-     in_transaction = false;
- 
--    /* Processing complete */
--    tevent_req_done(req);
-+    if (hash_count(state->missing_external) == 0) {
-+        /* No external members. Processing complete */
-+        DEBUG(SSSDBG_TRACE_INTERNAL, "No external members, done");
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    /* At the moment, we need to save the direct groups & members in one
-+     * transaction and then query the others in a separate requests
-+     */
-+    subreq = sdap_nested_group_lookup_external_send(state, state->ev,
-+                                                    state->dom,
-+                                                    state->opts->ext_ctx,
-+                                                    state->missing_external);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+    tevent_req_set_callback(subreq, sdap_nested_ext_done, req);
-     return;
- 
- fail:
-@@ -2357,6 +2378,28 @@ fail:
-     tevent_req_error(req, ret);
- }
- 
-+static void sdap_nested_ext_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct sdap_get_groups_state *state = tevent_req_data(req,
-+                                            struct sdap_get_groups_state);
-+
-+    ret = sdap_nested_group_lookup_external_recv(state, subreq);
-+    talloc_free(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Cannot resolve external members [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+    return;
-+}
-+
- static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx,
-                                                 struct sysdb_ctx *sysdb,
-                                                 struct sss_domain_info *domain,
-diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c
-index 08e199869ad16c3b19d998a2a28eae9a0dd0a371..f5be6b5a5946453151918f97aa0632df4b218a29 100644
---- a/src/providers/ldap/sdap_async_nested_groups.c
-+++ b/src/providers/ldap/sdap_async_nested_groups.c
-@@ -55,6 +55,13 @@ struct sdap_nested_group_member {
-     const char *group_filter;
- };
- 
-+const size_t external_members_chunk = 16;
-+
-+struct sdap_external_missing_member {
-+    const char **parent_group_dns;
-+    size_t parent_dn_idx;
-+};
-+
- struct sdap_nested_group_ctx {
-     struct sss_domain_info *domain;
-     struct sdap_options *opts;
-@@ -63,6 +70,7 @@ struct sdap_nested_group_ctx {
-     struct sdap_handle *sh;
-     hash_table_t *users;
-     hash_table_t *groups;
-+    hash_table_t *missing_external;
-     bool try_deref;
-     int deref_treshold;
-     int max_nesting_level;
-@@ -183,37 +191,32 @@ done:
-     return ret;
- }
- 
--static errno_t sdap_nested_group_hash_entry(hash_table_t *table,
--                                            struct sysdb_attrs *entry,
--                                            const char *table_name)
-+static errno_t sdap_nested_group_hash_insert(hash_table_t *table,
-+                                             const char *entry_key,
-+                                             void *entry_value,
-+                                             bool overwrite,
-+                                             const char *table_name)
- {
-     hash_key_t key;
-     hash_value_t value;
--    const char *name = NULL;
--    errno_t ret;
-     int hret;
- 
--    ret = sysdb_attrs_get_string(entry, SYSDB_ORIG_DN, &name);
--    if (ret != EOK) {
--        return ret;
--    }
--
-     DEBUG(SSSDBG_TRACE_ALL, "Inserting [%s] into hash table [%s]\n",
--                             name, table_name);
-+                             entry_key, table_name);
- 
-     key.type = HASH_KEY_STRING;
--    key.str = talloc_strdup(NULL, name);
-+    key.str = talloc_strdup(NULL, entry_key);
-     if (key.str == NULL) {
-         return ENOMEM;
-     }
- 
--    if (hash_has_key(table, &key)) {
-+    if (overwrite == false && hash_has_key(table, &key)) {
-         talloc_free(key.str);
-         return EEXIST;
-     }
- 
-     value.type = HASH_VALUE_PTR;
--    value.ptr = entry;
-+    value.ptr = entry_value;
- 
-     hret = hash_enter(table, &key, &value);
-     if (hret != HASH_SUCCESS) {
-@@ -227,6 +230,21 @@ static errno_t sdap_nested_group_hash_entry(hash_table_t *table,
-     return EOK;
- }
- 
-+static errno_t sdap_nested_group_hash_entry(hash_table_t *table,
-+                                            struct sysdb_attrs *entry,
-+                                            const char *table_name)
-+{
-+    const char *name = NULL;
-+    errno_t ret;
-+
-+    ret = sysdb_attrs_get_string(entry, SYSDB_ORIG_DN, &name);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    return sdap_nested_group_hash_insert(table, name, entry, false, table_name);
-+}
-+
- static errno_t
- sdap_nested_group_hash_user(struct sdap_nested_group_ctx *group_ctx,
-                             struct sysdb_attrs *user)
-@@ -296,6 +314,76 @@ sdap_nested_group_hash_group(struct sdap_nested_group_ctx *group_ctx,
-     return sdap_nested_group_hash_entry(group_ctx->groups, group, "groups");
- }
- 
-+static errno_t sdap_nested_group_external_add(hash_table_t *table,
-+                                              const char *ext_member,
-+                                              const char *parent_group_dn)
-+{
-+    hash_key_t key;
-+    hash_value_t value;
-+    int hret;
-+    int ret;
-+    struct sdap_external_missing_member *ext_mem;
-+
-+    key.type = HASH_KEY_STRING;
-+    key.str = discard_const(ext_member);
-+
-+    DEBUG(SSSDBG_TRACE_ALL,
-+          "Inserting external member [%s] into external members hash table\n",
-+          ext_member);
-+
-+    hret = hash_lookup(table, &key, &value);
-+    switch (hret) {
-+    case HASH_ERROR_KEY_NOT_FOUND:
-+        ext_mem = talloc_zero(table, struct sdap_external_missing_member);
-+        if (ext_mem == NULL) {
-+            return ENOMEM;
-+        }
-+        ext_mem->parent_group_dns = talloc_zero_array(ext_mem,
-+                                                      const char *,
-+                                                      external_members_chunk);
-+        if (ext_mem->parent_group_dns == NULL) {
-+            talloc_free(ext_mem);
-+            return ENOMEM;
-+        }
-+
-+        ret = sdap_nested_group_hash_insert(table, ext_member, ext_mem,
-+                                            true, "missing external users");
-+        if (ret != EOK) {
-+            return ret;
-+        }
-+        break;
-+
-+    case HASH_SUCCESS:
-+        ext_mem = talloc_get_type(value.ptr,
-+                                  struct sdap_external_missing_member);
-+        if (ext_mem->parent_dn_idx == \
-+                talloc_array_length(ext_mem->parent_group_dns)) {
-+            ext_mem->parent_group_dns = talloc_realloc(ext_mem,
-+                                                ext_mem->parent_group_dns,
-+                                                const char *,
-+                                                ext_mem->parent_dn_idx + \
-+                                                    external_members_chunk);
-+            if (ext_mem->parent_group_dns == NULL) {
-+                talloc_free(ext_mem);
-+                return ENOMEM;
-+            }
-+        }
-+        break;
-+    default:
-+        return EIO;
-+    }
-+
-+    ext_mem->parent_group_dns[ext_mem->parent_dn_idx] = \
-+                                        talloc_strdup(ext_mem->parent_group_dns,
-+                                                      parent_group_dn);
-+    if (ext_mem->parent_group_dns[ext_mem->parent_dn_idx] == NULL) {
-+        return ENOMEM;
-+    }
-+    ext_mem->parent_dn_idx++;
-+
-+    return EOK;
-+}
-+
- static errno_t sdap_nested_group_sysdb_search(struct sss_domain_info *domain,
-                                               const char *filter,
-                                               bool user)
-@@ -477,6 +565,13 @@ sdap_nested_group_split_members(TALLOC_CTX *mem_ctx,
-     errno_t ret;
-     int i;
- 
-+    if (members == NULL) {
-+        *_missing = NULL;
-+        *_num_missing = 0;
-+        *_num_groups = 0;
-+        return EOK;
-+    }
-+
-     tmp_ctx = talloc_new(NULL);
-     if (tmp_ctx == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-@@ -618,6 +713,66 @@ done:
-     return ret;
- }
- 
-+static errno_t
-+sdap_nested_group_add_ext_members(TALLOC_CTX *mem_ctx,
-+                                  struct sdap_nested_group_ctx *group_ctx,
-+                                  struct sysdb_attrs *group,
-+                                  struct ldb_message_element *ext_members)
-+{
-+    errno_t ret;
-+    const char *ext_member_attr;
-+    const char *orig_dn;
-+    size_t i;
-+
-+    if (ext_members == NULL) {
-+        return EOK;
-+    }
-+
-+    ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, &orig_dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "A group with no originalDN!?!\n");
-+        return ret;
-+    }
-+
-+    for (i = 0; i < ext_members->num_values; i++) {
-+        ext_member_attr = (const char *) ext_members->values[i].data;
-+
-+        ret = sdap_nested_group_external_add(group_ctx->missing_external,
-+                                             ext_member_attr,
-+                                             orig_dn);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                    "Cannot add %s into external members [%d]: %s\n",
-+                    ext_member_attr, ret, sss_strerror(ret));
-+            return ret;
-+        }
-+    }
-+
-+    return EOK;
-+}
-+
-+static struct ldb_message_element *
-+sdap_nested_group_ext_members(struct sdap_options *opts,
-+                              struct sysdb_attrs *group)
-+{
-+    errno_t ret;
-+    struct ldb_message_element *ext_members = NULL;
-+
-+    if (opts->ext_ctx == NULL) {
-+        return NULL;
-+    }
-+
-+    ret = sysdb_attrs_get_el_ext(group,
-+                 opts->group_map[SDAP_AT_GROUP_EXT_MEMBER].sys_name,
-+                 false, &ext_members);
-+    if (ret != EOK && ret != ENOENT) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve external member list "
-+                                   "[%d]: %s\n", ret, sss_strerror(ret));
-+    }
-+
-+    return ext_members;
-+}
-+
- 
- struct sdap_nested_group_state {
-     struct sdap_nested_group_ctx *group_ctx;
-@@ -666,6 +821,14 @@ sdap_nested_group_send(TALLOC_CTX *mem_ctx,
-         goto immediately;
-     }
- 
-+    ret = sss_hash_create(state->group_ctx, 32,
-+                          &state->group_ctx->missing_external);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n",
-+                                    ret, strerror(ret));
-+        goto immediately;
-+    }
-+
-     state->group_ctx->try_deref = true;
-     state->group_ctx->deref_treshold = dp_opt_get_int(opts->basic,
-                                                       SDAP_DEREF_THRESHOLD);
-@@ -759,7 +922,8 @@ errno_t sdap_nested_group_recv(TALLOC_CTX *mem_ctx,
-                                unsigned long *_num_users,
-                                struct sysdb_attrs ***_users,
-                                unsigned long *_num_groups,
--                               struct sysdb_attrs ***_groups)
-+                               struct sysdb_attrs ***_groups,
-+                               hash_table_t **_missing_external)
- {
-     struct sdap_nested_group_state *state = NULL;
-     struct sysdb_attrs **users = NULL;
-@@ -806,6 +970,11 @@ errno_t sdap_nested_group_recv(TALLOC_CTX *mem_ctx,
-         *_groups = talloc_steal(mem_ctx, groups);
-     }
- 
-+    if (_missing_external) {
-+        *_missing_external = talloc_steal(mem_ctx,
-+                                          state->group_ctx->missing_external);
-+    }
-+
-     return EOK;
- }
- 
-@@ -815,6 +984,7 @@ struct sdap_nested_group_process_state {
-     struct sdap_nested_group_member *missing;
-     int num_missing_total;
-     int num_missing_groups;
-+    struct ldb_message_element *ext_members;
-     int nesting_level;
-     char *group_dn;
-     bool deref;
-@@ -865,13 +1035,16 @@ sdap_nested_group_process_send(TALLOC_CTX *mem_ctx,
- 
-     DEBUG(SSSDBG_TRACE_INTERNAL, "About to process group [%s]\n", orig_dn);
- 
--    /* get member list */
-+    /* get member list, both direct and external */
-+    state->ext_members = sdap_nested_group_ext_members(state->group_ctx->opts,
-+                                                       group);
-+
-     ret = sysdb_attrs_get_el_ext(group, group_map[SDAP_AT_GROUP_MEMBER].sys_name,
-                                  false, &members);
--    if (ret == ENOENT) {
--        ret = EOK; /* no members */
-+    if (ret == ENOENT && state->ext_members == NULL) {
-+        ret = EOK; /* no members, direct or external */
-         goto immediately;
--    } else if (ret != EOK) {
-+    } else if (ret != EOK && ret != ENOENT) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve member list "
-                                     "[%d]: %s\n", ret, strerror(ret));
-         goto immediately;
-@@ -889,14 +1062,31 @@ sdap_nested_group_process_send(TALLOC_CTX *mem_ctx,
-         goto immediately;
-     }
- 
--    DEBUG(SSSDBG_TRACE_INTERNAL, "Looking up %d/%d members of group [%s]\n",
--          state->num_missing_total, members->num_values, orig_dn);
-+    ret = sdap_nested_group_add_ext_members(state,
-+                                            state->group_ctx,
-+                                            group,
-+                                            state->ext_members);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to split external member list "
-+                                    "[%d]: %s\n", ret, sss_strerror(ret));
-+        goto immediately;
-+    }
- 
--    if (state->num_missing_total == 0) {
-+    if (state->num_missing_total == 0
-+            && hash_count(state->group_ctx->missing_external) == 0) {
-         ret = EOK; /* we're done */
-         goto immediately;
-     }
- 
-+    /* If there are only indirect members of the group, it's still safe to
-+     * proceed and let the direct lookup code just fall through.
-+     */
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL, "Looking up %d/%d members of group [%s]\n",
-+                                 state->num_missing_total,
-+                                 members ? members->num_values : 0,
-+                                 orig_dn);
-+
-     /* process members */
-     if (group_ctx->try_deref
-             && state->num_missing_total > group_ctx->deref_treshold) {
-@@ -2332,3 +2522,387 @@ static errno_t sdap_nested_group_deref_recv(struct tevent_req *req)
- 
-     return EOK;
- }
-+
-+struct sdap_ext_member {
-+    struct sdap_external_missing_member *missing_mem;
-+    const char *ext_member_attr;
-+
-+    enum sysdb_member_type member_type;
-+    struct sss_domain_info *dom;
-+    struct sysdb_attrs *attrs;
-+};
-+
-+struct sdap_nested_group_lookup_external_state {
-+    struct tevent_context *ev;
-+    struct sdap_ext_member_ctx *ext_ctx;
-+    struct sss_domain_info *group_dom;
-+    hash_table_t *missing_external;
-+
-+    hash_entry_t *entries;
-+    unsigned long n_entries;
-+    unsigned long eniter;
-+
-+    struct sdap_ext_member *ext_members;
-+
-+    ext_member_send_fn_t ext_member_resolve_send;
-+    ext_member_recv_fn_t ext_member_resolve_recv;
-+};
-+
-+static errno_t
-+sdap_nested_group_lookup_external_step(struct tevent_req *req);
-+static void
-+sdap_nested_group_lookup_external_done(struct tevent_req *subreq);
-+static errno_t
-+sdap_nested_group_lookup_external_link(struct tevent_req *req);
-+static errno_t
-+sdap_nested_group_lookup_external_link_member(
-+                        struct sdap_nested_group_lookup_external_state *state,
-+                        struct sdap_ext_member *member);
-+static errno_t
-+sdap_nested_group_memberof_dn_by_original_dn(
-+                            TALLOC_CTX *mem_ctx,
-+                            struct sss_domain_info *group_dom,
-+                            const char *original_dn,
-+                            const char ***_parents);
-+
-+struct tevent_req *
-+sdap_nested_group_lookup_external_send(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_context *ev,
-+                                       struct sss_domain_info *group_dom,
-+                                       struct sdap_ext_member_ctx *ext_ctx,
-+                                       hash_table_t *missing_external)
-+{
-+    struct sdap_nested_group_lookup_external_state *state = NULL;
-+    struct tevent_req *req = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct sdap_nested_group_lookup_external_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-+        return NULL;
-+    }
-+
-+    state->ev = ev;
-+    state->group_dom = group_dom;
-+    state->ext_ctx = ext_ctx;
-+    state->missing_external = missing_external;
-+
-+    if (state->ext_ctx->ext_member_resolve_send == NULL
-+            || state->ext_ctx->ext_member_resolve_recv == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Wrong private context\n");
-+        ret = EINVAL;
-+        goto immediately;
-+    }
-+
-+    ret = hash_entries(state->missing_external,
-+                       &state->n_entries, &state->entries);
-+    if (ret != HASH_SUCCESS) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "hash_entries returned %d\n", ret);
-+        ret = EIO;
-+        goto immediately;
-+    }
-+    state->eniter = 0;
-+
-+    state->ext_members = talloc_zero_array(state,
-+                                           struct sdap_ext_member,
-+                                           state->n_entries);
-+    if (state->ext_members == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    ret = sdap_nested_group_lookup_external_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_nested_group_lookup_external_step(struct tevent_req *req)
-+{
-+    struct tevent_req *subreq = NULL;
-+    struct sdap_nested_group_lookup_external_state *state = NULL;
-+    state = tevent_req_data(req,
-+                            struct sdap_nested_group_lookup_external_state);
-+
-+    subreq = state->ext_ctx->ext_member_resolve_send(state,
-+                                        state->ev,
-+                                        state->entries[state->eniter].key.str,
-+                                        state->ext_ctx->pvt);
-+    if (subreq == NULL) {
-+        return ENOMEM;
-+    }
-+    DEBUG(SSSDBG_TRACE_FUNC, "Refreshing member %lu/%lu\n",
-+                             state->eniter, state->n_entries);
-+    tevent_req_set_callback(subreq,
-+                            sdap_nested_group_lookup_external_done,
-+                            req);
-+
-+    return EAGAIN;
-+}
-+
-+static void
-+sdap_nested_group_lookup_external_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    struct tevent_req *req = NULL;
-+    struct sdap_nested_group_lookup_external_state *state = NULL;
-+    enum sysdb_member_type member_type;
-+    struct sysdb_attrs *member;
-+    struct sss_domain_info *member_dom;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req,
-+                            struct sdap_nested_group_lookup_external_state);
-+
-+    ret = state->ext_ctx->ext_member_resolve_recv(state, subreq,
-+                                                  &member_type,
-+                                                  &member_dom,
-+                                                  &member);
-+    talloc_free(subreq);
-+    if (ret == EOK) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "Refreshing member %lu\n", state->eniter);
-+        state->ext_members[state->eniter].missing_mem = \
-+                                    state->entries[state->eniter].value.ptr;
-+        state->ext_members[state->eniter].dom = member_dom;
-+
-+        state->ext_members[state->eniter].ext_member_attr = \
-+                        talloc_steal(state->ext_members,
-+                                     state->entries[state->eniter].key.str);
-+        state->ext_members[state->eniter].member_type = member_type;
-+        state->ext_members[state->eniter].attrs = \
-+                            talloc_steal(state->ext_members, member);
-+    }
-+
-+    state->eniter++;
-+    if (state->eniter >= state->n_entries) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "All external members processed\n");
-+        ret = sdap_nested_group_lookup_external_link(req);
-+        if (ret != EOK) {
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    ret = sdap_nested_group_lookup_external_step(req);
-+    if (ret != EOK && ret != EAGAIN) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    return;
-+}
-+
-+static errno_t
-+sdap_nested_group_lookup_external_link(struct tevent_req *req)
-+{
-+    errno_t ret, tret;
-+    bool in_transaction = false;
-+    struct sdap_nested_group_lookup_external_state *state = NULL;
-+    state = tevent_req_data(req,
-+                            struct sdap_nested_group_lookup_external_state);
-+    size_t i;
-+
-+    ret = sysdb_transaction_start(state->group_dom->sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
-+        goto fail;
-+    }
-+    in_transaction = true;
-+
-+
-+    for (i = 0; i < state->eniter; i++) {
-+        if (state->ext_members[i].attrs == NULL) {
-+            DEBUG(SSSDBG_MINOR_FAILURE, "The member %s could not be resolved\n",
-+                                        state->ext_members[i].ext_member_attr);
-+            continue;
-+        }
-+
-+        ret = sdap_nested_group_lookup_external_link_member(state,
-+                                                    &state->ext_members[i]);
-+        if (ret != EOK) {
-+            goto fail;
-+        }
-+    }
-+
-+    ret = sysdb_transaction_commit(state->group_dom->sysdb);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
-+        goto fail;
-+    }
-+    in_transaction = false;
-+
-+    return EOK;
-+
-+fail:
-+    if (in_transaction) {
-+        tret = sysdb_transaction_cancel(state->group_dom->sysdb);
-+        if (tret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
-+        }
-+    }
-+    return EFAULT;
-+}
-+
-+static errno_t
-+sdap_nested_group_lookup_external_link_member(
-+                        struct sdap_nested_group_lookup_external_state *state,
-+                        struct sdap_ext_member *member)
-+{
-+    const char *name;
-+    int ret;
-+    const char **parents = NULL;
-+    size_t i;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *orig_dn;
-+
-+    tmp_ctx = talloc_new(state);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = sysdb_attrs_get_string(member->attrs, SYSDB_NAME, &name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "No name for a user\n");
-+        goto done;
-+    }
-+
-+    /* This only works because the groups were saved in a previous
-+     * transaction */
-+    for (i=0; i < member->missing_mem->parent_dn_idx; i++) {
-+        orig_dn = member->missing_mem->parent_group_dns[i];
-+        DEBUG(SSSDBG_TRACE_INTERNAL,
-+              "Linking external members %s from domain %s to parents of %s\n",
-+              name, member->dom->name, orig_dn);
-+        ret = sdap_nested_group_memberof_dn_by_original_dn(tmp_ctx,
-+                                                           state->group_dom,
-+                                                           orig_dn,
-+                                                           &parents);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  "Cannot find parents of %s\n", orig_dn);
-+            continue;
-+        }
-+
-+        /* We don't have to remove the members here, since all members attributes
-+         * are always written anew
-+         */
-+        ret = sysdb_update_members_dn(member->dom, name, member->member_type,
-+                                      parents, NULL);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot link %s@%s to its parents\n",
-+                                       name, member->dom->name);
-+            goto done;
-+        }
-+
-+    }
-+
-+    ret = EOK;
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t
-+sdap_nested_group_memberof_dn_by_original_dn(
-+                            TALLOC_CTX *mem_ctx,
-+                            struct sss_domain_info *group_dom,
-+                            const char *original_dn,
-+                            const char ***_parents)
-+{
-+    errno_t ret;
-+    char *sanitized_dn;
-+    char *filter;
-+    const char *attrs[] = { SYSDB_NAME,
-+                            SYSDB_MEMBEROF,
-+                            NULL };
-+    struct ldb_message **msgs = NULL;
-+    size_t count;
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_message_element *memberof;
-+    const char **parents;
-+    size_t i;
-+
-+    tmp_ctx = talloc_new(mem_ctx);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_filter_sanitize(tmp_ctx, original_dn, &sanitized_dn);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+                "Cannot sanitize originalDN [%s]\n", original_dn);
-+        goto done;
-+    }
-+
-+    filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_ORIG_DN, sanitized_dn);
-+    if (filter == NULL) {
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_groups(tmp_ctx, group_dom, filter, attrs,
-+                              &count, &msgs);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    if (count != 1) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "More than one entry found by originalDN?\n");
-+        goto done;
-+    }
-+
-+    memberof = ldb_msg_find_element(msgs[0], SYSDB_MEMBEROF);
-+    if (memberof == NULL || memberof->num_values == 0) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "The external group is not a member of any groups\n");
-+        ret = ENOENT;
-+        goto done;
-+    }
-+
-+    parents = talloc_zero_array(tmp_ctx,
-+                                const char *,
-+                                memberof->num_values + 1);
-+    if (parents == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    for (i = 0; i < memberof->num_values; i++) {
-+        parents[i] = talloc_strdup(parents,
-+                                   (const char *) memberof->values[i].data);
-+        if (parents[i] == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    *_parents = talloc_steal(mem_ctx, parents);
-+    ret = EOK;
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+errno_t
-+sdap_nested_group_lookup_external_recv(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_req *req)
-+{
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h
-index db542eaf869efcd53d0937bef3fc6e99cc78b938..9cde6f5dfe0114f797135b4989b9a4bd336a3f27 100644
---- a/src/providers/ldap/sdap_async_private.h
-+++ b/src/providers/ldap/sdap_async_private.h
-@@ -130,8 +130,20 @@ errno_t sdap_nested_group_recv(TALLOC_CTX *mem_ctx,
-                                unsigned long *_num_users,
-                                struct sysdb_attrs ***_users,
-                                unsigned long *_num_groups,
--                               struct sysdb_attrs ***_groups);
-+                               struct sysdb_attrs ***_groups,
-+                               hash_table_t **missing_external);
- 
-+struct tevent_req *
-+sdap_nested_group_lookup_external_send(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_context *ev,
-+                                       struct sss_domain_info *group_dom,
-+                                       struct sdap_ext_member_ctx *ext_ctx,
-+                                       hash_table_t *missing_external);
-+errno_t
-+sdap_nested_group_lookup_external_recv(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_req *req);
-+
-+/* from sdap_async_initgroups.c */
- errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
-                                    struct sss_domain_info *domain,
-                                    struct sdap_options *opts,
-@@ -139,7 +151,7 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
-                                    struct sysdb_attrs **ldap_groups,
-                                    int ldap_groups_count);
- 
--/* from sdap_async_nested_groups.c */
-+/* from sdap_ad_groups.c */
- errno_t sdap_check_ad_group_type(struct sss_domain_info *dom,
-                                  struct sdap_options *opts,
-                                  struct sysdb_attrs *group_attrs,
-diff --git a/src/tests/cmocka/test_nested_groups.c b/src/tests/cmocka/test_nested_groups.c
-index 8081ff26102e53b2e453838c3a18e4560ac5317e..22b8caefc92a44a2339cbdcaa98226ebb4dc1ef5 100644
---- a/src/tests/cmocka/test_nested_groups.c
-+++ b/src/tests/cmocka/test_nested_groups.c
-@@ -57,6 +57,7 @@ struct nested_groups_test_ctx {
-     struct sdap_domain *sdap_domain;
-     struct sdap_idmap_ctx *idmap_ctx;
-     struct sdap_id_ctx *sdap_id_ctx;
-+    hash_table_t *missing_external;
- 
-     struct sysdb_attrs **users;
-     struct sysdb_attrs **groups;
-@@ -110,7 +111,8 @@ static void nested_groups_test_done(struct tevent_req *req)
- 
-     ctx->tctx->error = sdap_nested_group_recv(ctx, req,
-                                               &ctx->num_users, &ctx->users,
--                                              &ctx->num_groups, &ctx->groups);
-+                                              &ctx->num_groups, &ctx->groups,
-+                                              &ctx->missing_external);
-     talloc_zfree(req);
- 
-     ctx->tctx->done = true;
--- 
-2.4.3
-
diff --git a/SOURCES/0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch b/SOURCES/0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch
new file mode 100644
index 0000000..0734ff1
--- /dev/null
+++ b/SOURCES/0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch
@@ -0,0 +1,94 @@
+From 60596973b503637c742b597aeb862eecae9f9c91 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 8 Aug 2016 14:07:04 +0200
+Subject: [PATCH 109/111] UTIL: Use sss_atomic_read_s in generate_csprng_buffer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There was a bug in generate_csprng_buffer() where if we read the exact
+amount of bytes from /dev/urandom, we would always return EIO. Instead,
+let's reuse the existing code from sss_atomic_read_s() which fixes this
+bug and reduces code duplication.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+---
+ Makefile.am                  |  2 ++
+ src/util/crypto/sss_crypto.c | 29 +++++------------------------
+ 2 files changed, 7 insertions(+), 24 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 4d90c7a46e2ee0fe652aa392cf647d056e06c7fc..a32a1e37c85e2370fa006ee73b730145f03c3fc1 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -815,6 +815,7 @@ if HAVE_NSS
+                         src/util/crypto/nss/nss_nite.c \
+                         src/util/crypto/nss/nss_util.c \
+ 			src/util/crypto/sss_crypto.c \
++			src/util/atomic_io.c \
+ 			$(NULL)
+     SSS_CRYPT_CFLAGS = $(NSS_CFLAGS)
+     SSS_CRYPT_LIBS = $(NSS_LIBS)
+@@ -836,6 +837,7 @@ else
+                         src/util/crypto/libcrypto/crypto_obfuscate.c \
+                         src/util/crypto/libcrypto/crypto_nite.c \
+ 			src/util/crypto/sss_crypto.c \
++			src/util/atomic_io.c \
+ 			$(NULL)
+     SSS_CRYPT_CFLAGS = $(CRYPTO_CFLAGS)
+     SSS_CRYPT_LIBS = $(CRYPTO_LIBS)
+diff --git a/src/util/crypto/sss_crypto.c b/src/util/crypto/sss_crypto.c
+index 4c775f3d926ae32f3cb72b1329c0a025a0550ed5..ac90bac07c7006a2950331b86bcc412207a3e401 100644
+--- a/src/util/crypto/sss_crypto.c
++++ b/src/util/crypto/sss_crypto.c
+@@ -25,41 +25,22 @@
+ int generate_csprng_buffer(uint8_t *buf, size_t size)
+ {
+     ssize_t rsize;
+-    ssize_t pos;
+     int ret;
+     int fd;
+ 
+     fd = open("/dev/urandom", O_RDONLY);
+     if (fd == -1) return errno;
+ 
+-    rsize = 0;
+-    pos = 0;
+-    while (rsize < size) {
+-        rsize = read(fd, buf + pos, size - pos);
+-        switch (rsize) {
+-        case -1:
+-            if (errno == EINTR) continue;
+-            ret = EIO;
+-            goto done;
+-        case 0:
+-            ret = EIO;
+-            goto done;
+-        default:
+-            if (rsize + pos < size - pos) {
+-                pos += rsize;
+-                continue;
+-            }
+-            ret = EIO;
+-            goto done;
+-        }
+-    }
+-    if (rsize != size) {
++    rsize = sss_atomic_read_s(fd, buf, size);
++    if (rsize == -1) {
++        ret = errno;
++        goto done;
++    } else if (rsize != size) {
+         ret = EFAULT;
+         goto done;
+     }
+ 
+     ret = EOK;
+-
+ done:
+     close(fd);
+     return ret;
+-- 
+2.4.11
+
diff --git a/SOURCES/0109-memberof-Don-t-allocate-on-a-NULL-context.patch b/SOURCES/0109-memberof-Don-t-allocate-on-a-NULL-context.patch
deleted file mode 100644
index 9e25a2d..0000000
--- a/SOURCES/0109-memberof-Don-t-allocate-on-a-NULL-context.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 50d5d5c2b8b304234b222c76413c47dc31a6379f Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 19 Feb 2016 15:50:12 +0100
-Subject: [PATCH 109/109] memberof: Don't allocate on a NULL context
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-https://fedorahosted.org/sssd/ticket/2959
-
-In case no previous delete operation occured, the del_ctx->muops pointer we
-allocate the diff structure was would be NULL, effectivelly leaking the
-diff array during the memberof processing.
-
-Allocating on del_ctx is safer as that pointer is always allocated and
-prevents the leak.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit cd7a272fb361626a45d54cd45daaab4bfe7ad93f)
----
- src/ldb_modules/memberof.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
-index 4d7b23ea1b95bed0ec5c7cc717b95e6da3cd0717..be7c07dbcda257b6d813bb232ec27973167c25c4 100644
---- a/src/ldb_modules/memberof.c
-+++ b/src/ldb_modules/memberof.c
-@@ -2145,7 +2145,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
-         if (!el || !el->num_values) {
-             return LDB_ERR_OPERATIONS_ERROR;
-         }
--        diff = talloc_array(del_ctx->muops, struct ldb_dn *,
-+        diff = talloc_array(del_ctx, struct ldb_dn *,
-                             el->num_values + 1);
-         if (!diff) {
-             return LDB_ERR_OPERATIONS_ERROR;
-@@ -2241,6 +2241,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
-             if (ret != LDB_SUCCESS) {
-                 return ret;
-             }
-+            talloc_steal(del_ctx->muops, diff[i]);
-         }
-     }
- 
--- 
-2.4.11
-
diff --git a/SOURCES/0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch b/SOURCES/0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch
new file mode 100644
index 0000000..1c66e09
--- /dev/null
+++ b/SOURCES/0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch
@@ -0,0 +1,46 @@
+From eb6a90621a53424e4d0a5534eca303b432509433 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 8 Aug 2016 13:50:54 +0200
+Subject: [PATCH 110/111] SECRETS: Use sss_atomic_read/write for better
+ readability
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sss_atomic_read_s and sss_atomic_write_s are macro-wrappers around
+sss_atomic_io_s but it's easier to follow the code with the read/write
+vairants used directly.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+---
+ src/responder/secrets/local.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
+index 470aec0e195a54dd2af2b929ff1b7a304331a214..17469249b357cbdc5e50ddff6b563fdf2f377577 100644
+--- a/src/responder/secrets/local.c
++++ b/src/responder/secrets/local.c
+@@ -621,7 +621,7 @@ int generate_master_key(const char *filename, size_t size)
+     fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600);
+     if (fd == -1) return errno;
+ 
+-    rsize = sss_atomic_io_s(fd, buf, size, false);
++    rsize = sss_atomic_write_s(fd, buf, size);
+     close(fd);
+     if (rsize != size) {
+         ret = unlink(filename);
+@@ -681,8 +681,8 @@ int local_secrets_provider_handle(struct sec_ctx *sctx,
+     }
+     if (ret) return EFAULT;
+ 
+-    size = sss_atomic_io_s(mfd, lctx->master_key.data,
+-                           lctx->master_key.length, true);
++    size = sss_atomic_read_s(mfd, lctx->master_key.data,
++                             lctx->master_key.length);
+     close(mfd);
+     if (size < 0 || size != lctx->master_key.length) return EIO;
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0110-memberof-Fix-a-memory-leak-when-removing-ghost-users.patch b/SOURCES/0110-memberof-Fix-a-memory-leak-when-removing-ghost-users.patch
deleted file mode 100644
index 1a8ab09..0000000
--- a/SOURCES/0110-memberof-Fix-a-memory-leak-when-removing-ghost-users.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 54aa951a69cb0d0d4f2b154bff520145ecd659cf Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 6 Apr 2016 18:35:39 +0200
-Subject: [PATCH 110/111] memberof: Fix a memory leak when removing ghost users
-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 c07fb3f111b4dc2780fa4e1408ea04cd36e95a4d)
----
- src/ldb_modules/memberof.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
-index be7c07dbcda257b6d813bb232ec27973167c25c4..118e95a4d3b6246f2c7775f300ac345ac63ff17a 100644
---- a/src/ldb_modules/memberof.c
-+++ b/src/ldb_modules/memberof.c
-@@ -2531,7 +2531,7 @@ static int mbof_del_fill_ghop_ex(struct mbof_del_ctx *del_ctx,
-               num_gh_vals, mbof->num_values);
- 
-     for (i = 0; i < mbof->num_values; i++) {
--        valdn = ldb_dn_from_ldb_val(del_ctx->ghops,
-+        valdn = ldb_dn_from_ldb_val(del_ctx,
-                                     ldb_module_get_ctx(del_ctx->ctx->module),
-                                     &mbof->values[i]);
-         if (!valdn || !ldb_dn_validate(valdn)) {
-@@ -2556,6 +2556,7 @@ static int mbof_del_fill_ghop_ex(struct mbof_del_ctx *del_ctx,
-             if (ret != LDB_SUCCESS) {
-                 return ret;
-             }
-+            talloc_steal(del_ctx->ghops, valdn);
-         }
-     }
- 
--- 
-2.4.11
-
diff --git a/SOURCES/0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch b/SOURCES/0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch
new file mode 100644
index 0000000..3b6ae74
--- /dev/null
+++ b/SOURCES/0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch
@@ -0,0 +1,154 @@
+From d0b2cd8d161e7fc6e6c96f51342c88e6572eb1da Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 15 Aug 2016 14:10:23 +0200
+Subject: [PATCH 111/111] BUILD: Ship systemd service file for sssd-secrets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds two new files: sssd-secrets.socket and sssd-secrets.service. These
+can be used to socket-acticate the secrets responder even without
+explicitly starting it in the sssd config file.
+
+The specfile activates the socket after installation which means that
+the admin would just be able to use the secrets socket and the
+sssd_secrets responder would be started automatically by systemd.
+
+The sssd-secrets responder is started as root, mostly because I didn't
+think of an easy way to pass the uid/gid to the responders without
+asking about the sssd user identity in the first place. But nonetheless,
+the sssd-secrets responder wasn't tested as non-root and at least the
+initialization should be performed as root for the time being.
+
+Reviewed-by: Fabiano Fidêncio <fabiano@fidencio.org>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ Makefile.am                              | 21 +++++++++++++++++++--
+ contrib/sssd.spec.in                     |  6 ++++++
+ src/sysv/systemd/sssd-secrets.service.in |  8 ++++++++
+ src/sysv/systemd/sssd-secrets.socket.in  |  8 ++++++++
+ 4 files changed, 41 insertions(+), 2 deletions(-)
+ create mode 100644 src/sysv/systemd/sssd-secrets.service.in
+ create mode 100644 src/sysv/systemd/sssd-secrets.socket.in
+
+diff --git a/Makefile.am b/Makefile.am
+index a32a1e37c85e2370fa006ee73b730145f03c3fc1..6ab4399d5b68644668198bc9b0e3056562a4e51a 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3888,7 +3888,10 @@ systemdunit_DATA =
+ systemdconf_DATA =
+ if HAVE_SYSTEMD_UNIT
+     systemdunit_DATA += \
+-        src/sysv/systemd/sssd.service
++        src/sysv/systemd/sssd.service \
++        src/sysv/systemd/sssd-secrets.socket \
++        src/sysv/systemd/sssd-secrets.service \
++        $(NULL)
+ if WITH_JOURNALD
+     systemdconf_DATA += \
+         src/sysv/systemd/journal.conf
+@@ -3926,6 +3929,7 @@ edit_cmd = $(SED) \
+         -e 's|@sbindir[@]|$(sbindir)|g' \
+         -e 's|@environment_file[@]|$(environment_file)|g' \
+         -e 's|@localstatedir[@]|$(localstatedir)|g' \
++        -e 's|@libexecdir[@]|$(libexecdir)|g' \
+         -e 's|@prefix[@]|$(prefix)|g'
+ 
+ replace_script = \
+@@ -3937,7 +3941,10 @@ replace_script = \
+ 
+ EXTRA_DIST += \
+     src/sysv/systemd/sssd.service.in \
+-    src/sysv/systemd/journal.conf.in
++    src/sysv/systemd/journal.conf.in \
++    src/sysv/systemd/sssd-secrets.socket.in \
++    src/sysv/systemd/sssd-secrets.service.in \
++    $(NULL)
+ 
+ src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile
+ 	@$(MKDIR_P) src/sysv/systemd/
+@@ -3947,6 +3954,14 @@ src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile
+ 	@$(MKDIR_P) src/sysv/systemd/
+ 	$(replace_script)
+ 
++src/sysv/systemd/sssd-secrets.socket: src/sysv/systemd/sssd-secrets.socket.in Makefile
++	@$(MKDIR_P) src/sysv/systemd/
++	$(replace_script)
++
++src/sysv/systemd/sssd-secrets.service: src/sysv/systemd/sssd-secrets.service.in Makefile
++	@$(MKDIR_P) src/sysv/systemd/
++	$(replace_script)
++
+ SSSD_USER_DIRS = \
+     $(DESTDIR)$(dbpath) \
+     $(DESTDIR)$(keytabdir) \
+@@ -4162,6 +4177,8 @@ endif
+ 	done;
+ 	rm -Rf ldb_mod_test_dir
+ 	rm -f $(builddir)/src/sysv/systemd/sssd.service
++	rm -f $(builddir)/src/sysv/systemd/sssd-secrets.socket
++	rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service
+ 	rm -f $(builddir)/src/sysv/systemd/journal.conf
+ 
+ CLEANFILES += *.X */*.X */*/*.X
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index 14f0cb27ac8f1acc3aa0786da576be33b727e024..f1ff16176cb8ca974b98948958cfa1e9290b0bca 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -737,6 +737,8 @@ done
+ %{_sbindir}/sssd
+ %if (0%{?use_systemd} == 1)
+ %{_unitdir}/sssd.service
++%{_unitdir}/sssd-secrets.socket
++%{_unitdir}/sssd-secrets.service
+ %else
+ %{_initrddir}/%{name}
+ %endif
+@@ -1069,12 +1071,16 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us
+ # systemd
+ %post common
+ %systemd_post sssd.service
++%systemd_post sssd-secrets.socket
+ 
+ %preun common
+ %systemd_preun sssd.service
++%systemd_preun sssd-secrets.socket
+ 
+ %postun common
+ %systemd_postun_with_restart sssd.service
++%systemd_postun_with_restart sssd-secrets.socket
++%systemd_postun_with_restart sssd-secrets.service
+ 
+ %else
+ # sysv
+diff --git a/src/sysv/systemd/sssd-secrets.service.in b/src/sysv/systemd/sssd-secrets.service.in
+new file mode 100644
+index 0000000000000000000000000000000000000000..119c9bb4b37b672159db707aa11a6d11215f29bf
+--- /dev/null
++++ b/src/sysv/systemd/sssd-secrets.service.in
+@@ -0,0 +1,8 @@
++[Unit]
++Description=SSSD Secrets Service responder
++
++[Install]
++Also=sssd-secrets.socket
++
++[Service]
++ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 --debug-to-files
+diff --git a/src/sysv/systemd/sssd-secrets.socket.in b/src/sysv/systemd/sssd-secrets.socket.in
+new file mode 100644
+index 0000000000000000000000000000000000000000..682e8f6e0fa58092a90259523f9f2f59e0131435
+--- /dev/null
++++ b/src/sysv/systemd/sssd-secrets.socket.in
+@@ -0,0 +1,8 @@
++[Unit]
++Description=SSSD Secrets Service responder socket
++
++[Socket]
++ListenStream=@localstatedir@/run/secrets.socket
++
++[Install]
++WantedBy=sockets.target
+-- 
+2.4.11
+
diff --git a/SOURCES/0111-memberof-Don-t-allocate-on-NULL-when-deleting-member.patch b/SOURCES/0111-memberof-Don-t-allocate-on-NULL-when-deleting-member.patch
deleted file mode 100644
index fdb2593..0000000
--- a/SOURCES/0111-memberof-Don-t-allocate-on-NULL-when-deleting-member.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 58e3bfad6a6fc5d44c928b37e79bc36775aee2a8 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 8 Apr 2016 11:47:44 +0200
-Subject: [PATCH 111/111] memberof: Don't allocate on NULL when deleting
- memberUids
-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 27a0be2bb6f21f66527e0edea4ed2cb4b5cafa53)
----
- src/ldb_modules/memberof.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
-index 118e95a4d3b6246f2c7775f300ac345ac63ff17a..6c0180a493ce0c013b5882100a85b453e4111e63 100644
---- a/src/ldb_modules/memberof.c
-+++ b/src/ldb_modules/memberof.c
-@@ -2471,7 +2471,7 @@ static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
-     for (i = 0; i < el->num_values; i++) {
-         struct ldb_dn *valdn;
- 
--        valdn = ldb_dn_from_ldb_val(del_ctx->muops,
-+        valdn = ldb_dn_from_ldb_val(del_ctx,
-                                     ldb_module_get_ctx(del_ctx->ctx->module),
-                                     &el->values[i]);
-         if (!valdn || !ldb_dn_validate(valdn)) {
-@@ -2489,6 +2489,7 @@ static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
-         if (ret != LDB_SUCCESS) {
-             return ret;
-         }
-+        talloc_steal(del_ctx->muops, valdn);
-     }
- 
-     return LDB_SUCCESS;
--- 
-2.4.11
-
diff --git a/SOURCES/0112-DP-Add-log-message-for-get-account-info.patch b/SOURCES/0112-DP-Add-log-message-for-get-account-info.patch
new file mode 100644
index 0000000..a2fa19c
--- /dev/null
+++ b/SOURCES/0112-DP-Add-log-message-for-get-account-info.patch
@@ -0,0 +1,33 @@
+From b05afb6811e42d3297e884b0664884aa47af923f Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 16 Aug 2016 08:49:57 +0200
+Subject: [PATCH 112/115] DP: Add log message for get account info
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+(cherry picked from commit 806f65f3c90dc0f7921932494228ad93f3ed3027)
+---
+ src/providers/data_provider/dp_target_id.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
+index 938651545ea995091d0aaf29da12bbb8110c9add..8b126d70e59cb33b6de8b678f5b4c1a15b391329 100644
+--- a/src/providers/data_provider/dp_target_id.c
++++ b/src/providers/data_provider/dp_target_id.c
+@@ -281,6 +281,11 @@ errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
+         goto done;
+     }
+ 
++    DEBUG(SSSDBG_FUNC_DATA,
++          "Got request for [%#"PRIx32"][%s][%"PRId32"][%s]\n",
++          data->entry_type, be_req2str(data->entry_type),
++          attr_type, filter);
++
+     key = talloc_asprintf(data, "%u:%u:%s:%s:%s", data->entry_type,
+                           data->attr_type, extra, domain, filter);
+     if (key == NULL) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0112-IPA-Handle-requests-for-netgroups-from-trusted-domai.patch b/SOURCES/0112-IPA-Handle-requests-for-netgroups-from-trusted-domai.patch
deleted file mode 100644
index e60a668..0000000
--- a/SOURCES/0112-IPA-Handle-requests-for-netgroups-from-trusted-domai.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 18cbf559addfeb77ad83b81e23431295a3e5c6ae Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 6 May 2016 15:02:19 +0200
-Subject: [PATCH] IPA: Handle requests for netgroups from trusted domains
- gracefully
-
-In ipa_account_info_handler we first check if the request is for a user
-from a trusted domain and go that way for all request types. In
-contrast, in the ipa_account_info_done we first check if the requested
-object is a netgroup. If both are true, we first start a subdomain
-lookup send but then call netgroup lookup recv, which results in talloc
-type mismatch and crashes sssd_be.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/3007
----
- src/providers/ipa/ipa_id.c | 22 ++++++++++++++--------
- 1 file changed, 14 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
-index 29e22982c415220c931f0422e10cd06dfa1a195b..dff4b23580d8c7502a1fbe9c57d21b8c555883be 100644
---- a/src/providers/ipa/ipa_id.c
-+++ b/src/providers/ipa/ipa_id.c
-@@ -115,21 +115,27 @@ void ipa_account_info_handler(struct be_req *breq)
-         return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success");
-     }
- 
--    if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
--        /* if domain names do not match, this is a subdomain case
--         * subdomain lookups are handled differently on the server
--         * and the client
--         */
--        req = ipa_subdomain_account_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
--
--    } else if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
-+    if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
-         /* netgroups are handled by a separate request function */
-         if (ar->filter_type != BE_FILTER_NAME) {
-             return sdap_handler_done(breq, DP_ERR_FATAL,
-                                      EINVAL, "Invalid filter type");
-         }
-+
-+        if ((strcasecmp(ar->domain, be_ctx->domain->name) != 0)) {
-+            return sdap_handler_done(breq, DP_ERR_OK, EOK,
-+                                     "netgroups in subdomains are "
-+                                     "not handled\n");
-+        }
-+
-         req = ipa_id_get_netgroup_send(breq, be_ctx->ev,
-                                        ipa_ctx, ar->filter_value);
-+    } else if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
-+        /* if domain names do not match, this is a subdomain case
-+         * subdomain lookups are handled differently on the server
-+         * and the client
-+         */
-+        req = ipa_subdomain_account_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
-     } else {
-         /* any account request is handled by sdap,
-          * any invalid request is caught there. */
--- 
-2.4.11
-
diff --git a/SOURCES/0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch b/SOURCES/0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch
new file mode 100644
index 0000000..678ec4e
--- /dev/null
+++ b/SOURCES/0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch
@@ -0,0 +1,65 @@
+From b415b9d2b6d016928a2bbcaa710cdc876e4ecc9c Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 16 Aug 2016 13:32:06 +0200
+Subject: [PATCH 113/115] LDAP: Log autofs rfc2307 config changes only with
+ enabled responder
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+grep -nE "0x0040" /var/log/sssd/sssd_example.com.log
+361:(Tue Aug 16 13:04:04 2016) [sssd[be[example.com]]]
+  [ldap_get_autofs_options] (0x0040): Your configuration uses the autofs
+  provider with schema set to rfc2307 and default attribute mappings.
+  The default map has changed in this release, please make sure
+  the configuration matches the server attributes.
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+---
+ src/providers/ldap/ldap_options.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c
+index 018f6c31fb6360952308e44979581790b8477dc3..15a2609f07506b6dd442b180651a7e25461976c0 100644
+--- a/src/providers/ldap/ldap_options.c
++++ b/src/providers/ldap/ldap_options.c
+@@ -444,6 +444,10 @@ static bool has_defaults(struct confdb_ctx *cdb,
+ static bool ldap_rfc2307_autofs_defaults(struct confdb_ctx *cdb,
+                                          const char *conf_path)
+ {
++    char **services = NULL;
++    errno_t ret;
++    bool has_autofs_defaults = false;
++
+     const char *attrs[] = {
+         rfc2307_autofs_entry_map[SDAP_OC_AUTOFS_ENTRY].opt_name,
+         /* SDAP_AT_AUTOFS_ENTRY_KEY missing on purpose, its value was
+@@ -455,7 +459,24 @@ static bool ldap_rfc2307_autofs_defaults(struct confdb_ctx *cdb,
+         NULL,
+     };
+ 
+-    return has_defaults(cdb, conf_path, attrs);
++    ret = confdb_get_string_as_list(cdb, cdb,
++                                    CONFDB_MONITOR_CONF_ENTRY,
++                                    CONFDB_MONITOR_ACTIVE_SERVICES, &services);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to read from confdb [%d]: %s\n",
++              ret, sss_strerror(ret));
++        goto done;
++    }
++
++    if (string_in_list("autofs", services, true) == false) {
++        goto done;
++    }
++
++    has_autofs_defaults = has_defaults(cdb, conf_path, attrs);
++done:
++    talloc_free(services);
++
++    return has_autofs_defaults;
+ }
+ 
+ int ldap_get_autofs_options(TALLOC_CTX *memctx,
+-- 
+2.4.11
+
diff --git a/SOURCES/0113-LDAP-Try-also-the-AD-access-control-for-IPA-users.patch b/SOURCES/0113-LDAP-Try-also-the-AD-access-control-for-IPA-users.patch
deleted file mode 100644
index ac735c0..0000000
--- a/SOURCES/0113-LDAP-Try-also-the-AD-access-control-for-IPA-users.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 01598f563378f8cf85e7a7fb0c29e7bf32518c3f Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 22 Apr 2016 18:32:26 +0200
-Subject: [PATCH] LDAP: Try also the AD access control for IPA users
-
-Resolves:
-    https://fedorahosted.org/sssd/ticket/2927
-
-If a user from an AD trusted domain is logging in, we should also check
-their AD lockout status. This helps cases where the user might have been
-disabled but is logging in with an SSH public key.
----
- src/providers/ldap/sdap_access.c | 15 +++++++++++++++
- 1 file changed, 15 insertions(+)
-
-diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
-index 3ef45b717787058ec61c4d6875cb41bb2e8195fc..14ec34508636c19b288a57cd305d874705bdb842 100644
---- a/src/providers/ldap/sdap_access.c
-+++ b/src/providers/ldap/sdap_access.c
-@@ -741,6 +741,21 @@ static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
-                 DEBUG(SSSDBG_CRIT_FAILURE,
-                       "sdap_account_expired_rhds failed.\n");
-             }
-+
-+            if (ret == EOK &&
-+                    strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0) {
-+                DEBUG(SSSDBG_TRACE_FUNC,
-+                      "IPA access control succeeded, checking AD "
-+                      "access control\n");
-+                ret = sdap_account_expired_ad(pd, user_entry);
-+                if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
-+                    DEBUG(SSSDBG_TRACE_FUNC,
-+                        "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
-+                } else if (ret != EOK) {
-+                    DEBUG(SSSDBG_CRIT_FAILURE,
-+                          "sdap_account_expired_ad failed.\n");
-+                }
-+            }
-         } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_NDS) == 0) {
-             ret = sdap_account_expired_nds(pd, user_entry);
-             if (ret == ERR_ACCESS_DENIED) {
--- 
-2.4.11
-
diff --git a/SOURCES/0114-NSS-Fix-memory-leak-netgroup.patch b/SOURCES/0114-NSS-Fix-memory-leak-netgroup.patch
deleted file mode 100644
index 7b94d48..0000000
--- a/SOURCES/0114-NSS-Fix-memory-leak-netgroup.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-From de876c0de1056008786f56aa56f1198479cb58d2 Mon Sep 17 00:00:00 2001
-From: Pavel Reichl <preichl@redhat.com>
-Date: Fri, 27 Nov 2015 07:53:00 -0500
-Subject: [PATCH] NSS: Fix memory leak netgroup
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2865
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 4231a17e66e0809a9c3d42207b45f95429cbb46c)
----
- src/responder/nss/nsssrv_netgroup.c | 41 ++++++++++++++++++++++++++-----------
- 1 file changed, 29 insertions(+), 12 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
-index c71043858988bbf6c66aaab1357d24d3701c777f..94fe3776d94a24dec03a5766c4026c3887b448aa 100644
---- a/src/responder/nss/nsssrv_netgroup.c
-+++ b/src/responder/nss/nsssrv_netgroup.c
-@@ -435,14 +435,18 @@ static errno_t create_negcache_netgr(struct setent_step_ctx *step_ctx)
-     errno_t ret;
-     struct getent_ctx *netgr;
- 
--    netgr = talloc_zero(step_ctx->nctx, struct getent_ctx);
--    if (netgr == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
--        ret = ENOMEM;
--        goto done;
--    } else {
--        netgr->ready = true;
--        netgr->found = false;
-+    /* Is there already netgroup with such name? */
-+    ret = get_netgroup_entry(step_ctx->nctx, step_ctx->name,
-+                             &netgr);
-+    if (ret != EOK || netgr == NULL) {
-+
-+        netgr = talloc_zero(step_ctx->nctx, struct getent_ctx);
-+        if (netgr == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-         netgr->entries = NULL;
-         netgr->lookup_table = step_ctx->nctx->netgroups;
-         netgr->name = talloc_strdup(netgr, step_ctx->name);
-@@ -457,13 +461,20 @@ static errno_t create_negcache_netgr(struct setent_step_ctx *step_ctx)
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_netgroup_entry failed.\n");
-             goto done;
-         }
--        set_netgr_lifetime(step_ctx->nctx->neg_timeout, step_ctx, netgr);
-     }
- 
-+    netgr->ready = true;
-+    netgr->found = false;
-+
-+    set_netgr_lifetime(step_ctx->nctx->neg_timeout, step_ctx, netgr);
-+
-+    ret = EOK;
-+
- done:
-     if (ret != EOK) {
-         talloc_free(netgr);
-     }
-+
-     return ret;
- }
- 
-@@ -474,6 +485,12 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
-     struct getent_ctx *netgr;
-     char *name = NULL;
-     uint32_t lifetime;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
- 
-     /* Check each domain for this netgroup name */
-     while (dom) {
-@@ -494,8 +511,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
-         /* make sure to update the dctx if we changed domain */
-         step_ctx->dctx->domain = dom;
- 
--        talloc_free(name);
--        name = sss_get_cased_name(step_ctx, step_ctx->name,
-+        name = sss_get_cased_name(tmp_ctx, step_ctx->name,
-                                   dom->case_sensitive);
-         if (!name) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "sss_get_cased_name failed\n");
-@@ -623,10 +639,11 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
-               "create_negcache_netgr failed with: %d:[%s], ignored.\n",
-               ret, sss_strerror(ret));
-     }
-+
-     ret = ENOENT;
- 
- done:
--    talloc_free(name);
-+    talloc_free(tmp_ctx);
-     return ret;
- }
- 
--- 
-2.4.11
-
diff --git a/SOURCES/0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch b/SOURCES/0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch
new file mode 100644
index 0000000..f59feff
--- /dev/null
+++ b/SOURCES/0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch
@@ -0,0 +1,36 @@
+From 2b8b5e03319ab72d2c74d61ec24038c5ca412661 Mon Sep 17 00:00:00 2001
+From: Justin Stephenson <jstephen@redhat.com>
+Date: Fri, 12 Aug 2016 12:12:57 -0400
+Subject: [PATCH 114/115] SSSCTL: More helpful error message when InfoPipe is
+ disabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3130
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/tools/sssctl/sssctl_sifp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/tools/sssctl/sssctl_sifp.c b/src/tools/sssctl/sssctl_sifp.c
+index 782a72d7ce8bbf1080c6d6ac988ffac2f432955f..c53119b4e199852d1d233c79a0ad3c0bc4de7470 100644
+--- a/src/tools/sssctl/sssctl_sifp.c
++++ b/src/tools/sssctl/sssctl_sifp.c
+@@ -26,7 +26,9 @@
+ #include "tools/sssctl/sssctl.h"
+ 
+ #define ERR_SSSD _("Check that SSSD is running and " \
+-                   "the InfoPipe responder is enabled.\n")
++                   "the InfoPipe responder is enabled. " \
++                   "Make sure 'ifp' is listed in the " \
++                   "'services' option in sssd.conf.\n")
+ 
+ struct sssctl_sifp_data {
+     sss_sifp_ctx *sifp;
+-- 
+2.4.11
+
diff --git a/SOURCES/0115-ipa_s2n_save_objects-use-configured-user-and-group-t.patch b/SOURCES/0115-ipa_s2n_save_objects-use-configured-user-and-group-t.patch
deleted file mode 100644
index 2829467..0000000
--- a/SOURCES/0115-ipa_s2n_save_objects-use-configured-user-and-group-t.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 8233ca6a64e673aad41f2aeb1f6152930fd16f72 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 5 Jan 2016 13:46:55 +0100
-Subject: [PATCH] ipa_s2n_save_objects(): use configured user and group timeout
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves https://fedorahosted.org/sssd/ticket/2899
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit acce97e8d97e81a9e660d46c4e3c00bcb423c035)
-(cherry picked from commit e8b5470df44c9f4eb0a4ccc0c79efe778c9658ba)
----
- src/providers/ipa/ipa_s2n_exop.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index bcd11749fbde4cae2a47b9b2182138ae04f2d6bc..d101a437dfaf2829013f9e3e3705a7161c654d78 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -1743,7 +1743,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
- {
-     int ret;
-     time_t now;
--    uint64_t timeout = 10*60*60; /* FIXME: find a better timeout ! */
-     struct sss_nss_homedir_ctx homedir_ctx;
-     char *name = NULL;
-     char *realm;
-@@ -1947,7 +1946,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-                  * SYSDB_INITGR_EXPIRE will be set.*/
-                 ret = sysdb_attrs_add_time_t(attrs->sysdb_attrs,
-                                              SYSDB_INITGR_EXPIRE,
--                                             time(NULL) + timeout);
-+                                             time(NULL) + dom->user_timeout);
-                 if (ret != EOK) {
-                     DEBUG(SSSDBG_OP_FAILURE,
-                           "sysdb_attrs_add_time_t failed.\n");
-@@ -2006,7 +2005,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-                                    gid, attrs->a.user.pw_gecos,
-                                    attrs->a.user.pw_dir, attrs->a.user.pw_shell,
-                                    NULL, attrs->sysdb_attrs, NULL,
--                                   timeout, now);
-+                                   dom->user_timeout, now);
-             if (ret == EEXIST && dom->mpg == true) {
-                 /* This handles the case where getgrgid() was called for
-                  * this user, so a group was created in the cache
-@@ -2034,7 +2033,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-                                        attrs->a.user.pw_dir,
-                                        attrs->a.user.pw_shell,
-                                        NULL, attrs->sysdb_attrs, NULL,
--                                       timeout, now);
-+                                       dom->user_timeout, now);
-                 if (ret != EOK) {
-                     DEBUG(SSSDBG_OP_FAILURE,
-                           "sysdb_store_user failed for MPG user [%d]: %s\n",
-@@ -2174,7 +2173,8 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-             }
- 
-             ret = sysdb_store_group(dom, name, attrs->a.group.gr_gid,
--                                    attrs->sysdb_attrs, timeout, now);
-+                                    attrs->sysdb_attrs, dom->group_timeout,
-+                                    now);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_group failed.\n");
-                 goto done;
--- 
-2.4.11
-
diff --git a/SOURCES/0115-sdap-Skip-exact-duplicates-when-extending-maps.patch b/SOURCES/0115-sdap-Skip-exact-duplicates-when-extending-maps.patch
new file mode 100644
index 0000000..cfd3300
--- /dev/null
+++ b/SOURCES/0115-sdap-Skip-exact-duplicates-when-extending-maps.patch
@@ -0,0 +1,111 @@
+From c4379aa97754b4c4cfc02663315b7c6319e3fa61 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 10 Aug 2016 15:41:34 +0200
+Subject: [PATCH 115/115] sdap: Skip exact duplicates when extending maps
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When extending map with entry that already
+exists in the map in the exacty same form,
+then there is no need to fail.
+
+We should only fail if we try to
+change purpose of already used sysdb
+attribute.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3120
+
+Signed-off-by: Lukas Slebodnik <lslebodn@redhat.com>
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ldap/sdap.c | 42 ++++++++++++++++++++++++++++++++----------
+ 1 file changed, 32 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
+index 97b8f126d4ed6bc59c510d5763789a458bd4863a..dc7d5e0caf223c3ee3c43054aa44e796f1b37766 100644
+--- a/src/providers/ldap/sdap.c
++++ b/src/providers/ldap/sdap.c
+@@ -122,19 +122,30 @@ static errno_t split_extra_attr(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
+-static bool is_sysdb_duplicate(struct sdap_attr_map *map,
+-                               int num_entries,
+-                               const char *sysdb_attr)
++enum duplicate_t {
++    NOT_FOUND = 0,
++    ALREADY_IN_MAP, /* nothing to add */
++    CONFLICT_WITH_MAP /* attempt to redefine attribute */
++};
++
++static enum duplicate_t check_duplicate(struct sdap_attr_map *map,
++                                        int num_entries,
++                                        const char *sysdb_attr,
++                                        const char *ldap_attr)
+ {
+     int i;
+ 
+     for (i = 0; i < num_entries; i++) {
+         if (strcmp(map[i].sys_name, sysdb_attr) == 0) {
+-            return true;
++            if (strcmp(map[i].name, ldap_attr) == 0) {
++                return ALREADY_IN_MAP;
++            } else {
++                return CONFLICT_WITH_MAP;
++            }
+         }
+     }
+ 
+-    return false;
++    return NOT_FOUND;
+ }
+ 
+ int sdap_extend_map(TALLOC_CTX *memctx,
+@@ -167,14 +178,20 @@ int sdap_extend_map(TALLOC_CTX *memctx,
+         return ENOMEM;
+     }
+ 
+-    for (i = 0; extra_attrs[i]; i++) {
+-        ret = split_extra_attr(map, extra_attrs[i], &sysdb_attr, &ldap_attr);
++    for (i = 0; *extra_attrs != NULL; extra_attrs++) {
++        ret = split_extra_attr(map, *extra_attrs, &sysdb_attr, &ldap_attr);
+         if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot split %s\n", extra_attrs[i]);
++            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot split %s\n", *extra_attrs);
+             continue;
+         }
+ 
+-        if (is_sysdb_duplicate(map, num_entries, sysdb_attr)) {
++        ret = check_duplicate(map, num_entries, sysdb_attr, ldap_attr);
++        if (ret == ALREADY_IN_MAP) {
++            DEBUG(SSSDBG_TRACE_FUNC,
++                  "Attribute %s (%s in LDAP) is already in map.\n",
++                  sysdb_attr, ldap_attr);
++            continue;
++        } else if (ret == CONFLICT_WITH_MAP) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+                   "Attribute %s (%s in LDAP) is already used by SSSD, please "
+                   "choose a different cache name\n", sysdb_attr, ldap_attr);
+@@ -193,9 +210,14 @@ int sdap_extend_map(TALLOC_CTX *memctx,
+             map[num_entries+i].def_name == NULL) {
+             return ENOMEM;
+         }
+-        DEBUG(SSSDBG_TRACE_FUNC, "Extending map with %s\n", extra_attrs[i]);
++        DEBUG(SSSDBG_TRACE_FUNC, "Extending map with %s\n", *extra_attrs);
++
++        /* index must be incremented only for appended entry. */
++        i++;
+     }
+ 
++    nextra = i;
++
+     /* Sentinel */
+     memset(&map[num_entries+nextra], 0, sizeof(struct sdap_attr_map));
+ 
+-- 
+2.4.11
+
diff --git a/SOURCES/0116-IPA-use-forest-name-when-looking-up-the-Global-Catal.patch b/SOURCES/0116-IPA-use-forest-name-when-looking-up-the-Global-Catal.patch
deleted file mode 100644
index 164e78d..0000000
--- a/SOURCES/0116-IPA-use-forest-name-when-looking-up-the-Global-Catal.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0a7c43151c362bf8e7276fc1d08c49cb91fdb005 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 17 May 2016 11:54:10 +0200
-Subject: [PATCH] IPA: use forest name when looking up the Global Catalog
-
-Resolves https://fedorahosted.org/sssd/ticket/3015
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 149174acae677d1e72a0da431bf0850d55f2ccb4)
----
- src/providers/ipa/ipa_subdomains_server.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index c561118946e2ba76b2b4076e5057b1b5c0075a41..b75266701904d8bd1723bc277ae96d407f90f30d 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -249,7 +249,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
-         DEBUG(SSSDBG_TRACE_ALL, "No extra attrs set.\n");
-     }
- 
--    gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
-+    gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->forest);
-     if (gc_service_name == NULL) {
-         talloc_free(ad_options);
-         return ENOMEM;
--- 
-2.4.11
-
diff --git a/SOURCES/0116-watchdog-cope-with-time-shift.patch b/SOURCES/0116-watchdog-cope-with-time-shift.patch
new file mode 100644
index 0000000..dbea5c2
--- /dev/null
+++ b/SOURCES/0116-watchdog-cope-with-time-shift.patch
@@ -0,0 +1,96 @@
+From c99c5bb88c8b02f24a2b0b15ea8bc9fe2a8dc6c4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 22 Aug 2016 13:15:04 +0200
+Subject: [PATCH 116/117] watchdog: cope with time shift
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When a time is changed into the past during sssd runtime
+(e.g. on boot during time correction), it is possible that
+we never hit watchdog tevent timer since it is based on
+system time.
+
+This patch adds a past-time shift detection mechanism. If a time
+shift is detected we restart watchdog.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3154
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+---
+ src/util/util_watchdog.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c
+index 5032fddba1b94b3fc7e560162c392dfa57d699cf..1c27d73f13b3042ecb549a2184e1368e8339d199 100644
+--- a/src/util/util_watchdog.c
++++ b/src/util/util_watchdog.c
+@@ -29,8 +29,39 @@ struct watchdog_ctx {
+     struct timeval interval;
+     struct tevent_timer *te;
+     volatile int ticks;
++
++    /* To detect time shift. */
++    struct tevent_context *ev;
++    int input_interval;
++    time_t timestamp;
+ } watchdog_ctx;
+ 
++static bool watchdog_detect_timeshift(void)
++{
++    time_t prev_time;
++    time_t cur_time;
++    errno_t ret;
++
++    prev_time = watchdog_ctx.timestamp;
++    cur_time = watchdog_ctx.timestamp = time(NULL);
++    if (cur_time < prev_time) {
++        /* Time shift detected. We need to restart watchdog. */
++        DEBUG(SSSDBG_IMPORTANT_INFO, "Time shift detected, "
++              "restarting watchdog!\n");
++        teardown_watchdog();
++        ret = setup_watchdog(watchdog_ctx.ev, watchdog_ctx.input_interval);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_FATAL_FAILURE, "Unable to restart watchdog "
++                  "[%d]: %s\n", ret, sss_strerror(ret));
++            orderly_shutdown(1);
++        }
++
++        return true;
++    }
++
++    return false;
++}
++
+ /* the watchdog is purposefully *not* handled by the tevent
+  * signal handler as it is meant to check if the daemon is
+  * still processing the event queue itself. A stuck process
+@@ -38,6 +69,12 @@ struct watchdog_ctx {
+  * signals either */
+ static void watchdog_handler(int sig)
+ {
++    /* Do not count ticks if time shift was detected
++     * since watchdog was restarted. */
++    if (watchdog_detect_timeshift()) {
++        return;
++    }
++
+     /* if 3 ticks passed by kills itself */
+ 
+     if (__sync_add_and_fetch(&watchdog_ctx.ticks, 1) > 3) {
+@@ -101,6 +138,10 @@ int setup_watchdog(struct tevent_context *ev, int interval)
+     watchdog_ctx.interval.tv_sec = interval;
+     watchdog_ctx.interval.tv_usec = 0;
+ 
++    watchdog_ctx.ev = ev;
++    watchdog_ctx.input_interval = interval;
++    watchdog_ctx.timestamp = time(NULL);
++
+     /* Start the timer */
+     /* we give 1 second head start to the watchdog event */
+     its.it_value.tv_sec = interval + 1;
+-- 
+2.4.11
+
diff --git a/SOURCES/0117-LDAP-Fix-leak-of-file-descriptors.patch b/SOURCES/0117-LDAP-Fix-leak-of-file-descriptors.patch
deleted file mode 100644
index 0db92d2..0000000
--- a/SOURCES/0117-LDAP-Fix-leak-of-file-descriptors.patch
+++ /dev/null
@@ -1,113 +0,0 @@
-From bb3365aee62f616c9d0c8cc8d737ef69d46544d3 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Thu, 22 Oct 2015 10:30:12 +0200
-Subject: [PATCH 117/117] LDAP: Fix leak of file descriptors
-
-The state "struct sss_ldap_init_state" contains socket
-created in function sss_ldap_init_send. We register callback
-sdap_async_sys_connect_timeout for handling issue with connection
-
-The tevent request "sss_ldap_init_send" is usually (nested) subrequest
-of "struct resolve_service_state" related request created in fucntion
-fo_resolve_service_send. Function fo_resolve_service_send also register
-timeout callback fo_resolve_service_timeout to state "struct
-resolve_service_state".
-
-It might happen that fo_resolve_service_timeout will be called before
-sss_ldap_init_send timeout and we could not handle tiemout error
-for state "struct sss_ldap_init_state" and therefore created socket
-was not closed.
-
-We tried to release resources in function sdap_handle_release.
-But the structure "struct sdap_handle" had not been initialized yet
-with LDAP handle and therefore associated file descriptor could not be closed.
-
-[fo_resolve_service_timeout] (0x0080): Service resolving timeout reached
-[fo_resolve_service_recv] (0x0020): TEVENT_REQ_RETURN_ON_ERROR ret[110]
-[sdap_handle_release] (0x2000): Trace: sh[0x7f6713410270], connected[0], ops[(nil)], ldap[(nil)], destructor_lock[0], release_memory
-[be_resolve_server_done] (0x1000): Server resolution failed: 14
-[be_resolve_server_recv] (0x0020): TEVENT_REQ_RETURN_ON_ERROR ret[14]
-[check_online_callback] (0x0100): Backend returned: (1, 0, <NULL>) [Provider is Offline (Success)]
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/2792
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit a10f67d4c64f3b1243de5d86a996475361adf0ac)
-(cherry picked from commit db2fdba6f3cecd0612439988e61be60d5d8576bf)
-(cherry picked from commit 2136f71c94660bcdde83f80feb83734389d57674)
----
- src/util/sss_ldap.c | 29 +++++++++++++++++++++--------
- 1 file changed, 21 insertions(+), 8 deletions(-)
-
-diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
-index dd63b4b4f22f0aa1b540bc04ede211ac9cb88ebe..f42f9404bb9b79cdeb6a01c0a6e5025bb0370a6c 100644
---- a/src/util/sss_ldap.c
-+++ b/src/util/sss_ldap.c
-@@ -304,6 +304,22 @@ struct sss_ldap_init_state {
- #endif
- };
- 
-+static int sss_ldap_init_state_destructor(void *data)
-+{
-+    struct sss_ldap_init_state *state = (struct sss_ldap_init_state *)data;
-+
-+    if (state->ldap) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "calling ldap_unbind_ext for ldap:[%p] sd:[%d]\n",
-+              state->ldap, state->sd);
-+        ldap_unbind_ext(state->ldap, NULL, NULL);
-+    } else if (state->sd != -1) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
-+        close(state->sd);
-+    }
-+
-+    return 0;
-+}
- 
- struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
-                                       struct tevent_context *ev,
-@@ -321,6 +337,8 @@ struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
-         return NULL;
-     }
- 
-+    talloc_set_destructor((TALLOC_CTX *)state, sss_ldap_init_state_destructor);
-+
-     state->ldap = NULL;
-     state->uri = uri;
- 
-@@ -370,9 +388,6 @@ struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
-     return req;
- 
- fail:
--    if(state->sd >= 0) {
--        close(state->sd);
--    }
-     tevent_req_error(req, ret);
- #else
-     DEBUG(SSSDBG_MINOR_FAILURE, "ldap_init_fd not available, "
-@@ -455,11 +470,6 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
-     return;
- 
- fail:
--    if (state->ldap) {
--        ldap_unbind_ext(state->ldap, NULL, NULL);
--    } else {
--        close(state->sd);
--    }
-     tevent_req_error(req, ret);
- }
- #endif
-@@ -470,6 +480,9 @@ int sss_ldap_init_recv(struct tevent_req *req, LDAP **ldap, int *sd)
-                                                     struct sss_ldap_init_state);
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
-+    /* Everything went well therefore we do not want to release resources */
-+    talloc_set_destructor(state, NULL);
-+
-     *ldap = state->ldap;
-     *sd = state->sd;
- 
--- 
-2.4.11
-
diff --git a/SOURCES/0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch b/SOURCES/0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch
new file mode 100644
index 0000000..a41eedb
--- /dev/null
+++ b/SOURCES/0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch
@@ -0,0 +1,39 @@
+From fe4117b3203c0464b1366066bf09d83978c632d8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Tue, 23 Aug 2016 23:46:59 +0200
+Subject: [PATCH 117/117] PROXY: Use the fqname when converting to lowercase
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When saving the user there is a comparison between the "cased alias"
+and the "lowercase password name". However, the first doesn't use fully
+qualified name while the second does, resulting in a not expected
+override of the "nameAlias" attribute of a stored user when trying to
+authenticate more than once using an alias.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3134
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/proxy/proxy_id.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
+index f633a5e1c71dfc7f8d124e62169cfda48773bbb1..df8a329d4a5a4bd7ed7723d0219089e7b4ef639d 100644
+--- a/src/providers/proxy/proxy_id.c
++++ b/src/providers/proxy/proxy_id.c
+@@ -256,7 +256,7 @@ static int save_user(struct sss_domain_info *domain,
+     }
+ 
+     if (lowercase) {
+-        lc_pw_name = sss_tc_utf8_str_tolower(attrs, pwd->pw_name);
++        lc_pw_name = sss_tc_utf8_str_tolower(attrs, real_name);
+         if (lc_pw_name == NULL) {
+             DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
+             ret = ENOMEM;
+-- 
+2.4.11
+
diff --git a/SOURCES/0118-BUILD-Allow-to-read-private-pipes-for-root.patch b/SOURCES/0118-BUILD-Allow-to-read-private-pipes-for-root.patch
new file mode 100644
index 0000000..8d87aad
--- /dev/null
+++ b/SOURCES/0118-BUILD-Allow-to-read-private-pipes-for-root.patch
@@ -0,0 +1,81 @@
+From 711a29023252013a8451ee1b90f045782fee1a38 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 19 Aug 2016 10:46:12 +0200
+Subject: [PATCH 118/121] BUILD: Allow to read private pipes for root
+
+Root can read anything from any directory even with permissions 000.
+
+However SELinux checks discretionary access control (DAC)
+and deny access if access is not allowed for root by DAC.
+The pam_sss use different unix socket /var/lib/sss/pipes/private/pam
+for user with uid 0. Therefore root need to be able read content
+of directory with private pipes.
+
+type=AVC msg=audit(08/19/2016 10:58:34.081:3369) : avc:  denied
+  { dac_read_search } for  pid=20257 comm=vsftpd capability=dac_read_search
+  scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023
+  tcontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tclass=capability
+
+type=AVC msg=audit(08/19/2016 10:58:34.081:3369) : avc:  denied
+  { dac_override } for  pid=20257 comm=vsftpd capability=dac_override
+  scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023
+  tcontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tclass=capability
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3143
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am          | 8 ++++----
+ contrib/sssd.spec.in | 2 +-
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 6ab4399d5b68644668198bc9b0e3056562a4e51a..b8cd8b64ca8a130a5dd3107e1fb1445310192059 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3967,7 +3967,6 @@ SSSD_USER_DIRS = \
+     $(DESTDIR)$(keytabdir) \
+     $(DESTDIR)$(mcpath) \
+     $(DESTDIR)$(pipepath) \
+-    $(DESTDIR)$(pipepath)/private \
+     $(DESTDIR)$(pubconfpath) \
+     $(DESTDIR)$(pubconfpath)/krb5.include.d \
+     $(DESTDIR)$(gpocachepath) \
+@@ -3994,16 +3993,17 @@ installsssddirs::
+     $(DESTDIR)$(sssddatadir) \
+     $(DESTDIR)$(sudolibdir) \
+     $(DESTDIR)$(autofslibdir) \
++    $(DESTDIR)$(pipepath)/private \
+     $(SSSD_USER_DIRS) \
+     $(NULL);
+ if SSSD_USER
+-	-chown $(SSSD_USER):$(SSSD_USER) \
+-	$(SSSD_USER_DIRS)
++	-chown $(SSSD_USER):$(SSSD_USER) $(SSSD_USER_DIRS)
++	-chown $(SSSD_USER) $(DESTDIR)$(pipepath)/private
+ endif
+ 	$(INSTALL) -d -m 0700 $(DESTDIR)$(dbpath) $(DESTDIR)$(logpath) \
+-            $(DESTDIR)$(pipepath)/private \
+ 	    $(DESTDIR)$(keytabdir) \
+ 	    $(NULL)
++	$(INSTALL) -d -m 0750 $(DESTDIR)$(pipepath)/private
+ 	$(INSTALL) -d -m 0755 $(DESTDIR)$(mcpath) $(DESTDIR)$(pipepath) \
+             $(DESTDIR)$(pubconfpath) \
+             $(DESTDIR)$(pubconfpath)/krb5.include.d $(DESTDIR)$(gpocachepath)
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index f1ff16176cb8ca974b98948958cfa1e9290b0bca..cb68a73e85122b016de7df37bcf4fc232a10a2ac 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -784,7 +784,7 @@ done
+ %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
+ %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups
+ %attr(755,sssd,sssd) %dir %{pipepath}
+-%attr(700,sssd,sssd) %dir %{pipepath}/private
++%attr(750,sssd,root) %dir %{pipepath}/private
+ %attr(755,sssd,sssd) %dir %{pubconfpath}
+ %attr(755,sssd,sssd) %dir %{gpocachepath}
+ %attr(750,sssd,sssd) %dir %{_var}/log/%{name}
+-- 
+2.4.11
+
diff --git a/SOURCES/0118-libwbclient-wbcSidsToUnixIds-don-t-fail-on-errors.patch b/SOURCES/0118-libwbclient-wbcSidsToUnixIds-don-t-fail-on-errors.patch
deleted file mode 100644
index 9bda53e..0000000
--- a/SOURCES/0118-libwbclient-wbcSidsToUnixIds-don-t-fail-on-errors.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 02a5b8945863755e8708b6a11954c1f398680e01 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 2 Jun 2016 21:01:11 +0200
-Subject: [PATCH 118/118] libwbclient: wbcSidsToUnixIds() don't fail on errors
-
-Resolves: https://fedorahosted.org/sssd/ticket/3028
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-(cherry picked from commit 52f1093ef3d7c44132ec10c57436865b2cbb19d7)
-(cherry picked from commit 15ad5f603a5797c61a01f67365c2581c7bddcdfa)
----
- src/sss_client/libwbclient/wbc_idmap_sssd.c | 15 +++++++--------
- 1 file changed, 7 insertions(+), 8 deletions(-)
-
-diff --git a/src/sss_client/libwbclient/wbc_idmap_sssd.c b/src/sss_client/libwbclient/wbc_idmap_sssd.c
-index 1b0e2e10a5ce1a0c7577d391b740ff988f920903..6b5f525f0433c948e4d570d177dc6cffd82eff40 100644
---- a/src/sss_client/libwbclient/wbc_idmap_sssd.c
-+++ b/src/sss_client/libwbclient/wbc_idmap_sssd.c
-@@ -172,15 +172,14 @@ wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids,
-     wbcErr wbc_status;
- 
-     for (c = 0; c < num_sids; c++) {
-+        type = SSS_ID_TYPE_NOT_SPECIFIED;
-         wbc_status = wbcSidToString(&sids[c], &sid_str);
--        if (!WBC_ERROR_IS_OK(wbc_status)) {
--            return wbc_status;
--        }
--
--        ret = sss_nss_getidbysid(sid_str, &id, &type);
--        wbcFreeMemory(sid_str);
--        if (ret != 0) {
--            return WBC_ERR_UNKNOWN_FAILURE;
-+        if (WBC_ERROR_IS_OK(wbc_status)) {
-+            ret = sss_nss_getidbysid(sid_str, &id, &type);
-+            wbcFreeMemory(sid_str);
-+            if (ret != 0) {
-+                type = SSS_ID_TYPE_NOT_SPECIFIED;
-+            }
-         }
- 
-         switch (type) {
--- 
-2.4.11
-
diff --git a/SOURCES/0119-IPA-ldap_group_external_member-defaults-to-ipaExtern.patch b/SOURCES/0119-IPA-ldap_group_external_member-defaults-to-ipaExtern.patch
deleted file mode 100644
index beab91b..0000000
--- a/SOURCES/0119-IPA-ldap_group_external_member-defaults-to-ipaExtern.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From fe540303e8fa2000160d087da4f19df317fb7de6 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 14 Jul 2016 12:21:25 +0200
-Subject: [PATCH 119/119] IPA: ldap_group_external_member defaults to
- ipaExternalMember
-
----
- 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 81ccc42fc0c9f21c8ef16e2d1735bc06199ba747..c1bfc9fde38a9c0fbd0a464b340e644cc4835455 100644
---- a/src/providers/ipa/ipa_opts.h
-+++ b/src/providers/ipa/ipa_opts.h
-@@ -221,7 +221,7 @@ struct sdap_attr_map ipa_group_map[] = {
-     { "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 },
--    { "ldap_group_external_member", NULL, SYSDB_EXTERNAL_MEMBER, NULL },
-+    { "ldap_group_external_member", "ipaExternalMember", SYSDB_EXTERNAL_MEMBER, NULL },
-     SDAP_ATTR_MAP_TERMINATOR
- };
- 
--- 
-2.4.11
-
diff --git a/SOURCES/0119-SYSDB-Rework-sysdb_cache_connect.patch b/SOURCES/0119-SYSDB-Rework-sysdb_cache_connect.patch
new file mode 100644
index 0000000..bc2bacb
--- /dev/null
+++ b/SOURCES/0119-SYSDB-Rework-sysdb_cache_connect.patch
@@ -0,0 +1,123 @@
+From 960eca66245f23cf8ae0f32c3e44581a0e1117f9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Tue, 16 Aug 2016 11:20:49 +0200
+Subject: [PATCH 119/121] SYSDB: Rework sysdb_cache_connect()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+As sysdb_cache_connect() has two very specific use cases (connect to the
+cache and connect to the timestamp cache) and each of those calls have a
+predetermined/fixed sets of values for a few parameters, let's try to
+make the code a bit simpler to follow by having explicit functions for
+connecting to the cache and connecting to the timestamp cache.
+
+Macros could be used as well, but I have a slightly preference for
+having two new functions instead of macros accessing internal parameters
+of the macro's parameter.
+
+Related:
+https://fedorahosted.org/sssd/ticket/3128
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb_init.c | 53 ++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 34 insertions(+), 19 deletions(-)
+
+diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
+index 9e3646bfeb9a494ebff2d348ab1c53336f8a5c03..59934701c4d2b9d770385a202af058404a6d3eb9 100644
+--- a/src/db/sysdb_init.c
++++ b/src/db/sysdb_init.c
+@@ -511,14 +511,14 @@ done:
+     return ret;
+ }
+ 
+-static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx,
+-                                   struct sss_domain_info *domain,
+-                                   const char *ldb_file,
+-                                   int flags,
+-                                   const char *exp_version,
+-                                   const char *base_ldif,
+-                                   struct ldb_context **_ldb,
+-                                   const char **_version)
++static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx,
++                                          struct sss_domain_info *domain,
++                                          const char *ldb_file,
++                                          int flags,
++                                          const char *exp_version,
++                                          const char *base_ldif,
++                                          struct ldb_context **_ldb,
++                                          const char **_version)
+ {
+     TALLOC_CTX *tmp_ctx = NULL;
+     struct ldb_message_element *el;
+@@ -619,6 +619,29 @@ done:
+     return ret;
+ }
+ 
++static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx,
++                                   struct sysdb_ctx *sysdb,
++                                   struct sss_domain_info *domain,
++                                   struct ldb_context **ldb,
++                                   const char **version)
++{
++    return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_file,
++                                      0, SYSDB_VERSION, SYSDB_BASE_LDIF,
++                                      ldb, version);
++}
++
++static errno_t sysdb_ts_cache_connect(TALLOC_CTX *mem_ctx,
++                                      struct sysdb_ctx *sysdb,
++                                      struct sss_domain_info *domain,
++                                      struct ldb_context **ldb,
++                                      const char **version)
++{
++    return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_ts_file,
++                                      LDB_FLG_NOSYNC, SYSDB_TS_VERSION,
++                                      SYSDB_TS_BASE_LDIF,
++                                      ldb, version);
++}
++
+ static errno_t remove_ts_cache(struct sysdb_ctx *sysdb)
+ {
+     errno_t ret;
+@@ -649,9 +672,7 @@ static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb,
+         return ENOMEM;
+     }
+ 
+-    ret = sysdb_cache_connect(tmp_ctx, domain, sysdb->ldb_file, 0,
+-                              SYSDB_VERSION, SYSDB_BASE_LDIF,
+-                              &ldb, &version);
++    ret = sysdb_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version);
+     switch (ret) {
+     case ERR_SYSDB_VERSION_TOO_OLD:
+         if (upgrade_ctx == NULL) {
+@@ -731,10 +752,7 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb,
+         return ENOMEM;
+     }
+ 
+-    ret = sysdb_cache_connect(tmp_ctx, domain,
+-                              sysdb->ldb_ts_file, LDB_FLG_NOSYNC,
+-                              SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF,
+-                              &ldb, &version);
++    ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version);
+     switch (ret) {
+     case ERR_SYSDB_VERSION_TOO_OLD:
+         if (upgrade_ctx == NULL) {
+@@ -801,10 +819,7 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb,
+         /* Now the connect must succeed because the previous cache doesn't
+          * exist anymore.
+          */
+-        ret = sysdb_cache_connect(tmp_ctx, domain,
+-                                  sysdb->ldb_ts_file, LDB_FLG_NOSYNC,
+-                                  SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF,
+-                                  &ldb, &version);
++        ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+                   "Could not delete the timestamp ldb file (%d) (%s)\n",
+-- 
+2.4.11
+
diff --git a/SOURCES/0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch b/SOURCES/0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch
new file mode 100644
index 0000000..9145773
--- /dev/null
+++ b/SOURCES/0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch
@@ -0,0 +1,151 @@
+From 9e5fc47e6636f6a149dba9a0a708892be85a6f22 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Tue, 16 Aug 2016 11:46:41 +0200
+Subject: [PATCH 120/121] SYSDB: Remove the timestamp cache for a newly created
+ cache
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+As many users are used to remove the persistent cache without removing
+the timestamp cache, let's throw away the timestamp cache in this case.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3128
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb_init.c | 69 ++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 47 insertions(+), 22 deletions(-)
+
+diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
+index 59934701c4d2b9d770385a202af058404a6d3eb9..c387c1b12c116f38d5a13f1adeac5ef64d593af8 100644
+--- a/src/db/sysdb_init.c
++++ b/src/db/sysdb_init.c
+@@ -511,12 +511,30 @@ done:
+     return ret;
+ }
+ 
++static errno_t remove_ts_cache(struct sysdb_ctx *sysdb)
++{
++    errno_t ret;
++
++    if (sysdb->ldb_ts_file == NULL) {
++        return EOK;
++    }
++
++    ret = unlink(sysdb->ldb_ts_file);
++    if (ret != EOK && errno != ENOENT) {
++        return errno;
++    }
++
++    return EOK;
++}
++
+ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx,
++                                          struct sysdb_ctx *sysdb,
+                                           struct sss_domain_info *domain,
+                                           const char *ldb_file,
+                                           int flags,
+                                           const char *exp_version,
+                                           const char *base_ldif,
++                                          bool *_newly_created,
+                                           struct ldb_context **_ldb,
+                                           const char **_version)
+ {
+@@ -527,6 +545,7 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx,
+     const char *version = NULL;
+     int ret;
+     struct ldb_context *ldb;
++    bool newly_created;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (!tmp_ctx) {
+@@ -592,8 +611,9 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    /* The cache has been newly created.
+-     * We need to reopen the LDB to ensure that
++    newly_created = true;
++
++    /* We need to reopen the LDB to ensure that
+      * all of the special values take effect
+      * (such as enabling the memberOf plugin and
+      * the various indexes).
+@@ -613,6 +633,9 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx,
+     }
+ done:
+     if (ret == EOK) {
++        if (_newly_created != NULL) {
++            *_newly_created = newly_created;
++        }
+         *_ldb = talloc_steal(mem_ctx, ldb);
+     }
+     talloc_free(tmp_ctx);
+@@ -625,9 +648,27 @@ static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx,
+                                    struct ldb_context **ldb,
+                                    const char **version)
+ {
+-    return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_file,
++    bool newly_created;
++    bool ldb_file_exists;
++    errno_t ret;
++
++    ldb_file_exists = !(access(sysdb->ldb_file, F_OK) == -1 && errno == ENOENT);
++
++    ret = sysdb_cache_connect_helper(mem_ctx, sysdb, domain, sysdb->ldb_file,
+                                       0, SYSDB_VERSION, SYSDB_BASE_LDIF,
+-                                      ldb, version);
++                                      &newly_created, ldb, version);
++
++    /* The cache has been newly created. */
++    if (ret == EOK && newly_created && !ldb_file_exists) {
++        ret = remove_ts_cache(sysdb);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Could not delete the timestamp ldb file (%d) (%s)\n",
++                  ret, sss_strerror(ret));
++        }
++    }
++
++    return ret;
+ }
+ 
+ static errno_t sysdb_ts_cache_connect(TALLOC_CTX *mem_ctx,
+@@ -636,28 +677,12 @@ static errno_t sysdb_ts_cache_connect(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context **ldb,
+                                       const char **version)
+ {
+-    return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_ts_file,
++    return sysdb_cache_connect_helper(mem_ctx, sysdb, domain, sysdb->ldb_ts_file,
+                                       LDB_FLG_NOSYNC, SYSDB_TS_VERSION,
+-                                      SYSDB_TS_BASE_LDIF,
++                                      SYSDB_TS_BASE_LDIF, NULL,
+                                       ldb, version);
+ }
+ 
+-static errno_t remove_ts_cache(struct sysdb_ctx *sysdb)
+-{
+-    errno_t ret;
+-
+-    if (sysdb->ldb_ts_file == NULL) {
+-        return EOK;
+-    }
+-
+-    ret = unlink(sysdb->ldb_ts_file);
+-    if (ret != EOK && errno != ENOENT) {
+-        return errno;
+-    }
+-
+-    return EOK;
+-}
+-
+ static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb,
+                                       struct sss_domain_info *domain,
+                                       struct sysdb_dom_upgrade_ctx *upgrade_ctx)
+-- 
+2.4.11
+
diff --git a/SOURCES/0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch b/SOURCES/0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch
new file mode 100644
index 0000000..80ff5bb
--- /dev/null
+++ b/SOURCES/0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch
@@ -0,0 +1,47 @@
+From 0f3b872aa881d5480fc98b0cfc7421ffc7f802a3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Wed, 17 Aug 2016 13:12:21 +0200
+Subject: [PATCH 121/121] SECRETS: Return ENOENT when_deleting a non-existent
+ secret
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For this, just make use of the sysdb_error_to_errno() function.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3125
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/secrets/local.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
+index 17469249b357cbdc5e50ddff6b563fdf2f377577..ac3049b62fa77f69d44ec5792139fe3378afb3f4 100644
+--- a/src/responder/secrets/local.c
++++ b/src/responder/secrets/local.c
+@@ -375,15 +375,10 @@ int local_db_delete(TALLOC_CTX *mem_ctx,
+     int ret;
+ 
+     ret = local_db_dn(mem_ctx, lctx->ldb, req_path, &dn);
+-    if (ret != EOK) goto done;
++    if (ret != EOK) return ret;
+ 
+     ret = ldb_delete(lctx->ldb, dn);
+-    if (ret != EOK) {
+-        ret = EIO;
+-    }
+-
+-done:
+-    return ret;
++    return sysdb_error_to_errno(ret);
+ }
+ 
+ int local_db_create(TALLOC_CTX *mem_ctx,
+-- 
+2.4.11
+
diff --git a/SOURCES/0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch b/SOURCES/0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch
new file mode 100644
index 0000000..8bc504d
--- /dev/null
+++ b/SOURCES/0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch
@@ -0,0 +1,61 @@
+From b93f618189d9906802c79d3090fcc477f762e6e6 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 9 Aug 2016 22:08:27 +0200
+Subject: [PATCH 122/126] IPA: Parse qualified names when guessing AD user
+ principal
+
+Most AD users store their UPN in an attribute. If they don't, or the sssd
+was configured (typically in earlier versions to work around a bug) to not
+look at the principal attribute, then sssd is supposed to guess
+the attribute.
+
+That currently doesn't work in 1.14, because the username is already
+qualified and then we also append the realm name to it. We need to parse
+the simple username from the qualified name first.
+
+The issue can be reproduced simply by authenticating as the Administrator
+account in IPA-AD trust setups.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3127
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 255dad45037a6cb8f399bf2df500215f6fb25b59..bfa6757046282d656627aa57cb9054b09facd2b8 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1941,6 +1941,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     struct sss_nss_homedir_ctx homedir_ctx;
+     char *name = NULL;
+     char *realm;
++    char *short_name = NULL;
+     char *upn = NULL;
+     gid_t gid;
+     gid_t orig_gid = 0;
+@@ -2092,8 +2093,17 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                     ret = ENOMEM;
+                     goto done;
+                 }
+-                upn = talloc_asprintf(tmp_ctx, "%s@%s",
+-                                      attrs->a.user.pw_name, realm);
++
++                ret = sss_parse_internal_fqname(tmp_ctx, attrs->a.user.pw_name,
++                                                &short_name, NULL);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Cannot parse internal name %s\n",
++                          attrs->a.user.pw_name);
++                    goto done;
++                }
++
++                upn = talloc_asprintf(tmp_ctx, "%s@%s", short_name, realm);
+                 if (!upn) {
+                     DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n");
+                     ret = ENOMEM;
+-- 
+2.4.11
+
diff --git a/SOURCES/0123-SYSDB-Fix-uninitialized-scalar-variable.patch b/SOURCES/0123-SYSDB-Fix-uninitialized-scalar-variable.patch
new file mode 100644
index 0000000..d9897ba
--- /dev/null
+++ b/SOURCES/0123-SYSDB-Fix-uninitialized-scalar-variable.patch
@@ -0,0 +1,35 @@
+From d6ecd69f63496446d23252426de41523ebe2bbf6 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 29 Aug 2016 09:13:49 +0200
+Subject: [PATCH 123/126] SYSDB: Fix uninitialized scalar variable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The boolean variable newly_created could be used uninitialized
+in done section in case of failure. The variable was firstly initialized
+to true after succesfull execution of function sysdb_cache_create_empty.
+
+Uninitialized variable usually means true for boolean variable.
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+---
+ src/db/sysdb_init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
+index c387c1b12c116f38d5a13f1adeac5ef64d593af8..d110aa7a2878e47650db177cfd342d0ac32248ab 100644
+--- a/src/db/sysdb_init.c
++++ b/src/db/sysdb_init.c
+@@ -545,7 +545,7 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx,
+     const char *version = NULL;
+     int ret;
+     struct ldb_context *ldb;
+-    bool newly_created;
++    bool newly_created = false;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (!tmp_ctx) {
+-- 
+2.4.11
+
diff --git a/SOURCES/0124-PROXY-Use-right-name-in-ldap-filter.patch b/SOURCES/0124-PROXY-Use-right-name-in-ldap-filter.patch
new file mode 100644
index 0000000..77703a5
--- /dev/null
+++ b/SOURCES/0124-PROXY-Use-right-name-in-ldap-filter.patch
@@ -0,0 +1,51 @@
+From d2636b0f34d6e4ff7cf99a44db8317fd485a3783 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 26 Aug 2016 14:57:22 +0200
+Subject: [PATCH 124/126] PROXY: Use right name in ldap filter
+
+We used internal fq name in ldap filter
+with id_provider proxy to files and auth provider
+ldap
+
+[sssd[be[LDAP]]] [sdap_get_generic_ext_step]
+    (0x0400): calling ldap_search_ext with
+    [(&(uid=testuser1@ldap)(objectclass=posixAccount))][dc=example,dc=com].
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ldap/ldap_auth.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
+index 35f16b0d4a6f8e566b0cf63b65ba46f31e7c1bcd..00d38284e428eea42254820fd08ee4fb125235a6 100644
+--- a/src/providers/ldap/ldap_auth.c
++++ b/src/providers/ldap/ldap_auth.c
+@@ -361,7 +361,7 @@ shadow_fail:
+ 
+ /* ==Get-User-DN========================================================== */
+ struct get_user_dn_state {
+-    const char *username;
++    char *username;
+ 
+     char *orig_dn;
+ };
+@@ -386,9 +386,14 @@ static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
+     req = tevent_req_create(memctx, &state, struct get_user_dn_state);
+     if (!req) return NULL;
+ 
+-    state->username = username;
++    ret = sss_parse_internal_fqname(state, username,
++                                    &state->username, NULL);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Cannot parse %s\n", username);
++        goto done;
++    }
+ 
+-    ret = sss_filter_sanitize(state, username, &clean_name);
++    ret = sss_filter_sanitize(state, state->username, &clean_name);
+     if (ret != EOK) {
+         goto done;
+     }
+-- 
+2.4.11
+
diff --git a/SOURCES/0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch b/SOURCES/0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch
new file mode 100644
index 0000000..f2581b1
--- /dev/null
+++ b/SOURCES/0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch
@@ -0,0 +1,50 @@
+From fde5249cee996276492886697be570b9e698e454 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 30 Aug 2016 15:37:43 +0200
+Subject: [PATCH 125/126] SYSDB: Fix error handling in
+ sysdb_get_user_members_recursively
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We ignored failures from sysdb_search_entry
+
+Reviewed-by: Petr Čech <pcech@redhat.com>
+---
+ src/db/sysdb_ops.c   | 3 +++
+ src/db/sysdb_views.c | 5 ++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 44fb5b70e6d33fffbca5824f831a3229254ecb57..e4c8e1e285e3bc49710f71c896ba9a30c742d4fa 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -4738,6 +4738,9 @@ errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx,
+ 
+     ret = sysdb_search_entry(tmp_ctx, dom->sysdb, base_dn, LDB_SCOPE_SUBTREE,
+                              filter, attrs, &count, &msgs);
++    if (ret != EOK) {
++        goto done;
++    }
+ 
+     res = talloc_zero(tmp_ctx, struct ldb_result);
+     if (res == NULL) {
+diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
+index 79f513d13ba41212a6cd84e1d9e609df6acba29c..9dc48f5b6c414bbc7c64bcd1fe73553f388588bd 100644
+--- a/src/db/sysdb_views.c
++++ b/src/db/sysdb_views.c
+@@ -1374,7 +1374,10 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+ 
+     ret = sysdb_get_user_members_recursively(tmp_ctx, domain, obj->dn,
+                                              &res_members);
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        ret = EOK;
++        goto done;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "sysdb_get_user_members_recursively failed.\n");
+         goto done;
+-- 
+2.4.11
+
diff --git a/SOURCES/0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch b/SOURCES/0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch
new file mode 100644
index 0000000..0cb5cc4
--- /dev/null
+++ b/SOURCES/0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch
@@ -0,0 +1,35 @@
+From 16196f3248a32a7bd9e395b0fdc85249ca4201d7 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Aug 2016 17:30:10 +0200
+Subject: [PATCH 126/126] sdap_initgr_nested_get_membership_diff: use
+ fully-qualified names
+
+I think this is a leftover from the change to use fully-qualified names
+in sysdb. To verify this you can create a nested group in IPA. Without
+this patch the id command will only show the groups the user is a direct
+member of. With the patch the indirect groups memberships should be
+shown as well.
+
+https://fedorahosted.org/sssd/ticket/3163
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/ldap/sdap_async_initgroups.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index 82c708c226bf1a645ff5a395947dfdbad71e0f1f..f9593f0dfaa2dc6e33fd6c9d1f0c9b78cad3a1d9 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -1414,7 +1414,7 @@ sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx,
+                group_name, parents_count);
+ 
+     if (parents_count > 0) {
+-        ret = sysdb_attrs_primary_name_list(dom, tmp_ctx,
++        ret = sysdb_attrs_primary_fqdn_list(dom, tmp_ctx,
+                                             ldap_parentlist,
+                                             parents_count,
+                                             opts->group_map[SDAP_AT_GROUP_NAME].name,
+-- 
+2.4.11
+
diff --git a/SOURCES/0127-Revert-CONFIG-Use-default-config-when-none-provided.patch b/SOURCES/0127-Revert-CONFIG-Use-default-config-when-none-provided.patch
new file mode 100644
index 0000000..623336d
--- /dev/null
+++ b/SOURCES/0127-Revert-CONFIG-Use-default-config-when-none-provided.patch
@@ -0,0 +1,196 @@
+From 17ba1565f6dc3874c554f37ca949ad284647141d Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 7 Sep 2016 17:21:19 +0200
+Subject: [PATCH 127/127] Revert "CONFIG: Use default config when none
+ provided"
+
+This reverts commit 59744cff6edb106ae799b2321cb8731edadf409a.
+---
+ Makefile.am                   | 10 ----------
+ contrib/sssd.spec.in          |  3 ---
+ src/confdb/confdb.h           |  1 -
+ src/confdb/confdb_setup.c     | 40 ++++------------------------------------
+ src/examples/sssd-shadowutils |  6 ------
+ src/examples/sssd.conf        | 17 -----------------
+ 6 files changed, 4 insertions(+), 73 deletions(-)
+ delete mode 100644 src/examples/sssd-shadowutils
+ delete mode 100644 src/examples/sssd.conf
+
+diff --git a/Makefile.am b/Makefile.am
+index b8cd8b64ca8a130a5dd3107e1fb1445310192059..056c73bb265523705a0de16d4d5e078f516f566f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -35,7 +35,6 @@ endif
+ 
+ sssdlibexecdir = $(libexecdir)/sssd
+ sssdlibdir = $(libdir)/sssd
+-sssddefaultconfdir = $(sssdlibdir)/conf
+ ldblibdir = @ldblibdir@
+ if BUILD_KRB5_LOCATOR_PLUGIN
+ krb5plugindir = @krb5pluginpath@
+@@ -85,7 +84,6 @@ pkgconfigdir = $(libdir)/pkgconfig
+ krb5rcachedir = @krb5rcachedir@
+ sudolibdir = @sudolibpath@
+ polkitdir = @polkitdir@
+-pamconfdir = $(sysconfdir)/pam.d
+ systemtap_tapdir = @tapset_dir@
+ 
+ secdbpath = @secdbpath@
+@@ -464,7 +462,6 @@ AM_CPPFLAGS = \
+     -DSSSDDATADIR=\"$(sssddatadir)\" \
+     -DSSSD_LIBEXEC_PATH=\"$(sssdlibexecdir)\" \
+     -DSSSD_CONF_DIR=\"$(sssdconfdir)\" \
+-    -DSSSD_DEFAULT_CONF_DIR=\"$(sssddefaultconfdir)\" \
+     -DSSS_NSS_MCACHE_DIR=\"$(mcpath)\" \
+     -DSSS_NSS_SOCKET_NAME=\"$(pipepath)/nss\" \
+     -DSSS_PAM_SOCKET_NAME=\"$(pipepath)/pam\" \
+@@ -1465,12 +1462,6 @@ dist_noinst_DATA += \
+     src/sss_client/COPYING.LESSER \
+     src/m4
+ 
+-dist_sssddefaultconf_DATA = \
+-    src/examples/sssd.conf
+-
+-dist_pamconf_DATA = \
+-    src/examples/sssd-shadowutils
+-
+ ######################
+ # Command-line Tools #
+ ######################
+@@ -3972,7 +3963,6 @@ SSSD_USER_DIRS = \
+     $(DESTDIR)$(gpocachepath) \
+     $(DESTDIR)$(sssdconfdir) \
+     $(DESTDIR)$(sssdconfdir)/conf.d \
+-    $(DESTDIR)$(sssddefaultconfdir) \
+     $(DESTDIR)$(logpath) \
+     $(NULL)
+ 
+diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
+index cb68a73e85122b016de7df37bcf4fc232a10a2ac..4e24aa39c65ad698607615d93de8624e2e1832ff 100644
+--- a/contrib/sssd.spec.in
++++ b/contrib/sssd.spec.in
+@@ -800,9 +800,6 @@ done
+ %dir %{_sysconfdir}/rwtab.d
+ %config(noreplace) %{_sysconfdir}/rwtab.d/sssd
+ %dir %{_datadir}/sssd
+-%{_sysconfdir}/pam.d/sssd-shadowutils
+-%{_libdir}/%{name}/conf/sssd.conf
+-
+ %{_datadir}/sssd/cfg_rules.ini
+ %{_datadir}/sssd/sssd.api.conf
+ %{_datadir}/sssd/sssd.api.d
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index 72adbd80ea534eb0becd3e517c00b0c26d00444c..e8df280562d7014e0dc5d4fe5c3336eaba204537 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -40,7 +40,6 @@
+ 
+ #define CONFDB_DEFAULT_CFG_FILE_VER 2
+ #define CONFDB_FILE "config.ldb"
+-#define SSSD_DEFAULT_CONFIG_FILE SSSD_DEFAULT_CONF_DIR"/sssd.conf"
+ #define SSSD_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf"
+ #define CONFDB_DEFAULT_CONFIG_DIR SSSD_CONF_DIR"/conf.d"
+ #define SSSD_MIN_ID 1
+diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
+index d6feab9000d54d2c3761de6d8e990053ade7e85f..a71d9dd1202824b3c9a7e69f1d8fa905ac1b8c02 100644
+--- a/src/confdb/confdb_setup.c
++++ b/src/confdb/confdb_setup.c
+@@ -21,14 +21,12 @@
+ 
+ #include "config.h"
+ #include <sys/stat.h>
+-#include <unistd.h>
+ #include "util/util.h"
+ #include "db/sysdb.h"
+ #include "confdb.h"
+ #include "confdb_private.h"
+ #include "confdb_setup.h"
+ #include "util/sss_ini.h"
+-#include "tools/tools_util.h"
+ 
+ 
+ static int confdb_test(struct confdb_ctx *cdb)
+@@ -161,41 +159,11 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "sss_ini_config_file_open failed: %s [%d]\n", strerror(ret),
+                ret);
+-        if (ret != ENOENT) {
+-            /* Anything other than ENOENT is unrecoverable */
+-            goto done;
+-        } else {
+-            /* Copy the default configuration file to the standard location
+-             * and then retry
+-             */
+-             ret = copy_file_secure(SSSD_DEFAULT_CONFIG_FILE,
+-                                    SSSD_CONFIG_FILE,
+-                                    0600,
+-                                    getuid(),
+-                                    getgid(),
+-                                    false);
+-             if (ret != EOK) {
+-                 DEBUG(SSSDBG_FATAL_FAILURE,
+-                       "Could not copy default configuration: %s",
+-                       sss_strerror(ret));
+-                 /* sss specific error denoting missing configuration file */
+-                 ret = ERR_MISSING_CONF;
+-                 goto done;
+-             }
+-
+-             /* Try again */
+-             ret = sss_ini_config_file_open(init_data, config_file);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_TRACE_FUNC,
+-                      "sss_ini_config_file_open(default) failed: %s [%d]\n",
+-                      strerror(ret), ret);
+-                if (ret == ENOENT) {
+-                    /* sss specific error denoting missing configuration file */
+-                    ret = ERR_MISSING_CONF;
+-                }
+-                goto done;
+-            }
++        if (ret == ENOENT) {
++            /* sss specific error denoting missing configuration file */
++            ret = ERR_MISSING_CONF;
+         }
++        goto done;
+     }
+ 
+     ret = sss_ini_config_access_check(init_data);
+diff --git a/src/examples/sssd-shadowutils b/src/examples/sssd-shadowutils
+deleted file mode 100644
+index 626c7d075dfbf97dd91e259f94c6061689c83e9e..0000000000000000000000000000000000000000
+--- a/src/examples/sssd-shadowutils
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#%PAM-1.0
+-auth        [success=done ignore=ignore default=die] pam_unix.so nullok try_first_pass
+-auth        required      pam_deny.so
+-
+-account     required      pam_unix.so
+-account     required      pam_permit.so
+diff --git a/src/examples/sssd.conf b/src/examples/sssd.conf
+deleted file mode 100644
+index a851dbb7ecd5c3220fbd6a946a6c7be2822dbd27..0000000000000000000000000000000000000000
+--- a/src/examples/sssd.conf
++++ /dev/null
+@@ -1,17 +0,0 @@
+-[sssd]
+-config_file_version = 2
+-services = nss, pam
+-domains = shadowutils
+-
+-[nss]
+-
+-[pam]
+-
+-[domain/shadowutils]
+-id_provider = proxy
+-proxy_lib_name = files
+-
+-auth_provider = proxy
+-proxy_pam_target = sssd-shadowutils
+-
+-proxy_fast_alias = True
+-- 
+2.7.4
+
diff --git a/SOURCES/0128-TOOLS-Fix-a-typo-in-groupadd.patch b/SOURCES/0128-TOOLS-Fix-a-typo-in-groupadd.patch
new file mode 100644
index 0000000..4476896
--- /dev/null
+++ b/SOURCES/0128-TOOLS-Fix-a-typo-in-groupadd.patch
@@ -0,0 +1,33 @@
+From bac0f5a1d74d2dbedc5873592edbbdd791db2ede Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 6 Sep 2016 12:13:08 +0200
+Subject: [PATCH 128/135] TOOLS: Fix a typo in groupadd()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3173
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 6be723a089a1e07a1cd19b4fa53fd142c13f0c69)
+---
+ src/tools/sss_sync_ops.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c
+index a23a0b8c30366d2fb68554bfed184b8fce675e2b..39ef5bec96bd3942da8a8adfd21c99b03a77e551 100644
+--- a/src/tools/sss_sync_ops.c
++++ b/src/tools/sss_sync_ops.c
+@@ -657,7 +657,7 @@ int groupadd(struct ops_ctx *data)
+     int ret;
+ 
+     data->sysdb_fqname = sss_create_internal_fqname(data,
+-                                                    data->sysdb_fqname,
++                                                    data->name,
+                                                     data->domain->name);
+     if (data->sysdb_fqname == NULL) {
+         return ENOMEM;
+-- 
+2.7.4
+
diff --git a/SOURCES/0129-TOOLS-sss_groupshow-did-not-work.patch b/SOURCES/0129-TOOLS-sss_groupshow-did-not-work.patch
new file mode 100644
index 0000000..7179654
--- /dev/null
+++ b/SOURCES/0129-TOOLS-sss_groupshow-did-not-work.patch
@@ -0,0 +1,60 @@
+From 7d8269e8a885cc0344dc78951d2880edac32a02c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Tue, 6 Sep 2016 13:46:53 +0200
+Subject: [PATCH 129/135] TOOLS: sss_groupshow did not work
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sss_groupshow used shortname to search
+in sysdb database. We have to u e sysdb_fqname
+(aka internal_fqname) format for all sysdb
+oprations.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3175
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 5210c5d3a5a83b5d08396ee23d88f6ba0994097d)
+---
+ src/tools/sss_groupshow.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/src/tools/sss_groupshow.c b/src/tools/sss_groupshow.c
+index 41d7475cef1093a4cb214ec4b017db59e6c26fe2..5870cc802c70366c47a0d30cb0d9795cf6035bc5 100644
+--- a/src/tools/sss_groupshow.c
++++ b/src/tools/sss_groupshow.c
+@@ -318,7 +318,7 @@ int group_show(TALLOC_CTX *mem_ctx,
+                struct sysdb_ctx *sysdb,
+                struct sss_domain_info *domain,
+                bool   recursive,
+-               const char *name,
++               const char *shortname,
+                struct group_info **res)
+ {
+     struct group_info *root;
+@@ -326,11 +326,20 @@ int group_show(TALLOC_CTX *mem_ctx,
+     struct ldb_message *msg = NULL;
+     const char **group_members = NULL;
+     int nmembers = 0;
++    char *sysdb_fqname = NULL;
+     int ret;
+     int i;
+ 
++    sysdb_fqname = sss_create_internal_fqname(mem_ctx,
++                                              shortname,
++                                              domain->name);
++    if (sysdb_fqname == NULL) {
++        return ENOMEM;
++    }
++
+     /* First, search for the root group */
+-    ret = sysdb_search_group_by_name(mem_ctx, domain, name, attrs, &msg);
++    ret = sysdb_search_group_by_name(mem_ctx, domain, sysdb_fqname, attrs,
++                                     &msg);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Search failed: %s (%d)\n", strerror(ret), ret);
+-- 
+2.7.4
+
diff --git a/SOURCES/0130-TESTS-sss_groupadd-groupshow-regressions.patch b/SOURCES/0130-TESTS-sss_groupadd-groupshow-regressions.patch
new file mode 100644
index 0000000..11e71cf
--- /dev/null
+++ b/SOURCES/0130-TESTS-sss_groupadd-groupshow-regressions.patch
@@ -0,0 +1,78 @@
+From cb355831d3f128688b33b9099ec047f8ef6a3234 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Tue, 6 Sep 2016 17:37:14 +0200
+Subject: [PATCH 130/135] TESTS: sss_groupadd/groupshow regressions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds regression CI test for ticket #3173 and #3175.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3173
+https://fedorahosted.org/sssd/ticket/3175
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 20c2d76d9430a1fc069531ff537df046a74c8f61)
+---
+ src/tests/intg/test_local_domain.py | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py
+index 31834b5b9ab93329ac5eb76e3676d6f89f5b996e..56e3812b113b36301d1ec6049e5a1210d3070442 100644
+--- a/src/tests/intg/test_local_domain.py
++++ b/src/tests/intg/test_local_domain.py
+@@ -19,11 +19,13 @@
+ import os
+ import stat
+ import pwd
++import grp
+ import time
+ import config
+ import signal
+ import subprocess
+ import pytest
++import ent
+ from util import unindent
+ 
+ 
+@@ -90,6 +92,11 @@ def assert_nonexistent_user(name):
+         pwd.getpwnam(name)
+ 
+ 
++def assert_nonexistent_group(name):
++    with pytest.raises(KeyError):
++        grp.getgrnam(name)
++
++
+ def test_wrong_LC_ALL(local_domain_only):
+     """
+     Regression test for ticket
+@@ -106,4 +113,23 @@ def test_wrong_LC_ALL(local_domain_only):
+     # sss_userdel must remove the user despite wrong LC_ALL
+     subprocess.check_call(["sss_userdel", "foo", "-R"])
+     assert_nonexistent_user("foo")
+-    os.environ["LC_LOCAL"] = oldvalue
++    os.environ["LC_ALL"] = oldvalue
++
++
++def test_sss_group_add_show_del(local_domain_only):
++    """
++    Regression test for tickets
++    https://fedorahosted.org/sssd/ticket/3173
++    https://fedorahosted.org/sssd/ticket/3175
++    """
++
++    subprocess.check_call(["sss_groupadd", "foo", "-g", "10001"])
++
++    "This should not raise KeyError"
++    ent.assert_group_by_name("foo", dict(name="foo", gid=10001))
++
++    "sss_grupshow should return 0 with existing group name"
++    subprocess.check_call(["sss_groupshow", "foo"])
++
++    subprocess.check_call(["sss_groupdel", "foo"])
++    assert_nonexistent_group("foo")
+-- 
+2.7.4
+
diff --git a/SOURCES/0131-TOOLS-use-internal-fqdn-for-DN.patch b/SOURCES/0131-TOOLS-use-internal-fqdn-for-DN.patch
new file mode 100644
index 0000000..9b77d88
--- /dev/null
+++ b/SOURCES/0131-TOOLS-use-internal-fqdn-for-DN.patch
@@ -0,0 +1,57 @@
+From bfbad5b20c8a34b545cea8df6c937125edf0e42c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 7 Sep 2016 10:58:25 +0200
+Subject: [PATCH 131/135] TOOLS: use internal fqdn for DN
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use internal fqdn when creating sysdb group dn.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3178
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 5e2142b66589e5e50cb404fc972ed5418bbaa772)
+---
+ src/tools/sss_sync_ops.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c
+index 39ef5bec96bd3942da8a8adfd21c99b03a77e551..a0291baeada49b9f21e040a54e303214d5a46332 100644
+--- a/src/tools/sss_sync_ops.c
++++ b/src/tools/sss_sync_ops.c
+@@ -137,6 +137,7 @@ static int mod_groups_member(struct sss_domain_info *dom,
+     struct ldb_dn *parent_dn;
+     int ret;
+     int i;
++    char *grp_sysdb_fqname = NULL;
+ 
+     tmpctx = talloc_new(NULL);
+     if (!tmpctx) {
+@@ -145,13 +146,21 @@ static int mod_groups_member(struct sss_domain_info *dom,
+ 
+ /* FIXME: add transaction around loop */
+     for (i = 0; grouplist[i]; i++) {
++        grp_sysdb_fqname = sss_create_internal_fqname(tmpctx, grouplist[i],
++                                                      dom->name);
++        if (grp_sysdb_fqname == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
+ 
+-        parent_dn = sysdb_group_dn(tmpctx, dom, grouplist[i]);
++        parent_dn = sysdb_group_dn(tmpctx, dom, grp_sysdb_fqname);
+         if (!parent_dn) {
+             ret = ENOMEM;
+             goto done;
+         }
+ 
++        talloc_free(grp_sysdb_fqname);
++
+         ret = sysdb_mod_group_member(dom, member_dn, parent_dn, optype);
+         if (ret) {
+             goto done;
+-- 
+2.7.4
+
diff --git a/SOURCES/0132-TESTS-Test-for-sss_user-groupmod-a.patch b/SOURCES/0132-TESTS-Test-for-sss_user-groupmod-a.patch
new file mode 100644
index 0000000..af34532
--- /dev/null
+++ b/SOURCES/0132-TESTS-Test-for-sss_user-groupmod-a.patch
@@ -0,0 +1,66 @@
+From 2eb23ddb5f03a71a329bf4874194455ff87e1806 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 7 Sep 2016 13:08:59 +0200
+Subject: [PATCH 132/135] TESTS: Test for sss_user/groupmod -a
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Regression tests for ticket #3178.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3178
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 7fa4964d84f41bd80a6d971ffaeef87a7c2f19be)
+---
+ src/tests/intg/test_local_domain.py | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py
+index 56e3812b113b36301d1ec6049e5a1210d3070442..5e3e3d4d1cdc6db5d68a6e5b9d96d94c2c694b14 100644
+--- a/src/tests/intg/test_local_domain.py
++++ b/src/tests/intg/test_local_domain.py
+@@ -133,3 +133,39 @@ def test_sss_group_add_show_del(local_domain_only):
+ 
+     subprocess.check_call(["sss_groupdel", "foo"])
+     assert_nonexistent_group("foo")
++
++
++def test_add_local_user_to_local_group(local_domain_only):
++    """
++    Regression test for ticket
++    https://fedorahosted.org/sssd/ticket/3178
++    """
++    subprocess.check_call(["sss_groupadd", "-g", "10009", "group10009"])
++    subprocess.check_call(["sss_useradd", "-u", "10009", "-M", "user10009"])
++    subprocess.check_call(["sss_usermod", "-a", "group10009", "user10009"])
++
++    ent.assert_group_by_name(
++        "group10009",
++        dict(name="group10009", passwd="*", gid=10009,
++             mem=ent.contains_only("user10009")))
++
++
++def test_add_local_group_to_local_group(local_domain_only):
++    """
++    Regression test for tickets
++    https://fedorahosted.org/sssd/ticket/3178
++    """
++    subprocess.check_call(["sss_groupadd", "-g", "10009", "group_child"])
++    subprocess.check_call(["sss_useradd", "-u", "10009", "-M", "user_child"])
++    subprocess.check_call(["sss_usermod", "-a", "group_child", "user_child"])
++
++    subprocess.check_call(["sss_groupadd", "-g", "10008", "group_parent"])
++    subprocess.check_call(
++        ["sss_groupmod", "-a", "group_parent", "group_child"])
++
++    # User from child_group is member of parent_group, so child_group's
++    # member must be also parent_group's member
++    ent.assert_group_by_name(
++        "group_parent",
++        dict(name="group_parent", passwd="*", gid=10008,
++             mem=ent.contains_only("user_child")))
+-- 
+2.7.4
+
diff --git a/SOURCES/0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch b/SOURCES/0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch
new file mode 100644
index 0000000..6f8b54e
--- /dev/null
+++ b/SOURCES/0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch
@@ -0,0 +1,137 @@
+From 1a1aaf46d1ee3ae4c9346c5c492520257c7c1b42 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 7 Sep 2016 14:43:13 +0200
+Subject: [PATCH 133/135] TOOLS: sss_mc_refresh_nested_group short/fqname usage
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We use shortname to refresh memory cache, but in case of nested groups,
+we used internal_fqname to refresh parent groups.
+
+We also wrongly used the shortname for sysdb_search operation.
+Which caused error message to be printed when sss_usermod -a or
+sss_groupmod -a where called.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tools/tools_mc_util.c | 66 +++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 47 insertions(+), 19 deletions(-)
+
+diff --git a/src/tools/tools_mc_util.c b/src/tools/tools_mc_util.c
+index 2516a1981ddd965d4cae8c469ed79aaef8fa7193..716e3760f67d958f2139adbb49998d9e352d23f4 100644
+--- a/src/tools/tools_mc_util.c
++++ b/src/tools/tools_mc_util.c
+@@ -293,62 +293,90 @@ errno_t sss_mc_refresh_group(const char *groupname)
+     return sss_mc_refresh_ent(groupname, SSS_TOOLS_GROUP);
+ }
+ 
+-errno_t sss_mc_refresh_nested_group(struct tools_ctx *tctx,
+-                                    const char *name)
++static errno_t sss_mc_refresh_nested_group(struct tools_ctx *tctx,
++                                           const char *shortname)
+ {
+     errno_t ret;
+-    struct ldb_message *msg;
++    struct ldb_message *msg = NULL;
+     struct ldb_message_element *el;
+     const char *attrs[] = { SYSDB_MEMBEROF,
+                             SYSDB_NAME,
+                             NULL };
+     size_t i;
+-    char *parent_name;
++    char *parent_internal_name;
++    char *parent_outname;
++    char *internal_name;
++    TALLOC_CTX *tmpctx;
+ 
+-    ret = sss_mc_refresh_group(name);
++    tmpctx = talloc_new(tctx);
++    if (tmpctx == NULL) {
++        return ENOMEM;
++    }
++
++    internal_name = sss_create_internal_fqname(tmpctx, shortname,
++                                               tctx->local->name);
++    if (internal_name == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sss_mc_refresh_group(shortname);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Cannot refresh group %s from memory cache\n", name);
++              "Cannot refresh group %s from memory cache\n", shortname);
+         /* try to carry on */
+     }
+ 
+-    ret = sysdb_search_group_by_name(tctx, tctx->local, name, attrs, &msg);
++    ret = sysdb_search_group_by_name(tmpctx, tctx->local, internal_name, attrs,
++                                     &msg);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE,
+                "Search failed: %s (%d)\n", strerror(ret), ret);
+-        return ret;
++        goto done;
+     }
+ 
+     el = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
+     if (!el || el->num_values == 0) {
+-        DEBUG(SSSDBG_TRACE_INTERNAL, "Group %s has no parents\n", name);
+-        talloc_free(msg);
+-        return EOK;
++        DEBUG(SSSDBG_TRACE_INTERNAL, "Group %s has no parents\n",
++              internal_name);
++        ret = EOK;
++        goto done;
+     }
+ 
+     /* This group is nested. We need to invalidate all its parents, too */
+     for (i=0; i < el->num_values; i++) {
+-        ret = sysdb_group_dn_name(tctx->sysdb, tctx,
++        ret = sysdb_group_dn_name(tctx->sysdb, tmpctx,
+                                   (const char *) el->values[i].data,
+-                                  &parent_name);
++                                  &parent_internal_name);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE, "Malformed DN [%s]? Skipping\n",
+                   (const char *) el->values[i].data);
+-            talloc_free(parent_name);
++            talloc_free(parent_internal_name);
+             continue;
+         }
+ 
+-        ret = sss_mc_refresh_group(parent_name);
+-        talloc_free(parent_name);
++        parent_outname = sss_output_name(tmpctx, parent_internal_name,
++                                         tctx->local->case_preserve, 0);
++        if (parent_outname == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++
++        ret = sss_mc_refresh_group(parent_outname);
++        talloc_free(parent_internal_name);
++        talloc_free(parent_outname);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Cannot refresh group %s from memory cache\n", name);
++                  "Cannot refresh group %s from memory cache\n", parent_outname);
+             /* try to carry on */
+         }
+     }
+ 
+-    talloc_free(msg);
+-    return EOK;
++    ret = EOK;
++
++done:
++    talloc_free(tmpctx);
++    return ret;
+ }
+ 
+ errno_t sss_mc_refresh_grouplist(struct tools_ctx *tctx,
+-- 
+2.7.4
+
diff --git a/SOURCES/0134-TESTS-Add-FQDN-variants-for-some-tests.patch b/SOURCES/0134-TESTS-Add-FQDN-variants-for-some-tests.patch
new file mode 100644
index 0000000..109d2ef
--- /dev/null
+++ b/SOURCES/0134-TESTS-Add-FQDN-variants-for-some-tests.patch
@@ -0,0 +1,116 @@
+From 28db1765c40137e9452b4aa27281a1deb25d1d36 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 7 Sep 2016 15:00:12 +0200
+Subject: [PATCH 134/135] TESTS: Add FQDN variants for some tests
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds FQDN variants of some already existing tests.
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/tests/intg/test_local_domain.py | 83 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 83 insertions(+)
+
+diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py
+index 5e3e3d4d1cdc6db5d68a6e5b9d96d94c2c694b14..b34e4a3d31cdbc1dc257d8fffcf0f5a07803b20c 100644
+--- a/src/tests/intg/test_local_domain.py
++++ b/src/tests/intg/test_local_domain.py
+@@ -87,6 +87,27 @@ def local_domain_only(request):
+     return None
+ 
+ 
++@pytest.fixture
++def local_domain_only_fqdn(request):
++    conf = unindent("""\
++        [sssd]
++        domains = LOCAL
++        services = nss
++
++        [nss]
++        memcache_timeout = 0
++
++        [domain/LOCAL]
++        id_provider = local
++        min_id = 10000
++        max_id = 20000
++        use_fully_qualified_names = True
++    """).format(**locals())
++    create_conf_fixture(request, conf)
++    create_sssd_fixture(request)
++    return None
++
++
+ def assert_nonexistent_user(name):
+     with pytest.raises(KeyError):
+         pwd.getpwnam(name)
+@@ -169,3 +190,65 @@ def test_add_local_group_to_local_group(local_domain_only):
+         "group_parent",
+         dict(name="group_parent", passwd="*", gid=10008,
+              mem=ent.contains_only("user_child")))
++
++
++def test_sss_group_add_show_del_fqdn(local_domain_only_fqdn):
++    """
++    Regression test for tickets
++    https://fedorahosted.org/sssd/ticket/3173
++    https://fedorahosted.org/sssd/ticket/3175
++    """
++
++    subprocess.check_call(["sss_groupadd", "foo@LOCAL", "-g", "10001"])
++
++    "This should not raise KeyError"
++    ent.assert_group_by_name("foo@LOCAL", dict(name="foo@LOCAL", gid=10001))
++
++    "sss_grupshow should return 0 with existing group name"
++    subprocess.check_call(["sss_groupshow", "foo@LOCAL"])
++
++    subprocess.check_call(["sss_groupdel", "foo@LOCAL"])
++    assert_nonexistent_group("foo@LOCAL")
++
++
++def test_add_local_user_to_local_group_fqdn(local_domain_only_fqdn):
++    """
++    Regression test for ticket
++    https://fedorahosted.org/sssd/ticket/3178
++    """
++    subprocess.check_call(
++        ["sss_groupadd", "-g", "10009", "group10009@LOCAL"])
++    subprocess.check_call(
++        ["sss_useradd", "-u", "10009", "-M", "user10009@LOCAL"])
++    subprocess.check_call(
++        ["sss_usermod", "-a", "group10009@LOCAL", "user10009@LOCAL"])
++
++    ent.assert_group_by_name(
++        "group10009@LOCAL",
++        dict(name="group10009@LOCAL", passwd="*", gid=10009,
++             mem=ent.contains_only("user10009@LOCAL")))
++
++
++def test_add_local_group_to_local_group_fqdn(local_domain_only_fqdn):
++    """
++    Regression test for tickets
++    https://fedorahosted.org/sssd/ticket/3178
++    """
++    subprocess.check_call(
++        ["sss_groupadd", "-g", "10009", "group_child@LOCAL"])
++    subprocess.check_call(
++        ["sss_useradd", "-u", "10009", "-M", "user_child@LOCAL"])
++    subprocess.check_call(
++        ["sss_usermod", "-a", "group_child@LOCAL", "user_child@LOCAL"])
++
++    subprocess.check_call(
++        ["sss_groupadd", "-g", "10008", "group_parent@LOCAL"])
++    subprocess.check_call(
++        ["sss_groupmod", "-a", "group_parent@LOCAL", "group_child@LOCAL"])
++
++    # User from child_group is member of parent_group, so child_group's
++    # member must be also parent_group's member
++    ent.assert_group_by_name(
++        "group_parent@LOCAL",
++        dict(name="group_parent@LOCAL", passwd="*", gid=10008,
++             mem=ent.contains_only("user_child@LOCAL")))
+-- 
+2.7.4
+
diff --git a/SOURCES/0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch b/SOURCES/0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch
new file mode 100644
index 0000000..a3368d4
--- /dev/null
+++ b/SOURCES/0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch
@@ -0,0 +1,155 @@
+From 0f0480dd1c227a841542d621a778e23cf637a644 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 7 Sep 2016 12:07:36 +0200
+Subject: [PATCH 135/135] KRB5: Send the output username, not internal fqname
+ to krb5_child
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+krb5_child calls krb5_kuserok() during the access phase which checks if
+a particular user is allowed to authenticate as a particular principal.
+We used to pass the internal fqname to krb5_kuserok() which broke the
+functionality and all users were denied access.
+
+This patch changes that to send the 'output' username to krb5_child,
+because that's the username the system receives through getpwnam() or
+getpwuid() anyway. The patch also adds a new structure member fo the
+krb5child_req structure to avoid reusing the pd->user variable but have
+an explicit one that serves as the input for the child process.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3172
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+---
+ src/providers/krb5/krb5_access.c        | 10 ++++++++--
+ src/providers/krb5/krb5_auth.c          | 18 ++++++++++++++----
+ src/providers/krb5/krb5_auth.h          |  9 ++++++---
+ src/providers/krb5/krb5_child_handler.c |  4 ++--
+ 4 files changed, 30 insertions(+), 11 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_access.c b/src/providers/krb5/krb5_access.c
+index 3afb90150d77ef4ab2c1b5b79abb95d68eb131f6..be9068c0f9180f8de0de259aae368534effaf7fb 100644
+--- a/src/providers/krb5/krb5_access.c
++++ b/src/providers/krb5/krb5_access.c
+@@ -51,6 +51,7 @@ struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx,
+     int ret;
+     const char **attrs;
+     struct ldb_result *res;
++    struct sss_domain_info *dom;
+ 
+     req = tevent_req_create(mem_ctx, &state, struct krb5_access_state);
+     if (req == NULL) {
+@@ -64,8 +65,13 @@ struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx,
+     state->krb5_ctx = krb5_ctx;
+     state->access_allowed = false;
+ 
+-    ret = krb5_setup(state, pd, krb5_ctx, be_ctx->domain->case_sensitive,
+-                     &state->kr);
++    ret = get_domain_or_subdomain(be_ctx, pd->domain, &dom);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "get_domain_or_subdomain failed.\n");
++        goto done;
++    }
++
++    ret = krb5_setup(state, pd, dom, krb5_ctx, &state->kr);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
+         goto done;
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index dabf55cf24a8afda16fee6697120c7c6f088b796..f0f2280022a3ee951ccfa0040b616c48c3b25706 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -174,8 +174,10 @@ done:
+     return ret;
+ }
+ 
+-errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
+-                   struct krb5_ctx *krb5_ctx, bool cs,
++errno_t krb5_setup(TALLOC_CTX *mem_ctx,
++                   struct pam_data *pd,
++                   struct sss_domain_info *dom,
++                   struct krb5_ctx *krb5_ctx,
+                    struct krb5child_req **_krb5_req)
+ {
+     struct krb5child_req *kr;
+@@ -201,13 +203,21 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
+     kr->krb5_ctx = krb5_ctx;
+ 
+     ret = get_krb_primary(krb5_ctx->name_to_primary,
+-                          pd->user, cs, &mapped_name);
++                          pd->user, dom->case_sensitive, &mapped_name);
+     if (ret == EOK) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Setting mapped name to: %s\n", mapped_name);
+         kr->user = mapped_name;
++        kr->kuserok_user = mapped_name;
+     } else if (ret == ENOENT) {
+         DEBUG(SSSDBG_TRACE_ALL, "No mapping for: %s\n", pd->user);
+         kr->user = pd->user;
++
++        kr->kuserok_user = sss_output_name(kr, kr->user,
++                                           dom->case_sensitive, 0);
++        if (kr->kuserok_user == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
+     } else {
+         DEBUG(SSSDBG_CRIT_FAILURE, "get_krb_primary failed - %s:[%d]\n",
+               sss_strerror(ret), ret);
+@@ -534,7 +544,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+     attrs[6] = SYSDB_AUTH_TYPE;
+     attrs[7] = NULL;
+ 
+-    ret = krb5_setup(state, pd, krb5_ctx, state->domain->case_sensitive,
++    ret = krb5_setup(state, pd, state->domain, krb5_ctx,
+                      &state->kr);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
+diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
+index dbad061f0203b6383daeeab506bf9950d892ea4b..11bb595833269177b7e2c5fc6372d6a6fb6d93d2 100644
+--- a/src/providers/krb5/krb5_auth.h
++++ b/src/providers/krb5/krb5_auth.h
+@@ -57,11 +57,14 @@ struct krb5child_req {
+     bool send_pac;
+ 
+     const char *user;
++    const char *kuserok_user;
+ };
+ 
+-errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
+-                   struct krb5_ctx *krb5_ctx, bool case_sensitive,
+-                   struct krb5child_req **krb5_req);
++errno_t krb5_setup(TALLOC_CTX *mem_ctx,
++                   struct pam_data *pd,
++                   struct sss_domain_info *dom,
++                   struct krb5_ctx *krb5_ctx,
++                   struct krb5child_req **_krb5_req);
+ 
+ struct tevent_req *
+ krb5_pam_handler_send(TALLOC_CTX *mem_ctx,
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 09a1e5f59494a5c07d5c9eefb94919ca9389cb27..1eec7261f00976b3725fee9323755edecd5409a5 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -161,7 +161,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
+     }
+ 
+     if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
+-        username_len = strlen(kr->pd->user);
++        username_len = strlen(kr->kuserok_user);
+         buf->size += sizeof(uint32_t) + username_len;
+     }
+ 
+@@ -217,7 +217,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
+ 
+     if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
+         SAFEALIGN_SET_UINT32(&buf->data[rp], username_len, &rp);
+-        safealign_memcpy(&buf->data[rp], kr->pd->user, username_len, &rp);
++        safealign_memcpy(&buf->data[rp], kr->kuserok_user, username_len, &rp);
+     }
+ 
+     *io_buf = buf;
+-- 
+2.7.4
+
diff --git a/SOURCES/0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch b/SOURCES/0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch
new file mode 100644
index 0000000..806432b
--- /dev/null
+++ b/SOURCES/0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch
@@ -0,0 +1,42 @@
+From abbbcb79ff0c5b82d7a3acb324c3d44f87479837 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 12 Sep 2016 17:36:09 +0200
+Subject: [PATCH 136/140] LDAP: Return partial results from adminlimit exceeded
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+    https://fedorahosted.org/sssd/ticket/3185
+
+Since commit c420ce830ac0b0b288a2a887ec2cfce5c748018c we try to move to
+the next server on any error on the connection, which in case there is
+only one server sends SSSD offline.
+
+It's more graceful to try to process the results, same as we already do
+with sizelimit exceeded.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 3319d964721396c07daba383ded6aaaf33ed6e3b)
+---
+ src/providers/ldap/sdap_async.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
+index 4195ba95d911f3956f8cca665310b4b92091e6cd..b8e04b9d8464d7c2c681080cba456c34b93b923a 100644
+--- a/src/providers/ldap/sdap_async.c
++++ b/src/providers/ldap/sdap_async.c
+@@ -1526,7 +1526,8 @@ static void sdap_get_generic_op_finished(struct sdap_op *op,
+                   sss_ldap_err2string(result), result,
+                   errmsg ? errmsg : "no errmsg set");
+ 
+-        if (result == LDAP_SIZELIMIT_EXCEEDED) {
++        if (result == LDAP_SIZELIMIT_EXCEEDED
++                || result == LDAP_ADMINLIMIT_EXCEEDED) {
+             /* Try to return what we've got */
+ 
+             if ( ! (state->flags & SDAP_SRCH_FLG_SIZELIMIT_SILENT)) {
+-- 
+2.7.4
+
diff --git a/SOURCES/0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch b/SOURCES/0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch
new file mode 100644
index 0000000..285ef6e
--- /dev/null
+++ b/SOURCES/0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch
@@ -0,0 +1,60 @@
+From 8125ddd951a9e66fb3b11e16489e003d32ce4890 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 12 Sep 2016 19:22:56 +0200
+Subject: [PATCH 137/140] TOOLS: sss_groupshow fails to show MPG
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The MPG search uses it's own search function
+that used sysdb operation with shortname,
+but it expects internal fqname.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3184
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit 812bed08943df8bf3fd1ff9eabcaf5bedc635c92)
+---
+ src/tools/sss_groupshow.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/src/tools/sss_groupshow.c b/src/tools/sss_groupshow.c
+index 5870cc802c70366c47a0d30cb0d9795cf6035bc5..00f6f12939b6bef2dd10085f8cf99304e87f1211 100644
+--- a/src/tools/sss_groupshow.c
++++ b/src/tools/sss_groupshow.c
+@@ -553,13 +553,14 @@ int group_show_recurse(TALLOC_CTX *mem_ctx,
+ 
+ static int group_show_mpg(TALLOC_CTX *mem_ctx,
+                           struct sss_domain_info *domain,
+-                          const char *name,
++                          const char *shortname,
+                           struct group_info **res)
+ {
+     const char *attrs[] = GROUP_SHOW_MPG_ATTRS;
+     struct ldb_message *msg;
+     struct group_info *info;
+     int ret;
++    char *sysdb_fqname;
+ 
+     info = talloc_zero(mem_ctx, struct group_info);
+     if (!info) {
+@@ -567,7 +568,14 @@ static int group_show_mpg(TALLOC_CTX *mem_ctx,
+         goto fail;
+     }
+ 
+-    ret = sysdb_search_user_by_name(info, domain, name, attrs, &msg);
++    sysdb_fqname = sss_create_internal_fqname(mem_ctx,
++                                              shortname,
++                                              domain->name);
++    if (sysdb_fqname == NULL) {
++        return ENOMEM;
++    }
++
++    ret = sysdb_search_user_by_name(info, domain, sysdb_fqname, attrs, &msg);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Search failed: %s (%d)\n", strerror(ret), ret);
+-- 
+2.7.4
+
diff --git a/SOURCES/0138-TESTS-sss_groupshow-with-MPG.patch b/SOURCES/0138-TESTS-sss_groupshow-with-MPG.patch
new file mode 100644
index 0000000..e273877
--- /dev/null
+++ b/SOURCES/0138-TESTS-sss_groupshow-with-MPG.patch
@@ -0,0 +1,55 @@
+From 6eb330b5370db40a55d18de2d932601d6b3128b2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 12 Sep 2016 19:25:13 +0200
+Subject: [PATCH 138/140] TESTS: sss_groupshow with MPG
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Regression test for ticket #3184
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3184
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+(cherry picked from commit bb14556c1df503314644fc424fbbf95759791db9)
+---
+ src/tests/intg/test_local_domain.py | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py
+index b34e4a3d31cdbc1dc257d8fffcf0f5a07803b20c..8e1d6fb2b69f5e6e033ae06d4bd52cc88e54872b 100644
+--- a/src/tests/intg/test_local_domain.py
++++ b/src/tests/intg/test_local_domain.py
+@@ -118,6 +118,28 @@ def assert_nonexistent_group(name):
+         grp.getgrnam(name)
+ 
+ 
++def test_groupshow_mpg(local_domain_only):
++    """
++    Regression test for ticket
++    https://fedorahosted.org/sssd/ticket/3184
++    """
++    subprocess.check_call(["sss_useradd", "foo", "-M"])
++
++    # The user's mpg has to be found (should return 0)
++    subprocess.check_call(["sss_groupshow", "foo"])
++
++
++def test_groupshow_mpg_fqdn(local_domain_only_fqdn):
++    """
++    Regression test for ticket (fq variant)
++    https://fedorahosted.org/sssd/ticket/3184
++    """
++    subprocess.check_call(["sss_useradd", "foo@LOCAL", "-M"])
++
++    # The user's mpg has to be found (should return 0)
++    subprocess.check_call(["sss_groupshow", "foo@LOCAL"])
++
++
+ def test_wrong_LC_ALL(local_domain_only):
+     """
+     Regression test for ticket
+-- 
+2.7.4
+
diff --git a/SOURCES/0139-TOOLS-sss_override-without-name-override.patch b/SOURCES/0139-TOOLS-sss_override-without-name-override.patch
new file mode 100644
index 0000000..b9114ef
--- /dev/null
+++ b/SOURCES/0139-TOOLS-sss_override-without-name-override.patch
@@ -0,0 +1,67 @@
+From e56e1396bab69d9498f4ec6a36e9e228ded90116 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 7 Sep 2016 17:09:53 +0200
+Subject: [PATCH 139/140] TOOLS: sss_override without name override
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sss_override failed to export user/group overrides
+if user had no overrides for name.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3179
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 07e7683f5a86991feaa764e2055116554ada1b93)
+---
+ src/tools/sss_override.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
+index d41da52e69acdb67b5a6d624254e3b89a8aa27b8..212bf9ab84b20d4777fc2601359fad58596bb7c4 100644
+--- a/src/tools/sss_override.c
++++ b/src/tools/sss_override.c
+@@ -1159,12 +1159,14 @@ list_user_overrides(TALLOC_CTX *mem_ctx,
+         }
+ 
+         fqname = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
+-        ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL);
+-        if (ret != EOK) {
+-            ret = ERR_WRONG_NAME_FORMAT;
+-            goto done;
++        if (fqname != NULL) {
++            ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL);
++            if (ret != EOK) {
++                ret = ERR_WRONG_NAME_FORMAT;
++                goto done;
++            }
++            objs[i].name = talloc_steal(objs, name);
+         }
+-        objs[i].name = talloc_steal(objs, name);
+ 
+         objs[i].uid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_UIDNUM, 0);
+         objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
+@@ -1248,12 +1250,14 @@ list_group_overrides(TALLOC_CTX *mem_ctx,
+         talloc_steal(objs, objs[i].orig_name);
+ 
+         fqname = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
+-        ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL);
+-        if (ret != EOK) {
+-            ret = ERR_WRONG_NAME_FORMAT;
+-            goto done;
++        if (fqname != NULL) {
++            ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL);
++            if (ret != EOK) {
++                ret = ERR_WRONG_NAME_FORMAT;
++                goto done;
++            }
++            objs[i].name = talloc_steal(objs, name);
+         }
+-        objs[i].name = talloc_steal(objs, name);
+ 
+         objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
+     }
+-- 
+2.7.4
+
diff --git a/SOURCES/0140-TEST-Add-regression-test-for-ticket-3179.patch b/SOURCES/0140-TEST-Add-regression-test-for-ticket-3179.patch
new file mode 100644
index 0000000..18f80b9
--- /dev/null
+++ b/SOURCES/0140-TEST-Add-regression-test-for-ticket-3179.patch
@@ -0,0 +1,203 @@
+From d3e93eafcf3e484ee8ec092c59914018b42ea4ad Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 7 Sep 2016 18:23:16 +0200
+Subject: [PATCH 140/140] TEST: Add regression test for ticket #3179
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/3179
+
+Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 1c72723cde8bea0d390b928c7cd29e48e7a7deab)
+---
+ src/tests/intg/ldap_local_override_test.py | 126 ++++++++++++++++++++++++++---
+ 1 file changed, 114 insertions(+), 12 deletions(-)
+
+diff --git a/src/tests/intg/ldap_local_override_test.py b/src/tests/intg/ldap_local_override_test.py
+index 046535c7727d0f2271f4b974f68ba0722222982b..832849713e1185e836f3dd6decf2deac79ab98dd 100644
+--- a/src/tests/intg/ldap_local_override_test.py
++++ b/src/tests/intg/ldap_local_override_test.py
+@@ -205,27 +205,38 @@ def assert_user_default():
+     ent.assert_passwd_by_name('user2@LDAP', user2)
+ 
+ 
+-def assert_user_overriden():
++def assert_user_overriden(override_name=True):
+ 
+-    user1 = dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
++    if override_name:
++        name1 = "ov_user1"
++        name2 = "ov_user2"
++    else:
++        name1 = "user1"
++        name2 = "user2"
++
++    user1 = dict(name=name1, passwd='*', uid=10010, gid=20010,
+                  gecos='Overriden User 1',
+                  dir='/home/ov/user1',
+                  shell='/bin/ov_user1_shell')
+ 
+-    user2 = dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
++    user2 = dict(name=name2, passwd='*', uid=10020, gid=20020,
+                  gecos='Overriden User 2',
+                  dir='/home/ov/user2',
+                  shell='/bin/ov_user2_shell')
+ 
+     ent.assert_passwd_by_name('user1', user1)
+     ent.assert_passwd_by_name('user1@LDAP', user1)
+-    ent.assert_passwd_by_name('ov_user1', user1)
+-    ent.assert_passwd_by_name('ov_user1@LDAP', user1)
++
++    if override_name:
++        ent.assert_passwd_by_name('ov_user1', user1)
++        ent.assert_passwd_by_name('ov_user1@LDAP', user1)
+ 
+     ent.assert_passwd_by_name('user2', user2)
+     ent.assert_passwd_by_name('user2@LDAP', user2)
+-    ent.assert_passwd_by_name('ov_user2', user2)
+-    ent.assert_passwd_by_name('ov_user2@LDAP', user2)
++
++    if override_name:
++        ent.assert_passwd_by_name('ov_user2', user2)
++        ent.assert_passwd_by_name('ov_user2@LDAP', user2)
+ 
+ 
+ #
+@@ -514,6 +525,54 @@ def test_imp_exp_user_override(ldap_conn, env_imp_exp_user_override):
+     assert_user_overriden()
+ 
+ 
++# Regression test for bug 3179
++
++
++def test_imp_exp_user_overrride_noname(ldap_conn,
++                                       env_two_users_and_group):
++
++    # Override
++    subprocess.check_call(["sss_override", "user-add", "user1",
++                           "-u", "10010",
++                           "-g", "20010",
++                           "-c", "Overriden User 1",
++                           "-h", "/home/ov/user1",
++                           "-s", "/bin/ov_user1_shell"])
++
++    subprocess.check_call(["sss_override", "user-add", "user2@LDAP",
++                           "-u", "10020",
++                           "-g", "20020",
++                           "-c", "Overriden User 2",
++                           "-h", "/home/ov/user2",
++                           "-s", "/bin/ov_user2_shell"])
++
++    # Restart SSSD so the override might take effect
++    restart_sssd()
++
++    # Assert entries are overriden
++    assert_user_overriden(override_name=False)
++
++    # Export overrides
++    subprocess.check_call(["sss_override", "user-export", OVERRIDE_FILENAME])
++
++    # Drop all overrides
++    subprocess.check_call(["sss_override", "user-del", "user1"])
++    subprocess.check_call(["sss_override", "user-del", "user2@LDAP"])
++
++    # Avoid hitting memory cache
++    time.sleep(2)
++
++    # Assert entries are not overridden
++    assert_user_default()
++
++    # Import overrides
++    subprocess.check_call(["sss_override", "user-import",
++                           OVERRIDE_FILENAME])
++    restart_sssd()
++
++    assert_user_overriden(override_name=False)
++
++
+ #
+ # Override user-show
+ #
+@@ -581,7 +640,7 @@ def test_find_user_override(ldap_conn, env_find_user_override):
+ # Common group asserts
+ #
+ 
+-def assert_group_overriden():
++def assert_group_overriden(override_name=True):
+ 
+     # Assert entries are overridden
+     empty_group = dict(gid=3002, mem=ent.contains_only())
+@@ -589,13 +648,17 @@ def assert_group_overriden():
+ 
+     ent.assert_group_by_name("group", group)
+     ent.assert_group_by_name("group@LDAP", group)
+-    ent.assert_group_by_name("ov_group", group)
+-    ent.assert_group_by_name("ov_group@LDAP", group)
++
++    if override_name:
++        ent.assert_group_by_name("ov_group", group)
++        ent.assert_group_by_name("ov_group@LDAP", group)
+ 
+     ent.assert_group_by_name("empty_group", empty_group)
+     ent.assert_group_by_name("empty_group@LDAP", empty_group)
+-    ent.assert_group_by_name("ov_empty_group", empty_group)
+-    ent.assert_group_by_name("ov_empty_group@LDAP", empty_group)
++
++    if override_name:
++        ent.assert_group_by_name("ov_empty_group", empty_group)
++        ent.assert_group_by_name("ov_empty_group@LDAP", empty_group)
+ 
+ 
+ def assert_group_default():
+@@ -841,6 +904,45 @@ def test_imp_exp_group_override(ldap_conn, env_imp_exp_group_override):
+     assert_group_overriden()
+ 
+ 
++# Regression test for bug 3179
++
++
++def test_imp_exp_group_override_noname(ldap_conn, env_group_basic):
++
++    # Override - do not use -n here)
++    subprocess.check_call(["sss_override", "group-add", "group",
++                           "-g", "3001"])
++
++    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
++                           "--gid", "3002"])
++
++    # Restart SSSD so the override might take effect
++    restart_sssd()
++
++    # Assert entries are overridden
++    assert_group_overriden(override_name=False)
++
++    # Export overrides
++    subprocess.check_call(["sss_override", "group-export",
++                           OVERRIDE_FILENAME])
++
++    # Drop all overrides
++    subprocess.check_call(["sss_override", "group-del", "group"])
++    subprocess.check_call(["sss_override", "group-del", "empty_group@LDAP"])
++
++    # Avoid hitting memory cache
++    time.sleep(2)
++
++    assert_group_default()
++
++    # Import overrides
++    subprocess.check_call(["sss_override", "group-import",
++                           OVERRIDE_FILENAME])
++    restart_sssd()
++
++    assert_group_overriden(override_name=False)
++
++
+ # Regression test for bug #2802
+ # sss_override segfaults when accidentally adding --help flag to some commands
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch b/SOURCES/0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch
new file mode 100644
index 0000000..2df0058
--- /dev/null
+++ b/SOURCES/0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch
@@ -0,0 +1,267 @@
+From 5000ad4c45d3cfb4ffa0d76d291c8b1b6c49b02b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 31 Aug 2016 14:32:31 +0200
+Subject: [PATCH 141/143] p11: only set PKCS11_LOGIN_TOKEN_NAME if
+ gdm-smartcard is used
+
+Resolves https://fedorahosted.org/sssd/ticket/3165
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 71cd9f98150577224559bdc12c53c01ce6f2c3d9)
+---
+ src/responder/pam/pamsrv_p11.c  | 33 +++++++++------
+ src/tests/cmocka/test_pam_srv.c | 89 +++++++++++++++++++++++++++++++++++------
+ 2 files changed, 97 insertions(+), 25 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
+index a2514f6a1d699de3a245063f49db1b7e51a2b10b..22da33067d5c479153376927855dcd6b43322d8b 100644
+--- a/src/responder/pam/pamsrv_p11.c
++++ b/src/responder/pam/pamsrv_p11.c
+@@ -505,7 +505,11 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ }
+ 
+ /* The PKCS11_LOGIN_TOKEN_NAME environment variable is e.g. used by the Gnome
+- * Settings Daemon to determine the name of the token used for login */
++ * Settings Daemon to determine the name of the token used for login but it
++ * should be only set if SSSD is called by gdm-smartcard. Otherwise desktop
++ * components might assume that gdm-smartcard PAM stack is configured
++ * correctly which might not be the case e.g. if Smartcard authentication was
++ * used when running gdm-password. */
+ #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME"
+ 
+ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
+@@ -553,19 +557,22 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
+         return ret;
+     }
+ 
+-    env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, token_name);
+-    if (env == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+-        return ENOMEM;
+-    }
++    if (strcmp(pd->service, "gdm-smartcard") == 0) {
++        env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME,
++                              token_name);
++        if (env == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++            return ENOMEM;
++        }
+ 
+-    ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env) + 1,
+-                           (uint8_t *)env);
+-    talloc_free(env);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "pam_add_response failed to add environment variable.\n");
+-        return ret;
++        ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env) + 1,
++                               (uint8_t *)env);
++        talloc_free(env);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "pam_add_response failed to add environment variable.\n");
++            return ret;
++        }
+     }
+ 
+     return ret;
+diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
+index 5de092d0f19318d1d6c773355dbb38e345600133..02199e6f121cab0784389256cdaac38baf9d73e3 100644
+--- a/src/tests/cmocka/test_pam_srv.c
++++ b/src/tests/cmocka/test_pam_srv.c
+@@ -554,7 +554,7 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
+ }
+ 
+ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
+-                                const char *pin)
++                                const char *pin, const char *service)
+ {
+     size_t buf_size;
+     uint8_t *m_buf;
+@@ -576,7 +576,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
+         pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN;
+     }
+ 
+-    pi.pam_service = "login";
++    pi.pam_service = service == NULL ? "login" : service;
+     pi.pam_service_size = strlen(pi.pam_service) + 1;
+     pi.pam_tty = "/dev/tty";
+     pi.pam_tty_size = strlen(pi.pam_tty) + 1;
+@@ -626,7 +626,8 @@ static int test_pam_simple_check(uint32_t status, uint8_t *body, size_t blen)
+ 
+ #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME"
+ 
+-static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
++static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
++                                             size_t blen)
+ {
+     size_t rp = 0;
+     uint32_t val;
+@@ -675,6 +676,44 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
+     return EOK;
+ }
+ 
++static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
++{
++    size_t rp = 0;
++    uint32_t val;
++
++    assert_int_equal(status, 0);
++
++    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
++    assert_int_equal(val, pam_test_ctx->exp_pam_status);
++
++    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
++    assert_int_equal(val, 2);
++
++    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
++    assert_int_equal(val, SSS_PAM_DOMAIN_NAME);
++
++    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
++    assert_int_equal(val, 9);
++
++    assert_int_equal(*(body + rp + val - 1), 0);
++    assert_string_equal(body + rp, TEST_DOM_NAME);
++    rp += val;
++
++    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
++    assert_int_equal(val, SSS_PAM_CERT_INFO);
++
++    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
++    assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME)));
++
++    assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0);
++    assert_string_equal(body + rp, "pamuser");
++    rp += sizeof("pamuser");
++
++    assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0);
++    assert_string_equal(body + rp, TEST_TOKEN_NAME);
++
++    return EOK;
++}
+ 
+ static int test_pam_offline_chauthtok_check(uint32_t status,
+                                             uint8_t *body, size_t blen)
+@@ -1438,7 +1477,7 @@ void test_pam_preauth_no_logon_name(void **state)
+ {
+     int ret;
+ 
+-    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
++    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1465,7 +1504,7 @@ void test_pam_preauth_cert_nocert(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
+ 
+-    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
++    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1544,7 +1583,7 @@ void test_pam_preauth_cert_nomatch(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
+ 
+-    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
++    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1566,7 +1605,7 @@ void test_pam_preauth_cert_match(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
+ 
+-    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
++    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1583,13 +1622,37 @@ void test_pam_preauth_cert_match(void **state)
+     assert_int_equal(ret, EOK);
+ }
+ 
++/* Test if PKCS11_LOGIN_TOKEN_NAME is added for the gdm-smartcard service */
++void test_pam_preauth_cert_match_gdm_smartcard(void **state)
++{
++    int ret;
++
++    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
++
++    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, "gdm-smartcard");
++
++    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
++    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
++    mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
++                      discard_const(TEST_TOKEN_CERT));
++
++    set_cmd_cb(test_pam_cert_check_gdm_smartcard);
++    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
++                          pam_test_ctx->pam_cmds);
++    assert_int_equal(ret, EOK);
++
++    /* Wait until the test finishes with EOK */
++    ret = test_ev_loop(pam_test_ctx->tctx);
++    assert_int_equal(ret, EOK);
++}
++
+ void test_pam_preauth_cert_match_wrong_user(void **state)
+ {
+     int ret;
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
+ 
+-    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
++    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1613,7 +1676,7 @@ void test_pam_preauth_cert_no_logon_name(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
+ 
+-    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
++    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1636,7 +1699,7 @@ void test_pam_preauth_no_cert_no_logon_name(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
+ 
+-    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
++    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1657,7 +1720,7 @@ void test_pam_preauth_cert_no_logon_name_no_match(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
+ 
+-    mock_input_pam_cert(pam_test_ctx, NULL, NULL);
++    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1679,7 +1742,7 @@ void test_pam_cert_auth(void **state)
+ 
+     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
+ 
+-    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456");
++    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL);
+ 
+     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
+     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+@@ -1790,6 +1853,8 @@ int main(int argc, const char *argv[])
+                                         pam_test_setup, pam_test_teardown),
+         cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match,
+                                         pam_test_setup, pam_test_teardown),
++        cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match_gdm_smartcard,
++                                        pam_test_setup, pam_test_teardown),
+         cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match_wrong_user,
+                                         pam_test_setup, pam_test_teardown),
+         cmocka_unit_test_setup_teardown(test_pam_preauth_cert_no_logon_name,
+-- 
+2.7.4
+
diff --git a/SOURCES/0142-p11-return-a-fully-qualified-name.patch b/SOURCES/0142-p11-return-a-fully-qualified-name.patch
new file mode 100644
index 0000000..195b9cc
--- /dev/null
+++ b/SOURCES/0142-p11-return-a-fully-qualified-name.patch
@@ -0,0 +1,100 @@
+From e87e0059520de24047e8448a5b417393adc6c5b4 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 16 Sep 2016 11:47:40 +0200
+Subject: [PATCH 142/143] p11: return a fully-qualified name
+
+Related to https://fedorahosted.org/sssd/ticket/3165
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 3649b959709f1ab187092f054d4aace0798c98fa)
+---
+ src/responder/pam/pamsrv_p11.c  | 20 +++++++++-----------
+ src/tests/cmocka/test_pam_srv.c | 16 ++++++++--------
+ 2 files changed, 17 insertions(+), 19 deletions(-)
+
+diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
+index 22da33067d5c479153376927855dcd6b43322d8b..570bfe09d4385a038e7e03fcb64c72dd794774a6 100644
+--- a/src/responder/pam/pamsrv_p11.c
++++ b/src/responder/pam/pamsrv_p11.c
+@@ -521,33 +521,31 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
+     size_t msg_len;
+     size_t slot_len;
+     int ret;
+-    char *username;
+ 
+     if (sysdb_username == NULL || token_name == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n");
+         return EINVAL;
+     }
+ 
+-    ret = sss_parse_internal_fqname(pd, sysdb_username, &username, NULL);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot parse [%s]\n", sysdb_username);
+-        return ret;
+-    }
+-
+-    user_len = strlen(username) + 1;
++    user_len = strlen(sysdb_username) + 1;
+     slot_len = strlen(token_name) + 1;
+     msg_len = user_len + slot_len;
+ 
+     msg = talloc_zero_size(pd, msg_len);
+     if (msg == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
+-        talloc_free(username);
+         return ENOMEM;
+     }
+ 
+-    memcpy(msg, username, user_len);
++    /* sysdb_username is a fully-qualified name which is used by pam_sss when
++     * prompting the user for the PIN and as login name if it wasn't set by
++     * the PAM caller but has to be determined based on the inserted
++     * Smartcard. If this type of name is irritating at the PIN prompt or the
++     * re_expression config option was set in a way that user@domain cannot be
++     * handled anymore some more logic has to be added here. But for the time
++     * being I think using sysdb_username is fine. */
++    memcpy(msg, sysdb_username, user_len);
+     memcpy(msg + user_len, token_name, slot_len);
+-    talloc_free(username);
+ 
+     ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg);
+     talloc_free(msg);
+diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
+index 02199e6f121cab0784389256cdaac38baf9d73e3..4b2dea4be6a819b23afd243ba99cd9bd57c16c20 100644
+--- a/src/tests/cmocka/test_pam_srv.c
++++ b/src/tests/cmocka/test_pam_srv.c
+@@ -664,11 +664,11 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
+     assert_int_equal(val, SSS_PAM_CERT_INFO);
+ 
+     SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
+-    assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME)));
++    assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME)));
+ 
+-    assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0);
+-    assert_string_equal(body + rp, "pamuser");
+-    rp += sizeof("pamuser");
++    assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0);
++    assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME);
++    rp += sizeof("pamuser@"TEST_DOM_NAME);
+ 
+     assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0);
+     assert_string_equal(body + rp, TEST_TOKEN_NAME);
+@@ -703,11 +703,11 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
+     assert_int_equal(val, SSS_PAM_CERT_INFO);
+ 
+     SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
+-    assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME)));
++    assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME)));
+ 
+-    assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0);
+-    assert_string_equal(body + rp, "pamuser");
+-    rp += sizeof("pamuser");
++    assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0);
++    assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME);
++    rp += sizeof("pamuser@"TEST_DOM_NAME);
+ 
+     assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0);
+     assert_string_equal(body + rp, TEST_TOKEN_NAME);
+-- 
+2.7.4
+
diff --git a/SOURCES/0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch b/SOURCES/0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch
new file mode 100644
index 0000000..1cd1c77
--- /dev/null
+++ b/SOURCES/0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch
@@ -0,0 +1,109 @@
+From b5a092b4b0e4f072f0f402146a83addb97cf2977 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 16 Sep 2016 11:48:18 +0200
+Subject: [PATCH 143/143] pam_sss: check PKCS11_LOGIN_TOKEN_NAME
+
+Check if PKCS11_LOGIN_TOKEN_NAME is set and prompt the user if the
+matching Smartcard is not inserted.
+
+Related to https://fedorahosted.org/sssd/ticket/3165
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 35ba922bc51416f02877b53a6f25c04104ae5f03)
+---
+ src/sss_client/pam_sss.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 65 insertions(+)
+
+diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
+index fdb9c907644f1317b6f8e58619f01ad2753deafc..2049d5fb0c6092aaaa914385c79d02d8f44b447e 100644
+--- a/src/sss_client/pam_sss.c
++++ b/src/sss_client/pam_sss.c
+@@ -1410,6 +1410,7 @@ done:
+ }
+ 
+ #define SC_PROMPT_FMT "PIN for %s for user %s"
++
+ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
+ {
+     int ret;
+@@ -1691,6 +1692,62 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
+     return PAM_SUCCESS;
+ }
+ 
++#define SC_ENTER_FMT "Please enter smart card labeled\n %s\nand press enter"
++
++static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
++                                  bool quiet_mode)
++{
++    int ret;
++    int pam_status;
++    char *login_token_name;
++    char *prompt = NULL;
++    size_t size;
++    char *answer = NULL;
++
++    login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
++    if (login_token_name == NULL) {
++        return PAM_SUCCESS;
++    }
++
++    while (pi->token_name == NULL
++            || strcmp(login_token_name, pi->token_name) != 0) {
++        size = sizeof(SC_ENTER_FMT) + strlen(login_token_name);
++        prompt = malloc(size);
++        if (prompt == NULL) {
++            D(("malloc failed."));
++            return ENOMEM;
++        }
++
++        ret = snprintf(prompt, size, SC_ENTER_FMT,
++                       login_token_name);
++        if (ret < 0 || ret >= size) {
++            D(("snprintf failed."));
++            free(prompt);
++            return EFAULT;
++        }
++
++        ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt,
++                                  NULL, &answer);
++        free(prompt);
++        free(answer);
++        if (ret != PAM_SUCCESS) {
++            D(("do_pam_conversation failed."));
++            return ret;
++        }
++
++        pam_status = send_and_receive(pamh, pi, SSS_PAM_PREAUTH, quiet_mode);
++        if (pam_status != PAM_SUCCESS) {
++            D(("send_and_receive returned [%d] during pre-auth", pam_status));
++        /*
++         * Since we are waiting for the right Smartcard to be inserted errors
++         * can be ignored here.
++         */
++        }
++    }
++
++    return PAM_SUCCESS;
++}
++
+ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
+                    int pam_flags, int argc, const char **argv)
+ {
+@@ -1758,6 +1815,14 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
+                     }
+                 }
+ 
++                if (strcmp(pi.pam_service, "gdm-smartcard") == 0) {
++                    ret = check_login_token_name(pamh, &pi, quiet_mode);
++                    if (ret != PAM_SUCCESS) {
++                        D(("check_login_token_name failed.\n"));
++                        return ret;
++                    }
++                }
++
+                 ret = get_authtok_for_authentication(pamh, &pi, flags);
+                 if (ret != PAM_SUCCESS) {
+                     D(("failed to get authentication token: %s",
+-- 
+2.7.4
+
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
index 84381b9..370e6d7 100644
--- a/SPECS/sssd.spec
+++ b/SPECS/sssd.spec
@@ -4,17 +4,20 @@
 %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
+    %global install_pcscd_polkit_rule 1
 
 # Determine the location of the LDB modules directory
 %global ldb_modulesdir %(pkg-config --variable=modulesdir ldb)
 %global ldb_version 1.1.17
 
-%global with_krb5_localauth_plugin 1
+
+%if (0%{?fedora} || 0%{?rhel} >= 7)
+    %global with_cifs_utils_plugin 1
+%else
+    %global with_cifs_utils_plugin_option --disable-cifs-idmap-plugin
+%endif
+
+    %global with_krb5_localauth_plugin 1
 
 %global libwbc_alternatives_version 0.12
 %global libwbc_lib_version %{libwbc_alternatives_version}.0
@@ -23,148 +26,174 @@
 %global libwbc_alternatives_suffix -64
 %endif
 
+%global enable_systemtap 1
+%if (0%{?enable_systemtap} == 1)
+    %global enable_systemtap_opt --enable-systemtap
+%endif
+
 Name: sssd
-Version: 1.13.0
-Release: 40%{?dist}.12
+Version: 1.14.0
+Release: 43%{?dist}
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
 URL: http://fedorahosted.org/sssd/
 Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz
-Source1: cert9.db
-Source2: key4.db
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 ### Patches ###
-Patch0001:  0001-test-common-sss_dp_get_account_recv-fix-assignment.patch
-Patch0002:  0002-tests-Move-N_ELEMENTS-definition-to-tests-common.h.patch
-Patch0003:  0003-SYSDB-Add-functions-to-look-up-multiple-entries-incl.patch
-Patch0004:  0004-DP-Add-DP_WILDCARD-and-SSS_DP_WILDCARD_USER-SSS_DP_W.patch
-Patch0005:  0005-cache_req-Extend-cache_req-with-wildcard-lookups.patch
-Patch0006:  0006-UTIL-Add-sss_filter_sanitize_ex.patch
-Patch0007:  0007-LDAP-Fetch-users-and-groups-using-wildcards.patch
-Patch0008:  0008-LDAP-Add-sdap_get_and_parse_generic_send.patch
-Patch0009:  0009-LDAP-Use-sdap_get_and_parse_generic_-_recv.patch
-Patch0010:  0010-LDAP-Add-sdap_lookup_type-enum.patch
-Patch0011:  0011-LDAP-Add-the-wildcard_limit-option.patch
-Patch0012:  0012-IFP-Add-wildcard-requests.patch
-Patch0013:  0013-KRB5-Return-right-data-provider-error-code.patch
-Patch0014:  0014-nss_check_name_of_well_known_sid-improve-name-splitt.patch
-Patch0015:  0015-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch
-Patch0016:  0016-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch
-Patch0017:  0017-DYNDNS-special-value-for-dyndns_iface-option.patch
-Patch0018:  0018-TESTS-dyndns-tests-support-AAAA-addresses.patch
-Patch0019:  0019-DYNDNS-support-for-dualstack.patch
-Patch0020:  0020-VIEWS-TEST-add-null-check.patch
-Patch0021:  0021-SYSDB-prepare-for-LOCAL-view.patch
-Patch0022:  0022-TOOLS-add-common-command-framework.patch
-Patch0023:  0023-TOOLS-add-sss_override-for-local-overrides.patch
-Patch0024:  0024-IPA-Better-debugging.patch
-Patch0025:  0025-UTIL-Lower-debug-level-in-perform_checks.patch
-Patch0026:  0026-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch
-Patch0027:  0027-TESTS-fix-compiler-warnings.patch
-Patch0028:  0028-intg-Invalidate-memory-cache-before-removing-files.patch
-Patch0029:  0029-krb5-do-not-send-SSS_OTP-if-two-factors-were-used.patch
-Patch0030:  0030-utils-add-NSS-version-of-cert-utils.patch
-Patch0031:  0031-Add-NSS-version-of-p11_child.patch
-Patch0032:  0032-pack_message_v3-allow-empty-name.patch
-Patch0033:  0033-authok-add-support-for-Smart-Card-related-authtokens.patch
-Patch0034:  0034-PAM-add-certificate-support-to-PAM-pre-auth-NOTEST.patch
-Patch0035:  0035-pam_sss-add-sc-support.patch
-Patch0036:  0036-ssh-generate-public-keys-from-certificate.patch
-Patch0037:  0037-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch
-Patch0038:  0038-mmap_cache-Rename-variables.patch
-Patch0039:  0039-mmap_cache-Override-functions-for-initgr-mmap-cache.patch
-Patch0040:  0040-mmap-Invalidate-initgroups-memory-cache-after-any-ch.patch
-Patch0041:  0041-sss_client-Update-integrity-check-of-records-in-mmap.patch
-Patch0042:  0042-intg_test-Add-module-for-simulation-of-utility-id.patch
-Patch0043:  0043-intg_test-Add-integration-test-for-memory-cache.patch
-Patch0044:  0044-NSS-Initgr-memory-cache-should-work-with-fq-names.patch
-Patch0045:  0045-test_memory_cache-Add-test-for-initgroups-mc-with-fq.patch
-Patch0046:  0046-test_memory_cache-Test-mmap-cache-after-initgroups.patch
-Patch0047:  0047-test_memory_cache-Test-invalidation-with-sss_cache.patch
-Patch0048:  0048-krb5-utils-add-sss_krb5_realm_has_proxy.patch
-Patch0049:  0049-krb5-do-not-create-kdcinfo-file-if-proxy-configurati.patch
-Patch0050:  0050-krb5-assume-online-state-if-KDC-proxy-is-configured.patch
-Patch0051:  0051-sss_cache-Wait-a-while-for-invalidation-of-mc-by-nss.patch
-Patch0052:  0052-IFP-use-default-limit-if-provided-is-0.patch
-Patch0053:  0053-sudo-use-higher-value-wins-when-ordering-rules.patch
-Patch0054:  0054-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch
-Patch0055:  0055-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch
-Patch0056:  0056-UTIL-Provide-a-common-interface-to-safely-create-tem.patch
-Patch0057:  0057-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch
-Patch0058:  0058-p11child-set-restrictive-umask-and-clear-environment.patch
-Patch0059:  0059-pam-Incerease-p11-child-timeout.patch
-Patch0060:  0060-SYSDB-Index-the-objectSIDString-attribute.patch
-Patch0061:  0061-sss_override-print-input-name-if-unable-to-parse-it.patch
-Patch0062:  0062-sss_override-support-domains-that-require-fqname.patch
-Patch0063:  0063-TOOLS-add-sss_colondb-API.patch
-Patch0064:  0064-sss_override-decompose-code-better.patch
-Patch0065:  0065-sss_override-support-import-and-export.patch
-Patch0066:  0066-NSS-Fix-use-after-free.patch
-Patch0067:  0067-sss_override-document-debug-options.patch
-Patch0068:  0068-NSS-Don-t-ignore-backslash-in-usernames-with-ldap-pr.patch
-Patch0069:  0069-GPO-fix-memory-leak.patch
-Patch0070:  0070-sss_override-support-fqn-in-override-name.patch
-Patch0071:  0071-views-do-not-require-overrideDN-in-grous-when-LOCAL-.patch
-Patch0072:  0072-views-fix-two-typos-in-debug-messages.patch
-Patch0073:  0073-views-allow-ghost-members-for-LOCAL-view.patch
-Patch0074:  0074-UTIL-Convert-domain-disabled-into-tri-state-with-dom.patch
-Patch0075:  0075-DP-Provide-a-way-to-mark-subdomain-as-disabled-and-a.patch
-Patch0076:  0076-SDAP-Do-not-set-is_offline-if-ignore_mark_offline-is.patch
-Patch0077:  0077-AD-Only-ignore-errors-from-SDAP-lookups-if-there-s-a.patch
-Patch0078:  0078-KRB5-Offline-operation-with-disabled-domain.patch
-Patch0079:  0079-AD-Do-not-mark-the-whole-back-end-as-offline-if-subd.patch
-Patch0080:  0080-AD-Set-ignore_mark_offline-false-when-resolving-AD-r.patch
-Patch0081:  0081-IPA-Do-not-allow-the-AD-lookup-code-to-set-backend-a.patch
-Patch0082:  0082-sss_override-remove-d-from-manpage.patch
-Patch0083:  0083-LDAP-imposing-sizelimit-1-for-single-entry-searches-.patch
-Patch0084:  0084-DYNDNS-Add-a-new-option-dyndns_server.patch
-Patch0085:  0085-DYNDNS-Don-t-use-server-cmd-in-nsupdate-by-default.patch
-Patch0086:  0086-DYNDNS-remove-redundant-talloc_steal.patch
-Patch0087:  0087-DYNDNS-remove-zone-command.patch
-Patch0088:  0088-DYNDNS-rename-field-of-sdap_dyndns_update_state.patch
-Patch0089:  0089-DYNDNS-remove-code-duplication.patch
-Patch0090:  0090-DDNS-execute-nsupdate-for-single-update-of-PTR-rec.patch
-Patch0091:  0091-DYNDNS-Return-right-error-code-in-case-of-failure.patch
-Patch0092:  0092-IPA-Change-ipa_server_trust_add_send-request-to-be-r.patch
-Patch0093:  0093-DEBUG-Add-new-debug-category-for-fail-over.patch
-Patch0094:  0094-FO-Add-an-API-to-reset-all-servers-in-a-single-servi.patch
-Patch0095:  0095-FO-Also-reset-the-server-common-data-in-addition-to-.patch
-Patch0096:  0096-IPA-Retry-fetching-keytab-if-IPA-user-lookup-fails.patch
-Patch0097:  0097-AD-inicialize-root_domain_attrs-field.patch
-Patch0098:  0098-PAM-only-allow-missing-user-name-for-certificate-aut.patch
-Patch0099:  0099-Fix-memory-leak-in-sssdpac_verify.patch
-Patch0100:  0100-AD-Provide-common-connection-list-construction-funct.patch
-Patch0101:  0101-AD-Consolidate-connection-list-construction-on-ad_co.patch
-Patch0102:  0102-nss-send-original-name-and-id-with-local-views-if-po.patch
-Patch0103:  0103-sudo-search-with-view-even-if-user-is-found.patch
-Patch0104:  0104-sudo-send-original-name-and-id-with-local-views-if-p.patch
-Patch0105:  0105-IPA-fix-override-with-the-same-name.patch
-Patch0106:  0106-Add-a-new-option-ldap_group_external_member.patch
-Patch0107:  0107-IPA-Add-interface-to-call-into-IPA-provider-from-LDA.patch
-Patch0108:  0108-LDAP-Use-the-IPA-provider-interface-to-resolve-exter.patch
-Patch0109:  0109-memberof-Don-t-allocate-on-a-NULL-context.patch
-Patch0110:  0110-memberof-Fix-a-memory-leak-when-removing-ghost-users.patch
-Patch0111:  0111-memberof-Don-t-allocate-on-NULL-when-deleting-member.patch
-Patch0112:  0112-IPA-Handle-requests-for-netgroups-from-trusted-domai.patch
-Patch0113:  0113-LDAP-Try-also-the-AD-access-control-for-IPA-users.patch
-Patch0114:  0114-NSS-Fix-memory-leak-netgroup.patch
-Patch0115:  0115-ipa_s2n_save_objects-use-configured-user-and-group-t.patch
-Patch0116:  0116-IPA-use-forest-name-when-looking-up-the-Global-Catal.patch
-Patch0117:  0117-LDAP-Fix-leak-of-file-descriptors.patch
-Patch0118:  0118-libwbclient-wbcSidsToUnixIds-don-t-fail-on-errors.patch
-Patch0119:  0119-IPA-ldap_group_external_member-defaults-to-ipaExtern.patch
+Patch0001: 0001-SYSDB-Fixing-DB-update.patch
+Patch0002: 0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch
+Patch0003: 0003-sssctl-config-check-access-check-report.patch
+Patch0004: 0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch
+Patch0005: 0005-sssctl-Fix-format-string-for-size_t.patch
+Patch0006: 0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch
+Patch0007: 0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch
+Patch0008: 0008-sssctl-Fix-warning-maybe-uninitialized.patch
+Patch0009: 0009-NOUPSTREAM-Bundle-http-parser.patch
+Patch0010: 0010-MAN-Update-description-of-sssctl.patch
+Patch0011: 0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch
+Patch0012: 0012-TOOLS-Prevent-dereference-of-null-pointer.patch
+Patch0013: 0013-config-override_space-is-monitor-s-option.patch
+Patch0014: 0014-config-Fix-user_attributes.patch
+Patch0015: 0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch
+Patch0016: 0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch
+Patch0017: 0017-config-Allow-timeout-for-all-sevices.patch
+Patch0018: 0018-config-Add-config_file_version-to-schema.patch
+Patch0019: 0019-dyndns-Add-checks-for-NULL.patch
+Patch0020: 0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch
+Patch0021: 0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch
+Patch0022: 0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch
+Patch0023: 0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch
+Patch0024: 0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch
+Patch0025: 0025-DP-add-dp_get_module_data.patch
+Patch0026: 0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch
+Patch0027: 0027-IPA-enable-enterprise-principals-if-server-supports-.patch
+Patch0028: 0028-views-allow-override-added-for-non-default-views-at-.patch
+Patch0029: 0029-sssctl-move-filter-creation-to-separate-function.patch
+Patch0030: 0030-sssctl-improve-readability-of-a-condition.patch
+Patch0031: 0031-sssctl-Use-localtime-for-time-stamps.patch
+Patch0032: 0032-SECRETS-Log-message-for-failures-with-removing-file.patch
+Patch0033: 0033-IPA-fix-capaths-output.patch
+Patch0034: 0034-UTIL-make-domain-mapping-content-testable.patch
+Patch0035: 0035-tests-add-tests-for-sss_get_domain_mappings_content.patch
+Patch0036: 0036-Amend-debug-messages-after-failure-of-unlink.patch
+Patch0037: 0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch
+Patch0038: 0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch
+Patch0039: 0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch
+Patch0040: 0040-tests-add-tests-for-netlogon_get_domain_info.patch
+Patch0041: 0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch
+Patch0042: 0042-sysdb_master_domain_add_info-properly-set-do_update.patch
+Patch0043: 0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch
+Patch0044: 0044-test_utils-Fixing-assignment-discards-const-qualifie.patch
+Patch0045: 0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch
+Patch0046: 0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch
+Patch0047: 0047-sysdb-add-sysdb_get_user_members_recursively.patch
+Patch0048: 0048-views-properly-override-group-member-names.patch
+Patch0049: 0049-IPA-fix-lookup-by-UPN-for-subdomains.patch
+Patch0050: 0050-LDAP-allow-multiple-user-principals.patch
+Patch0051: 0051-LDAP-new-attribute-option-ldap_user_email.patch
+Patch0052: 0052-sysdb-include-email-in-UPN-searches.patch
+Patch0053: 0053-LDAP-include-email-in-UPN-searches.patch
+Patch0054: 0054-NSS-add-user-email-to-fill_orig.patch
+Patch0055: 0055-utils-add-is_email_from_domain.patch
+Patch0056: 0056-LDAP-IPA-add-local-email-address-to-aliases.patch
+Patch0057: 0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch
+Patch0058: 0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch
+Patch0059: 0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch
+Patch0060: 0060-PAM-Fix-domain-for-UPN-based-lookups.patch
+Patch0061: 0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch
+Patch0062: 0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch
+Patch0063: 0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch
+Patch0064: 0064-LDAP-Changing-of-confusing-debug-message.patch
+Patch0065: 0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch
+Patch0066: 0066-sssctl-Consistent-commands-naming.patch
+Patch0067: 0067-SDAP-sanitize-member-name-before-using-in-filter.patch
+Patch0068: 0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch
+Patch0069: 0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch
+Patch0070: 0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch
+Patch0071: 0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch
+Patch0072: 0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch
+Patch0073: 0073-LDAP-Fix-Dereference-after-NULL-check.patch
+Patch0074: 0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch
+Patch0075: 0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch
+Patch0076: 0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch
+Patch0077: 0077-DP-Initialize-D-Bus-as-soon-as-possible.patch
+Patch0078: 0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch
+Patch0079: 0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch
+Patch0080: 0080-config_schema-Add-ldap_user_email-to-schema.patch
+Patch0081: 0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch
+Patch0082: 0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch
+Patch0083: 0083-SIMPLE-Do-not-parse-names-on-startup.patch
+Patch0084: 0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch
+Patch0085: 0085-SIMPLE-Make-the-DP-handlers-testable.patch
+Patch0086: 0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch
+Patch0087: 0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch
+Patch0088: 0088-sss_ini-Change-debug-level-of-config-error-msgs.patch
+Patch0089: 0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch
+Patch0090: 0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch
+Patch0091: 0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch
+Patch0092: 0092-sbus-add-sbus_request_reply_error.patch
+Patch0093: 0093-sbus-add-utility-function-to-simplify-message-and-re.patch
+Patch0094: 0094-sssctl-use-talloc-with-sifp.patch
+Patch0095: 0095-failover-mark-subdomain-service-with-sd_-prefix.patch
+Patch0096: 0096-sssctl-print-active-server-and-server-list.patch
+Patch0097: 0097-sifp-fix-coverity-warning.patch
+Patch0098: 0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch
+Patch0099: 0099-PROXY-Do-not-abuse-data-provider-interface.patch
+Patch0100: 0100-DP-Remove-old-data-provider-interface.patch
+Patch0101: 0101-NSS-Remove-unused-functions.patch
+Patch0102: 0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch
+Patch0103: 0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch
+Patch0104: 0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch
+Patch0105: 0105-AD_PROVIDER-ad_enabled_domains-only-master.patch
+Patch0106: 0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch
+Patch0107: 0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch
+Patch0109: 0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch
+Patch0110: 0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch
+Patch0111: 0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch
+Patch0112: 0112-DP-Add-log-message-for-get-account-info.patch
+Patch0113: 0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch
+Patch0114: 0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch
+Patch0115: 0115-sdap-Skip-exact-duplicates-when-extending-maps.patch
+Patch0116: 0116-watchdog-cope-with-time-shift.patch
+Patch0117: 0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch
+Patch0118: 0118-BUILD-Allow-to-read-private-pipes-for-root.patch
+Patch0119: 0119-SYSDB-Rework-sysdb_cache_connect.patch
+Patch0120: 0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch
+Patch0121: 0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch
+Patch0122: 0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch
+Patch0123: 0123-SYSDB-Fix-uninitialized-scalar-variable.patch
+Patch0124: 0124-PROXY-Use-right-name-in-ldap-filter.patch
+Patch0125: 0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch
+Patch0126: 0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch
+Patch0127: 0127-Revert-CONFIG-Use-default-config-when-none-provided.patch
+Patch0128: 0128-TOOLS-Fix-a-typo-in-groupadd.patch
+Patch0129: 0129-TOOLS-sss_groupshow-did-not-work.patch
+Patch0130: 0130-TESTS-sss_groupadd-groupshow-regressions.patch
+Patch0131: 0131-TOOLS-use-internal-fqdn-for-DN.patch
+Patch0132: 0132-TESTS-Test-for-sss_user-groupmod-a.patch
+Patch0133: 0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch
+Patch0134: 0134-TESTS-Add-FQDN-variants-for-some-tests.patch
+Patch0135: 0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch
+Patch0136: 0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch
+Patch0137: 0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch
+Patch0138: 0138-TESTS-sss_groupshow-with-MPG.patch
+Patch0139: 0139-TOOLS-sss_override-without-name-override.patch
+Patch0140: 0140-TEST-Add-regression-test-for-ticket-3179.patch
+Patch0141: 0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch
+Patch0142: 0142-p11-return-a-fully-qualified-name.patch
+Patch0143: 0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch
 
 #This patch should not be removed in RHEL-7
 Patch999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
 
 ### Dependencies ###
+
 Requires: sssd-common = %{version}-%{release}
 Requires: sssd-ldap = %{version}-%{release}
 Requires: sssd-krb5 = %{version}-%{release}
 Requires: sssd-ipa = %{version}-%{release}
-Requires: sssd-common-pac = %{version}-%{release}
 Requires: sssd-ad = %{version}-%{release}
 Requires: sssd-proxy = %{version}-%{release}
 Requires: python-sssdconfig = %{version}-%{release}
@@ -177,6 +206,7 @@ Requires: python-sssdconfig = %{version}-%{release}
 %global mcpath %{sssdstatedir}/mc
 %global pubconfpath %{sssdstatedir}/pubconf
 %global gpocachepath %{sssdstatedir}/gpo_cache
+%global secdbpath %{sssdstatedir}/secrets
 
 ### Build Dependencies ###
 
@@ -193,23 +223,18 @@ BuildRequires: libtdb-devel
 BuildRequires: libldb-devel >= %{ldb_version}
 BuildRequires: libdhash-devel >= 0.4.2
 BuildRequires: libcollection-devel
-BuildRequires: libini_config-devel >= 1.1.0-24
+BuildRequires: libini_config-devel >= 1.3.0
 BuildRequires: dbus-devel
 BuildRequires: dbus-libs
 BuildRequires: openldap-devel
 BuildRequires: pam-devel
 BuildRequires: nss-devel
-BuildRequires: openssl-devel
 BuildRequires: nspr-devel
 BuildRequires: pcre-devel
 BuildRequires: libxslt
 BuildRequires: libxml2
 BuildRequires: docbook-style-xsl
-%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
@@ -218,20 +243,22 @@ BuildRequires: libselinux-devel
 BuildRequires: libsemanage-devel
 BuildRequires: bind-utils
 BuildRequires: keyutils-libs-devel
-BuildRequires: libnl3-devel
 BuildRequires: gettext-devel
 BuildRequires: pkgconfig
-BuildRequires: glib2-devel
 BuildRequires: diffstat
 BuildRequires: findutils
-BuildRequires: samba4-devel >= 4.0.0-59beta2
+BuildRequires: glib2-devel
 BuildRequires: selinux-policy-targeted
+BuildRequires: libnl3-devel
 BuildRequires: systemd-devel
-BuildRequires: libsmbclient-devel
 %if (0%{?with_cifs_utils_plugin} == 1)
 BuildRequires: cifs-utils-devel
 %endif
 BuildRequires: libnfsidmap-devel
+BuildRequires: samba4-devel >= 4.0.0-59beta2
+BuildRequires: libsmbclient-devel
+BuildRequires: systemtap-sdt-devel
+BuildRequires: jansson-devel
 
 %description
 Provides a set of daemons to manage access to remote directories and
@@ -252,15 +279,10 @@ 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.1.0-24
+Requires: libsss_sudo%{?_isa}  = %{version}-%{release}
+Requires: libsss_autofs%{?_isa} = %{version}-%{release}
 Requires(post): systemd-units chkconfig
 Requires(preun): systemd-units chkconfig
 Requires(postun): systemd-units chkconfig
@@ -268,12 +290,8 @@ Requires(pre): shadow-utils
 
 
 ### Provides ###
-Provides: libsss_sudo = %{version}-%{release}
-Obsoletes: libsss_sudo <= 1.10.0-7%{?dist}.beta1
 Provides: libsss_sudo-devel = %{version}-%{release}
 Obsoletes: libsss_sudo-devel <= 1.10.0-7%{?dist}.beta1
-Provides: libsss_autofs = %{version}-%{release}
-Obsoletes: libsss_autofs <= 1.10.0-7%{?dist}.beta1
 
 %description common
 Common files for the SSSD. The common package includes all the files needed
@@ -293,6 +311,24 @@ Requires(preun): /usr/sbin/alternatives
 Provides the libraries needed by the PAM and NSS stacks to connect to the SSSD
 service.
 
+%package -n libsss_sudo
+Summary: A library to allow communication between SUDO and SSSD
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_sudo
+A utility library to allow communication between SUDO and SSSD
+
+%package -n libsss_autofs
+Summary: A library to allow communication between Autofs and SSSD
+Group: Development/Libraries
+License: LGPLv3+
+
+%description -n libsss_autofs
+A utility library to allow communication between Autofs and SSSD
+
 %package tools
 Summary: Userspace tools for use with the SSSD
 Group: Applications/System
@@ -309,6 +345,7 @@ Also provides several other administrative tools:
     * sss_debuglevel to change the debug level on the fly
     * sss_seed which pre-creates a user entry for use in kickstarts
     * sss_obfuscate for generating an obfuscated LDAP password
+    * sssctl -- an sssd status and control utility
 
 %package -n python-sssdconfig
 Summary: SSSD and IPA configuration file manipulation classes and functions
@@ -317,7 +354,7 @@ License: GPLv3+
 BuildArch: noarch
 
 %description -n python-sssdconfig
-Provides python files for manipulation SSSD and IPA configuration files.
+Provides python2 files for manipulation SSSD and IPA configuration files.
 
 %package -n python-sss
 Summary: Python2 bindings for sssd
@@ -378,8 +415,6 @@ Requires: sssd-krb5-common = %{version}-%{release}
 Provides the Kerberos back end that the SSSD can utilize authenticate
 against a Kerberos server.
 
-# RHEL 5 is too old to support the PAC responder
-%if !0%{?is_rhel5}
 %package common-pac
 Summary: Common files needed for supporting PAC processing
 Group: Applications/System
@@ -389,7 +424,6 @@ Requires: sssd-common = %{version}-%{release}
 %description common-pac
 Provides common files needed by SSSD providers such as IPA and Active Directory
 for handling Kerberos PACs.
-%endif #is_rhel5
 
 %package ipa
 Summary: The IPA back end of the SSSD
@@ -474,7 +508,7 @@ Requires: libipa_hbac = %{version}-%{release}
 Utility library to validate FreeIPA HBAC rules for authorization requests
 
 %package -n python-libipa_hbac
-Summary: Python bindings for the FreeIPA HBAC Evaluator library
+Summary: Python2 bindings for the FreeIPA HBAC Evaluator library
 Group: Development/Libraries
 License: LGPLv3+
 Requires: libipa_hbac = %{version}-%{release}
@@ -486,26 +520,26 @@ The python-libipa_hbac contains the bindings so that libipa_hbac can be
 used by Python applications.
 
 %package -n libsss_nss_idmap
-Summary: Library for SID based lookups
+Summary: Library for SID and certificate based lookups
 Group: Development/Libraries
 License: LGPLv3+
 Requires(post): /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
 
 %description -n libsss_nss_idmap
-Utility library for SID based lookups
+Utility library for SID and certificate based lookups
 
 %package -n libsss_nss_idmap-devel
-Summary: Library for SID based lookups
+Summary: Library for SID and certificate based lookups
 Group: Development/Libraries
 License: LGPLv3+
 Requires: libsss_nss_idmap = %{version}-%{release}
 
 %description -n libsss_nss_idmap-devel
-Utility library for SID based lookups
+Utility library for SID and certificate based lookups
 
 %package -n python-libsss_nss_idmap
-Summary: Python bindings for libsss_nss_idmap
+Summary: Python2 bindings for libsss_nss_idmap
 Group: Development/Libraries
 License: LGPLv3+
 Requires: libsss_nss_idmap = %{version}-%{release}
@@ -527,11 +561,23 @@ Requires: sssd-common = %{version}-%{release}
 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.
 
+%if (0%{?install_pcscd_polkit_rule} == 1)
+%package polkit-rules
+Summary: Rules for polkit integration for SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: polkit >= 0.106
+Requires: sssd-common = %{version}-%{release}
+
+%description polkit-rules
+Provides rules for polkit integration with SSSD. This is required
+for smartcard support.
+%endif
+
 %package -n libsss_simpleifp
 Summary: The SSSD D-Bus responder helper library
 Group: Development/Libraries
 License: GPLv3+
-Requires: dbus-libs
 Requires: sssd-dbus = %{version}-%{release}
 Requires(post): /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
@@ -567,6 +613,15 @@ Conflicts: libwbclient-devel < 4.1.12
 %description libwbclient-devel
 Development libraries for the SSSD libwbclient implementation.
 
+%package winbind-idmap
+Summary: SSSSD's idmap_sss Backend for Winbind
+Group:  Applications/System
+License: GPLv3+ and LGPLv3+
+
+%description winbind-idmap
+The idmap_sss module provides a way for Winbind to call SSSD to map UIDs/GIDs
+and SIDs.
+
 %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"
@@ -590,19 +645,15 @@ for p in %patches ; do
     UpdateTimestamps -p1 $p
 done
 
-# patch(1) doesn't handle binary files we need for tests. Package them
-# as additional sources and add to the source tree
-mkdir src/tests/cmocka/p11_nssdb/
-cp %{SOURCE1} src/tests/cmocka/p11_nssdb/
-cp %{SOURCE2} src/tests/cmocka/p11_nssdb/
-
 %build
 autoreconf -ivf
+
 %configure \
+    --with-test-dir=/dev/shm \
     --with-db-path=%{dbpath} \
+    --with-mcache-path=%{mcpath} \
     --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 \
@@ -612,14 +663,14 @@ autoreconf -ivf
     --disable-static \
     --disable-rpath \
     --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} \
     --without-python3-bindings \
-    --with-ad-gpo-default=permissive
+    --with-ad-gpo-default=permissive \
+    %{?enable_polkit_rules_option} \
+    %{?enable_systemtap_opt}
 
 make %{?_smp_mflags} all docs
 
@@ -629,7 +680,6 @@ make %{?_smp_mflags} check VERBOSE=yes
 unset CK_TIMEOUT_MULTIPLIER
 
 %install
-rm -rf $RPM_BUILD_ROOT
 
 make install DESTDIR=$RPM_BUILD_ROOT
 
@@ -642,10 +692,6 @@ fi
 # Prepare language files
 /usr/lib/rpm/find-lang.sh $RPM_BUILD_ROOT sssd
 
-# Prepare empty config file
-mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sssd
-touch $RPM_BUILD_ROOT/%{_sysconfdir}/sssd/sssd.conf
-
 # Copy default logrotate file
 mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d
 install -m644 src/examples/logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/sssd
@@ -654,6 +700,12 @@ install -m644 src/examples/logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/s
 mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rwtab.d
 install -m644 src/examples/rwtab $RPM_BUILD_ROOT%{_sysconfdir}/rwtab.d/sssd
 
+%if (0%{?with_cifs_utils_plugin} == 1)
+# Create directory for cifs-idmap alternative
+# Otherwise this directory could not be owned by sssd-client
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/cifs-utils
+%endif
+
 # Replace sysv init script with systemd unit file
 rm -f $RPM_BUILD_ROOT/%{_initrddir}/%{name}
 mkdir -p $RPM_BUILD_ROOT/%{_unitdir}/
@@ -732,10 +784,6 @@ do
     cat sssd_$provider.lang
 done
 
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
 %files
 %defattr(-,root,root,-)
 %doc COPYING
@@ -744,14 +792,17 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(-,root,root,-)
 %doc COPYING
 %doc src/examples/sssd-example.conf
-%{_unitdir}/sssd.service
 %{_sbindir}/sssd
+%{_unitdir}/sssd.service
+%{_unitdir}/sssd-secrets.socket
+%{_unitdir}/sssd-secrets.service
 
 %dir %{_libexecdir}/%{servicename}
 %{_libexecdir}/%{servicename}/sssd_be
 %{_libexecdir}/%{servicename}/sssd_nss
 %{_libexecdir}/%{servicename}/sssd_pam
 %{_libexecdir}/%{servicename}/sssd_autofs
+%{_libexecdir}/%{servicename}/sssd_secrets
 %{_libexecdir}/%{servicename}/sssd_ssh
 %{_libexecdir}/%{servicename}/sssd_sudo
 %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/p11_child
@@ -770,8 +821,6 @@ rm -rf $RPM_BUILD_ROOT
 %{_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
@@ -784,21 +833,27 @@ rm -rf $RPM_BUILD_ROOT
 %dir %{_localstatedir}/cache/krb5rcache
 %attr(700,sssd,sssd) %dir %{dbpath}
 %attr(755,sssd,sssd) %dir %{mcpath}
+%attr(700,root,root) %dir %{secdbpath}
 %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd
 %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
 %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups
 %attr(755,sssd,sssd) %dir %{pipepath}
+%attr(750,sssd,root) %dir %{pipepath}/private
 %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
+%attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d
 %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
+%dir %{_sysconfdir}/logrotate.d
 %config(noreplace) %{_sysconfdir}/logrotate.d/sssd
+%dir %{_sysconfdir}/rwtab.d
 %config(noreplace) %{_sysconfdir}/rwtab.d/sssd
 %dir %{_datadir}/sssd
+
+%{_datadir}/sssd/cfg_rules.ini
 %{_datadir}/sssd/sssd.api.conf
 %{_datadir}/sssd/sssd.api.d
 %{_mandir}/man1/sss_ssh_authorizedkeys.1*
@@ -809,6 +864,20 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man5/sss_rpcidmapd.5*
 %{_mandir}/man8/sssd.8*
 %{_mandir}/man8/sss_cache.8*
+%if (0%{?enable_systemtap} == 1)
+%dir %{_datadir}/sssd/systemtap
+%{_datadir}/sssd/systemtap/id_perf.stp
+%{_datadir}/sssd/systemtap/nested_group_perf.stp
+%dir %{_datadir}/systemtap
+%dir %{_datadir}/systemtap/tapset
+%{_datadir}/systemtap/tapset/sssd.stp
+%{_datadir}/systemtap/tapset/sssd_functions.stp
+%endif
+
+%if (0%{?install_pcscd_polkit_rule} == 1)
+%files polkit-rules
+%{_datadir}/polkit-1/rules.d/*
+%endif
 
 %files ldap -f sssd_ldap.lang
 %defattr(-,root,root,-)
@@ -819,6 +888,7 @@ rm -rf $RPM_BUILD_ROOT
 %files krb5-common
 %defattr(-,root,root,-)
 %doc COPYING
+%attr(755,sssd,sssd) %dir %{pubconfpath}/krb5.include.d
 %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child
 %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child
 
@@ -836,7 +906,6 @@ rm -rf $RPM_BUILD_ROOT
 %files ipa -f sssd_ipa.lang
 %defattr(-,root,root,-)
 %doc COPYING
-%attr(755,root,root) %dir %{pubconfpath}/krb5.include.d
 %attr(700,sssd,sssd) %dir %{keytabdir}
 %{_libdir}/%{name}/libsss_ipa.so
 %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child
@@ -846,7 +915,6 @@ rm -rf $RPM_BUILD_ROOT
 %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*
 
@@ -872,12 +940,7 @@ rm -rf $RPM_BUILD_ROOT
 
 %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
@@ -891,15 +954,30 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
 %{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
 %if (0%{?with_cifs_utils_plugin} == 1)
+%dir %{_libdir}/cifs-utils
 %{_libdir}/cifs-utils/cifs_idmap_sss.so
+%dir %{_sysconfdir}/cifs-utils
 %ghost %{_sysconfdir}/cifs-utils/idmap-plugin
 %endif
 %if (0%{?with_krb5_localauth_plugin} == 1)
+%dir %{_libdir}/%{name}
+%dir %{_libdir}/%{name}/modules
 %{_libdir}/%{name}/modules/sssd_krb5_localauth_plugin.so
 %endif
 %{_mandir}/man8/pam_sss.8*
 %{_mandir}/man8/sssd_krb5_locator_plugin.8*
 
+%files -n libsss_sudo
+%defattr(-,root,root,-)
+%doc src/sss_client/COPYING
+%{_libdir}/libsss_sudo.so*
+
+%files -n libsss_autofs
+%defattr(-,root,root,-)
+%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/libsss_autofs.so
+
 %files tools -f sssd_tools.lang
 %defattr(-,root,root,-)
 %doc COPYING
@@ -914,6 +992,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/sss_override
 %{_sbindir}/sss_debuglevel
 %{_sbindir}/sss_seed
+%{_sbindir}/sssctl
 %{_mandir}/man8/sss_groupadd.8*
 %{_mandir}/man8/sss_groupdel.8*
 %{_mandir}/man8/sss_groupmod.8*
@@ -925,6 +1004,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/sss_override.8*
 %{_mandir}/man8/sss_debuglevel.8*
 %{_mandir}/man8/sss_seed.8*
+%{_mandir}/man8/sssctl.8*
 
 %files -n python-sssdconfig -f python_sssdconfig.lang
 %defattr(-,root,root,-)
@@ -934,12 +1014,10 @@ rm -rf $RPM_BUILD_ROOT
 %files -n python-sss
 %defattr(-,root,root,-)
 %{python_sitearch}/pysss.so
-%{python_sitearch}/_py2sss.so
 
 %files -n python-sss-murmur
 %defattr(-,root,root,-)
 %{python_sitearch}/pysss_murmur.so
-%{python_sitearch}/_py2sss_murmur.so
 
 %files -n libsss_idmap
 %defattr(-,root,root,-)
@@ -965,11 +1043,6 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/libipa_hbac.so
 %{_libdir}/pkgconfig/ipa_hbac.pc
 
-%files -n python-libipa_hbac
-%defattr(-,root,root,-)
-%{python_sitearch}/pyhbac.so
-%{python_sitearch}/_py2hbac.so
-
 %files -n libsss_nss_idmap
 %defattr(-,root,root,-)
 %doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
@@ -985,10 +1058,15 @@ rm -rf $RPM_BUILD_ROOT
 %files -n python-libsss_nss_idmap
 %defattr(-,root,root,-)
 %{python_sitearch}/pysss_nss_idmap.so
-%{python_sitearch}/_py2sss_nss_idmap.so
+
+%files -n python-libipa_hbac
+%defattr(-,root,root,-)
+%{python_sitearch}/pyhbac.so
 
 %files libwbclient
 %defattr(-,root,root,-)
+%dir %{_libdir}/%{name}
+%dir %{_libdir}/%{name}/modules
 %{_libdir}/%{name}/modules/libwbclient.so.*
 
 %files libwbclient-devel
@@ -997,6 +1075,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/%{name}/modules/libwbclient.so
 %{_libdir}/pkgconfig/wbclient_sssd.pc
 
+%files winbind-idmap
+%dir %{_libdir}/samba/idmap
+%{_libdir}/samba/idmap/sss.so
+%{_mandir}/man8/idmap_sss.8*
+
 %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
@@ -1011,17 +1094,17 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us
 /bin/systemctl status sssd.service >/dev/null 2>&1 && touch /var/tmp/sssd.upgrade || :
 
 %post common
-if [ $1 -ge 1 ] ; then
-    # Initial installation
-    /bin/systemctl daemon-reload >/dev/null 2>&1 || :
-fi
+%systemd_post sssd.service
+%systemd_post sssd-secrets.socket
 
 %preun common
-if [ $1 -eq 0 ] ; then
-     # Package removal, not upgrade
-    /bin/systemctl --no-reload disable sssd.service > /dev/null 2>&1 || :
-    /bin/systemctl stop sssd.service > /dev/null 2>&1 || :
-fi
+%systemd_preun sssd.service
+%systemd_preun sssd-secrets.socket
+
+%postun common
+%systemd_postun_with_restart sssd.service
+%systemd_postun_with_restart sssd-secrets.socket
+%systemd_postun_with_restart sssd-secrets.service
 
 %if (0%{?with_cifs_utils_plugin} == 1)
 %post client
@@ -1038,6 +1121,10 @@ fi
 
 %postun client -p /sbin/ldconfig
 
+%post -n libsss_sudo -p /sbin/ldconfig
+
+%postun -n libsss_sudo -p /sbin/ldconfig
+
 %post -n libipa_hbac -p /sbin/ldconfig
 
 %postun -n libipa_hbac -p /sbin/ldconfig
@@ -1050,6 +1137,10 @@ fi
 
 %postun -n libsss_nss_idmap -p /sbin/ldconfig
 
+%post -n libsss_simpleifp -p /sbin/ldconfig
+
+%postun -n libsss_simpleifp -p /sbin/ldconfig
+
 %post libwbclient
 %{_sbindir}/update-alternatives \
     --install %{_libdir}/libwbclient.so.%{libwbc_alternatives_version} \
@@ -1087,51 +1178,302 @@ fi
 /usr/bin/rm -f /var/tmp/sssd.upgrade || :
 
 %changelog
-* Thu Jul 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.12
-- Resolves: rhbz#1356433 - ldap_group_external_member is no set for the
-                           IPA provider
+* Tue Sep 20 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-43
+- Resolves: rhbz#1376831 - sssd-common is missing dependency on sssd-sudo
+
+* Fri Sep 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-42
+- Resolves: rhbz#1371631 - login using gdm calls for gdm-smartcard when
+                           smartcard authentication is not enabled
+
+* Wed Sep 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-41
+- Resolves: rhbz#1373420 - sss_override fails to export
+
+* Wed Sep 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-40
+- Resolves: rhbz#1375299 - sss_groupshow <user> fails with error "No such
+                           group in local domain. Printing groups only
+                           allowed in local domain"
 
-* Fri Jul  8 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.11
-- Resolves: rhbz#1353605 - sssd-libwbclient: wbcSidsToUnixIds should not
+* Wed Sep 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-39
+- Resolves: rhbz#1375182 - SSSD goes offline when the LDAP server returns
+                           sizelimit exceeded
+
+* Mon Sep 12 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-38
+- Resolves: rhbz#1372753 - Access denied for user when access_provider =
+                           krb5 is set in sssd.conf
+
+* Mon Sep 12 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-37
+- Resolves: rhbz#1373444 - unable to create group in sssd cache
+- Resolves: rhbz#1373577 - unable to add local user in sssd to a group in sssd
+
+* Wed Sep  7 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-36
+- Resolves: rhbz#1369118 - Don't enable the default shadowtils domain in RHEL
+
+* Mon Sep  5 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-35
+- Fix permissions for the private pipe directory
+- Resolves: rhbz#1362716 - selinux avc denial for vsftp login as ipa user
+
+* Fri Sep  2 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-34
+- Resolves: rhbz#1371977 - resolving IPA nested user groups is broken in 1.14
+
+* Fri Sep  2 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-33
+- Resolves: rhbz#1368496 - sssd is not able to authenticate with alias
+
+* Fri Sep  2 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-32
+- Resolves: rhbz#1371152 - SSSD qualifies principal twice in IPA-AD trust
+                           if the principal attribute doesn't exist on the
+                           AD side
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-31
+- Apply forgotten patch
+- Resolves: rhbz#1368496 - sssd is not able to authenticate with alias
+- Resolves: rhbz#1366470 - sssd: throw away the timestamp cache if
+                           re-initializing the persistent cache
+- Fix deleting non-existent secret
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-30
+- Resolves: rhbz#1362716 - selinux avc denial for vsftp login as ipa user
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-29
+- Resolves: rhbz#1368496 - sssd is not able to authenticate with alias
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-28
+- Resolves: rhbz#1364033 - sssd exits if clock is adjusted backwards
+                           after boot
+
+* Fri Aug 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-27
+- Resolves: rhbz#1362023 - SSSD fails to start when ldap_user_extra_attrs
+                           contains mail
+
+* Fri Aug 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-26
+- Resolves: rhbz#1368324 - libsss_autofs.so is packaged in two packages
+                           sssd-common and libsss_autofs
+
+* Fri Aug 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-25
+- Fix RPM scriptlet plumbing for the sssd-secrets responder
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Wed Aug 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-24
+- Add socket-activation plumbing for the sssd-secrets responder
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Wed Aug 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-23
+- Own the secrets directory
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Wed Aug 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-22
+- Resolves: rhbz#1268874 - Add an option to disable checking for trusted
+                           domains in the subdomains provider
+
+* Tue Aug 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-21
+- Resolves: rhbz#1271280 - sssd stores and returns incorrect information
+                           about empty netgroup (ldap-server: 389-ds)
+
+* Tue Aug 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-20
+- Resolves: rhbz#1290500 - [feat] command to manually list
+                           fo_add_server_to_list information
+
+* Tue Aug 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-19
+- Add several small fixes related to the config API
+- Related: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Thu Aug 11 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-18
+- Resolves: rhbz#1349900 - gpo search errors out and gpo_cache file is
+                           never created
+
+* Wed Aug 10 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-17
+- Fix regressions in the simple access provider
+- Resolves: rhbz#1360806 - sssd does not start if sub-domain user is used
+                           with simple access provider
+- Apply a number of specfile patches to better match the upstream spefile
+- Related: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+
+* Wed Aug 10 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-16
+- Cherry-pick patches from upstream that fix several regressions
+- Avoid checking local users in all cases
+- Resolves: rhbz#1353951 - sssd_pam leaks file descriptors
+
+* Mon Aug  8 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-15
+- Resolves: rhbz#1364118 - [abrt] [faf] sssd: unknown function():
+                           /usr/libexec/sssd/sssd_nss killed by 11
+- Resolves: rhbz#1361563 - Wrong pam error code returned for password
+                           change in offline mode
+
+* Fri Jul 29 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-14
+- Resolves: rhbz#1309745 - Support multiple principals for IPA users
+
+* Fri Jul 29 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-13
+- Resolves: rhbz#1304992 - Handle overriden name of members in the
+                           memberUid attribute
+
+* Wed Jul 27 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-12
+- handle unresolvable sites more gracefully
+- Resolves: rhbz#1346011 - sssd is looking at a server in the GC of a
+                           subdomain, not the root domain.
+- fix compilation warnings in unit tests
+
+* Wed Jul 27 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-11
+- fix capaths output
+- Resolves: rhbz#1344940 - GSSAPI error causes failures for child domain
+                           user logins across IPA - AD trust
+- also fix Coverity issues in the secrets responder and suppress noisy
+  debug messages when setting the timestamp cache
+
+* Tue Jul 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-10
+- Resolves: rhbz#1356577 - sssctl: Time stamps without time zone information
+
+* Tue Jul 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-9
+- Resolves: rhbz#1354414 - New or modified ID-View User overrides are not
+                           visible unless rm -f /var/lib/sss/db/*cache*
+
+* Mon Jul 18 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-8
+- Resolves: rhbz#1211631 - [RFE] Support of UPN for IdM trusted domains
+
+* Thu Jul 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-7
+- Resolves: rhbz#1350520 - [abrt] sssd-common: ipa_dyndns_update_send():
+                           sssd_be killed by SIGSEGV
+
+* Wed Jul 13 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-6
+- Resolves: rhbz#1349882 - sssd does not work under non-root user
+- Also cherry-pick a few patches from upstream to fix config schema
+- Related: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Wed Jul 13 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-5
+- Sync a few minor patches from upstream
+- Fix sssctl manpage
+- Fix nss-tests unit test on big-endian machines
+- Fix several issues in the config schema
+- Related: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Wed Jul 13 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-4
+- Bundle http-parser
+- Resolves: rhbz#1311056 - Add a Secrets as a Service component
+
+* Tue Jul 12 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-3
+- Sync a few minor patches from upstream
+- Fix a failover issue
+- Resolves: rhbz#1334749 - sssd fails to mark a connection as bad on
+                           searches that time out
+
+* Mon Jul 11 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-2
+- Explicitly BuildRequire newer ding-libs
+- Resolves: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Fri Jul  8 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-1
+- New upstream release 1.14.0
+- Resolves: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+- Resolves: rhbz#835492 - [RFE] SSSD admin tool request - force reload
+- Resolves: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+- Resolves: rhbz#1278691 - Please fix rfc2307 autofs schema defaults
+- Resolves: rhbz#1287209 - default_domain_suffix Appended to User Name
+- Resolves: rhbz#1300663 - Improve sudo protocol to support configurations
+                           with default_domain_suffix
+- Resolves: rhbz#1312275 - Support authentication indicators from IPA
+
+* Thu Jun 30 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0beta1-2
+- Resolves: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+- Resolves: rhbz#790113 - [RFE] "include" directive in sssd.conf
+- Resolves: rhbz#874985 - [RFE] AD provider support for automount lookups
+- Resolves: rhbz#879333 - [RFE] SSSD admin tool request - status overview
+- Resolves: rhbz#1140022 - [RFE]Allow sssd to add a new option that would
+                           specify which server to update DNS with
+- Resolves: rhbz#1290380 - RFE: Improve SSSD performance in large
+                           environments
+- Resolves: rhbz#883886 - sssd: incorrect checks on length values during
+                          packet decoding
+- Resolves: rhbz#988207 - sssd does not detail which line in configuration
+                          is invalid
+- Resolves: rhbz#1007969 - sssd_cache does not remove have an option to
+                           remove the sssd database
+- Resolves: rhbz#1103249 - PAC responder needs much time to process large
+                           group lists
+- Resolves: rhbz#1118257 - Users in ipa groups, added to netgroups are
+                           not resovable
+- Resolves: rhbz#1269018 - Too much logging from sssd_be
+- Resolves: rhbz#1293695 - sssd mixup nested group from AD trusted domains
+- Resolves: rhbz#1308935 - After removing certificate from user in IPA
+                           and even after sss_cache, FindByCertificate
+                           still finds the user
+- Resolves: rhbz#1315766 - SSSD PAM module does not support multiple
+                           password prompts (e.g. Password + Token) with sudo
+- Resolves: rhbz#1316164 - SSSD fails to process GPO from Active Directory
+- Resolves: rhbz#1322458 - sssd_be[11010]: segfault at 0 ip 00007ff889ff61bb
+                           sp 00007ffc7d66a3b0 error 4 in
+                           libsss_ipa.so[7ff889fcf000+5d000]
+
+* Mon Jun 20 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0alpha-1
+- Resolves: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+- The rebase includes fixes for the following bugzillas:
+- Resolves: rhbz#789477 - [RFE] SUDO: Support the IPA schema
+- Resolves: rhbz#1059972 - RFE: SSSD: Automatically assign new slices for
+                           any AD domain
+- Resolves: rhbz#1233200 - man sssd.conf should clarify details about
+                           subdomain_inherit option.
+- Resolves: rhbz#1238144 - Need better libhbac debuging added to sssd
+- Resolves: rhbz#1265366 - sss_override segfaults when accidentally adding
+                           --help flag to some commands
+- Resolves: rhbz#1269512 - sss_override: memory violation
+- Resolves: rhbz#1278566 - crash in sssd when non-Englsh locale is used
+                           and pam_strerror prints non-ASCII characters
+- Resolves: rhbz#1283686 - groups get deleted from the cache
+- Resolves: rhbz#1290378 - Smart Cards: Certificate in the ID View
+- Resolves: rhbz#1292238 - extreme memory usage in libnfsidmap sss.so
+                           plug-in when resolving groups with many members
+- Resolves: rhbz#1292456 - sssd_be AD segfaults on missing A record
+- Resolves: rhbz#1294670 - Local users with local sudo rules causes
+                           LDAP queries
+- Resolves: rhbz#1296618 - Properly remove OriginalMemberOf attribute in
+                           SSSD cache if user has no secondary groups anymore
+- Resolves: rhbz#1299553 - Cannot retrieve users after upgrade from 1.12
+                           to 1.13
+- Resolves: rhbz#1302821 - Cannot start sssd after switching to non-root
+- Resolves: rhbz#1310877 - [RFE] Support Automatic Renewing of Kerberos
+                           Host Keytabs
+- Resolves: rhbz#1313014 - sssd is not closing sockets properly
+- Resolves: rhbz#1318996 - SSSD does not fail over to next GC
+- Resolves: rhbz#1327270 - local overrides: issues with sub-domain users
+                           and mixed case names
+- Resolves: rhbz#1342547 - sssd-libwbclient: wbcSidsToUnixIds should not
                            fail on lookup errors
 
-* Tue Jun 21 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.10
-- Resolves: rhbz#1347723 - sssd is not closing sockets properly
+* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-50
+- Build the PAC plugin with krb5-1.14
+- Related: rhbz#1336688 - sssd tries to resolve global catalog servers
+                          from AD forest sub-domains in AD-IPA trust setup
 
-* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.9
-- Resolves: rhbz#1339509 - sssd tries to resolve global catalog servers
+* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-49
+- Resolves: rhbz#1336688 - sssd tries to resolve global catalog servers
                            from AD forest sub-domains in AD-IPA trust setup
 
-* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.8
-- Resolves: rhbz#1339258 - [sssd] Trusted (AD) user's info stays in sssd
+* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-48
+- Resolves: rhbz#1290853 - [sssd] Trusted (AD) user's info stays in sssd
                            cache for much more than expected.
 
-* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.7
-- Resolves: rhbz#1339207 - sssd_nss memory usage keeps growing when trying
+* Mon May 23 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-47
+- Resolves: rhbz#1336706 - sssd_nss memory usage keeps growing when trying
                            to retrieve non-existing netgroups
 
-* Thu May 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.6
-- Resolves: rhbz#1337292 - In IPA-AD trust environment access is granted
+* Tue May 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-46
+- Resolves: rhbz#1296902 - In IPA-AD trust environment access is granted
                            to AD user even if the user is disabled on AD.
 
-* Tue May 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.5
-- Resolves: rhbz#1336836 - IPA provider crashes if a netgroup from a
+* Tue May 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-45
+- Resolves: rhbz#1334159 - IPA provider crashes if a netgroup from a
                            trusted domain is requested
 
-* Mon Apr 18 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.4
-- Resolves: rhbz#1324442 - sssd be memory leak in sssd's memberof plugin
+* Mon Apr 18 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-44
+- Resolves: rhbz#1308913 - sssd be memory leak in sssd's memberof plugin
 - More patches from upstream related to the memory leak
 
-* Wed Apr  6 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.3
-- Resolves: rhbz#1324442 - sssd be memory leak in sssd's memberof plugin
+* Fri Apr  1 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-43
+- Resolves: rhbz#1308913 - sssd be memory leak in sssd's memberof plugin
 
-* Wed Feb 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.2
-- Resolves: rhbz#1311569 - [RFE] IPA: resolve external group memberships
+* Wed Feb 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-42
+- Resolves: rhbz#1300740 - [RFE] IPA: resolve external group memberships
                            of IPA groups during getgrnam and getgrgid
 
-* Tue Nov 24 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40.1
+* Tue Nov 24 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-41
 - Resolves: rhbz#1284814  - sssd: [sysdb_add_user] (0x0400): Error: 17
-                           (File exists)
 
 * Wed Oct 14 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40
 - Resolves: rhbz#1270827 - local overrides: don't contact server with