diff --git a/SOURCES/0197-LDAP-AD-do-not-resolve-group-members-during-tokenGro.patch b/SOURCES/0197-LDAP-AD-do-not-resolve-group-members-during-tokenGro.patch
new file mode 100644
index 0000000..3c458ee
--- /dev/null
+++ b/SOURCES/0197-LDAP-AD-do-not-resolve-group-members-during-tokenGro.patch
@@ -0,0 +1,297 @@
+From b8d9eca0d9469c1209161b31a0109d8e4ea2868c Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 9 Mar 2015 16:36:29 +0100
+Subject: [PATCH] LDAP/AD: do not resolve group members during tokenGroups
+ request
+
+During initgroups requests we try to avoid to resolve the complete
+member list of groups if possible, e.g. if there are no nested groups.
+The tokenGroups LDAP lookup return the complete list of memberships for
+a user hence it is not necessary lookup the other group member and
+un-roll nested groups. With this patch only the group entry is looked up
+and saved as incomplete group to the cache.
+
+This is achieved by adding a new boolean parameter no_members to
+groups_get_send() and sdap_get_groups_send(). The difference to config
+options like ldap_group_nesting_level = 0 or ignore_group_members is
+that if no_members is set to true groups which are missing in the cache
+are created a incomplete groups. As a result a request to lookup this
+group will trigger a new LDAP request to resolve the group completely.
+This way no information is ignored but the time needed to read all data
+is better distributed between different requests.
+
+https://fedorahosted.org/sssd/ticket/2601
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit d81d8d3dc151ebc95cd0e3f3b14c1cdaa48980f1)
+---
+ src/providers/ipa/ipa_subdomains_ext_groups.c |  2 +-
+ src/providers/ldap/ldap_common.h              |  3 ++-
+ src/providers/ldap/ldap_id.c                  | 14 +++++++----
+ src/providers/ldap/sdap_async.h               |  3 ++-
+ src/providers/ldap/sdap_async_enum.c          |  2 +-
+ src/providers/ldap/sdap_async_groups.c        | 36 ++++++++++++++++++++++++++-
+ src/providers/ldap/sdap_async_initgroups.c    | 14 +++++------
+ src/providers/ldap/sdap_async_initgroups_ad.c |  2 +-
+ src/providers/ldap/sdap_async_private.h       |  6 +++++
+ 9 files changed, 64 insertions(+), 18 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
+index ad278b248ec2a2a157fed0a455dbe97049e83f9d..976a71cfe3ab42425e3884c5f6d9e096fe61bb34 100644
+--- a/src/providers/ipa/ipa_subdomains_ext_groups.c
++++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
+@@ -872,7 +872,7 @@ static void ipa_add_ad_memberships_get_next(struct tevent_req *req)
+                                  state->sdap_id_ctx->conn,
+                                  (const char *) val->data,
+                                  BE_FILTER_NAME, BE_ATTR_CORE,
+-                                 false);
++                                 false, false);
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "groups_get_send failed.\n");
+         ret = ENOMEM;
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index bf69489a79e903a98878edb53d372d2242df2b0f..57ad1b8458988d7e108f019c20f67bcde32539d4 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -212,7 +212,8 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+                                    const char *name,
+                                    int filter_type,
+                                    int attrs_type,
+-                                   bool noexist_delete);
++                                   bool noexist_delete,
++                                   bool no_members);
+ int groups_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret);
+ 
+ struct tevent_req *ldap_netgroup_get_send(TALLOC_CTX *memctx,
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index 6de5b72a8b66cd95b16d25a2c37dc21a57695de3..55bb3c9fbd6f623e7795d7399c9e5ac4d5192e85 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -528,6 +528,7 @@ struct groups_get_state {
+     int dp_error;
+     int sdap_ret;
+     bool noexist_delete;
++    bool no_members;
+ };
+ 
+ static int groups_get_retry(struct tevent_req *req);
+@@ -544,7 +545,8 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+                                    const char *name,
+                                    int filter_type,
+                                    int attrs_type,
+-                                   bool noexist_delete)
++                                   bool noexist_delete,
++                                   bool no_members)
+ {
+     struct tevent_req *req;
+     struct groups_get_state *state;
+@@ -567,6 +569,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+     state->conn = conn;
+     state->dp_error = DP_ERR_FATAL;
+     state->noexist_delete = noexist_delete;
++    state->no_members = no_members;
+ 
+     state->op = sdap_id_op_create(state, state->conn->conn_cache);
+     if (!state->op) {
+@@ -713,7 +716,8 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+ 
+     /* TODO: handle attrs_type */
+     ret = build_attrs_from_map(state, ctx->opts->group_map, SDAP_OPTS_GROUP,
+-                               state->domain->ignore_group_members ?
++                               (state->domain->ignore_group_members
++                                    || state->no_members) ?
+                                    (const char **)member_filter : NULL,
+                                &state->attrs, NULL);
+ 
+@@ -845,7 +849,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),
+-                                  false);
++                                  false, state->no_members);
+     if (!subreq) {
+         tevent_req_error(req, ENOMEM);
+         return;
+@@ -1383,7 +1387,7 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
+                                  ar->filter_value,
+                                  ar->filter_type,
+                                  ar->attr_type,
+-                                 noexist_delete);
++                                 noexist_delete, false);
+         break;
+ 
+     case BE_REQ_INITGROUPS: /* init groups for user */
+@@ -1718,7 +1722,7 @@ static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx,
+     subreq = groups_get_send(req, state->ev, state->id_ctx,
+                              state->sdom, state->conn,
+                              state->filter_val, state->filter_type,
+-                             state->attrs_type, state->noexist_delete);
++                             state->attrs_type, state->noexist_delete, false);
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "users_get_send failed.\n");
+         ret = ENOMEM;
+diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
+index 1239f28c173373aac23c5796d694c7bd5ca24c96..ef9b3bbadba830bcf730b6fa70867c17d51380af 100644
+--- a/src/providers/ldap/sdap_async.h
++++ b/src/providers/ldap/sdap_async.h
+@@ -96,7 +96,8 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
+                                        const char **attrs,
+                                        const char *filter,
+                                        int timeout,
+-                                       bool enumeration);
++                                       bool enumeration,
++                                       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 242b3172f367b0b35738bd2e86ea927a4409d2d6..1cc09abdf1aa14e3d1690ea1abe32604ae4ff1cd 100644
+--- a/src/providers/ldap/sdap_async_enum.c
++++ b/src/providers/ldap/sdap_async_enum.c
+@@ -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);
++                                  true, 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 c86b5c6b59a4de7e945b95cafae9149f681e2e18..818f30b95d4a4707c32d16b9866b008d89141e4d 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -1750,6 +1750,7 @@ struct sdap_get_groups_state {
+     char *filter;
+     int timeout;
+     bool enumeration;
++    bool no_members;
+ 
+     char *higher_usn;
+     struct sysdb_attrs **groups;
+@@ -1779,7 +1780,8 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
+                                        const char **attrs,
+                                        const char *filter,
+                                        int timeout,
+-                                       bool enumeration)
++                                       bool enumeration,
++                                       bool no_members)
+ {
+     errno_t ret;
+     struct tevent_req *req;
+@@ -1802,6 +1804,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
+     state->count = 0;
+     state->timeout = timeout;
+     state->enumeration = enumeration;
++    state->no_members = no_members;
+     state->base_filter = filter;
+     state->base_iter = 0;
+     state->search_bases = sdom->group_search_bases;
+@@ -1926,6 +1929,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
+     bool next_base = false;
+     size_t count;
+     struct sysdb_attrs **groups;
++    char **groupnamelist;
+ 
+     ret = sdap_get_generic_recv(subreq, state,
+                                 &count, &groups);
+@@ -1992,6 +1996,36 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
+         return;
+     }
+ 
++    if (state->no_members) {
++        ret = sysdb_attrs_primary_name_list(state->sysdb, state,
++                                state->groups, state->count,
++                                state->opts->group_map[SDAP_AT_GROUP_NAME].name,
++                                &groupnamelist);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "sysdb_attrs_primary_name_list failed.\n");
++            tevent_req_error(req, ret);
++            return;
++        }
++
++        ret = sdap_add_incomplete_groups(state->sysdb, state->dom, state->opts,
++                                         groupnamelist, state->groups,
++                                         state->count);
++        if (ret == EOK) {
++            DEBUG(SSSDBG_TRACE_LIBS,
++                  "Reading only group data without members successful.\n");
++            tevent_req_done(req);
++        } else {
++            DEBUG(SSSDBG_OP_FAILURE, "sdap_add_incomplete_groups failed.\n");
++            tevent_req_error(req, ret);
++        }
++        return;
++
++        ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
++                               state->groups, state->count, false,
++                               NULL, true, NULL);
++    }
++
+     /* Check whether we need to do nested searches
+      * for RFC2307bis/FreeIPA/ActiveDirectory
+      * We don't need to do this for enumeration,
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index 48c16b71637f83399d9a523f64f6d812b91681ef..2fd235f2868b877c0e5d5d9f7b1b76d269eee8ee 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -29,12 +29,12 @@
+ #include "providers/ldap/sdap_users.h"
+ 
+ /* ==Save-fake-group-list=====================================*/
+-static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+-                                          struct sss_domain_info *domain,
+-                                          struct sdap_options *opts,
+-                                          char **groupnames,
+-                                          struct sysdb_attrs **ldap_groups,
+-                                          int ldap_groups_count)
++errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
++                                   struct sss_domain_info *domain,
++                                   struct sdap_options *opts,
++                                   char **groupnames,
++                                   struct sysdb_attrs **ldap_groups,
++                                   int ldap_groups_count)
+ {
+     TALLOC_CTX *tmp_ctx;
+     struct ldb_message *msg;
+@@ -3152,7 +3152,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
+ 
+     subreq = groups_get_send(req, state->ev, state->id_ctx,
+                              state->id_ctx->opts->sdom, state->conn,
+-                             gid, BE_FILTER_IDNUM, BE_ATTR_ALL, NULL);
++                             gid, BE_FILTER_IDNUM, BE_ATTR_ALL, false, false);
+     if (!subreq) {
+         ret = ENOMEM;
+         goto fail;
+diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
+index 1b8c8d981ea14ac0fca0903f16296c8a6701c5dd..9915f1863f172d5d3f59afe03abbbfb87fdf3409 100644
+--- a/src/providers/ldap/sdap_async_initgroups_ad.c
++++ b/src/providers/ldap/sdap_async_initgroups_ad.c
+@@ -630,7 +630,7 @@ static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req)
+ 
+     subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain,
+                              state->conn, state->current_sid,
+-                             BE_FILTER_SECID, BE_ATTR_CORE, false);
++                             BE_FILTER_SECID, BE_ATTR_CORE, false, true);
+     if (subreq == NULL) {
+         return ENOMEM;
+     }
+diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h
+index e689394c5db8a3385c333e6b98372c6f6d34366c..3995a2ac357c52f546696284d71d2127d0302409 100644
+--- a/src/providers/ldap/sdap_async_private.h
++++ b/src/providers/ldap/sdap_async_private.h
+@@ -132,4 +132,10 @@ errno_t sdap_nested_group_recv(TALLOC_CTX *mem_ctx,
+                                unsigned long *_num_groups,
+                                struct sysdb_attrs ***_groups);
+ 
++errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
++                                   struct sss_domain_info *domain,
++                                   struct sdap_options *opts,
++                                   char **groupnames,
++                                   struct sysdb_attrs **ldap_groups,
++                                   int ldap_groups_count);
+ #endif /* _SDAP_ASYNC_PRIVATE_H_ */
+-- 
+2.1.0
+
diff --git a/SOURCES/0198-SDAP-Do-not-set-gid-0-twice.patch b/SOURCES/0198-SDAP-Do-not-set-gid-0-twice.patch
new file mode 100644
index 0000000..a6c60ee
--- /dev/null
+++ b/SOURCES/0198-SDAP-Do-not-set-gid-0-twice.patch
@@ -0,0 +1,49 @@
+From 63209a5d62f2ef1a184b5d1799a27bab8278f43a Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 10 Apr 2015 14:33:35 +0200
+Subject: [PATCH 198/200] SDAP: Do not set gid 0 twice
+
+The gid o was added to sysdb attrs directly in sdap_save_group for 1st time
+and for second time in the function sdap_store_group_with_gid,
+which was called every time from function sdap_save_group
+
+[sysdb_set_entry_attr] (0x0080): ldb_modify failed:
+    [Attribute or value exists](20)[attribute 'gidNumber': value #1
+    on 'name=domainlocalgroup1_dom2-493341@sssdad_tree.com,cn=groups,cn=sssdad_tree.com,cn=sysdb' provided more than once]
+[sysdb_set_entry_attr] (0x0040): Error: 17 (File exists)
+[sysdb_store_group] (0x1000): sysdb_set_group_attr failed.
+[sysdb_store_group] (0x0400): Error: 17 (File exists)
+[sdap_store_group_with_gid] (0x0040):
+    Could not store group domainlocalgroup1_dom2-493341@sssdad_tree.com
+[sdap_save_group] (0x0080): Could not store group with GID: [File exists]
+[sdap_save_group] (0x0080):
+    Failed to save group [domainlocalgroup1_dom2-493341@sssdad_tree.com]: [File exists]
+[sdap_save_groups] (0x0040): Failed to store group 0. Ignoring.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 5d864e7a9d0e1e6fb7dd8158c5b8bfb71040b908)
+---
+ src/providers/ldap/sdap_async_groups.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
+index 818f30b95d4a4707c32d16b9866b008d89141e4d..4be8c502ea77a3913ddac2a24fbacbc522b2ef6b 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -608,13 +608,6 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+             gid = 0;
+             DEBUG(SSSDBG_TRACE_FUNC, "Filtering AD group [%s].\n",
+                                       group_name);
+-            ret = sysdb_attrs_add_uint32(group_attrs,
+-                                         opts->group_map[SDAP_AT_GROUP_GID].sys_name, 0);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Failed to add a GID to non-posix group!\n");
+-                return ret;
+-            }
+             ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE,
+-- 
+2.1.0
+
diff --git a/SOURCES/0199-SDAP-Extract-filtering-AD-group-to-function.patch b/SOURCES/0199-SDAP-Extract-filtering-AD-group-to-function.patch
new file mode 100644
index 0000000..263918e
--- /dev/null
+++ b/SOURCES/0199-SDAP-Extract-filtering-AD-group-to-function.patch
@@ -0,0 +1,240 @@
+From 64eb7055b640e9c92701886effc36f74fe9e709f Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 13 Apr 2015 09:44:35 +0200
+Subject: [PATCH 199/200] SDAP: Extract filtering AD group to function
+
+Patch remove code duplication.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit bad2fc8133d941e5a6c8d8016c9689e039265c61)
+---
+ Makefile.am                                   |  2 +
+ src/providers/ldap/sdap_ad_groups.c           | 68 +++++++++++++++++++++++++++
+ src/providers/ldap/sdap_async_groups.c        | 40 ++++++----------
+ src/providers/ldap/sdap_async_nested_groups.c | 31 ++++--------
+ src/providers/ldap/sdap_async_private.h       |  7 +++
+ 5 files changed, 101 insertions(+), 47 deletions(-)
+ create mode 100644 src/providers/ldap/sdap_ad_groups.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 8202659e0933529ca7911952bbf1476dbb4a76fc..f402239af2cfaf77dde1ce6ff261015f5d9bfacc 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1858,6 +1858,7 @@ nestedgroups_tests_SOURCES = \
+     src/providers/ldap/sdap_idmap.c \
+     src/tests/cmocka/test_nested_groups.c \
+     src/providers/ldap/sdap_async_nested_groups.c \
++    src/providers/ldap/sdap_ad_groups.c \
+     $(NULL)
+ nestedgroups_tests_CFLAGS = \
+     $(AM_CFLAGS) \
+@@ -2307,6 +2308,7 @@ libsss_ldap_common_la_SOURCES = \
+     src/providers/ldap/sdap_async_connection.c \
+     src/providers/ldap/sdap_async_netgroups.c \
+     src/providers/ldap/sdap_async_services.c \
++    src/providers/ldap/sdap_ad_groups.c \
+     src/providers/ldap/sdap_child_helpers.c \
+     src/providers/ldap/sdap_fd_events.c \
+     src/providers/ldap/sdap_id_op.c \
+diff --git a/src/providers/ldap/sdap_ad_groups.c b/src/providers/ldap/sdap_ad_groups.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..0e36328b9b52643a2ec698b2a41f2a56a8ff69b6
+--- /dev/null
++++ b/src/providers/ldap/sdap_ad_groups.c
+@@ -0,0 +1,68 @@
++/*
++    SSSD
++
++    AD groups helper routines
++
++    Authors:
++        Lukas Slebodnik <lslebodn@redhat.com>
++
++    Copyright (C) 2013 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 "db/sysdb.h"
++#include "providers/ldap/sdap.h"
++#include "providers/ldap/sdap_async_private.h"
++
++/* ==Group-Parsing Routines=============================================== */
++
++errno_t sdap_check_ad_group_type(struct sss_domain_info *dom,
++                                 struct sdap_options *opts,
++                                 struct sysdb_attrs *group_attrs,
++                                 const char *group_name,
++                                 bool *_need_filter)
++{
++    int32_t ad_group_type;
++    errno_t ret = EOK;
++    *_need_filter = false;
++
++    if (opts->schema_type == SDAP_SCHEMA_AD) {
++        ret = sysdb_attrs_get_int32_t(group_attrs, SYSDB_GROUP_TYPE,
++                                      &ad_group_type);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_int32_t failed.\n");
++            return ret;
++        }
++
++        DEBUG(SSSDBG_TRACE_ALL,
++              "AD group [%s] has type flags %#x.\n",
++              group_name, ad_group_type);
++
++        /* Only security groups from AD are considered for POSIX groups.
++         * Additionally only global and universal group are taken to account
++         * for trusted domains. */
++        if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY)
++            || (IS_SUBDOMAIN(dom)
++                && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL)
++                      || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) {
++            DEBUG(SSSDBG_TRACE_FUNC,
++                  "Filtering AD group [%s].\n", group_name);
++
++            *_need_filter = true;
++        }
++    }
++
++    return ret;
++}
+diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
+index 4be8c502ea77a3913ddac2a24fbacbc522b2ef6b..00a676372fa042dfc2d57e5799261f9a45ed4a73 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -510,10 +510,10 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     TALLOC_CTX *tmpctx = NULL;
+     bool posix_group;
+     bool use_id_mapping;
++    bool need_filter;
+     char *sid_str;
+     const char *uuid;
+     struct sss_domain_info *subdomain;
+-    int32_t ad_group_type;
+ 
+     tmpctx = talloc_new(NULL);
+     if (!tmpctx) {
+@@ -588,32 +588,20 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", group_name);
+ 
+     posix_group = true;
+-    if (opts->schema_type == SDAP_SCHEMA_AD) {
+-        ret = sysdb_attrs_get_int32_t(attrs, SYSDB_GROUP_TYPE, &ad_group_type);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_int32_t failed.\n");
+-            goto done;
+-        }
++    ret = sdap_check_ad_group_type(dom, opts, attrs, group_name,
++                                   &need_filter);
++    if (ret != EOK) {
++        goto done;
++    }
++    if (need_filter) {
++        posix_group = false;
++        gid = 0;
+ 
+-        DEBUG(SSSDBG_TRACE_ALL, "AD group [%s] has type flags %#x.\n",
+-                                 group_name, ad_group_type);
+-        /* Only security groups from AD are considered for POSIX groups.
+-         * Additionally only global and universal group are taken to account
+-         * for trusted domains. */
+-        if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY)
+-                || (IS_SUBDOMAIN(dom)
+-                    && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL)
+-                        || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) {
+-            posix_group = false;
+-            gid = 0;
+-            DEBUG(SSSDBG_TRACE_FUNC, "Filtering AD group [%s].\n",
+-                                      group_name);
+-            ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE,
+-                      "Error: Failed to mark group as non-posix!\n");
+-                return ret;
+-            }
++        ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "Error: Failed to mark group as non-posix!\n");
++            return ret;
+         }
+     }
+ 
+diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c
+index 1eba35ae8ac90acac8a2d46e8cc5f2b57e3a9256..08e199869ad16c3b19d998a2a28eae9a0dd0a371 100644
+--- a/src/providers/ldap/sdap_async_nested_groups.c
++++ b/src/providers/ldap/sdap_async_nested_groups.c
+@@ -240,32 +240,21 @@ sdap_nested_group_hash_group(struct sdap_nested_group_ctx *group_ctx,
+ {
+     struct sdap_attr_map *map = group_ctx->opts->group_map;
+     gid_t gid;
+-    errno_t ret = ENOENT;
+-    int32_t ad_group_type;
++    errno_t ret;
+     bool posix_group = true;
+     bool use_id_mapping;
+     bool can_find_gid;
++    bool need_filter;
+ 
+-    if (group_ctx->opts->schema_type == SDAP_SCHEMA_AD) {
+-        ret = sysdb_attrs_get_int32_t(group, SYSDB_GROUP_TYPE, &ad_group_type);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_int32_t failed.\n");
+-            return ret;
+-        }
++    ret = sdap_check_ad_group_type(group_ctx->domain, group_ctx->opts,
++                                   group, "", &need_filter);
++    if (ret != EOK) {
++        return ret;
++    }
+ 
+-        DEBUG(SSSDBG_TRACE_ALL, "AD group has type flags %#x.\n",
+-                                 ad_group_type);
+-        /* Only security groups from AD are considered for POSIX groups.
+-         * Additionally only global and universal group are taken to account
+-         * for trusted domains. */
+-        if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY)
+-                || (IS_SUBDOMAIN(group_ctx->domain)
+-                    && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL)
+-                        || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) {
+-            posix_group = false;
+-            gid = 0;
+-            DEBUG(SSSDBG_TRACE_FUNC, "Filtering AD group.\n");
+-        }
++    if (need_filter) {
++        posix_group = false;
++        gid = 0;
+     }
+ 
+     use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
+diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h
+index 3995a2ac357c52f546696284d71d2127d0302409..db542eaf869efcd53d0937bef3fc6e99cc78b938 100644
+--- a/src/providers/ldap/sdap_async_private.h
++++ b/src/providers/ldap/sdap_async_private.h
+@@ -138,4 +138,11 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+                                    char **groupnames,
+                                    struct sysdb_attrs **ldap_groups,
+                                    int ldap_groups_count);
++
++/* from sdap_async_nested_groups.c */
++errno_t sdap_check_ad_group_type(struct sss_domain_info *dom,
++                                 struct sdap_options *opts,
++                                 struct sysdb_attrs *group_attrs,
++                                 const char *group_name,
++                                 bool *_need_filter);
+ #endif /* _SDAP_ASYNC_PRIVATE_H_ */
+-- 
+2.1.0
+
diff --git a/SOURCES/0200-SDAP-Filter-ad-groups-in-initgroups.patch b/SOURCES/0200-SDAP-Filter-ad-groups-in-initgroups.patch
new file mode 100644
index 0000000..42b8547
--- /dev/null
+++ b/SOURCES/0200-SDAP-Filter-ad-groups-in-initgroups.patch
@@ -0,0 +1,50 @@
+From bea6b6c6bcf711e0d96a4263f60e0e1b0a64c45f Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Mon, 13 Apr 2015 09:50:29 +0200
+Subject: [PATCH 200/200] SDAP: Filter ad groups in initgroups
+
+Function sdap_add_incomplete_groups stored domain local groups
+from subdomain as POSIX group, which should not be done.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2614
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit b9fbeb75e7a4f50f98d979a70a710f9221892483)
+---
+ src/providers/ldap/sdap_async_initgroups.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index bc6b5e45e6a7f7dc0c482a6bbbf2aa602371a647..43b72fe2051b452c6ea755c8842117cceafa143a 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -51,6 +51,7 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+     time_t now;
+     char *sid_str = NULL;
+     bool use_id_mapping;
++    bool need_filter;
+     char *tmp_name;
+ 
+     /* There are no groups in LDAP but we should add user to groups ?? */
+@@ -205,6 +206,17 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+                     uuid = NULL;
+                 }
+ 
++                ret = sdap_check_ad_group_type(domain, opts, ldap_groups[ai],
++                                               groupname, &need_filter);
++                if (ret != EOK) {
++                    goto done;
++                }
++
++                if (need_filter) {
++                    posix = false;
++                    gid = 0;
++                }
++
+                 DEBUG(SSSDBG_TRACE_INTERNAL,
+                       "Adding fake group %s to sysdb\n", groupname);
+                 ret = sysdb_add_incomplete_group(domain, groupname, gid,
+-- 
+2.1.0
+
diff --git a/SOURCES/0201-sdap-properly-handle-binary-objectGuid-attribute.patch b/SOURCES/0201-sdap-properly-handle-binary-objectGuid-attribute.patch
new file mode 100644
index 0000000..35ba8ec
--- /dev/null
+++ b/SOURCES/0201-sdap-properly-handle-binary-objectGuid-attribute.patch
@@ -0,0 +1,501 @@
+From 745cf4cc7f4e8f7cdc6ea74b5c39a70f0201a883 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 17 Feb 2015 04:41:21 +0100
+Subject: [PATCH 201/207] sdap: properly handle binary objectGuid attribute
+
+Although in the initial processing SSSD treats the binary value right at
+some point it mainly assumes that it is a string. Depending on the value
+this might end up with the correct binary value stored in the cache but
+in most cases there will be only a broken entry in the cache.
+
+This patch converts the binary value into a string representation which
+is described in [MS-DTYP] and stores the result in the cache.
+
+Resolves https://fedorahosted.org/sssd/ticket/2588
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/db/sysdb.h                             |   6 ++
+ src/db/sysdb_ops.c                         |  52 +++++++++++
+ src/providers/ldap/sdap_async_groups.c     |  25 ++----
+ src/providers/ldap/sdap_async_initgroups.c |   7 +-
+ src/providers/ldap/sdap_async_users.c      |  23 ++---
+ src/tests/cmocka/test_string_utils.c       |  59 +++++++++++++
+ src/tests/cmocka/test_sysdb_utils.c        | 134 +++++++++++++++++++++++++++++
+ src/tests/cmocka/test_utils.h              |   1 +
+ src/tests/cwrap/Makefile.am                |   2 +
+ src/util/string_utils.c                    |  25 ++++++
+ src/util/util.h                            |   7 ++
+ 11 files changed, 307 insertions(+), 34 deletions(-)
+ create mode 100644 src/tests/cmocka/test_sysdb_utils.c
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index cf6028acb806d5d4eedf4cf0680cf4ac9fd6368d..ee5757130ec24a4ddfef854af5f59fc3ccc5b8ae 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1113,4 +1113,10 @@ errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
+                                   const char ***_sids,
+                                   const char ***_dns,
+                                   size_t *_n);
++
++errno_t sysdb_handle_original_uuid(const char *orig_name,
++                                   struct sysdb_attrs *src_attrs,
++                                   const char *src_name,
++                                   struct sysdb_attrs *dest_attrs,
++                                   const char *dest_name);
+ #endif /* __SYS_DB_H__ */
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 6085762dcc5585114dd3049dd3a365856cb6b190..7e1c1d9763a04cd33374770f4ea5d51286bcfee2 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -3670,3 +3670,55 @@ done:
+     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,
++                                   struct sysdb_attrs *dest_attrs,
++                                   const char *dest_name)
++{
++    int ret;
++    struct ldb_message_element *el;
++    char guid_str_buf[GUID_STR_BUF_SIZE];
++
++    if (orig_name == NULL || src_attrs == NULL || src_name == NULL
++            || dest_attrs == NULL || dest_name == NULL) {
++        return EINVAL;
++    }
++
++    ret = sysdb_attrs_get_el_ext(src_attrs, src_name, false, &el);
++    if (ret != EOK) {
++        if (ret != ENOENT) {
++            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el failed.\n");
++        }
++        return ret;
++    }
++
++    if (el->num_values != 1) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Found more than one UUID value, using the first.\n");
++    }
++
++    /* Check if we got a binary AD objectGUID */
++    if (el->values[0].length == GUID_BIN_LENGTH
++            && strcasecmp(orig_name, "objectGUID") == 0) {
++        ret = guid_blob_to_string_buf(el->values[0].data, guid_str_buf,
++                                      GUID_STR_BUF_SIZE);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "guid_blob_to_string_buf failed.\n");
++            return ret;
++        }
++
++        ret = sysdb_attrs_add_string(dest_attrs, dest_name, guid_str_buf);
++    } else {
++        ret = sysdb_attrs_add_string(dest_attrs, dest_name,
++                                     (const char *)el->values[0].data);
++    }
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
++        return ret;;
++    }
++
++    return EOK;
++}
+diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
+index 00a676372fa042dfc2d57e5799261f9a45ed4a73..1714188bee681ff70a03db741cf50058f145abbe 100644
+--- a/src/providers/ldap/sdap_async_groups.c
++++ b/src/providers/ldap/sdap_async_groups.c
+@@ -512,7 +512,6 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     bool use_id_mapping;
+     bool need_filter;
+     char *sid_str;
+-    const char *uuid;
+     struct sss_domain_info *subdomain;
+ 
+     tmpctx = talloc_new(NULL);
+@@ -549,22 +548,14 @@ static int sdap_save_group(TALLOC_CTX *memctx,
+     }
+ 
+     /* Always store UUID if available */
+-    ret = sysdb_attrs_get_string(attrs,
+-                                 opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
+-                                 &uuid);
+-    if (ret == EOK) {
+-        ret = sysdb_attrs_add_string(group_attrs, SYSDB_UUID, uuid);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not add UUID string: [%s]\n",
+-                                         sss_strerror(ret));
+-            goto done;
+-        }
+-    } else if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_ALL, "UUID not available for group [%s].\n",
+-                                 group_name);
+-    } else {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify UUID [%s]\n",
+-                                     sss_strerror(ret));
++    ret = sysdb_handle_original_uuid(
++                                   opts->group_map[SDAP_AT_GROUP_UUID].def_name,
++                                   attrs,
++                                   opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
++                                   group_attrs, SYSDB_UUID);
++    if (ret != EOK) {
++        DEBUG((ret == ENOENT) ? SSSDBG_TRACE_ALL : SSSDBG_MINOR_FAILURE,
++              "Failed to retrieve UUID [%d][%s].\n", ret, sss_strerror(ret));
+     }
+ 
+     /* If this object has a SID available, we will determine the correct
+diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
+index 43b72fe2051b452c6ea755c8842117cceafa143a..416d2a9594e456b159f24c224fdd8bf8617377d7 100644
+--- a/src/providers/ldap/sdap_async_initgroups.c
++++ b/src/providers/ldap/sdap_async_initgroups.c
+@@ -197,8 +197,13 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+                     original_dn = NULL;
+                 }
+ 
++                ret = sysdb_handle_original_uuid(
++                                   opts->group_map[SDAP_AT_GROUP_UUID].def_name,
++                                   ldap_groups[ai],
++                                   opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
++                                   ldap_groups[ai], "uniqueIDstr");
+                 ret = sysdb_attrs_get_string(ldap_groups[ai],
+-                                             SYSDB_UUID,
++                                             "uniqueIDstr",
+                                              &uuid);
+                 if (ret) {
+                     DEBUG(SSSDBG_FUNC_DATA,
+diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
+index 367e3d795ddd0db5c1c2f8e57d700419f371cd15..82b4df4793f5f0679046f259c251f5897af831cf 100644
+--- a/src/providers/ldap/sdap_async_users.c
++++ b/src/providers/ldap/sdap_async_users.c
+@@ -140,7 +140,6 @@ int sdap_save_user(TALLOC_CTX *memctx,
+     TALLOC_CTX *tmpctx = NULL;
+     bool use_id_mapping;
+     char *sid_str;
+-    const char *uuid;
+     char *dom_sid_str = NULL;
+     struct sss_domain_info *subdomain;
+ 
+@@ -179,21 +178,13 @@ int sdap_save_user(TALLOC_CTX *memctx,
+     }
+ 
+     /* Always store UUID if available */
+-    ret = sysdb_attrs_get_string(attrs,
+-                                 opts->user_map[SDAP_AT_USER_UUID].sys_name,
+-                                 &uuid);
+-    if (ret == EOK) {
+-        ret = sysdb_attrs_add_string(user_attrs, SYSDB_UUID, uuid);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not add UUID string: [%s]\n",
+-                                         sss_strerror(ret));
+-            goto done;
+-        }
+-    } else if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_ALL, "UUID not available for user.\n");
+-    } else {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify UUID [%s]\n",
+-                                     sss_strerror(ret));
++    ret = sysdb_handle_original_uuid(opts->user_map[SDAP_AT_USER_UUID].def_name,
++                                     attrs,
++                                     opts->user_map[SDAP_AT_USER_UUID].sys_name,
++                                     user_attrs, SYSDB_UUID);
++    if (ret != EOK) {
++        DEBUG((ret == ENOENT) ? SSSDBG_TRACE_ALL : SSSDBG_MINOR_FAILURE,
++              "Failed to retrieve UUID [%d][%s].\n", ret, sss_strerror(ret));
+     }
+ 
+     /* If this object has a SID available, we will determine the correct
+diff --git a/src/tests/cmocka/test_string_utils.c b/src/tests/cmocka/test_string_utils.c
+index e446387d6c429515360b23b428555befa915b49a..5d3fcf4fe454a0be3a4c72b778003481f66910bb 100644
+--- a/src/tests/cmocka/test_string_utils.c
++++ b/src/tests/cmocka/test_string_utils.c
+@@ -133,3 +133,62 @@ void test_reverse_replace_whitespaces(void **state)
+     assert_true(check_leaks_pop(mem_ctx) == true);
+     talloc_free(mem_ctx);
+ }
++
++void test_guid_blob_to_string_buf(void **state)
++{
++    int ret;
++    char str_buf[GUID_STR_BUF_SIZE];
++    size_t c;
++
++    /* How to get test data:
++     * The objectGUID attribute contains a 16byte long binary value
++     * representing the GUID of the object. This data can be converted
++     * manually to the string representation but it might be easier to use
++     * LDAP_SERVER_EXTENDED_DN_OID as described in [MS-ADST] section
++     * 3.1.1.3.4.1.5. This is an LDAP extended control which adds the GUID and
++     * the SID to the DN of an object. This can be activate with the -E
++     * ldapsearch option like:
++     *
++     *  ldapsearch -E 1.2.840.113556.1.4.529=::MAMCAQE= ....
++     *
++     * where 'MAMCAQE=' is the base64 encoded BER sequence with the integer
++     * value 1 (see [MS-ADTS] for details about possible values).
++     *
++     * Btw, if you want to use the string representation of a GUID to search
++     * for an object in AD you have to use the GUID as the search base in the
++     * following form:
++     *
++     *  ldapsearch b '<GUID=fea80d8d-dbd5-4f84-8574-7db0477f962e>' ...
++     *
++     * (please note that the '<' and '>' are really needed).
++     */
++    struct test_data {
++        uint8_t blob[16];
++        const char *guid_str;
++    } test_data[] = {
++        {{0x8d, 0x0d, 0xa8, 0xfe, 0xd5, 0xdb, 0x84, 0x4f,
++          0x85, 0x74, 0x7d, 0xb0, 0x47, 0x7f, 0x96, 0x2e},
++        "fea80d8d-dbd5-4f84-8574-7db0477f962e"},
++        {{0x91, 0x7e, 0x2e, 0xf8, 0x4e, 0x44, 0xfa, 0x4e,
++         0xb1, 0x13, 0x08, 0x98, 0x63, 0x49, 0x6c, 0xc6},
++        "f82e7e91-444e-4efa-b113-089863496cc6"},
++        {{0}, NULL}
++    };
++
++    ret = guid_blob_to_string_buf(NULL, str_buf, GUID_STR_BUF_SIZE);
++    assert_int_equal(ret, EINVAL);
++
++    ret = guid_blob_to_string_buf((const uint8_t *) "1234567812345678", NULL,
++                                  GUID_STR_BUF_SIZE);
++    assert_int_equal(ret, EINVAL);
++
++    ret = guid_blob_to_string_buf((const uint8_t *) "1234567812345678", str_buf, 0);
++    assert_int_equal(ret, EINVAL);
++
++    for (c = 0; test_data[c].guid_str != NULL; c++) {
++        ret = guid_blob_to_string_buf(test_data[c].blob, str_buf,
++                                      sizeof(str_buf));
++        assert_int_equal(ret, EOK);
++        assert_string_equal(test_data[c].guid_str, str_buf);
++    }
++}
+diff --git a/src/tests/cmocka/test_sysdb_utils.c b/src/tests/cmocka/test_sysdb_utils.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..d217314ccb9234f8d0d329d87c5dc9e847acbcf0
+--- /dev/null
++++ b/src/tests/cmocka/test_sysdb_utils.c
+@@ -0,0 +1,134 @@
++/*
++    SSSD
++
++    sysdb_utils - Tests for various sysdb calls
++
++    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 <stdarg.h>
++#include <stddef.h>
++#include <setjmp.h>
++#include <cmocka.h>
++#include <popt.h>
++
++#include "tests/cmocka/common_mock.h"
++
++#define IPA_UUID "bcae7c40-97eb-11e4-88ca-525400e96a6b"
++
++#define AD_GUID_BIN {0x8d, 0x0d, 0xa8, 0xfe, 0xd5, 0xdb, 0x84, 0x4f, \
++                     0x85, 0x74, 0x7d, 0xb0, 0x47, 0x7f, 0x96, 0x2e};
++#define AD_GUID "fea80d8d-dbd5-4f84-8574-7db0477f962e"
++static void test_sysdb_handle_original_uuid(void **state)
++{
++    int ret;
++    struct sysdb_attrs *src_attrs;
++    struct sysdb_attrs *dest_attrs;
++    const char *guid;
++    uint8_t bin_guid[] = AD_GUID_BIN;
++    struct ldb_val guid_val = {bin_guid, 16};
++
++    ret = sysdb_handle_original_uuid(NULL, NULL, NULL, NULL, NULL);
++    assert_int_equal(ret, EINVAL);
++
++    src_attrs = sysdb_new_attrs(NULL);
++    assert_non_null(src_attrs);
++
++    dest_attrs = sysdb_new_attrs(NULL);
++    assert_non_null(dest_attrs);
++
++    ret = sysdb_handle_original_uuid("xyz", src_attrs, "abc", dest_attrs,
++                                     "def");
++    assert_int_equal(ret, ENOENT);
++
++    ret = sysdb_attrs_add_val(src_attrs, "GUID", &guid_val);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_attrs_add_string(src_attrs, "UUID", IPA_UUID);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_handle_original_uuid("objectGUID", src_attrs, "GUID",
++                                     dest_attrs, "def");
++    assert_int_equal(ret, EOK);
++    ret = sysdb_attrs_get_string(dest_attrs, "def", &guid);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(guid, AD_GUID);
++
++    ret = sysdb_handle_original_uuid("ipaUniqueID", src_attrs, "UUID",
++                                     dest_attrs, "ghi");
++    assert_int_equal(ret, EOK);
++    ret = sysdb_attrs_get_string(dest_attrs, "ghi", &guid);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(guid, IPA_UUID);
++
++    talloc_free(src_attrs);
++    src_attrs = sysdb_new_attrs(NULL);
++    assert_non_null(src_attrs);
++
++    /* check objectGUID with length other than 16 */
++    ret = sysdb_attrs_add_string(src_attrs, "GUID", IPA_UUID);
++    assert_int_equal(ret, EOK);
++    ret = sysdb_handle_original_uuid("objectGUID", src_attrs, "GUID",
++                                     dest_attrs, "jkl");
++    assert_int_equal(ret, EOK);
++    ret = sysdb_attrs_get_string(dest_attrs, "jkl", &guid);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(guid, IPA_UUID);
++
++    talloc_free(src_attrs);
++    talloc_free(dest_attrs);
++}
++
++int main(int argc, const char *argv[])
++{
++    int rv;
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const UnitTest tests[] = {
++        unit_test(test_sysdb_handle_original_uuid),
++    };
++
++    /* Set debug level to invalid value so we can deside if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    tests_set_cwd();
++    rv = run_tests(tests);
++
++    return rv;
++}
+diff --git a/src/tests/cmocka/test_utils.h b/src/tests/cmocka/test_utils.h
+index f85ac2f2b3c50a60099970752b06adbad38b9fd1..61ef7e43a82649d775d9b932def9e957b0761bed 100644
+--- a/src/tests/cmocka/test_utils.h
++++ b/src/tests/cmocka/test_utils.h
+@@ -29,5 +29,6 @@ void test_textual_public_key(void **state);
+ /* from src/tests/cmocka/test_string_utils.c */
+ void test_replace_whitespaces(void **state);
+ void test_reverse_replace_whitespaces(void **state);
++void test_guid_blob_to_string_buf(void **state);
+ 
+ #endif /* __TESTS__CMOCKA__TEST_UTILS_H__ */
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 46abab5ae32189b0561d1901407d2bb38a1ec4c0..7e603fda15024da71cf57912acc69bddcc882357 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -78,6 +78,7 @@ server_tests_SOURCES = \
+     ../../../src/util/atomic_io.c \
+     ../../../src/util/signal.c \
+     ../../../src/util/util.c \
++    ../../../src/util/string_utils.c \
+     ../../../src/util/strtonum.c \
+     ../../../src/util/util_errors.c \
+     ../../../src/util/safe-format-string.c \
+@@ -115,6 +116,7 @@ usertools_tests_SOURCES = \
+     ../../../src/util/domain_info_utils.c \
+     ../../../src/util/safe-format-string.c \
+     ../../../src/util/usertools.c \
++    ../../../src/util/string_utils.c \
+     ../../../src/util/strtonum.c \
+     ../../../src/util/backup_file.c \
+     ../../../src/util/atomic_io.c \
+diff --git a/src/util/string_utils.c b/src/util/string_utils.c
+index a39b950e852de7ed43d6e8a32de3e7fb08a0dc56..71b2a092018076fd9c20ef9ac39a11964876cfc3 100644
+--- a/src/util/string_utils.c
++++ b/src/util/string_utils.c
+@@ -83,3 +83,28 @@ char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx,
+ 
+     return replace_char(mem_ctx, orig_name, subst, ' ');
+ }
++
++errno_t guid_blob_to_string_buf(const uint8_t *blob, char *str_buf,
++                                size_t buf_size)
++{
++    int ret;
++
++    if (blob == NULL || str_buf == NULL || buf_size < GUID_STR_BUF_SIZE) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Buffer too small.\n");
++        return EINVAL;
++    }
++
++    ret = snprintf(str_buf, buf_size,
++         "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
++         blob[3], blob[2], blob[1], blob[0],
++         blob[5], blob[4],
++         blob[7], blob[6],
++         blob[8], blob[9],
++         blob[10], blob[11],blob[12], blob[13],blob[14], blob[15]);;
++    if (ret != (GUID_STR_BUF_SIZE -1)) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "snprintf failed.\n");
++        return EIO;
++    }
++
++    return EOK;
++}
+diff --git a/src/util/util.h b/src/util/util.h
+index bf3a9a057aed77e93949370f8651af2631d91432..1530b550bb85c121cbc33c8c6353b7ecae9edaae 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -618,6 +618,13 @@ char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx,
+                                  const char *orig_name,
+                                  const char replace_char);
+ 
++#define GUID_BIN_LENGTH 16
++/* 16 2-digit hex values + 4 dashes + terminating 0 */
++#define GUID_STR_BUF_SIZE (2 * GUID_BIN_LENGTH + 4 + 1)
++
++errno_t guid_blob_to_string_buf(const uint8_t *blob, char *str_buf,
++                                size_t buf_size);
++
+ /* from become_user.c */
+ errno_t become_user(uid_t uid, gid_t gid);
+ struct sss_creds;
+-- 
+2.1.0
+
diff --git a/SOURCES/0202-Download-complete-groups-if-ignore_group_members-is-.patch b/SOURCES/0202-Download-complete-groups-if-ignore_group_members-is-.patch
new file mode 100644
index 0000000..59b00f7
--- /dev/null
+++ b/SOURCES/0202-Download-complete-groups-if-ignore_group_members-is-.patch
@@ -0,0 +1,76 @@
+From 591ee6dee11c4509e8e748ce83414913143e751d Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 22 May 2015 15:19:31 +0200
+Subject: [PATCH 202/207] Download complete groups if ignore_group_members is
+ set with tokengroups
+
+Resolves:
+    https://fedorahosted.org/sssd/ticket/2644
+
+When tokenGroups are enabled, we save groups using their SID as the RDN
+attribute during initgroups() and later, if the groups is requested and saved
+again with the full name, remove the original and save the new group entry.
+
+Saving the new group entry would break if ignore_group_members is also
+set, because the new group entry would lack the "member" attribute, so the
+member/memberof links between the new group and the user entry wouldn't
+be established again.
+
+This patch changes the initgroups processing so that the full group
+object is fetched when initgroups is enabled but together with
+ignore_group_members. This solution imposes some performance impact,
+because instead of one search for tokenGroups we also need to resolve the
+groups. The more systematic solution would be to get rid of removing the
+group entry as described in https://fedorahosted.org/sssd/ticket/2656
+
+To reproduce the bug, set: ignore_group_members = True with a
+backend that uses:
+    id_provider = ad
+Then run:
+    $ id aduser@ad_domain.com
+    $ id aduser@ad_domain.com
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit ee44aac95e42c3cb634876286a2aa4960ac69a2b)
+---
+ src/providers/ldap/sdap_async_initgroups_ad.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
+index 9915f18..463d850 100644
+--- a/src/providers/ldap/sdap_async_initgroups_ad.c
++++ b/src/providers/ldap/sdap_async_initgroups_ad.c
+@@ -1445,7 +1445,18 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
+     state->use_id_mapping = use_id_mapping;
+     state->domain = domain;
+ 
+-    if (state->use_id_mapping && !IS_SUBDOMAIN(state->domain)) {
++    /* We can compute the the gidNumber attribute from SIDs obtained from
++     * the tokenGroups lookup in case ID mapping is used for a user from the
++     * parent domain. For trusted domains, we need to know the group type
++     * to be able to filter out domain-local groups. Additionally, as a
++     * temporary workaround until https://fedorahosted.org/sssd/ticket/2656
++     * is fixed, we also fetch the group object if group members are ignored
++     * to avoid having to transfer and retain members when the fake
++     * tokengroups object without name is replaced by the full group object
++     */
++    if (state->use_id_mapping
++            && !IS_SUBDOMAIN(state->domain)
++            && state->domain->ignore_group_members == false) {
+         subreq = sdap_ad_tokengroups_initgr_mapping_send(state, ev, opts,
+                                                          sysdb, domain, sh,
+                                                          name, orig_dn,
+@@ -1485,7 +1496,9 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
+ 
+-    if (state->use_id_mapping && !IS_SUBDOMAIN(state->domain)) {
++    if (state->use_id_mapping
++            && !IS_SUBDOMAIN(state->domain)
++            && state->domain->ignore_group_members == false) {
+         ret = sdap_ad_tokengroups_initgr_mapping_recv(subreq);
+     } else {
+         ret = sdap_ad_tokengroups_initgr_posix_recv(subreq);
+-- 
+2.1.0
+
diff --git a/SOURCES/0203-confdb-Add-new-option-subdomain_inherit.patch b/SOURCES/0203-confdb-Add-new-option-subdomain_inherit.patch
new file mode 100644
index 0000000..8659f29
--- /dev/null
+++ b/SOURCES/0203-confdb-Add-new-option-subdomain_inherit.patch
@@ -0,0 +1,152 @@
+From a4dcc9a1290cfb82fde44bb8f4a4ab8d4668cd5b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 29 Apr 2015 19:41:14 +0200
+Subject: [PATCH 203/207] confdb: Add new option subdomain_inherit
+
+Adds a new option subdomain_inherit that would allow administrators to pick
+and choose which option to pass to subdomains.
+
+This option is required for:
+    https://fedorahosted.org/sssd/ticket/2644
+as a short-term fix.
+
+The proper solution is described in:
+    https://fedorahosted.org/sssd/ticket/2599
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit 1711cbfd2e36d44af1ae50e3a2beeec3a1f0b5e8)
+---
+ src/confdb/confdb.c                  | 13 +++++++++++++
+ src/confdb/confdb.h                  |  2 ++
+ src/config/SSSDConfig/__init__.py.in |  1 +
+ src/config/SSSDConfigTest.py         |  6 ++++--
+ src/config/etc/sssd.api.conf         |  1 +
+ src/man/sssd.conf.5.xml              | 20 +++++++++++++++++++-
+ 6 files changed, 40 insertions(+), 3 deletions(-)
+
+diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
+index c55a945..6b2ce73 100644
+--- a/src/confdb/confdb.c
++++ b/src/confdb/confdb.c
+@@ -1212,6 +1212,19 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+         }
+     }
+ 
++    tmp = ldb_msg_find_attr_as_string(res->msgs[0],
++                                      CONFDB_DOMAIN_SUBDOMAIN_INHERIT,
++                                      NULL);
++    if (tmp != NULL) {
++        ret = split_on_separator(domain, tmp, ',', true, true,
++                                 &domain->sd_inherit, NULL);
++        if (ret != 0) {
++            DEBUG(SSSDBG_FATAL_FAILURE,
++                  "Cannot parse %s\n", CONFDB_SUBDOMAIN_ENUMERATE);
++            goto done;
++        }
++    }
++
+     ret = get_entry_as_uint32(res->msgs[0], &domain->subdomain_refresh_interval,
+                               CONFDB_DOMAIN_SUBDOMAIN_REFRESH, 14400);
+     if (ret != EOK || domain->subdomain_refresh_interval == 0) {
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index 159aa9f..468c757 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -183,6 +183,7 @@
+ #define CONFDB_DOMAIN_PWD_EXPIRATION_WARNING "pwd_expiration_warning"
+ #define CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL "refresh_expired_interval"
+ #define CONFDB_DOMAIN_OFFLINE_TIMEOUT "offline_timeout"
++#define CONFDB_DOMAIN_SUBDOMAIN_INHERIT "subdomain_inherit"
+ 
+ /* Local Provider */
+ #define CONFDB_LOCAL_DEFAULT_SHELL   "default_shell"
+@@ -263,6 +264,7 @@ struct sss_domain_info {
+     struct sss_domain_info *next;
+ 
+     bool disabled;
++    char **sd_inherit;
+ };
+ 
+ /**
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 500bd71..8b9ab5a 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -144,6 +144,7 @@ option_strings = {
+     'dyndns_auth' : _("What kind of authentication should be 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'),
+ 
+     # [provider/ipa]
+     'ipa_domain' : _('IPA domain'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 78e22f6..6719132 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -538,7 +538,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'hostid_provider',
+             'subdomains_provider',
+             'realmd_tags',
+-            'subdomain_refresh_interval']
++            'subdomain_refresh_interval',
++            'subdomain_inherit']
+ 
+         self.assertTrue(type(options) == dict,
+                         "Options should be a dictionary")
+@@ -897,7 +898,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'hostid_provider',
+             'subdomains_provider',
+             'realmd_tags',
+-            'subdomain_refresh_interval']
++            'subdomain_refresh_interval',
++            'subdomain_inherit']
+ 
+         self.assertTrue(type(options) == dict,
+                         "Options should be a dictionary")
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index c16769a..8b3dee6 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -129,6 +129,7 @@ default_shell = str, None, false
+ description = str, None, false
+ realmd_tags = str, None, false
+ subdomain_refresh_interval = int, None, false
++subdomain_inherit = str, None, false
+ 
+ #Entry cache timeouts
+ entry_cache_user_timeout = int, None, false
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 2002ccc..f7d688a 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -476,7 +476,25 @@
+                         </para>
+                     </listitem>
+                 </varlistentry>
+-
++                <varlistentry>
++                    <term>subdomain_inherit (string)</term>
++                    <listitem>
++                        <para>
++                            Specifies a list of configuration parameters that
++                            should be inherited by a subdomain. Please note
++                            that only selected parameters can be inherited.
++                        </para>
++                        <para>
++                            Example:
++                            <programlisting>
++subdomain_inherit = ldap_purge_cache_timeout
++                            </programlisting>
++                        </para>
++                        <para>
++                            Default: none
++                        </para>
++                    </listitem>
++                </varlistentry>
+             </variablelist>
+         </refsect2>
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/0204-DP-Add-a-function-to-inherit-DP-options-if-set.patch b/SOURCES/0204-DP-Add-a-function-to-inherit-DP-options-if-set.patch
new file mode 100644
index 0000000..a2f16fe
--- /dev/null
+++ b/SOURCES/0204-DP-Add-a-function-to-inherit-DP-options-if-set.patch
@@ -0,0 +1,308 @@
+From 092c9d35a4cc85c9910669bb3a8169f000ebc69c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 6 May 2015 08:06:53 +0200
+Subject: [PATCH 204/207] DP: Add a function to inherit DP options, if set
+
+Related to:
+    https://fedorahosted.org/sssd/ticket/2644
+
+Adds a utility function that checks if a DP option is present in
+the subdomain_inherit list. If it is, then the option is set from source
+to destination dp_option array.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit b3d110fbc424a03674a6e50e489a7cbab9702f0b)
+
+Conflicts:
+	src/tests/cmocka/test_dp_opts.c
+---
+ src/providers/data_provider.h      |   5 ++
+ src/providers/data_provider_opts.c |  57 +++++++++++++++++
+ src/tests/cmocka/test_dp_opts.c    | 127 ++++++++++++++++++++++++++++++++++---
+ 3 files changed, 181 insertions(+), 8 deletions(-)
+
+diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
+index 5df493e..657d2b7 100644
+--- a/src/providers/data_provider.h
++++ b/src/providers/data_provider.h
+@@ -277,6 +277,11 @@ struct dp_option {
+ 
+ #define DP_OPTION_TERMINATOR { NULL, 0, NULL_STRING, NULL_STRING }
+ 
++void dp_option_inherit(char **inherit_opt_list,
++                       int option,
++                       struct dp_option *parent_opts,
++                       struct dp_option *subdom_opts);
++
+ int dp_get_options(TALLOC_CTX *memctx,
+                    struct confdb_ctx *cdb,
+                    const char *conf_path,
+diff --git a/src/providers/data_provider_opts.c b/src/providers/data_provider_opts.c
+index 8ad8456..9db43fc 100644
+--- a/src/providers/data_provider_opts.c
++++ b/src/providers/data_provider_opts.c
+@@ -21,6 +21,63 @@
+ 
+ #include "data_provider.h"
+ 
++/* =Copy-Option-From-Subdomain-If-Allowed================================= */
++void dp_option_inherit(char **inherit_opt_list,
++                       int option,
++                       struct dp_option *parent_opts,
++                       struct dp_option *subdom_opts)
++{
++    errno_t ret;
++    bool inherit_option;
++
++    inherit_option = string_in_list(parent_opts[option].opt_name,
++                                    inherit_opt_list, false);
++    if (inherit_option == false) {
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "Option %s is not set up to be inherited\n",
++              parent_opts[option].opt_name);
++        return;
++    }
++
++    DEBUG(SSSDBG_CONF_SETTINGS,
++          "Will inherit option %s\n", parent_opts[option].opt_name);
++    switch (parent_opts[option].type) {
++    case DP_OPT_NUMBER:
++        ret = dp_opt_set_int(subdom_opts,
++                             option,
++                             dp_opt_get_int(parent_opts,
++                                            option));
++        break;
++    case DP_OPT_STRING:
++        ret = dp_opt_set_string(subdom_opts,
++                                option,
++                                dp_opt_get_string(parent_opts,
++                                                  option));
++        break;
++    case DP_OPT_BLOB:
++        ret = dp_opt_set_blob(subdom_opts,
++                              option,
++                              dp_opt_get_blob(parent_opts,
++                                              option));
++        break;
++    case DP_OPT_BOOL:
++        ret = dp_opt_set_bool(subdom_opts,
++                              option,
++                              dp_opt_get_bool(parent_opts,
++                                              option));
++        break;
++    default:
++        ret = EINVAL;
++        break;
++    }
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Failed to inherit option %s\n", parent_opts[option].opt_name);
++        /* Not fatal */
++    }
++}
++
+ /* =Retrieve-Options====================================================== */
+ 
+ int dp_get_options(TALLOC_CTX *memctx,
+diff --git a/src/tests/cmocka/test_dp_opts.c b/src/tests/cmocka/test_dp_opts.c
+index 0f3052a..60267ab 100644
+--- a/src/tests/cmocka/test_dp_opts.c
++++ b/src/tests/cmocka/test_dp_opts.c
+@@ -284,37 +284,63 @@ void opt_test_getset_teardown(void **state)
+     talloc_free(opts);
+ }
+ 
+-void opt_test_getset_string(void **state)
++static void assert_nondefault_string_empty(struct dp_option *opts)
+ {
+-    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
+-    int ret;
+     char *s;
+ 
+     s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
+     assert_null(s);
++}
++
++static void set_nondefault_string(struct dp_option *opts)
++{
++    int ret;
+ 
+     ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1");
+     assert_int_equal(ret, EOK);
++}
++
++static void check_nondefault_string(struct dp_option *opts)
++{
++    char *s;
+ 
+     s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
+     assert_non_null(s);
+     assert_string_equal(s, "str1");
+ }
+ 
+-void opt_test_getset_blob(void **state)
++void opt_test_getset_string(void **state)
+ {
+     struct dp_option *opts = talloc_get_type(*state, struct dp_option);
+-    int ret;
++
++    assert_nondefault_string_empty(opts);
++    set_nondefault_string(opts);
++    check_nondefault_string(opts);
++}
++
++static void assert_nondefault_blob_empty(struct dp_option *opts)
++{
+     struct dp_opt_blob b;
+ 
+     b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
+     assert_null(b.data);
+     assert_int_equal(b.length, 0);
++}
++
++static void set_nondefault_blob(struct dp_option *opts)
++{
++    struct dp_opt_blob b;
++    int ret;
+ 
+     b.data = discard_const_p(uint8_t, "blob2");
+     b.length = strlen("blob2");
+     ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b);
+     assert_int_equal(ret, EOK);
++}
++
++static void check_nondefault_blob(struct dp_option *opts)
++{
++    struct dp_opt_blob b;
+ 
+     b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
+     assert_non_null(b.data);
+@@ -322,22 +348,45 @@ void opt_test_getset_blob(void **state)
+     assert_memory_equal(b.data, "blob2", strlen("blob2"));
+ }
+ 
+-void opt_test_getset_int(void **state)
++void opt_test_getset_blob(void **state)
+ {
+     struct dp_option *opts = talloc_get_type(*state, struct dp_option);
+-    int ret;
+-    int i;
+ 
++    assert_nondefault_blob_empty(opts);
++    set_nondefault_blob(opts);
++    check_nondefault_blob(opts);
++}
++
++static void assert_nondefault_int_notset(struct dp_option *opts)
++{
++    int i;
+     i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
+     assert_int_equal(i, 0);
++}
+ 
++static void set_nondefault_int(struct dp_option *opts)
++{
++    int ret;
+     ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456);
+     assert_int_equal(ret, EOK);
++}
+ 
++static void assert_nondefault_int_set(struct dp_option *opts)
++{
++    int i;
+     i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
+     assert_int_equal(i, 456);
+ }
+ 
++void opt_test_getset_int(void **state)
++{
++    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
++
++    assert_nondefault_int_notset(opts);
++    set_nondefault_int(opts);
++    assert_nondefault_int_set(opts);
++}
++
+ void opt_test_getset_bool(void **state)
+ {
+     struct dp_option *opts = talloc_get_type(*state, struct dp_option);
+@@ -354,6 +403,65 @@ void opt_test_getset_bool(void **state)
+     assert_false(b == true);
+ }
+ 
++void opt_test_inherit(void **state)
++{
++    struct dp_option *opts = talloc_get_type(*state, struct dp_option);
++    int ret;
++    struct dp_option *opts_copy;
++    const char *s;
++    const char *sd_inherit_match[] = { "string_nodefault",
++                                       "blob_nodefault",
++                                       "int_nodefault",
++                                       "bool_true",
++                                       NULL };
++
++    ret = dp_copy_defaults(opts, test_def_opts,
++                           OPT_NUM_OPTS, &opts_copy);
++    assert_int_equal(ret, EOK);
++    assert_defaults(opts);
++
++    dp_option_inherit(NULL, OPT_STRING_NODEFAULT,
++                      opts, opts_copy);
++    s = dp_opt_get_string(opts_copy, OPT_STRING_NODEFAULT);
++    assert_null(s);
++
++    /* string */
++    assert_nondefault_string_empty(opts_copy);
++    set_nondefault_string(opts);
++    dp_option_inherit(discard_const(sd_inherit_match),
++                      OPT_STRING_NODEFAULT,
++                      opts, opts_copy);
++    check_nondefault_string(opts_copy);
++
++    /* blob */
++    assert_nondefault_blob_empty(opts_copy);
++    set_nondefault_blob(opts);
++    dp_option_inherit(discard_const(sd_inherit_match),
++                      OPT_BLOB_NODEFAULT,
++                      opts, opts_copy);
++    check_nondefault_blob(opts_copy);
++
++    /* number */
++    assert_nondefault_int_notset(opts_copy);
++    set_nondefault_int(opts);
++    dp_option_inherit(discard_const(sd_inherit_match),
++                      OPT_INT_NODEFAULT,
++                      opts, opts_copy);
++    assert_nondefault_int_set(opts_copy);
++
++    /* bool */
++    assert_true(dp_opt_get_bool(opts_copy, OPT_BOOL_TRUE));
++
++    ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false);
++    assert_int_equal(ret, EOK);
++
++    dp_option_inherit(discard_const(sd_inherit_match),
++                      OPT_BOOL_TRUE,
++                      opts, opts_copy);
++
++    assert_false(dp_opt_get_bool(opts_copy, OPT_BOOL_TRUE));
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int no_cleanup = 0;
+@@ -380,6 +488,9 @@ int main(int argc, const char *argv[])
+         unit_test_setup_teardown(opt_test_getset_blob,
+                                  opt_test_getset_setup,
+                                  opt_test_getset_teardown),
++        unit_test_setup_teardown(opt_test_inherit,
++                                 opt_test_getset_setup,
++                                 opt_test_getset_teardown),
+         unit_test(opt_test_copy_default),
+         unit_test(opt_test_copy_options),
+         unit_test(opt_test_get)
+-- 
+2.1.0
+
diff --git a/SOURCES/0205-SDAP-Add-sdap_copy_map_entry.patch b/SOURCES/0205-SDAP-Add-sdap_copy_map_entry.patch
new file mode 100644
index 0000000..f3f7307
--- /dev/null
+++ b/SOURCES/0205-SDAP-Add-sdap_copy_map_entry.patch
@@ -0,0 +1,162 @@
+From 62416ef0d547018872da915d0fe863780926d7be Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 22 May 2015 18:31:42 +0200
+Subject: [PATCH 205/207] SDAP: Add sdap_copy_map_entry
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit 12089241f6a6eabf4f0c95669e5fc2bb3b503c06)
+
+Conflicts:
+	src/tests/cmocka/test_sdap.c
+---
+ src/providers/ldap/sdap.c    | 17 +++++++++
+ src/providers/ldap/sdap.h    |  4 +++
+ src/tests/cmocka/test_sdap.c | 82 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 103 insertions(+)
+
+diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
+index e428d5f..bc9f8b3 100644
+--- a/src/providers/ldap/sdap.c
++++ b/src/providers/ldap/sdap.c
+@@ -28,6 +28,23 @@
+ 
+ /* =Retrieve-Options====================================================== */
+ 
++errno_t sdap_copy_map_entry(const struct sdap_attr_map *src_map,
++                            struct sdap_attr_map *dst_map,
++                            int entry_index)
++{
++    if (src_map[entry_index].name != NULL) {
++        dst_map[entry_index].name = talloc_strdup(dst_map,
++                                                  src_map[entry_index].name);
++        if (dst_map[entry_index].name == NULL) {
++            return ENOMEM;
++        }
++    } else {
++        dst_map->name = NULL;
++    }
++
++    return EOK;
++}
++
+ int sdap_copy_map(TALLOC_CTX *memctx,
+                  struct sdap_attr_map *src_map,
+                  int num_entries,
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index 921051b..c0e9ff9 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -467,6 +467,10 @@ struct sdap_deref_attrs {
+     struct sysdb_attrs *attrs;
+ };
+ 
++errno_t sdap_copy_map_entry(const struct sdap_attr_map *src_map,
++                            struct sdap_attr_map *dst_map,
++                            int entry_index);
++
+ int sdap_copy_map(TALLOC_CTX *memctx,
+                  struct sdap_attr_map *src_map,
+                  int num_entries,
+diff --git a/src/tests/cmocka/test_sdap.c b/src/tests/cmocka/test_sdap.c
+index 404e100..d1e6959 100644
+--- a/src/tests/cmocka/test_sdap.c
++++ b/src/tests/cmocka/test_sdap.c
+@@ -718,6 +718,80 @@ void test_parse_no_dn(void **state)
+     talloc_free(map);
+ }
+ 
++struct copy_map_entry_test_ctx {
++    struct sdap_attr_map *src_map;
++    struct sdap_attr_map *dst_map;
++};
++
++static void copy_map_entry_test_setup(void **state)
++{
++    int ret;
++    struct copy_map_entry_test_ctx *test_ctx;
++
++    assert_true(leak_check_setup());
++
++    test_ctx = talloc_zero(global_talloc_context,
++                           struct copy_map_entry_test_ctx);
++    assert_non_null(test_ctx);
++
++    ret = sdap_copy_map(test_ctx, rfc2307_user_map,
++                        SDAP_OPTS_USER, &test_ctx->src_map);
++    assert_int_equal(ret, ERR_OK);
++
++    ret = sdap_copy_map(test_ctx, rfc2307_user_map,
++                        SDAP_OPTS_USER, &test_ctx->dst_map);
++    assert_int_equal(ret, ERR_OK);
++
++    check_leaks_push(test_ctx);
++    *state = test_ctx;
++}
++
++static void copy_map_entry_test_teardown(void **state)
++{
++    struct copy_map_entry_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                               struct copy_map_entry_test_ctx);
++    assert_true(check_leaks_pop(test_ctx) == true);
++    talloc_free(test_ctx);
++    assert_true(leak_check_teardown());
++    return 0;
++}
++
++static const char *copy_uuid(struct copy_map_entry_test_ctx *test_ctx)
++{
++    errno_t ret;
++
++    assert_null(test_ctx->dst_map[SDAP_AT_USER_UUID].name);
++    ret = sdap_copy_map_entry(test_ctx->src_map, test_ctx->dst_map,
++                              SDAP_AT_USER_UUID);
++    assert_int_equal(ret, EOK);
++    return test_ctx->dst_map[SDAP_AT_USER_UUID].name;
++}
++
++static void test_sdap_copy_map_entry(void **state)
++{
++    struct copy_map_entry_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                               struct copy_map_entry_test_ctx);
++    const char *uuid_set_val = "test_uuid_val";
++    const char *uuid_val = NULL;
++
++    test_ctx->src_map[SDAP_AT_USER_UUID].name = discard_const(uuid_set_val);
++
++    uuid_val = copy_uuid(test_ctx);
++    assert_non_null(uuid_val);
++    assert_string_equal(uuid_val, uuid_set_val);
++    talloc_free(test_ctx->dst_map[SDAP_AT_USER_UUID].name);
++}
++
++static void test_sdap_copy_map_entry_null_name(void **state)
++{
++    struct copy_map_entry_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                               struct copy_map_entry_test_ctx);
++    const char *uuid_val = NULL;
++
++    uuid_val = copy_uuid(test_ctx);
++    assert_null(uuid_val);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -763,6 +837,14 @@ int main(int argc, const char *argv[])
+         unit_test_setup_teardown(test_parse_deref_map_mismatch,
+                                  parse_entry_test_setup,
+                                  parse_entry_test_teardown),
++
++        /* Map option tests */
++        unit_test_setup_teardown(test_sdap_copy_map_entry,
++                                 copy_map_entry_test_setup,
++                                 copy_map_entry_test_teardown),
++        unit_test_setup_teardown(test_sdap_copy_map_entry_null_name,
++                                 copy_map_entry_test_setup,
++                                 copy_map_entry_test_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.1.0
+
diff --git a/SOURCES/0206-UTIL-Inherit-ignore_group_members.patch b/SOURCES/0206-UTIL-Inherit-ignore_group_members.patch
new file mode 100644
index 0000000..1e26b84
--- /dev/null
+++ b/SOURCES/0206-UTIL-Inherit-ignore_group_members.patch
@@ -0,0 +1,65 @@
+From 71565f0969738171e04f35e9aba93e63e4e83a8e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 28 Apr 2015 17:04:51 +0200
+Subject: [PATCH 206/207] UTIL: Inherit ignore_group_members
+
+Resolves:
+    https://fedorahosted.org/sssd/ticket/2644
+
+Allows the administrators to extend ignore_group_members to subdomains
+as well by setting:
+    subdomain_inherit = ignore_group_members
+in the domain section.
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit 01c049ceef55c7bbfca1e47cecb2a0a2cf0a5d44)
+---
+ src/man/sssd.conf.5.xml      | 4 ++++
+ src/util/domain_info_utils.c | 9 +++++++++
+ 2 files changed, 13 insertions(+)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index f7d688a..19995be 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -483,6 +483,10 @@
+                             Specifies a list of configuration parameters that
+                             should be inherited by a subdomain. Please note
+                             that only selected parameters can be inherited.
++                            Currently the following options can be inherited:
++                        </para>
++                        <para>
++                            ignore_group_members
+                         </para>
+                         <para>
+                             Example:
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index e0f1120..75eca8a 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -206,6 +206,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
+                                       const char *forest)
+ {
+     struct sss_domain_info *dom;
++    bool inherit_option;
+ 
+     DEBUG(SSSDBG_TRACE_FUNC,
+           "Creating [%s] as subdomain of [%s]!\n", name, parent->name);
+@@ -281,6 +282,14 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
+     dom->enumerate = enumerate;
+     dom->fqnames = true;
+     dom->mpg = mpg;
++    /* 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,
++                                    parent->sd_inherit, false);
++    if (inherit_option) {
++        dom->ignore_group_members = parent->ignore_group_members;
++    }
++
+     /* If the parent domain explicitly limits ID ranges, the subdomain
+      * should honour the limits as well.
+      */
+-- 
+2.1.0
+
diff --git a/SOURCES/0207-subdomains-Inherit-cleanup-period-and-tokengroup-set.patch b/SOURCES/0207-subdomains-Inherit-cleanup-period-and-tokengroup-set.patch
new file mode 100644
index 0000000..b888870
--- /dev/null
+++ b/SOURCES/0207-subdomains-Inherit-cleanup-period-and-tokengroup-set.patch
@@ -0,0 +1,340 @@
+From 8e382375715232130f7b96d3098a7c7a0d6cef7d Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 28 Apr 2015 13:48:42 +0200
+Subject: [PATCH 207/207] subdomains: Inherit cleanup period and tokengroup
+ settings from parent domain
+
+Allows the administrator to extend the functionality of
+ldap_purge_cache_timeout, ldap_user_principal and ldap_use_tokengroups to
+the subdomains.
+
+This is a less intrusive way of achieving:
+    https://fedorahosted.org/sssd/ticket/2627
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit 9b162bf39ef75629f54ffa1d0bd5f9c13119b650)
+
+Conflicts:
+	src/tests/cmocka/test_sdap.c
+---
+ src/man/sssd.conf.5.xml            |   9 +++
+ src/providers/ad/ad_subdomains.c   |   4 +
+ src/providers/ipa/ipa_subdomains.c |   4 +
+ src/providers/ldap/sdap.c          |  58 ++++++++++++++
+ src/providers/ldap/sdap.h          |   4 +
+ src/tests/cmocka/test_sdap.c       | 158 +++++++++++++++++++++++++++++++++++++
+ 6 files changed, 237 insertions(+)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 19995be..ef82dcd 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -489,6 +489,15 @@
+                             ignore_group_members
+                         </para>
+                         <para>
++                            ldap_purge_cache_timeout
++                        </para>
++                        <para>
++                            ldap_use_tokengroups
++                        </para>
++                        <para>
++                            ldap_user_principal
++                        </para>
++                        <para>
+                             Example:
+                             <programlisting>
+ subdomain_inherit = ldap_purge_cache_timeout
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 3c61d13..554da69 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -180,6 +180,10 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+         return EFAULT;
+     }
+ 
++    sdap_inherit_options(subdom->parent->sd_inherit,
++                         id_ctx->sdap_id_ctx->opts,
++                         ad_id_ctx->sdap_id_ctx->opts);
++
+     /* Set up the ID mapping object */
+     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
+         id_ctx->sdap_id_ctx->opts->idmap_ctx;
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 3148389..e529454 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -228,6 +228,10 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+         return EFAULT;
+     }
+ 
++    sdap_inherit_options(subdom->parent->sd_inherit,
++                         id_ctx->sdap_id_ctx->opts,
++                         ad_id_ctx->sdap_id_ctx->opts);
++
+     ret = sdap_id_setup_tasks(be_ctx,
+                               ad_id_ctx->sdap_id_ctx,
+                               sdom,
+diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
+index bc9f8b3..9b65940 100644
+--- a/src/providers/ldap/sdap.c
++++ b/src/providers/ldap/sdap.c
+@@ -243,6 +243,64 @@ int sdap_extend_map_with_list(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++static void sdap_inherit_basic_options(char **inherit_opt_list,
++                                       struct dp_option *parent_opts,
++                                       struct dp_option *subdom_opts)
++{
++    int inherit_options[] = {
++        SDAP_CACHE_PURGE_TIMEOUT,
++        SDAP_AD_USE_TOKENGROUPS,
++        SDAP_OPTS_BASIC     /* sentinel */
++    };
++    int i;
++
++    for (i = 0; inherit_options[i] != SDAP_OPTS_BASIC; i++) {
++        dp_option_inherit(inherit_opt_list,
++                          inherit_options[i],
++                          parent_opts,
++                          subdom_opts);
++    }
++}
++
++static void sdap_inherit_user_options(char **inherit_opt_list,
++                                      struct sdap_attr_map *parent_user_map,
++                                      struct sdap_attr_map *child_user_map)
++{
++    int inherit_options[] = {
++        SDAP_AT_USER_PRINC,
++        SDAP_OPTS_USER          /* sentinel */
++    };
++    int i;
++    int opt_index;
++    bool inherit_option;
++
++    for (i = 0; inherit_options[i] != SDAP_OPTS_USER; i++) {
++        opt_index = inherit_options[i];
++
++        inherit_option = string_in_list(parent_user_map[opt_index].opt_name,
++                                        inherit_opt_list,
++                                        false);
++        if (inherit_option == false) {
++            continue;
++        }
++
++        sdap_copy_map_entry(parent_user_map, child_user_map, opt_index);
++    }
++}
++
++void sdap_inherit_options(char **inherit_opt_list,
++                          struct sdap_options *parent_sdap_opts,
++                          struct sdap_options *child_sdap_opts)
++{
++    sdap_inherit_basic_options(inherit_opt_list,
++                               parent_sdap_opts->basic,
++                               child_sdap_opts->basic);
++
++    sdap_inherit_user_options(inherit_opt_list,
++                              parent_sdap_opts->user_map,
++                              child_sdap_opts->user_map);
++}
++
+ int sdap_get_map(TALLOC_CTX *memctx,
+                  struct confdb_ctx *cdb,
+                  const char *conf_path,
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index c0e9ff9..19fc039 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -491,6 +491,10 @@ int sdap_extend_map_with_list(TALLOC_CTX *mem_ctx,
+                               struct sdap_attr_map **_map,
+                               size_t *_new_size);
+ 
++void sdap_inherit_options(char **inherit_opt_list,
++                          struct sdap_options *parent_sdap_opts,
++                          struct sdap_options *child_sdap_opts);
++
+ int sdap_get_map(TALLOC_CTX *memctx,
+                  struct confdb_ctx *cdb,
+                  const char *conf_path,
+diff --git a/src/tests/cmocka/test_sdap.c b/src/tests/cmocka/test_sdap.c
+index d1e6959..5488694 100644
+--- a/src/tests/cmocka/test_sdap.c
++++ b/src/tests/cmocka/test_sdap.c
+@@ -792,6 +792,150 @@ static void test_sdap_copy_map_entry_null_name(void **state)
+     assert_null(uuid_val);
+ }
+ 
++struct test_sdap_inherit_ctx {
++    struct sdap_options *parent_sdap_opts;
++    struct sdap_options *child_sdap_opts;
++};
++
++struct sdap_options *mock_sdap_opts(TALLOC_CTX *mem_ctx)
++{
++    int ret;
++    struct sdap_options *opts;
++
++    opts = talloc_zero(mem_ctx, struct sdap_options);
++    assert_non_null(opts);
++
++    ret = sdap_copy_map(opts, rfc2307_user_map,
++                        SDAP_OPTS_USER, &opts->user_map);
++    assert_int_equal(ret, ERR_OK);
++
++    ret = dp_copy_defaults(opts, default_basic_opts,
++                           SDAP_OPTS_BASIC, &opts->basic);
++    assert_int_equal(ret, ERR_OK);
++
++    return opts;
++}
++
++static void test_sdap_inherit_option_setup(void **state)
++{
++    int ret;
++    struct test_sdap_inherit_ctx *test_ctx;
++
++    assert_true(leak_check_setup());
++
++    test_ctx = talloc_zero(global_talloc_context,
++                           struct test_sdap_inherit_ctx);
++    assert_non_null(test_ctx);
++
++    test_ctx->child_sdap_opts = talloc_zero(test_ctx, struct sdap_options);
++
++    test_ctx->parent_sdap_opts = mock_sdap_opts(test_ctx);
++    assert_non_null(test_ctx->parent_sdap_opts);
++    test_ctx->child_sdap_opts = mock_sdap_opts(test_ctx);
++    assert_non_null(test_ctx->child_sdap_opts);
++
++    test_ctx->parent_sdap_opts->user_map[SDAP_AT_USER_PRINC].name = \
++                                                  discard_const("test_princ");
++
++    ret = dp_opt_set_int(test_ctx->parent_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT, 123);
++    assert_int_equal(ret, EOK);
++
++    *state = test_ctx;
++}
++
++static void test_sdap_inherit_option_teardown(void **state)
++{
++    struct test_sdap_inherit_ctx *test_ctx = \
++                talloc_get_type_abort(*state, struct test_sdap_inherit_ctx);
++
++    talloc_free(test_ctx);
++    assert_true(leak_check_teardown());
++}
++
++static void test_sdap_inherit_option_null(void **state)
++{
++    struct test_sdap_inherit_ctx *test_ctx = \
++                talloc_get_type_abort(*state, struct test_sdap_inherit_ctx);
++    int val;
++
++    val = dp_opt_get_int(test_ctx->child_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT);
++    assert_int_equal(val, 10800);
++
++    sdap_inherit_options(NULL,
++                         test_ctx->parent_sdap_opts,
++                         test_ctx->child_sdap_opts);
++
++    val = dp_opt_get_int(test_ctx->child_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT);
++    assert_int_equal(val, 10800);
++}
++
++static void test_sdap_inherit_option_notset(void **state)
++{
++    struct test_sdap_inherit_ctx *test_ctx = \
++                talloc_get_type_abort(*state, struct test_sdap_inherit_ctx);
++    int val;
++    const char *inherit_options[] = { "ldap_use_tokengroups", NULL };
++
++    val = dp_opt_get_int(test_ctx->child_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT);
++    assert_int_equal(val, 10800);
++
++    /* parent has nondefault, but it's not supposed to be inherited */
++    sdap_inherit_options(discard_const(inherit_options),
++                         test_ctx->parent_sdap_opts,
++                         test_ctx->child_sdap_opts);
++
++    val = dp_opt_get_int(test_ctx->child_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT);
++    assert_int_equal(val, 10800);
++}
++
++static void test_sdap_inherit_option_basic(void **state)
++{
++    struct test_sdap_inherit_ctx *test_ctx = \
++                talloc_get_type_abort(*state, struct test_sdap_inherit_ctx);
++    int val;
++    const char *inherit_options[] = { "ldap_purge_cache_timeout", NULL };
++
++    val = dp_opt_get_int(test_ctx->child_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT);
++    assert_int_equal(val, 10800);
++
++    /* parent has nondefault, but it's not supposed to be inherited */
++    sdap_inherit_options(discard_const(inherit_options),
++                         test_ctx->parent_sdap_opts,
++                         test_ctx->child_sdap_opts);
++
++    val = dp_opt_get_int(test_ctx->child_sdap_opts->basic,
++                         SDAP_CACHE_PURGE_TIMEOUT);
++    assert_int_equal(val, 123);
++}
++
++static void test_sdap_inherit_option_user(void **state)
++{
++    struct test_sdap_inherit_ctx *test_ctx = \
++                talloc_get_type_abort(*state, struct test_sdap_inherit_ctx);
++    const char *inherit_options[] = { "ldap_user_principal", NULL };
++
++    assert_string_equal(
++            test_ctx->child_sdap_opts->user_map[SDAP_AT_USER_PRINC].name,
++            "krbPrincipalName");
++
++    /* parent has nondefault, but it's not supposed to be inherited */
++    sdap_inherit_options(discard_const(inherit_options),
++                         test_ctx->parent_sdap_opts,
++                         test_ctx->child_sdap_opts);
++
++    assert_string_equal(
++            test_ctx->child_sdap_opts->user_map[SDAP_AT_USER_PRINC].name,
++            "test_princ");
++
++    talloc_free(test_ctx->child_sdap_opts->user_map[SDAP_AT_USER_PRINC].name);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -845,6 +989,20 @@ int main(int argc, const char *argv[])
+         unit_test_setup_teardown(test_sdap_copy_map_entry_null_name,
+                                  copy_map_entry_test_setup,
+                                  copy_map_entry_test_teardown),
++
++        /* Option inherit tests */
++        unit_test_setup_teardown(test_sdap_inherit_option_null,
++                                 test_sdap_inherit_option_setup,
++                                 test_sdap_inherit_option_teardown),
++        unit_test_setup_teardown(test_sdap_inherit_option_notset,
++                                 test_sdap_inherit_option_setup,
++                                 test_sdap_inherit_option_teardown),
++        unit_test_setup_teardown(test_sdap_inherit_option_basic,
++                                 test_sdap_inherit_option_setup,
++                                 test_sdap_inherit_option_teardown),
++        unit_test_setup_teardown(test_sdap_inherit_option_user,
++                                 test_sdap_inherit_option_setup,
++                                 test_sdap_inherit_option_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can deside if -d 0 was used. */
+-- 
+2.1.0
+
diff --git a/SOURCES/0208-sudo-sanitize-filter-values.patch b/SOURCES/0208-sudo-sanitize-filter-values.patch
new file mode 100644
index 0000000..89e3f39
--- /dev/null
+++ b/SOURCES/0208-sudo-sanitize-filter-values.patch
@@ -0,0 +1,62 @@
+From ea10cbf8ec9669f4041c1df511b5f1b48aecce21 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 9 Apr 2015 13:03:08 +0200
+Subject: [PATCH 208/208] sudo: sanitize filter values
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2613
+
+Reviewed-by: Pavel Reichl <preichl@redhat.com>
+(cherry picked from commit c526cd124515cc2d44a413dcbfd4a74ddb490150)
+(cherry picked from commit 2fb2a267d0d15cce84b0ccea7e088a4b580e42fb)
+---
+ src/db/sysdb_sudo.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c
+index 261ed82d672cd95f0c0f429a177dae39d3b9c204..cd072dd2900757c69f7fd7f559559e310ceccda7 100644
+--- a/src/db/sysdb_sudo.c
++++ b/src/db/sysdb_sudo.c
+@@ -221,6 +221,7 @@ sysdb_get_sudo_filter(TALLOC_CTX *mem_ctx, const char *username,
+     TALLOC_CTX *tmp_ctx = NULL;
+     char *filter = NULL;
+     char *specific_filter = NULL;
++    char *sanitized = NULL;
+     time_t now;
+     errno_t ret;
+     int i;
+@@ -246,9 +247,14 @@ sysdb_get_sudo_filter(TALLOC_CTX *mem_ctx, const char *username,
+     }
+ 
+     if ((flags & SYSDB_SUDO_FILTER_USERNAME) && (username != NULL)) {
++        ret = sss_filter_sanitize(tmp_ctx, username, &sanitized);
++        if (ret != EOK) {
++            goto done;
++        }
++
+         specific_filter = talloc_asprintf_append(specific_filter, "(%s=%s)",
+                                                  SYSDB_SUDO_CACHE_AT_USER,
+-                                                 username);
++                                                 sanitized);
+         NULL_CHECK(specific_filter, ret, done);
+     }
+ 
+@@ -261,9 +267,14 @@ sysdb_get_sudo_filter(TALLOC_CTX *mem_ctx, const char *username,
+ 
+     if ((flags & SYSDB_SUDO_FILTER_GROUPS) && (groupnames != NULL)) {
+         for (i=0; groupnames[i] != NULL; i++) {
++            ret = sss_filter_sanitize(tmp_ctx, groupnames[i], &sanitized);
++            if (ret != EOK) {
++                goto done;
++            }
++
+             specific_filter = talloc_asprintf_append(specific_filter, "(%s=%%%s)",
+                                                      SYSDB_SUDO_CACHE_AT_USER,
+-                                                     groupnames[i]);
++                                                     sanitized);
+             NULL_CHECK(specific_filter, ret, done);
+         }
+     }
+-- 
+2.4.3
+
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
index 854a9be..aef7830 100644
--- a/SPECS/sssd.spec
+++ b/SPECS/sssd.spec
@@ -23,7 +23,7 @@
 
 Name: sssd
 Version: 1.12.2
-Release: 58%{?dist}.6
+Release: 58%{?dist}.14
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
@@ -228,6 +228,18 @@ Patch0193:  0193-selinux-Handle-setup-with-empty-default-and-no-confi.patch
 Patch0194:  0194-IPA-idviews-check-if-view-name-is-set.patch
 Patch0195:  0195-IPA-make-sure-output-variable-is-set.patch
 Patch0196:  0196-IPA-set-EINVAL-if-dn-can-t-be-linearized.patch
+Patch0197:  0197-LDAP-AD-do-not-resolve-group-members-during-tokenGro.patch
+Patch0198:  0198-SDAP-Do-not-set-gid-0-twice.patch
+Patch0199:  0199-SDAP-Extract-filtering-AD-group-to-function.patch
+Patch0200:  0200-SDAP-Filter-ad-groups-in-initgroups.patch
+Patch0201:  0201-sdap-properly-handle-binary-objectGuid-attribute.patch
+Patch0202:  0202-Download-complete-groups-if-ignore_group_members-is-.patch
+Patch0203:  0203-confdb-Add-new-option-subdomain_inherit.patch
+Patch0204:  0204-DP-Add-a-function-to-inherit-DP-options-if-set.patch
+Patch0205:  0205-SDAP-Add-sdap_copy_map_entry.patch
+Patch0206:  0206-UTIL-Inherit-ignore_group_members.patch
+Patch0207:  0207-subdomains-Inherit-cleanup-period-and-tokengroup-set.patch
+Patch0208:  0208-sudo-sanitize-filter-values.patch
 
 
 ### Dependencies ###
@@ -260,7 +272,7 @@ BuildRequires: libtevent-devel
 BuildRequires: libtdb-devel
 
 # LDB needs a strict version match to build
-BuildRequires: libldb-devel = %{ldb_version}
+BuildRequires: libldb-devel >= %{ldb_version}
 BuildRequires: libdhash-devel >= 0.4.2
 BuildRequires: libcollection-devel
 BuildRequires: libini_config-devel >= 1.1.0-24
@@ -324,7 +336,7 @@ Conflicts: sssd < 1.10.0-8%{?dist}.beta2
 # 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: libldb%{?_isa} >= %{ldb_version}
 
 Requires: libtdb%{?_isa} >= 1.1.3
 Requires: sssd-client%{?_isa} = %{version}-%{release}
@@ -642,7 +654,6 @@ autoreconf -ivf
     --with-krb5-rcache-dir=%{_localstatedir}/cache/krb5rcache \
     --enable-nsslibdir=%{_libdir} \
     --enable-pammoddir=%{_libdir}/security \
-    --enable-ldb-version-check \
     --enable-nfsidmaplibdir=%{_libdir}/libnfsidmap \
     --disable-static \
     --disable-rpath \
@@ -1093,6 +1104,29 @@ fi
 /usr/bin/rm -f /var/tmp/sssd.upgrade || :
 
 %changelog
+* Mon Jul 20 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.14
+- Resolves: rhbz#1244761 - Relax the libldb requirements to unblock
+                           RH Storage
+
+* Thu Jun 18 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.13
+- Resolves: rhbz#1232130 - sysdb sudo search doesn't escape special characters
+
+* Mon Jun  8 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.12
+- Resolves: rhbz#1226801 - ignore_group_members doesn't work for subdomains
+- Resolves: rhbz#1226180 - Provide a way to disable the cleanup task
+
+* Thu May 28 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.9
+- Resolves: rhbz#1227772 - Properly handle AD's binary objectGUID
+
+* Wed Apr 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.8
+- Filter out domain-local groups during AD initgroups operation
+- Related: rhbz#1214286 - SSSD downloads too much information when fetching
+                          information about groups
+
+* Wed Apr 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.7
+- Resolves: rhbz#1214286 - SSSD downloads too much information when fetching
+                           information about groups
+
 * Thu Mar 19 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.6
 - Initialize variable in the views code in one success and one failure path
 - Resolves: rhbz#1203365 - sssd_be segfault on IPA(when auth with AD