diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d94250a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/sssd-1.16.4.tar.gz
diff --git a/.sssd.metadata b/.sssd.metadata
new file mode 100644
index 0000000..ab6b049
--- /dev/null
+++ b/.sssd.metadata
@@ -0,0 +1 @@
+9deedae904567f197ddcdc6ef69c72956d14d39e SOURCES/sssd-1.16.4.tar.gz
diff --git a/SOURCES/0001-Providers-Delay-online-check-on-startup.patch b/SOURCES/0001-Providers-Delay-online-check-on-startup.patch
new file mode 100644
index 0000000..6ab2a19
--- /dev/null
+++ b/SOURCES/0001-Providers-Delay-online-check-on-startup.patch
@@ -0,0 +1,229 @@
+From dab55626ce859dd519fe108b89fa723a38fb21d1 Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Wed, 20 Mar 2019 15:44:02 +0100
+Subject: [PATCH] Providers: Delay online check on startup
+
+Typical usecase is system startup or network restart. In such
+cases SSSD receives several messages from the system about
+network change and immediately starts connecting.
+With multiple addresses on interface or multiple interfaces
+SSSD receives even more messages.
+
+This patch introduces 1s delay for online check after first
+message.
+
+Online callback tries 3 times to go online. There is increasing
+delay between online checks up to 4s.
+
+Resolves: https://pagure.io/SSSD/sssd/issue/3467
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit fe4288088e6cccf7650e5c5def3bd67be90756be)
+---
+ src/providers/backend.h          |  1 +
+ src/providers/data_provider_be.c | 94 ++++++++++++++++++++++++--------
+ 2 files changed, 72 insertions(+), 23 deletions(-)
+
+diff --git a/src/providers/backend.h b/src/providers/backend.h
+index 1fe1c2313..5ab47b29a 100644
+--- a/src/providers/backend.h
++++ b/src/providers/backend.h
+@@ -112,6 +112,7 @@ struct be_ctx {
+     struct be_refresh_ctx *refresh_ctx;
+ 
+     size_t check_online_ref_count;
++    int check_online_retry_delay;
+ 
+     struct data_provider *provider;
+ 
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index fad6f2801..17513111c 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -50,6 +50,9 @@
+ #include "resolv/async_resolv.h"
+ #include "monitor/monitor_interfaces.h"
+ 
++#define ONLINE_CB_RETRY 3
++#define ONLINE_CB_RETRY_MAX_DELAY 4
++
+ static int data_provider_res_init(struct sbus_request *dbus_req, void *data);
+ static int data_provider_go_offline(struct sbus_request *dbus_req, void *data);
+ static int data_provider_reset_offline(struct sbus_request *dbus_req, void *data);
+@@ -71,7 +74,7 @@ bool be_is_offline(struct be_ctx *ctx)
+     return ctx->offstat.offline;
+ }
+ 
+-static void check_if_online(struct be_ctx *be_ctx);
++static void check_if_online(struct be_ctx *be_ctx, int delay);
+ 
+ static errno_t
+ try_to_go_online(TALLOC_CTX *mem_ctx,
+@@ -82,7 +85,7 @@ try_to_go_online(TALLOC_CTX *mem_ctx,
+ {
+     struct be_ctx *ctx = (struct be_ctx*) be_ctx_void;
+ 
+-    check_if_online(ctx);
++    check_if_online(ctx, 0);
+     return EOK;
+ }
+ 
+@@ -247,10 +250,39 @@ static errno_t be_check_online_request(struct be_ctx *be_ctx)
+     return EOK;
+ }
+ 
++static void check_if_online_delayed(struct tevent_context *ev,
++                                    struct tevent_timer *tim,
++                                    struct timeval current_time,
++                                    void *private_data)
++{
++    errno_t ret;
++    struct be_ctx *be_ctx = talloc_get_type(private_data, struct be_ctx);
++
++    be_run_unconditional_online_cb(be_ctx);
++
++    if (!be_is_offline(be_ctx)) {
++        DEBUG(SSSDBG_TRACE_INTERNAL,
++              "Backend is already online, nothing to do.\n");
++        be_ctx->check_online_ref_count = 0;
++        return;
++    }
++
++    DEBUG(SSSDBG_TRACE_INTERNAL, "Trying to go back online!\n");
++
++    ret = be_check_online_request(be_ctx);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create check online req.\n");
++    } else {
++        DEBUG(SSSDBG_TRACE_INTERNAL, "Check online req created.\n");
++    }
++}
++
+ static void be_check_online_done(struct tevent_req *req)
+ {
+     struct be_ctx *be_ctx;
+     struct dp_reply_std *reply;
++    struct tevent_timer *time_event;
++    struct timeval schedule;
+     errno_t ret;
+ 
+     be_ctx = tevent_req_callback_data(req, struct be_ctx);
+@@ -285,11 +317,24 @@ static void be_check_online_done(struct tevent_req *req)
+     be_ctx->check_online_ref_count--;
+ 
+     if (reply->dp_error != DP_ERR_OK && be_ctx->check_online_ref_count > 0) {
+-        ret = be_check_online_request(be_ctx);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create check online req.\n");
++        be_ctx->check_online_retry_delay *= 2;
++        if (be_ctx->check_online_retry_delay > ONLINE_CB_RETRY_MAX_DELAY) {
++            be_ctx->check_online_retry_delay = ONLINE_CB_RETRY_MAX_DELAY;
++        }
++
++        schedule = tevent_timeval_current_ofs(be_ctx->check_online_retry_delay,
++                                              0);
++        time_event = tevent_add_timer(be_ctx->ev, be_ctx, schedule,
++                                      check_if_online_delayed, be_ctx);
++
++        if (time_event == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE, "Failed to schedule online check\n");
+             goto done;
+         }
++
++        DEBUG(SSSDBG_TRACE_INTERNAL,
++              "Schedule check_if_online_delayed in %ds.\n",
++              be_ctx->check_online_retry_delay);
+         return;
+     }
+ 
+@@ -303,28 +348,23 @@ done:
+     }
+ }
+ 
+-static void check_if_online(struct be_ctx *be_ctx)
++static void check_if_online(struct be_ctx *be_ctx, int delay)
+ {
+-    errno_t ret;
+-
+-    be_run_unconditional_online_cb(be_ctx);
+-
+-    if (!be_is_offline(be_ctx)) {
+-        DEBUG(SSSDBG_TRACE_INTERNAL,
+-              "Backend is already online, nothing to do.\n");
+-        return;
+-    }
++    struct tevent_timer *time_event;
++    struct timeval schedule;
+ 
+     /* Make sure nobody tries to go online while we are checking */
+     be_ctx->offstat.went_offline = time(NULL);
+ 
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "Trying to go back online!\n");
+-
+     be_ctx->check_online_ref_count++;
+ 
+     if (be_ctx->check_online_ref_count != 1) {
+         DEBUG(SSSDBG_TRACE_INTERNAL,
+               "There is an online check already running.\n");
++        /* Do not have more than ONLINE_CB_RETRY retries in the queue */
++        if (be_ctx->check_online_ref_count > ONLINE_CB_RETRY) {
++            be_ctx->check_online_ref_count--;
++        }
+         return;
+     }
+ 
+@@ -334,12 +374,20 @@ static void check_if_online(struct be_ctx *be_ctx)
+         goto failed;
+     }
+ 
+-    ret = be_check_online_request(be_ctx);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create check online req.\n");
++    schedule = tevent_timeval_current_ofs(delay, 0);
++    time_event = tevent_add_timer(be_ctx->ev, be_ctx, schedule,
++                                  check_if_online_delayed, be_ctx);
++
++    if (time_event == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Scheduling check_if_online_delayed failed.\n");
+         goto failed;
+     }
+ 
++    be_ctx->check_online_ref_count = ONLINE_CB_RETRY;
++    be_ctx->check_online_retry_delay = 1;
++    DEBUG(SSSDBG_TRACE_INTERNAL,
++          "Schedule check_if_online_delayed in %ds.\n", delay);
+     return;
+ 
+ failed:
+@@ -373,7 +421,7 @@ static void signal_be_reset_offline(struct tevent_context *ev,
+                                     void *private_data)
+ {
+     struct be_ctx *ctx = talloc_get_type(private_data, struct be_ctx);
+-    check_if_online(ctx);
++    check_if_online(ctx, 0);
+ }
+ 
+ errno_t be_process_init(TALLOC_CTX *mem_ctx,
+@@ -649,7 +697,7 @@ static int data_provider_res_init(struct sbus_request *dbus_req, void *data)
+     be_ctx = talloc_get_type(data, struct be_ctx);
+ 
+     resolv_reread_configuration(be_ctx->be_res->resolv);
+-    check_if_online(be_ctx);
++    check_if_online(be_ctx, 1);
+ 
+     return monitor_common_res_init(dbus_req, data);
+ }
+@@ -666,7 +714,7 @@ static int data_provider_reset_offline(struct sbus_request *dbus_req, void *data
+ {
+     struct be_ctx *be_ctx;
+     be_ctx = talloc_get_type(data, struct be_ctx);
+-    check_if_online(be_ctx);
++    check_if_online(be_ctx, 1);
+     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
+ }
+ 
+-- 
+2.19.1
+
diff --git a/SOURCES/0002-KCM-Fall-back-to-using-the-first-ccache-if-the-defau.patch b/SOURCES/0002-KCM-Fall-back-to-using-the-first-ccache-if-the-defau.patch
new file mode 100644
index 0000000..0b2ee89
--- /dev/null
+++ b/SOURCES/0002-KCM-Fall-back-to-using-the-first-ccache-if-the-defau.patch
@@ -0,0 +1,49 @@
+From 6c568c9126e950d56cee734934e455eb2f5a3659 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 28 Sep 2018 17:29:10 +0200
+Subject: [PATCH] KCM: Fall back to using the first ccache if the default does
+ not exist
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3838
+
+KCM stores the default ccache in a separate DB entry. If the DB entry
+contains a UUID that cannot be found in the DB for whatever reason, we
+should just use the first ccache as the default. (This is what we
+already do if there is no default)
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 6bf5bcad6b9c5fb5fd867cbb094fef2a02ebf22d)
+---
+ src/responder/kcm/kcmsrv_ops.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
+index 1e229adc4..5c4ece79e 100644
+--- a/src/responder/kcm/kcmsrv_ops.c
++++ b/src/responder/kcm/kcmsrv_ops.c
+@@ -1509,7 +1509,17 @@ static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq)
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Cannot get ccahe by UUID [%d]: %s\n",
+               ret, sss_strerror(ret));
+-        tevent_req_error(req, ret);
++        /* Instead of failing the whole operation, return the first
++         * ccache as a fallback
++         */
++        subreq = kcm_ccdb_list_send(state, state->ev,
++                                    state->op_ctx->kcm_data->db,
++                                    state->op_ctx->client);
++        if (subreq == NULL) {
++            tevent_req_error(req, ENOMEM);
++            return;
++        }
++        tevent_req_set_callback(subreq, kcm_op_get_default_ccache_list_done, req);
+         return;
+     }
+ 
+-- 
+2.19.1
+
diff --git a/SOURCES/0003-GPO-Add-option-ad_gpo_ignore_unreadable.patch b/SOURCES/0003-GPO-Add-option-ad_gpo_ignore_unreadable.patch
new file mode 100644
index 0000000..088ce18
--- /dev/null
+++ b/SOURCES/0003-GPO-Add-option-ad_gpo_ignore_unreadable.patch
@@ -0,0 +1,219 @@
+From ad058011b6b75b15c674be46a3ae9b3cc5228175 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Wed, 17 Oct 2018 16:57:20 +0200
+Subject: [PATCH] GPO: Add option ad_gpo_ignore_unreadable
+
+Add option to ignore group policy containers in AD
+with unreadable or missing attributes. This is
+for the case when server contains GPOs that
+have very strict permissions on their attributes
+in AD but are unrelated to access control.
+
+Rather then using this option it is better to
+change the permissions on the AD objects but
+that may not be always possible (company policy,
+not access to server etc.).
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3867
+CVE-2018-16838
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 2f27dd9f05c2d3ed1c190ba387bc97738988efb0)
+---
+ src/config/cfg_rules.ini     |  1 +
+ src/man/sssd-ad.5.xml        | 19 ++++++++++
+ src/providers/ad/ad_common.h |  1 +
+ src/providers/ad/ad_gpo.c    | 67 +++++++++++++++++++++++++++++++++---
+ src/providers/ad/ad_opts.c   |  1 +
+ 5 files changed, 85 insertions(+), 4 deletions(-)
+
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 887428437..603211711 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -439,6 +439,7 @@ option = ad_enabled_domains
+ option = ad_enable_gc
+ option = ad_gpo_access_control
+ option = ad_gpo_implicit_deny
++option = ad_gpo_ignore_unreadable
+ option = ad_gpo_cache_timeout
+ option = ad_gpo_default_right
+ option = ad_gpo_map_batch
+diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
+index f9b7f7667..b14f07f7f 100644
+--- a/src/man/sssd-ad.5.xml
++++ b/src/man/sssd-ad.5.xml
+@@ -437,6 +437,25 @@ DOM:dom1:(memberOf:1.2.840.113556.1.4.1941:=cn=nestedgroup,ou=groups,dc=example,
+                     </listitem>
+                 </varlistentry>
+ 
++                <varlistentry>
++                    <term>ad_gpo_ignore_unreadable (boolean)</term>
++                    <listitem>
++                        <para>
++                            Normally when some group policy containers (AD
++                            object) of applicable group policy objects are
++                            not readable by SSSD then users are denied access.
++                            This option allows to ignore group policy
++                            containers and with them associated policies
++                            if their attributes in group policy containers
++                            are not readable for SSSD.
++                        </para>
++                        <para>
++                            Default: False
++                        </para>
++                    </listitem>
++                </varlistentry>
++
++
+ 
+                 <varlistentry>
+                     <term>ad_gpo_cache_timeout (integer)</term>
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index 2c52c997a..529753a8a 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -53,6 +53,7 @@ enum ad_basic_opt {
+     AD_ENABLE_GC,
+     AD_GPO_ACCESS_CONTROL,
+     AD_GPO_IMPLICIT_DENY,
++    AD_GPO_IGNORE_UNREADABLE,
+     AD_GPO_CACHE_TIMEOUT,
+     AD_GPO_MAP_INTERACTIVE,
+     AD_GPO_MAP_REMOTE_INTERACTIVE,
+diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
+index 3b472e0e9..5f85910a9 100644
+--- a/src/providers/ad/ad_gpo.c
++++ b/src/providers/ad/ad_gpo.c
+@@ -3603,6 +3603,7 @@ struct ad_gpo_process_gpo_state {
+     struct ad_access_ctx *access_ctx;
+     struct tevent_context *ev;
+     struct sdap_id_op *sdap_op;
++    struct dp_option *ad_options;
+     struct sdap_options *opts;
+     char *server_hostname;
+     struct sss_domain_info *host_domain;
+@@ -3647,6 +3648,7 @@ ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
+ 
+     state->ev = ev;
+     state->sdap_op = sdap_op;
++    state->ad_options = access_ctx->ad_options;
+     state->opts = opts;
+     state->server_hostname = server_hostname;
+     state->host_domain = host_domain;
+@@ -3871,6 +3873,54 @@ static bool machine_ext_names_is_blank(char *attr_value)
+     return true;
+ }
+ 
++static errno_t
++ad_gpo_missing_or_unreadable_attr(struct ad_gpo_process_gpo_state *state,
++                                  struct tevent_req *req)
++{
++    bool ignore_unreadable = dp_opt_get_bool(state->ad_options,
++                                             AD_GPO_IGNORE_UNREADABLE);
++
++    if (ignore_unreadable) {
++        /* If admins decided to skip GPOs with unreadable
++         * attributes just log the SID of skipped GPO */
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "Group Policy Container with DN [%s] has unreadable or missing "
++              "attributes -> skipping this GPO "
++              "(ad_gpo_ignore_unreadable = True)\n",
++              state->candidate_gpos[state->gpo_index]->gpo_dn);
++        state->gpo_index++;
++        return ad_gpo_get_gpo_attrs_step(req);
++    } else {
++        /* Inform in logs and syslog that this GPO can
++         * not be processed due to unreadable or missing
++         * attributes and point to possible server side
++         * and client side solutions. */
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Group Policy Container with DN [%s] is unreadable or has "
++              "unreadable or missing attributes. In order to fix this "
++              "make sure that this AD object has following attributes "
++              "readable: nTSecurityDescriptor, cn, gPCFileSysPath, "
++              "gPCMachineExtensionNames, gPCFunctionalityVersion, flags. "
++              "Alternatively if you do not have access to the server or can "
++              "not change permissions on this object, you can use option "
++              "ad_gpo_ignore_unreadable = True which will skip this GPO."
++              "See 'man ad_gpo_ignore_unreadable for details.'\n",
++              state->candidate_gpos[state->gpo_index]->gpo_dn);
++        sss_log(SSSDBG_CRIT_FAILURE,
++                "Group Policy Container with DN [%s] is unreadable or has "
++                "unreadable or missing attributes. In order to fix this "
++                "make sure that this AD object has following attributes "
++                "readable: nTSecurityDescriptor, cn, gPCFileSysPath, "
++                "gPCMachineExtensionNames, gPCFunctionalityVersion, flags. "
++                "Alternatively if you do not have access to the server or can "
++                "not change permissions on this object, you can use option "
++                "ad_gpo_ignore_unreadable = True which will skip this GPO."
++                "See 'man ad_gpo_ignore_unreadable for details.'\n",
++                state->candidate_gpos[state->gpo_index]->gpo_dn);
++        return EFAULT;
++    }
++}
++
+ static errno_t
+ ad_gpo_sd_process_attrs(struct tevent_req *req,
+                         char *smb_host,
+@@ -3890,7 +3940,10 @@ ad_gpo_sd_process_attrs(struct tevent_req *req,
+ 
+     /* retrieve AD_AT_CN */
+     ret = sysdb_attrs_get_string(result, AD_AT_CN, &gpo_guid);
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        ret = ad_gpo_missing_or_unreadable_attr(state, req);
++        goto done;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "sysdb_attrs_get_string failed: [%d](%s)\n",
+               ret, sss_strerror(ret));
+@@ -3911,7 +3964,10 @@ ad_gpo_sd_process_attrs(struct tevent_req *req,
+                                  AD_AT_FILE_SYS_PATH,
+                                  &raw_file_sys_path);
+ 
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        ret = ad_gpo_missing_or_unreadable_attr(state, req);
++        goto done;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "sysdb_attrs_get_string failed: [%d](%s)\n",
+               ret, sss_strerror(ret));
+@@ -3959,7 +4015,10 @@ ad_gpo_sd_process_attrs(struct tevent_req *req,
+     /* retrieve AD_AT_FLAGS */
+     ret = sysdb_attrs_get_int32_t(result, AD_AT_FLAGS,
+                                   &gp_gpo->gpo_flags);
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        ret = ad_gpo_missing_or_unreadable_attr(state, req);
++        goto done;
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "sysdb_attrs_get_int32_t failed: [%d](%s)\n",
+               ret, sss_strerror(ret));
+@@ -3977,7 +4036,7 @@ ad_gpo_sd_process_attrs(struct tevent_req *req,
+     if ((ret == ENOENT) || (el->num_values == 0)) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "nt_sec_desc attribute not found or has no value\n");
+-        ret = ENOENT;
++        ret = ad_gpo_missing_or_unreadable_attr(state, req);
+         goto done;
+     }
+ 
+diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
+index b274ba9b3..c408295f3 100644
+--- a/src/providers/ad/ad_opts.c
++++ b/src/providers/ad/ad_opts.c
+@@ -39,6 +39,7 @@ struct dp_option ad_basic_opts[] = {
+     { "ad_enable_gc", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "ad_gpo_access_control", DP_OPT_STRING, { AD_GPO_ACCESS_MODE_DEFAULT }, NULL_STRING },
+     { "ad_gpo_implicit_deny", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
++    { "ad_gpo_ignore_unreadable", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "ad_gpo_cache_timeout", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER },
+     { "ad_gpo_map_interactive", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ad_gpo_map_remote_interactive", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+-- 
+2.19.1
+
diff --git a/SOURCES/0004-AD-Allow-configuring-auto_private_groups-per-subdoma.patch b/SOURCES/0004-AD-Allow-configuring-auto_private_groups-per-subdoma.patch
new file mode 100644
index 0000000..86c2403
--- /dev/null
+++ b/SOURCES/0004-AD-Allow-configuring-auto_private_groups-per-subdoma.patch
@@ -0,0 +1,297 @@
+From 6f6b3b1f4fcec79a1640a97fb3cd875f2cd8b83a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 19 Mar 2019 11:01:10 +0100
+Subject: [PATCH] AD: Allow configuring auto_private_groups per subdomain or
+ with subdomain_inherit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3965
+
+Previously, subdomains that used ID mapping always only used MPGs and
+POSIX subdomains always inherited the parent domain settings. This patch
+is a small RFE which allows to either set the auto_private_groups option
+directly per subdomain or set it for all subdomains using the
+subdomain_inherit option
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 41c497b8b9e6efb9f2aa8e4cc869d465c3b954b3)
+---
+ src/man/sssd.conf.5.xml               |  38 +++++----
+ src/providers/ad/ad_subdomains.c      | 107 ++++++++++++++++++++++----
+ src/providers/ldap/sdap_async_users.c |   2 +-
+ src/util/domain_info_utils.c          |  14 +++-
+ src/util/util.h                       |   3 +
+ 5 files changed, 130 insertions(+), 34 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 41ba7b924..3d017f638 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2995,6 +2995,13 @@ subdomain_inherit = ldap_purge_cache_timeout
+                                             Create user's private group unconditionally from user's UID number.
+                                             The GID number is ignored in this case.
+                                         </para>
++                                        <para>
++                                            NOTE: Because the GID number and the user private group
++                                            are inferred from the UID number, it is not supported
++                                            to have multiple entries with the same UID or GID number
++                                            with this option. In other words, enabling this option
++                                            enforces uniqueness across the ID space.
++                                        </para>
+                                     </listitem>
+                                 </varlistentry>
+                                 <varlistentry>
+@@ -3041,24 +3048,25 @@ subdomain_inherit = ldap_purge_cache_timeout
+                                 </varlistentry>
+                             </variablelist>
+                         </para>
+-			<para>
+-			    For POSIX subdomains, setting the option in the main
+-			    domain is inherited in the subdomain.
+-			</para>
+-			<para>
+-			    For ID-mapping subdomains, auto_private_groups is
+-			    already enabled for the subdomains and setting it to
+-			    false will not have any effect for the subdomain.
+-			</para>
+                         <para>
+-                            NOTE: Because the GID number and the user private group
+-                            are inferred from the UID number, it is not supported
+-                            to have multiple entries with the same UID or GID number
+-                            with this option. In other words, enabling this option
+-                            enforces uniqueness across the ID space.
++                            For subdomains, the default value is False for
++                            subdomains that use assigned POSIX IDs and True
++                            for subdomains that use automatic ID-mapping.
+                         </para>
+                         <para>
+-                            Default: False
++                            The value of auto_private_groups can either be set per subdomains
++                            in a subsection, for example:
++<programlisting>
++[domain/forest.domain/sub.domain]
++auto_private_groups = false
++</programlisting>
++                            or globally for all subdomains in the main domain section
++                            using the subdomain_inherit option:
++<programlisting>
++[domain/forest.domain]
++subdomain_inherit = auto_private_groups
++auto_private_groups = false
++</programlisting>
+                         </para>
+                     </listitem>
+                 </varlistentry>
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 5b046773c..4fc4be094 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -436,8 +436,87 @@ static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
+     return EOK;
+ }
+ 
++static enum sss_domain_mpg_mode
++get_default_subdom_mpg_mode(struct sdap_idmap_ctx *idmap_ctx,
++                            struct sss_domain_info *parent,
++                            const char *subdom_name,
++                            char *subdom_sid_str)
++{
++    bool use_id_mapping;
++    bool inherit_option;
++    enum sss_domain_mpg_mode default_mpg_mode;
++
++    inherit_option = string_in_list(CONFDB_DOMAIN_AUTO_UPG,
++                                    parent->sd_inherit, false);
++    if (inherit_option) {
++        return get_domain_mpg_mode(parent);
++    }
++
++    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx,
++                                                               subdom_name,
++                                                               subdom_sid_str);
++    if (use_id_mapping == true) {
++        default_mpg_mode = MPG_ENABLED;
++    } else {
++        /* Domains that use the POSIX attributes set by the admin must
++         * inherit the MPG setting from the parent domain so that the
++         * auto_private_groups options works for trusted domains as well
++         */
++        default_mpg_mode = get_domain_mpg_mode(parent);
++    }
++
++    return default_mpg_mode;
++}
++
++static enum sss_domain_mpg_mode
++ad_subdom_mpg_mode(TALLOC_CTX *mem_ctx,
++                   struct confdb_ctx *cdb,
++                   struct sss_domain_info *parent,
++                   enum sss_domain_mpg_mode default_mpg_mode,
++                   const char *subdom_name)
++{
++    char *subdom_conf_path;
++    char *mpg_str_opt;
++    errno_t ret;
++    enum sss_domain_mpg_mode ret_mode;
++
++    subdom_conf_path = subdomain_create_conf_path_from_str(mem_ctx,
++                                                           parent->name,
++                                                           subdom_name);
++    if (subdom_conf_path == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "subdom_conf_path failed, will use %s mode as fallback\n",
++              str_domain_mpg_mode(default_mpg_mode));
++        return default_mpg_mode;
++    }
++
++    ret = confdb_get_string(cdb, mem_ctx, subdom_conf_path,
++                            CONFDB_DOMAIN_AUTO_UPG,
++                            NULL,
++                            &mpg_str_opt);
++    talloc_free(subdom_conf_path);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "condb_get_string failed, will use %s mode as fallback\n",
++              str_domain_mpg_mode(default_mpg_mode));
++        return default_mpg_mode;
++    }
++
++    if (mpg_str_opt == NULL) {
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "Subdomain MPG mode not set, using %s\n",
++              str_domain_mpg_mode(default_mpg_mode));
++        return default_mpg_mode;
++    }
++
++    ret_mode = str_to_domain_mpg_mode(mpg_str_opt);
++    talloc_free(mpg_str_opt);
++    return ret_mode;
++}
++
+ static errno_t
+-ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
++ad_subdom_store(struct confdb_ctx *cdb,
++                struct sdap_idmap_ctx *idmap_ctx,
+                 struct sss_domain_info *domain,
+                 struct sysdb_attrs *subdom_attrs,
+                 bool enumerate)
+@@ -451,8 +530,8 @@ ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
+     struct ldb_message_element *el;
+     char *sid_str = NULL;
+     uint32_t trust_type;
+-    bool use_id_mapping;
+     enum sss_domain_mpg_mode mpg_mode;
++    enum sss_domain_mpg_mode default_mpg_mode;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -501,17 +580,13 @@ ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
+         goto done;
+     }
+ 
+-    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx,
+-                                                               name, sid_str);
+-    if (use_id_mapping == true) {
+-        mpg_mode = MPG_ENABLED;
+-    } else {
+-        /* Domains that use the POSIX attributes set by the admin must
+-         * inherit the MPG setting from the parent domain so that the
+-         * auto_private_groups options works for trusted domains as well
+-         */
+-        mpg_mode = get_domain_mpg_mode(domain);
+-    }
++    default_mpg_mode = get_default_subdom_mpg_mode(idmap_ctx, domain,
++                                                   name, sid_str);
++
++    mpg_mode = ad_subdom_mpg_mode(tmp_ctx, cdb, domain,
++                                  default_mpg_mode, name);
++    DEBUG(SSSDBG_CONF_SETTINGS, "MPG mode of %s is %s\n",
++                                name, str_domain_mpg_mode(mpg_mode));
+ 
+     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
+                                 mpg_mode, enumerate, domain->forest, 0, NULL);
+@@ -625,7 +700,8 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
+                 goto done;
+             }
+ 
+-            ret = ad_subdom_store(idmap_ctx, domain, subdomains[c], enumerate);
++            ret = ad_subdom_store(be_ctx->cdb, idmap_ctx, domain,
++                                  subdomains[c], enumerate);
+             if (ret) {
+                 /* Nothing we can do about the error. Let's at least try
+                  * to reuse the existing domains
+@@ -660,7 +736,8 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
+             goto done;
+         }
+ 
+-        ret = ad_subdom_store(idmap_ctx, domain, subdomains[c], enumerate);
++        ret = ad_subdom_store(be_ctx->cdb, idmap_ctx, domain,
++                              subdomains[c], enumerate);
+         if (ret) {
+             DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
+                   "will try to use cached subdomain\n");
+diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
+index 92eeda1d3..af4dc1a17 100644
+--- a/src/providers/ldap/sdap_async_users.c
++++ b/src/providers/ldap/sdap_async_users.c
+@@ -389,7 +389,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
+             goto done;
+         }
+ 
+-        if (IS_SUBDOMAIN(dom) || sss_domain_is_mpg(dom) == true) {
++        if (sss_domain_is_mpg(dom) == true) {
+             /* For subdomain users, only create the private group as
+              * the subdomain is an MPG domain.
+              * But we have to save the GID of the original primary group
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 4896ef051..4b1c9df39 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -889,6 +889,14 @@ bool sss_domain_is_forest_root(struct sss_domain_info *dom)
+     return (dom->forest_root == dom);
+ }
+ 
++char *subdomain_create_conf_path_from_str(TALLOC_CTX *mem_ctx,
++                                          const char *parent_name,
++                                          const char *subdom_name)
++{
++    return talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL "/%s",
++                           parent_name, subdom_name);
++}
++
+ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *subdomain)
+ {
+@@ -899,9 +907,9 @@ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
+         return NULL;
+     }
+ 
+-    return talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL "/%s",
+-                           subdomain->parent->name,
+-                           subdomain->name);
++    return subdomain_create_conf_path_from_str(mem_ctx,
++                                               subdomain->parent->name,
++                                               subdomain->name);
+ }
+ 
+ const char *sss_domain_type_str(struct sss_domain_info *dom)
+diff --git a/src/util/util.h b/src/util/util.h
+index 1e36bf02a..3003583b7 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -557,6 +557,9 @@ find_domain_by_object_name_ex(struct sss_domain_info *domain,
+ bool subdomain_enumerates(struct sss_domain_info *parent,
+                           const char *sd_name);
+ 
++char *subdomain_create_conf_path_from_str(TALLOC_CTX *mem_ctx,
++                                          const char *parent_name,
++                                          const char *subdom_name);
+ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *subdomain);
+ 
+-- 
+2.19.1
+
diff --git a/SOURCES/0005-ipa-store-sudo-runas-attribute-with-internal-fqname.patch b/SOURCES/0005-ipa-store-sudo-runas-attribute-with-internal-fqname.patch
new file mode 100644
index 0000000..cd5415f
--- /dev/null
+++ b/SOURCES/0005-ipa-store-sudo-runas-attribute-with-internal-fqname.patch
@@ -0,0 +1,62 @@
+From 5ad7f5e817b2bd8ca0f49b1001f4fb987de32c08 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 27 Feb 2019 14:04:54 +0100
+Subject: [PATCH 5/6] ipa: store sudo runas attribute with internal fqname
+
+We need to be able to differentiate between external users and IPA user.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3957
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit d411febc98da36eb961b9251c1674af802151786)
+---
+ src/providers/ipa/ipa_sudo_conversion.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c
+index bfa66b2c6..9586e6a2a 100644
+--- a/src/providers/ipa/ipa_sudo_conversion.c
++++ b/src/providers/ipa/ipa_sudo_conversion.c
+@@ -908,6 +908,27 @@ convert_group(TALLOC_CTX *mem_ctx,
+     return rdn;
+ }
+ 
++static const char *
++convert_group_fqdn(TALLOC_CTX *mem_ctx,
++                   struct ipa_sudo_conv *conv,
++                   const char *value,
++                   bool *skip_entry)
++{
++    const char *shortname = NULL;
++    char *fqdn = NULL;
++
++    *skip_entry = false;
++
++    shortname = convert_group(mem_ctx, conv, value, skip_entry);
++    if (shortname == NULL) {
++        return NULL;
++    }
++
++    fqdn = sss_create_internal_fqname(mem_ctx, shortname, conv->dom->name);
++    talloc_free(discard_const(shortname));
++    return fqdn;
++}
++
+ static const char *
+ convert_runasextusergroup(TALLOC_CTX *mem_ctx,
+                           struct ipa_sudo_conv *conv,
+@@ -954,8 +975,8 @@ convert_attributes(struct ipa_sudo_conv *conv,
+     } table[] = {{SYSDB_NAME,                            SYSDB_SUDO_CACHE_AT_CN         , NULL},
+                  {SYSDB_IPA_SUDORULE_HOST,               SYSDB_SUDO_CACHE_AT_HOST       , convert_host},
+                  {SYSDB_IPA_SUDORULE_USER,               SYSDB_SUDO_CACHE_AT_USER       , convert_user_fqdn},
+-                 {SYSDB_IPA_SUDORULE_RUNASUSER,          SYSDB_SUDO_CACHE_AT_RUNASUSER  , convert_user},
+-                 {SYSDB_IPA_SUDORULE_RUNASGROUP,         SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_group},
++                 {SYSDB_IPA_SUDORULE_RUNASUSER,          SYSDB_SUDO_CACHE_AT_RUNASUSER  , convert_user_fqdn},
++                 {SYSDB_IPA_SUDORULE_RUNASGROUP,         SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_group_fqdn},
+                  {SYSDB_IPA_SUDORULE_OPTION,             SYSDB_SUDO_CACHE_AT_OPTION     , NULL},
+                  {SYSDB_IPA_SUDORULE_NOTAFTER,           SYSDB_SUDO_CACHE_AT_NOTAFTER   , NULL},
+                  {SYSDB_IPA_SUDORULE_NOTBEFORE,          SYSDB_SUDO_CACHE_AT_NOTBEFORE  , NULL},
+-- 
+2.19.1
+
diff --git a/SOURCES/0006-sudo-format-runas-attributes-to-correct-output-name.patch b/SOURCES/0006-sudo-format-runas-attributes-to-correct-output-name.patch
new file mode 100644
index 0000000..237febc
--- /dev/null
+++ b/SOURCES/0006-sudo-format-runas-attributes-to-correct-output-name.patch
@@ -0,0 +1,176 @@
+From 3a18e33f983cd17860b6ff41f9d538ee8fcc6d98 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 27 Feb 2019 14:06:06 +0100
+Subject: [PATCH 6/6] sudo: format runas attributes to correct output name
+
+sudo internally calls getpwnam and getgrnam on user and groups
+that should be used for the invoked command. Output of these calls
+is compared to values in runAsUser/Group attributes.
+
+When different output format is used then what is present in LDAP,
+this comparison will fail, denying user to use sudo. Now, we convert
+these attributes into correct output name, respecting domain resolution
+order, fully qualified domains and fqname format.
+
+E.g. sudo call:
+sudo -u tuser@ipa.vm -g tgroup@ipa.vm id
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3957
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 0aa657165f189035c160beda4840e3271fc56c88)
+---
+ src/responder/sudo/sudosrv_get_sudorules.c | 101 ++++++++++++++++++++-
+ 1 file changed, 99 insertions(+), 2 deletions(-)
+
+diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
+index a420c76fb..d928a5ead 100644
+--- a/src/responder/sudo/sudosrv_get_sudorules.c
++++ b/src/responder/sudo/sudosrv_get_sudorules.c
+@@ -113,6 +113,95 @@ sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool lower_wins)
+     return EOK;
+ }
+ 
++static errno_t sudosrv_format_runas(struct resp_ctx *rctx,
++                                    struct sysdb_attrs *rule,
++                                    const char *attr)
++{
++    TALLOC_CTX *tmp_ctx;
++    struct ldb_message_element *el;
++    struct sss_domain_info *dom;
++    const char *value;
++    char *fqname;
++    unsigned int i;
++    errno_t ret;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
++        return ENOMEM;
++    }
++
++    ret = sysdb_attrs_get_el_ext(rule, attr, false, &el);
++    if (ret == ENOENT) {
++        ret = EOK;
++        goto done;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get %s attribute "
++              "[%d]: %s\n", attr, ret, sss_strerror(ret));
++        goto done;
++    }
++
++    for (i = 0; i < el->num_values; i++) {
++        value = (const char *)el->values[i].data;
++        if (value == NULL) {
++            continue;
++        }
++
++        dom = find_domain_by_object_name_ex(rctx->domains, value, true);
++        if (dom == NULL) {
++            continue;
++        }
++
++        ret = sss_output_fqname(tmp_ctx, dom, value,
++                                rctx->override_space, &fqname);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert %s to output fqname "
++                  "[%d]: %s\n", value, ret, sss_strerror(ret));
++            goto done;
++        }
++
++        talloc_free(el->values[i].data);
++        el->values[i].data = (uint8_t*)talloc_steal(el->values, fqname);
++        el->values[i].length = strlen(fqname);
++    }
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
++static errno_t sudosrv_format_rules(struct resp_ctx *rctx,
++                                    struct sysdb_attrs **rules,
++                                    uint32_t num_rules)
++{
++    uint32_t i;
++    errno_t ret;
++
++
++    for (i = 0; i < num_rules; i++) {
++        ret = sudosrv_format_runas(rctx, rules[i],
++                                   SYSDB_SUDO_CACHE_AT_RUNAS);
++        if (ret != EOK) {
++            return ret;
++        }
++
++        ret = sudosrv_format_runas(rctx, rules[i],
++                                   SYSDB_SUDO_CACHE_AT_RUNASUSER);
++        if (ret != EOK) {
++            return ret;
++        }
++
++        ret = sudosrv_format_runas(rctx, rules[i],
++                                   SYSDB_SUDO_CACHE_AT_RUNASGROUP);
++        if (ret != EOK) {
++            return ret;
++        }
++    }
++
++    return ret;
++}
++
+ static errno_t sudosrv_query_cache(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *domain,
+                                    const char **attrs,
+@@ -301,6 +390,7 @@ static errno_t sudosrv_cached_rules_by_ng(TALLOC_CTX *mem_ctx,
+ }
+ 
+ static errno_t sudosrv_cached_rules(TALLOC_CTX *mem_ctx,
++                                    struct resp_ctx *rctx,
+                                     struct sss_domain_info *domain,
+                                     uid_t cli_uid,
+                                     uid_t orig_uid,
+@@ -368,6 +458,12 @@ static errno_t sudosrv_cached_rules(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
++    ret = sudosrv_format_rules(rctx, rules, num_rules);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Could not format sudo rules\n");
++        goto done;
++    }
++
+     *_rules = talloc_steal(mem_ctx, rules);
+     *_num_rules = num_rules;
+ 
+@@ -412,6 +508,7 @@ static errno_t sudosrv_cached_defaults(TALLOC_CTX *mem_ctx,
+ }
+ 
+ static errno_t sudosrv_fetch_rules(TALLOC_CTX *mem_ctx,
++                                   struct resp_ctx *rctx,
+                                    enum sss_sudo_type type,
+                                    struct sss_domain_info *domain,
+                                    uid_t cli_uid,
+@@ -433,7 +530,7 @@ static errno_t sudosrv_fetch_rules(TALLOC_CTX *mem_ctx,
+               username, domain->name);
+         debug_name = "rules";
+ 
+-        ret = sudosrv_cached_rules(mem_ctx, domain,
++        ret = sudosrv_cached_rules(mem_ctx, rctx, domain,
+                                    cli_uid, orig_uid, username, groups,
+                                    inverse_order, &rules, &num_rules);
+ 
+@@ -760,7 +857,7 @@ static void sudosrv_get_rules_done(struct tevent_req *subreq)
+               "in cache.\n");
+     }
+ 
+-    ret = sudosrv_fetch_rules(state, state->type, state->domain,
++    ret = sudosrv_fetch_rules(state, state->rctx, state->type, state->domain,
+                               state->cli_uid,
+                               state->orig_uid,
+                               state->orig_username,
+-- 
+2.19.1
+
diff --git a/SOURCES/0007-SYSDB-Inherit-cached_auth_timeout-from-the-main-doma.patch b/SOURCES/0007-SYSDB-Inherit-cached_auth_timeout-from-the-main-doma.patch
new file mode 100644
index 0000000..b6b74bb
--- /dev/null
+++ b/SOURCES/0007-SYSDB-Inherit-cached_auth_timeout-from-the-main-doma.patch
@@ -0,0 +1,59 @@
+From fedfc4fa5978dc0ef2c3b6efcd1e9462a8575b3a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 7 Mar 2019 22:13:32 +0100
+Subject: [PATCH] SYSDB: Inherit cached_auth_timeout from the main domain
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+cached_auth_timeout is a domain option used by the responder. And
+because at the moment the options read from a subdomain section (e.g.
+[domain/main/trusted] are only those represented by the back end specific
+dp_option structure instance, the option cached_auth_timeout, which
+is directly read from the confdb was not set for the main domain.
+
+This is a minimal patch that just inherits the option from the main
+domain until SSSD has a more systematic way of inheriting config
+attributes regardless of how they are read and set.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3960
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 4dd268333ca9ca13555f5dfbd2928154b885a3e7)
+---
+ src/db/sysdb_subdomains.c | 1 +
+ src/man/sssd.conf.5.xml   | 5 +++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index e380e6c8b..34d052fdd 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -154,6 +154,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
+     dom->cache_credentials = parent->cache_credentials;
+     dom->cache_credentials_min_ff_length =
+                                         parent->cache_credentials_min_ff_length;
++    dom->cached_auth_timeout = parent->cached_auth_timeout;
+     dom->case_sensitive = false;
+     dom->user_timeout = parent->user_timeout;
+     dom->group_timeout = parent->group_timeout;
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index ef5a4b952..41ba7b924 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2962,6 +2962,11 @@ subdomain_inherit = ldap_purge_cache_timeout
+                             authenticated using cached credentials while
+                             SSSD is in the online mode.
+                         </para>
++                        <para>
++                            This option's value is inherited by all trusted
++                            domains. At the moment it is not possible to set
++                            a different value per trusted domain.
++                        </para>
+                         <para>
+                             Special value 0 implies that this feature is
+                             disabled.
+-- 
+2.19.1
+
diff --git a/SOURCES/0008-krb5-Do-not-use-unindexed-objectCategory-in-a-search.patch b/SOURCES/0008-krb5-Do-not-use-unindexed-objectCategory-in-a-search.patch
new file mode 100644
index 0000000..d5cdf41
--- /dev/null
+++ b/SOURCES/0008-krb5-Do-not-use-unindexed-objectCategory-in-a-search.patch
@@ -0,0 +1,48 @@
+From e4dd2843a4a302ababd3ccedfbf23832244a1655 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 23 Mar 2019 21:53:05 +0100
+Subject: [PATCH] krb5: Do not use unindexed objectCategory in a search filter
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3968
+
+Since we switched to using objectcategory instead of objectclass for
+users and groups, the objectCategory attribute is also not indexed. This
+means that searches using this attribute must traverse the whole
+database which can be very slow.
+
+This patch uses the cn=users container instead of the full sysdb
+container as the search base which is more or less equivalent to using
+objectCategory=user anyway.
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+(cherry picked from commit e474c2dd305db654b42f2a123a6f60d12d7978c5)
+---
+ src/providers/krb5/krb5_renew_tgt.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c
+index 549c08c6f..c7e2bd91f 100644
+--- a/src/providers/krb5/krb5_renew_tgt.c
++++ b/src/providers/krb5/krb5_renew_tgt.c
+@@ -385,7 +385,7 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx)
+ {
+     TALLOC_CTX *tmp_ctx;
+     int ret;
+-    const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)("SYSDB_UC"))";
++    const char *ccache_filter = SYSDB_CCACHE_FILE"=*";
+     const char *ccache_attrs[] = { SYSDB_CCACHE_FILE, SYSDB_UPN, SYSDB_NAME,
+                                    SYSDB_CANONICAL_UPN, NULL };
+     size_t msgs_count = 0;
+@@ -403,7 +403,7 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx)
+         return ENOMEM;
+     }
+ 
+-    base_dn = sysdb_base_dn(renew_tgt_ctx->be_ctx->domain->sysdb, tmp_ctx);
++    base_dn = sysdb_user_base_dn(tmp_ctx, renew_tgt_ctx->be_ctx->domain);
+     if (base_dn == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_base_dn failed.\n");
+         ret = ENOMEM;
+-- 
+2.19.1
+
diff --git a/SOURCES/0009-SYSDB-Index-the-ccacheFile-attribute.patch b/SOURCES/0009-SYSDB-Index-the-ccacheFile-attribute.patch
new file mode 100644
index 0000000..1117004
--- /dev/null
+++ b/SOURCES/0009-SYSDB-Index-the-ccacheFile-attribute.patch
@@ -0,0 +1,141 @@
+From 7d8b28ad691335ebb679c6230b5e4818a7434bc5 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 23 Mar 2019 22:18:18 +0100
+Subject: [PATCH] SYSDB: Index the ccacheFile attribute
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3968
+
+The Kerberos ticket renewal code searches for user entries which have
+the ccacheFile attribute set. Since the search can potentially traverse
+all the users, it might be a good idea to index the attribute.
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+(cherry picked from commit 96013bbb7d937d1a9e4e5c678df3034520d98f32)
+---
+ src/db/sysdb_init.c    |  7 ++++++
+ src/db/sysdb_private.h |  5 +++-
+ src/db/sysdb_upgrade.c | 52 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 63 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
+index 89f8c6a5b..48e21baab 100644
+--- a/src/db/sysdb_init.c
++++ b/src/db/sysdb_init.c
+@@ -558,6 +558,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
++    if (strcmp(version, SYSDB_VERSION_0_20) == 0) {
++        ret = sysdb_upgrade_20(sysdb, &version);
++        if (ret != EOK) {
++            goto done;
++        }
++    }
++
+ 
+     ret = EOK;
+ done:
+diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
+index c297715cd..58544d826 100644
+--- a/src/db/sysdb_private.h
++++ b/src/db/sysdb_private.h
+@@ -23,6 +23,7 @@
+ #ifndef __INT_SYS_DB_H__
+ #define __INT_SYS_DB_H__
+ 
++#define SYSDB_VERSION_0_21 "0.21"
+ #define SYSDB_VERSION_0_20 "0.20"
+ #define SYSDB_VERSION_0_19 "0.19"
+ #define SYSDB_VERSION_0_18 "0.18"
+@@ -44,7 +45,7 @@
+ #define SYSDB_VERSION_0_2 "0.2"
+ #define SYSDB_VERSION_0_1 "0.1"
+ 
+-#define SYSDB_VERSION SYSDB_VERSION_0_20
++#define SYSDB_VERSION SYSDB_VERSION_0_21
+ 
+ #define SYSDB_BASE_LDIF \
+      "dn: @ATTRIBUTES\n" \
+@@ -79,6 +80,7 @@
+      "@IDXATTR: uniqueID\n" \
+      "@IDXATTR: mail\n" \
+      "@IDXATTR: userMappedCertificate\n" \
++     "@IDXATTR: ccacheFile\n" \
+      "\n" \
+      "dn: @MODULES\n" \
+      "@LIST: asq,memberof\n" \
+@@ -171,6 +173,7 @@ int sysdb_upgrade_17(struct sysdb_ctx *sysdb,
+                      const char **ver);
+ int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver);
+ int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver);
++int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver);
+ 
+ int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver);
+ 
+diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
+index 46df971e9..f6a481147 100644
+--- a/src/db/sysdb_upgrade.c
++++ b/src/db/sysdb_upgrade.c
+@@ -2501,6 +2501,58 @@ done:
+     return ret;
+ }
+ 
++int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver)
++{
++    struct upgrade_ctx *ctx;
++    errno_t ret;
++    struct ldb_message *msg = NULL;
++
++    ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_21, &ctx);
++    if (ret) {
++        return ret;
++    }
++
++    /* Add missing indices */
++    msg = ldb_msg_new(ctx);
++    if (msg == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
++    if (msg->dn == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
++    if (ret != LDB_SUCCESS) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_CCACHE_FILE);
++    if (ret != LDB_SUCCESS) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = ldb_modify(sysdb->ldb, msg);
++    if (ret != LDB_SUCCESS) {
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
++    talloc_free(msg);
++
++    /* conversion done, update version number */
++    ret = update_version(ctx);
++
++done:
++    ret = finish_upgrade(ret, &ctx, ver);
++    return ret;
++}
++
+ int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver)
+ {
+     struct upgrade_ctx *ctx;
+-- 
+2.19.1
+
diff --git a/SOURCES/0010-krb5-Silence-an-error-message-if-no-cache-entries-ha.patch b/SOURCES/0010-krb5-Silence-an-error-message-if-no-cache-entries-ha.patch
new file mode 100644
index 0000000..99a2c27
--- /dev/null
+++ b/SOURCES/0010-krb5-Silence-an-error-message-if-no-cache-entries-ha.patch
@@ -0,0 +1,33 @@
+From 23fb7ea2f98c08a7df21b68bf96ddfe982fa284e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 25 Mar 2019 10:17:39 +0100
+Subject: [PATCH] krb5: Silence an error message if no cache entries have
+ ccache stored but renewal is enabled
+
+If no user entries had the ccacheFile attribute, the code would treat
+ENOENT as an error and print a CRIT-level debug message.
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+(cherry picked from commit 22fc051df8bd1a9ec9e22aac85659d1da3bdbaec)
+---
+ src/providers/krb5/krb5_renew_tgt.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c
+index c7e2bd91f..8b2159e92 100644
+--- a/src/providers/krb5/krb5_renew_tgt.c
++++ b/src/providers/krb5/krb5_renew_tgt.c
+@@ -413,7 +413,9 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx)
+     ret = sysdb_search_entry(tmp_ctx, renew_tgt_ctx->be_ctx->domain->sysdb, base_dn,
+                              LDB_SCOPE_SUBTREE, ccache_filter, ccache_attrs,
+                              &msgs_count, &msgs);
+-    if (ret != EOK) {
++    if (ret == ENOENT) {
++        msgs_count = 0; /* Fall through */
++    } else if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry failed.\n");
+         goto done;
+     }
+-- 
+2.19.1
+
diff --git a/SOURCES/0011-Util-added-facility-to-load-nss-lib-syms.patch b/SOURCES/0011-Util-added-facility-to-load-nss-lib-syms.patch
new file mode 100644
index 0000000..e16eb66
--- /dev/null
+++ b/SOURCES/0011-Util-added-facility-to-load-nss-lib-syms.patch
@@ -0,0 +1,555 @@
+From ac1c193a3d8d2e0be39fc647e9a4b616b7513a45 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Fri, 22 Mar 2019 15:33:22 +0100
+Subject: [PATCH 11/15] Util: added facility to load nss lib syms
+
+Factored out (from proxy provider code) utility to load NSS symbols
+from shared library.
+
+Related: https://pagure.io/SSSD/sssd/issue/3964
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 6a6aad282e56a5f0bf52f20b98c1764d43abbbaf)
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                      |   2 +
+ src/providers/proxy/proxy.h      |  54 +---------
+ src/providers/proxy/proxy_init.c | 163 ++++++++++++-------------------
+ src/util/nss_dl_load.c           | 106 ++++++++++++++++++++
+ src/util/nss_dl_load.h           |  81 +++++++++++++++
+ 5 files changed, 255 insertions(+), 151 deletions(-)
+ create mode 100644 src/util/nss_dl_load.c
+ create mode 100644 src/util/nss_dl_load.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 4475b3d12..05f5f4e26 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -677,6 +677,7 @@ dist_noinst_HEADERS = \
+     src/util/inotify.h \
+     src/util/sss_iobuf.h \
+     src/util/tev_curl.h \
++    src/util/nss_dl_load.h \
+     src/monitor/monitor.h \
+     src/monitor/monitor_interfaces.h \
+     src/monitor/monitor_iface_generated.h \
+@@ -3996,6 +3997,7 @@ libsss_proxy_la_SOURCES = \
+     src/providers/proxy/proxy_services.c \
+     src/providers/proxy/proxy_auth.c \
+     src/providers/proxy/proxy_iface_generated.c \
++    src//util/nss_dl_load.c \
+     $(NULL)
+ libsss_proxy_la_CFLAGS = \
+     $(AM_CFLAGS)
+diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h
+index 3b0475d08..6debd4953 100644
+--- a/src/providers/proxy/proxy.h
++++ b/src/providers/proxy/proxy.h
+@@ -25,11 +25,7 @@
+ #ifndef __PROXY_H__
+ #define __PROXY_H__
+ 
+-#include <nss.h>
+ #include <errno.h>
+-#include <pwd.h>
+-#include <grp.h>
+-#include <dlfcn.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ 
+@@ -37,58 +33,13 @@
+ #include <security/pam_modules.h>
+ 
+ #include "util/util.h"
++#include "util/nss_dl_load.h"
+ #include "providers/backend.h"
+ #include "db/sysdb.h"
+-#include "sss_client/nss_compat.h"
+ #include <dhash.h>
+ 
+ #define PROXY_CHILD_PATH "/org/freedesktop/sssd/proxychild"
+ 
+-struct proxy_nss_ops {
+-    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
+-                                  char *buffer, size_t buflen, int *errnop);
+-    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
+-                                  char *buffer, size_t buflen, int *errnop);
+-    enum nss_status (*setpwent)(void);
+-    enum nss_status (*getpwent_r)(struct passwd *result,
+-                                  char *buffer, size_t buflen, int *errnop);
+-    enum nss_status (*endpwent)(void);
+-
+-    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
+-                                  char *buffer, size_t buflen, int *errnop);
+-    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
+-                                  char *buffer, size_t buflen, int *errnop);
+-    enum nss_status (*setgrent)(void);
+-    enum nss_status (*getgrent_r)(struct group *result,
+-                                  char *buffer, size_t buflen, int *errnop);
+-    enum nss_status (*endgrent)(void);
+-    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
+-                                      long int *start, long int *size,
+-                                      gid_t **groups, long int limit,
+-                                      int *errnop);
+-    enum nss_status (*setnetgrent)(const char *netgroup,
+-                                   struct __netgrent *result);
+-    enum nss_status (*getnetgrent_r)(struct __netgrent *result, char *buffer,
+-                                     size_t buflen, int *errnop);
+-    enum nss_status (*endnetgrent)(struct __netgrent *result);
+-
+-    /* Services */
+-    enum nss_status (*getservbyname_r)(const char *name,
+-                                        const char *protocol,
+-                                        struct servent *result,
+-                                        char *buffer, size_t buflen,
+-                                        int *errnop);
+-    enum nss_status (*getservbyport_r)(int port, const char *protocol,
+-                                        struct servent *result,
+-                                        char *buffer, size_t buflen,
+-                                        int *errnop);
+-    enum nss_status (*setservent)(void);
+-    enum nss_status (*getservent_r)(struct servent *result,
+-                                    char *buffer, size_t buflen,
+-                                    int *errnop);
+-    enum nss_status (*endservent)(void);
+-};
+-
+ struct authtok_conv {
+     struct sss_auth_token *authtok;
+     struct sss_auth_token *newauthtok;
+@@ -99,8 +50,7 @@ struct authtok_conv {
+ struct proxy_id_ctx {
+     struct be_ctx *be;
+     bool fast_alias;
+-    struct proxy_nss_ops ops;
+-    void *handle;
++    struct sss_nss_ops ops;
+ };
+ 
+ struct proxy_auth_ctx {
+diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
+index 7d997cb16..e3273d9a7 100644
+--- a/src/providers/proxy/proxy_init.c
++++ b/src/providers/proxy/proxy_init.c
+@@ -27,44 +27,15 @@
+ #include "util/sss_format.h"
+ #include "providers/proxy/proxy.h"
+ 
+-#define NSS_FN_NAME "_nss_%s_%s"
+-
+ #define OPT_MAX_CHILDREN_DEFAULT 10
+ 
+-#define ERROR_INITGR "The '%s' library does not provides the " \
+-                         "_nss_XXX_initgroups_dyn function!\n" \
+-                         "initgroups will be slow as it will require " \
+-                         "full groups enumeration!\n"
+-#define ERROR_NETGR "The '%s' library does not support netgroups.\n"
+-#define ERROR_SERV "The '%s' library does not support services.\n"
+-
+-static void *proxy_dlsym(void *handle,
+-                         const char *name,
+-                         const char *libname)
+-{
+-    char *funcname;
+-    void *funcptr;
+-
+-    funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name);
+-    if (funcname == NULL) {
+-        return NULL;
+-    }
+-
+-    funcptr = dlsym(handle, funcname);
+-    talloc_free(funcname);
+-
+-    return funcptr;
+-}
+-
+ static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx,
+                              struct be_ctx *be_ctx,
+                              char **_libname,
+-                             char **_libpath,
+                              bool *_fast_alias)
+ {
+     TALLOC_CTX *tmp_ctx;
+     char *libname;
+-    char *libpath;
+     bool fast_alias;
+     errno_t ret;
+ 
+@@ -94,15 +65,7 @@ static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    libpath = talloc_asprintf(tmp_ctx, "libnss_%s.so.2", libname);
+-    if (libpath == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+     *_libname = talloc_steal(mem_ctx, libname);
+-    *_libpath = talloc_steal(mem_ctx, libpath);
+     *_fast_alias = fast_alias;
+ 
+     ret = EOK;
+@@ -113,57 +76,6 @@ done:
+     return ret;
+ }
+ 
+-static errno_t proxy_id_load_symbols(struct proxy_nss_ops *ops,
+-                                     const char *libname,
+-                                     void *handle)
+-{
+-    int i;
+-    struct {void **dest;
+-            const char *name;
+-            const char *custom_error;
+-            bool is_fatal;
+-    } symbols[] = {
+-        {(void**)&ops->getpwnam_r, "getpwnam_r", NULL, true},
+-        {(void**)&ops->getpwuid_r, "getpwuid_r", NULL, true},
+-        {(void**)&ops->setpwent, "setpwent", NULL, true},
+-        {(void**)&ops->getpwent_r, "getpwent_r", NULL, true},
+-        {(void**)&ops->endpwent, "endpwent", NULL, true},
+-        {(void**)&ops->getgrnam_r, "getgrnam_r", NULL, true},
+-        {(void**)&ops->getgrgid_r, "getgrgid_r", NULL, true},
+-        {(void**)&ops->setgrent, "setgrent", NULL, true},
+-        {(void**)&ops->getgrent_r, "getgrent_r", NULL, true},
+-        {(void**)&ops->endgrent, "endgrent", NULL, true},
+-        {(void**)&ops->initgroups_dyn, "initgroups_dyn", ERROR_INITGR, false},
+-        {(void**)&ops->setnetgrent, "setnetgrent", ERROR_NETGR, false},
+-        {(void**)&ops->getnetgrent_r, "getnetgrent_r", ERROR_NETGR, false},
+-        {(void**)&ops->endnetgrent, "endnetgrent", ERROR_NETGR, false},
+-        {(void**)&ops->getservbyname_r, "getservbyname_r", ERROR_SERV, false},
+-        {(void**)&ops->getservbyport_r, "getservbyport_r", ERROR_SERV, false},
+-        {(void**)&ops->setservent, "setservent", ERROR_SERV, false},
+-        {(void**)&ops->getservent_r, "getservent_r", ERROR_SERV, false},
+-        {(void**)&ops->endservent, "endservent", ERROR_SERV, false},
+-        {NULL, NULL, NULL, false}
+-    };
+-
+-    for (i = 0; symbols[i].dest != NULL; i++) {
+-        *symbols[i].dest = proxy_dlsym(handle, symbols[i].name, libname);
+-        if (*symbols[i].dest == NULL) {
+-            DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load _nss_%s_%s, "
+-                  "error: %s.\n", libname, symbols[i].name, dlerror());
+-
+-            if (symbols[i].custom_error != NULL) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, symbols[i].custom_error, libname);
+-            }
+-
+-            if (symbols[i].is_fatal) {
+-                return ELIBBAD;
+-            }
+-        }
+-    }
+-
+-    return EOK;
+-}
+-
+ static errno_t proxy_setup_sbus(TALLOC_CTX *mem_ctx,
+                                 struct proxy_auth_ctx *ctx,
+                                 struct be_ctx *be_ctx)
+@@ -310,6 +222,68 @@ errno_t sssm_proxy_init(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++
++#define ERROR_INITGR "The '%s' library does not provides the " \
++                         "_nss_XXX_initgroups_dyn function!\n" \
++                         "initgroups will be slow as it will require " \
++                         "full groups enumeration!\n"
++#define ERROR_NETGR "The '%s' library does not support netgroups.\n"
++#define ERROR_SERV "The '%s' library does not support services.\n"
++
++static errno_t proxy_load_nss_symbols(struct sss_nss_ops *ops,
++                                      const char *libname)
++{
++    errno_t ret;
++    size_t i;
++
++    ret = sss_load_nss_symbols(ops, libname);
++    if (ret != EOK) {
++        return ret;
++    }
++
++    struct {
++        void *fptr;
++        const char* custom_error;
++    } optional_syms[] = {
++        {(void*)ops->initgroups_dyn,  ERROR_INITGR},
++        {(void*)ops->setnetgrent,     ERROR_NETGR},
++        {(void*)ops->getnetgrent_r,   ERROR_NETGR},
++        {(void*)ops->endnetgrent,     ERROR_NETGR},
++        {(void*)ops->getservbyname_r, ERROR_SERV},
++        {(void*)ops->getservbyport_r, ERROR_SERV},
++        {(void*)ops->setservent,      ERROR_SERV},
++        {(void*)ops->getservent_r,    ERROR_SERV},
++        {(void*)ops->endservent,      ERROR_SERV},
++    };
++    for (i = 0; i < sizeof(optional_syms) / sizeof(optional_syms[0]); ++i) {
++        if (!optional_syms[i].fptr) {
++            DEBUG(SSSDBG_CRIT_FAILURE, optional_syms[i].custom_error, libname);
++        }
++    }
++
++    void *mandatory_syms[] = {
++        (void*)ops->getpwnam_r,
++        (void*)ops->getpwuid_r,
++        (void*)ops->setpwent,
++        (void*)ops->getpwent_r,
++        (void*)ops->endpwent,
++        (void*)ops->getgrnam_r,
++        (void*)ops->getgrgid_r,
++        (void*)ops->setgrent,
++        (void*)ops->getgrent_r,
++        (void*)ops->endgrent,
++    };
++    for (i = 0; i < sizeof(mandatory_syms)/sizeof(mandatory_syms[0]); ++i) {
++        if (!mandatory_syms[i]) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "The '%s' library does not provide mandatory function", libname);
++            return ELIBBAD;
++        }
++    }
++
++    return EOK;
++}
++
++
+ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
+                            struct be_ctx *be_ctx,
+                            void *module_data,
+@@ -317,7 +291,6 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
+ {
+     struct proxy_id_ctx *ctx;
+     char *libname;
+-    char *libpath;
+     errno_t ret;
+ 
+     ctx = talloc_zero(mem_ctx, struct proxy_id_ctx);
+@@ -327,20 +300,12 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
+ 
+     ctx->be = be_ctx;
+ 
+-    ret = proxy_id_conf(ctx, be_ctx, &libname, &libpath, &ctx->fast_alias);
++    ret = proxy_id_conf(ctx, be_ctx, &libname, &ctx->fast_alias);
+     if (ret != EOK) {
+         goto done;
+     }
+ 
+-    ctx->handle = dlopen(libpath, RTLD_NOW);
+-    if (ctx->handle == NULL) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, "
+-              "error: %s\n", libpath, dlerror());
+-        ret = ELIBACC;
+-        goto done;
+-    }
+-
+-    ret = proxy_id_load_symbols(&ctx->ops, libname, ctx->handle);
++    ret = proxy_load_nss_symbols(&ctx->ops, libname);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n",
+               ret, sss_strerror(ret));
+diff --git a/src/util/nss_dl_load.c b/src/util/nss_dl_load.c
+new file mode 100644
+index 000000000..60df33376
+--- /dev/null
++++ b/src/util/nss_dl_load.c
+@@ -0,0 +1,106 @@
++/*
++    Copyright (C) 2019 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 <dlfcn.h>
++#include <talloc.h>
++#include <stdbool.h>
++#include <errno.h>
++
++#include "util/util_errors.h"
++#include "util/debug.h"
++#include "nss_dl_load.h"
++
++
++#define NSS_FN_NAME "_nss_%s_%s"
++
++
++static void *proxy_dlsym(void *handle,
++                         const char *name,
++                         const char *libname)
++{
++    char *funcname;
++    void *funcptr;
++
++    funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name);
++    if (funcname == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
++        return NULL;
++    }
++
++    funcptr = dlsym(handle, funcname);
++    talloc_free(funcname);
++
++    return funcptr;
++}
++
++
++errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname)
++{
++    char *libpath;
++    size_t i;
++    struct {
++        void **dest;
++        const char *name;
++    } symbols[] = {
++        {(void**)&ops->getpwnam_r,      "getpwnam_r"},
++        {(void**)&ops->getpwuid_r,      "getpwuid_r"},
++        {(void**)&ops->setpwent,        "setpwent"},
++        {(void**)&ops->getpwent_r,      "getpwent_r"},
++        {(void**)&ops->endpwent,        "endpwent"},
++        {(void**)&ops->getgrnam_r,      "getgrnam_r"},
++        {(void**)&ops->getgrgid_r,      "getgrgid_r"},
++        {(void**)&ops->setgrent,        "setgrent"},
++        {(void**)&ops->getgrent_r,      "getgrent_r"},
++        {(void**)&ops->endgrent,        "endgrent"},
++        {(void**)&ops->initgroups_dyn,  "initgroups_dyn"},
++        {(void**)&ops->setnetgrent,     "setnetgrent"},
++        {(void**)&ops->getnetgrent_r,   "getnetgrent_r"},
++        {(void**)&ops->endnetgrent,     "endnetgrent"},
++        {(void**)&ops->getservbyname_r, "getservbyname_r"},
++        {(void**)&ops->getservbyport_r, "getservbyport_r"},
++        {(void**)&ops->setservent,      "setservent"},
++        {(void**)&ops->getservent_r,    "getservent_r"},
++        {(void**)&ops->endservent,      "endservent"}
++    };
++
++    libpath = talloc_asprintf(NULL, "libnss_%s.so.2", libname);
++    if (libpath == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
++        return ENOMEM;
++    }
++
++    ops->dl_handle = dlopen(libpath, RTLD_NOW);
++    if (ops->dl_handle == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, "
++              "error: %s\n", libpath, dlerror());
++        talloc_free(libpath);
++        return ELIBACC;
++    }
++    talloc_free(libpath);
++
++    for (i = 0; i < sizeof(symbols)/sizeof(symbols[0]); ++i) {
++        *symbols[i].dest = proxy_dlsym(ops->dl_handle, symbols[i].name,
++                                       libname);
++        if (*symbols[i].dest == NULL) {
++            DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load "NSS_FN_NAME", "
++                  "error: %s.\n", libname, symbols[i].name, dlerror());
++        }
++    }
++
++    return EOK;
++}
+diff --git a/src/util/nss_dl_load.h b/src/util/nss_dl_load.h
+new file mode 100644
+index 000000000..5097acacd
+--- /dev/null
++++ b/src/util/nss_dl_load.h
+@@ -0,0 +1,81 @@
++/*
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#ifndef __SSSD_NSS_DL_LOAD_H__
++#define __SSSD_NSS_DL_LOAD_H__
++
++
++#include <nss.h>
++#include <pwd.h>
++#include <grp.h>
++#include <netdb.h>
++#include "util/util_errors.h"
++#include "sss_client/nss_compat.h"
++
++
++struct sss_nss_ops {
++    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
++                                  char *buffer, size_t buflen, int *errnop);
++    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
++                                  char *buffer, size_t buflen, int *errnop);
++    enum nss_status (*setpwent)(void);
++    enum nss_status (*getpwent_r)(struct passwd *result,
++                                  char *buffer, size_t buflen, int *errnop);
++    enum nss_status (*endpwent)(void);
++
++    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
++                                  char *buffer, size_t buflen, int *errnop);
++    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
++                                  char *buffer, size_t buflen, int *errnop);
++    enum nss_status (*setgrent)(void);
++    enum nss_status (*getgrent_r)(struct group *result,
++                                  char *buffer, size_t buflen, int *errnop);
++    enum nss_status (*endgrent)(void);
++    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
++                                      long int *start, long int *size,
++                                      gid_t **groups, long int limit,
++                                      int *errnop);
++    enum nss_status (*setnetgrent)(const char *netgroup,
++                                   struct __netgrent *result);
++    enum nss_status (*getnetgrent_r)(struct __netgrent *result, char *buffer,
++                                     size_t buflen, int *errnop);
++    enum nss_status (*endnetgrent)(struct __netgrent *result);
++
++    /* Services */
++    enum nss_status (*getservbyname_r)(const char *name,
++                                        const char *protocol,
++                                        struct servent *result,
++                                        char *buffer, size_t buflen,
++                                        int *errnop);
++    enum nss_status (*getservbyport_r)(int port, const char *protocol,
++                                        struct servent *result,
++                                        char *buffer, size_t buflen,
++                                        int *errnop);
++    enum nss_status (*setservent)(void);
++    enum nss_status (*getservent_r)(struct servent *result,
++                                    char *buffer, size_t buflen,
++                                    int *errnop);
++    enum nss_status (*endservent)(void);
++
++    void *dl_handle;
++};
++
++
++errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname);
++
++
++#endif /* __SSSD_NSS_DL_LOAD_H__ */
+-- 
+2.19.1
+
diff --git a/SOURCES/0012-responder-negcache-avoid-calling-nsswitch-NSS-API.patch b/SOURCES/0012-responder-negcache-avoid-calling-nsswitch-NSS-API.patch
new file mode 100644
index 0000000..554a973
--- /dev/null
+++ b/SOURCES/0012-responder-negcache-avoid-calling-nsswitch-NSS-API.patch
@@ -0,0 +1,1107 @@
+From b08906169216fdec43008c38891145386017d12f Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Fri, 22 Mar 2019 16:06:49 +0100
+Subject: [PATCH 12/15] responder/negcache: avoid calling nsswitch NSS API
+
+Changed "negcache_files.c::is_*_local_by_*()" to use functions from
+"libnss_files" directly to check users (instead of calling glibc
+NSS API).
+Changed affected tests to avoid using NSS-wrapper and to use real
+local user&group (otherwise tests were broken).
+
+Resolves: https://pagure.io/SSSD/sssd/issue/3964
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 2b564f849a20289a857cf19bbfaa5c6eb8670bad)
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                           |  20 +++
+ src/responder/common/negcache.c       |  52 +++++-
+ src/responder/common/negcache_files.c |  74 ++++-----
+ src/responder/common/negcache_files.h |  12 +-
+ src/tests/cwrap/Makefile.am           |   4 +
+ src/tests/cwrap/test_negcache.c       | 227 +++++++++++++++++++-------
+ src/tests/intg/test_ldap.py           | 114 ++++++-------
+ 7 files changed, 333 insertions(+), 170 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 05f5f4e26..6a67dc7b1 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -569,6 +569,7 @@ SSSD_RESPONDER_IFACE_OBJ = \
+ SSSD_RESPONDER_OBJ = \
+     src/responder/common/negcache_files.c \
+     src/responder/common/negcache.c \
++    src/util/nss_dl_load.c \
+     src/responder/common/responder_cmd.c \
+     src/responder/common/responder_common.c \
+     src/responder/common/responder_dp.c \
+@@ -1380,6 +1381,7 @@ sssd_nss_SOURCES = \
+     src/responder/nss/nsssrv_mmap_cache.c \
+     $(SSSD_RESPONDER_OBJ)
+ sssd_nss_LDADD = \
++    $(LIBADD_DL) \
+     $(TDB_LIBS) \
+     $(SSSD_LIBS) \
+     libsss_idmap.la \
+@@ -1396,6 +1398,7 @@ sssd_pam_SOURCES = \
+     src/responder/pam/pam_helpers.c \
+     $(SSSD_RESPONDER_OBJ)
+ sssd_pam_LDADD = \
++    $(LIBADD_DL) \
+     $(TDB_LIBS) \
+     $(SSSD_LIBS) \
+     $(SELINUX_LIBS) \
+@@ -1414,6 +1417,7 @@ sssd_sudo_SOURCES = \
+     src/responder/sudo/sudosrv_dp.c \
+     $(SSSD_RESPONDER_OBJ)
+ sssd_sudo_LDADD = \
++    $(LIBADD_DL) \
+     $(SSSD_LIBS) \
+     $(SYSTEMD_DAEMON_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS)
+@@ -1426,6 +1430,7 @@ sssd_autofs_SOURCES = \
+     src/responder/autofs/autofssrv_dp.c \
+     $(SSSD_RESPONDER_OBJ)
+ sssd_autofs_LDADD = \
++    $(LIBADD_DL) \
+     $(SSSD_LIBS) \
+     $(SYSTEMD_DAEMON_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS)
+@@ -1441,6 +1446,7 @@ sssd_ssh_SOURCES = \
+     $(SSSD_RESPONDER_OBJ) \
+     $(NULL)
+ sssd_ssh_LDADD = \
++    $(LIBADD_DL) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+     $(SYSTEMD_DAEMON_LIBS) \
+@@ -1457,6 +1463,7 @@ sssd_pac_CFLAGS = \
+     $(AM_CFLAGS) \
+     $(NDR_KRB5PAC_CFLAGS)
+ sssd_pac_LDADD = \
++    $(LIBADD_DL) \
+     $(NDR_KRB5PAC_LIBS) \
+     $(TDB_LIBS) \
+     $(SSSD_LIBS) \
+@@ -1481,6 +1488,7 @@ sssd_ifp_SOURCES = \
+ sssd_ifp_CFLAGS = \
+     $(AM_CFLAGS)
+ sssd_ifp_LDADD = \
++    $(LIBADD_DL) \
+     $(SSSD_LIBS) \
+     $(SYSTEMD_DAEMON_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+@@ -1525,6 +1533,7 @@ sssd_secrets_SOURCES = \
+     $(SSSD_RESPONDER_OBJ) \
+     $(NULL)
+ sssd_secrets_LDADD = \
++    $(LIBADD_DL) \
+     $(HTTP_PARSER_LIBS) \
+     $(JANSSON_LIBS) \
+     $(TDB_LIBS) \
+@@ -1559,6 +1568,7 @@ sssd_kcm_CFLAGS = \
+     $(JANSSON_CFLAGS) \
+     $(NULL)
+ sssd_kcm_LDADD = \
++    $(LIBADD_DL) \
+     $(KRB5_LIBS) \
+     $(CURL_LIBS) \
+     $(JANSSON_LIBS) \
+@@ -2254,6 +2264,7 @@ responder_socket_access_tests_SOURCES = \
+     src/tests/responder_socket_access-tests.c \
+     src/responder/common/negcache_files.c \
+     src/responder/common/negcache.c \
++    src/util/nss_dl_load.c \
+     src/responder/common/responder_common.c \
+     src/responder/common/responder_packet.c \
+     src/responder/common/responder_cmd.c \
+@@ -2267,6 +2278,7 @@ responder_socket_access_tests_CFLAGS = \
+     $(AM_CFLAGS) \
+     $(CHECK_CFLAGS)
+ responder_socket_access_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CHECK_LIBS) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+@@ -2358,6 +2370,7 @@ TEST_MOCK_RESP_OBJ = \
+      src/responder/common/responder_cmd.c \
+      src/responder/common/negcache_files.c \
+      src/responder/common/negcache.c \
++     src/util/nss_dl_load.c \
+      src/responder/common/responder_common.c \
+      src/responder/common/data_provider/rdp_message.c \
+      src/responder/common/data_provider/rdp_client.c \
+@@ -2409,6 +2422,7 @@ nss_srv_tests_LDFLAGS = \
+     -Wl,-wrap,sss_cmd_send_empty \
+     -Wl,-wrap,sss_cmd_done
+ nss_srv_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+@@ -2444,6 +2458,7 @@ pam_srv_tests_LDFLAGS = \
+     -Wl,-wrap,pam_dp_send_req \
+     $(NULL)
+ pam_srv_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(PAM_LIBS) \
+     $(SSSD_LIBS) \
+@@ -2480,6 +2495,7 @@ ssh_srv_tests_LDFLAGS = \
+     -Wl,-wrap,ssh_dp_send_req \
+     $(NULL)
+ ssh_srv_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+@@ -2499,6 +2515,7 @@ responder_get_domains_tests_LDFLAGS = \
+     -Wl,-wrap,sss_parse_name_for_domains \
+     -Wl,-wrap,sss_ncache_reset_repopulate_permanent
+ responder_get_domains_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+@@ -2578,6 +2595,7 @@ test_negcache_CFLAGS = \
+     $(TALLOC_CFLAGS) \
+     $(DHASH_CFLAGS)
+ test_negcache_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SYSTEMD_DAEMON_LIBS) \
+@@ -2922,6 +2940,7 @@ ifp_tests_SOURCES = \
+ ifp_tests_CFLAGS = \
+     $(AM_CFLAGS)
+ ifp_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+@@ -3178,6 +3197,7 @@ responder_cache_req_tests_LDFLAGS = \
+     -Wl,-wrap,sss_dp_get_account_send \
+     $(NULL)
+ responder_cache_req_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SSSD_INTERNAL_LTLIBS) \
+diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
+index f9034d164..d6f72d816 100644
+--- a/src/responder/common/negcache.c
++++ b/src/responder/common/negcache.c
+@@ -19,14 +19,16 @@
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+ 
++#include <fcntl.h>
++#include <time.h>
++#include "tdb.h"
+ #include "util/util.h"
++#include "util/nss_dl_load.h"
+ #include "confdb/confdb.h"
+ #include "responder/common/negcache_files.h"
+ #include "responder/common/responder.h"
+ #include "responder/common/negcache.h"
+-#include <fcntl.h>
+-#include <time.h>
+-#include "tdb.h"
++
+ 
+ #define NC_ENTRY_PREFIX "NCE/"
+ #define NC_USER_PREFIX NC_ENTRY_PREFIX"USER"
+@@ -44,6 +46,7 @@ struct sss_nc_ctx {
+     struct tdb_context *tdb;
+     uint32_t timeout;
+     uint32_t local_timeout;
++    struct sss_nss_ops ops;
+ };
+ 
+ typedef int (*ncache_set_byname_fn_t)(struct sss_nc_ctx *, bool,
+@@ -63,14 +66,49 @@ static int string_to_tdb_data(char *str, TDB_DATA *ret)
+     return EOK;
+ }
+ 
++static errno_t ncache_load_nss_symbols(struct sss_nss_ops *ops)
++{
++    errno_t ret;
++    size_t i;
++
++    ret = sss_load_nss_symbols(ops, "files");
++    if (ret != EOK) {
++        return ret;
++    }
++
++    void *mandatory_syms[] = {
++        (void*)ops->getpwnam_r,
++        (void*)ops->getpwuid_r,
++        (void*)ops->getgrnam_r,
++        (void*)ops->getgrgid_r
++    };
++    for (i = 0; i < sizeof(mandatory_syms)/sizeof(mandatory_syms[0]); ++i) {
++        if (!mandatory_syms[i]) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "The 'files' library does not provide mandatory function");
++            return ELIBBAD;
++        }
++    }
++
++    return EOK;
++}
++
+ int sss_ncache_init(TALLOC_CTX *memctx, uint32_t timeout,
+                     uint32_t local_timeout, struct sss_nc_ctx **_ctx)
+ {
++    errno_t ret;
+     struct sss_nc_ctx *ctx;
+ 
+     ctx = talloc_zero(memctx, struct sss_nc_ctx);
+     if (!ctx) return ENOMEM;
+ 
++    ret = ncache_load_nss_symbols(&ctx->ops);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n",
++              ret, sss_strerror(ret));
++        talloc_free(ctx);
++        return ret;
++    }
++
+     errno = 0;
+     /* open a memory only tdb with default hash size */
+     ctx->tdb = tdb_open("memcache", 0, TDB_INTERNAL, O_RDWR|O_CREAT, 0);
+@@ -488,7 +526,7 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+     if (!str) return ENOMEM;
+ 
+     if ((!permanent) && (ctx->local_timeout > 0)) {
+-        use_local_negative = is_user_local_by_name(name);
++        use_local_negative = is_user_local_by_name(&ctx->ops, name);
+     }
+     ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+@@ -509,7 +547,7 @@ static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent,
+     if (!str) return ENOMEM;
+ 
+     if ((!permanent) && (ctx->local_timeout > 0)) {
+-        use_local_negative = is_group_local_by_name(name);
++        use_local_negative = is_group_local_by_name(&ctx->ops, name);
+     }
+     ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+@@ -606,7 +644,7 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent,
+     if (!str) return ENOMEM;
+ 
+     if ((!permanent) && (ctx->local_timeout > 0)) {
+-        use_local_negative = is_user_local_by_uid(uid);
++        use_local_negative = is_user_local_by_uid(&ctx->ops, uid);
+     }
+     ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+@@ -630,7 +668,7 @@ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent,
+     if (!str) return ENOMEM;
+ 
+     if ((!permanent) && (ctx->local_timeout > 0)) {
+-        use_local_negative = is_group_local_by_gid(gid);
++        use_local_negative = is_group_local_by_gid(&ctx->ops, gid);
+     }
+     ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative);
+ 
+diff --git a/src/responder/common/negcache_files.c b/src/responder/common/negcache_files.c
+index 4256186d9..85a7065a4 100644
+--- a/src/responder/common/negcache_files.c
++++ b/src/responder/common/negcache_files.c
+@@ -19,94 +19,90 @@
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+ 
+-#include <sys/types.h>
+-#include <pwd.h>
+-#include <grp.h>
+ #include "util/util.h"
++#include "util/nss_dl_load.h"
+ #include "responder/common/negcache_files.h"
+ 
+ #define BUFFER_SIZE 16384
+ 
+-bool is_user_local_by_name(const char *name)
++bool is_user_local_by_name(const struct sss_nss_ops *ops, const char *name)
+ {
+     struct passwd pwd = { 0 };
+-    struct passwd *pwd_result;
++    int errnop;
+     char buffer[BUFFER_SIZE];
+-    bool is_local = false;
+-    int ret;
++    enum nss_status ret;
+     char *shortname = NULL;
++    int parse_ret;
+ 
+-    ret = sss_parse_internal_fqname(NULL, name, &shortname, NULL);
+-    if (ret != EOK) {
++    parse_ret = sss_parse_internal_fqname(NULL, name, &shortname, NULL);
++    if (parse_ret != EOK) {
+         return false;
+     }
+ 
+-    ret = getpwnam_r(shortname, &pwd, buffer, BUFFER_SIZE, &pwd_result);
++    ret = ops->getpwnam_r(shortname, &pwd, buffer, BUFFER_SIZE, &errnop);
+     talloc_free(shortname);
+-    if (ret == EOK && pwd_result != NULL) {
++    if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC, "User %s is a local user\n", name);
+-        is_local = true;
++        return true;
+     }
+ 
+-    return is_local;
++    return false;
+ }
+ 
+-bool is_user_local_by_uid(uid_t uid)
++bool is_user_local_by_uid(const struct sss_nss_ops *ops, uid_t uid)
+ {
+     struct passwd pwd = { 0 };
+-    struct passwd *pwd_result;
++    int errnop;
+     char buffer[BUFFER_SIZE];
+-    bool is_local = false;
+-    int ret;
++    enum nss_status ret;
+ 
+-    ret = getpwuid_r(uid, &pwd, buffer, BUFFER_SIZE, &pwd_result);
+-    if (ret == EOK && pwd_result != NULL) {
++    ret = ops->getpwuid_r(uid, &pwd, buffer, BUFFER_SIZE, &errnop);
++    if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "User with UID %"SPRIuid" is a local user\n", uid);
+-        is_local = true;
++        return true;
+     }
+ 
+-    return is_local;
++    return false;
+ }
+ 
+-bool is_group_local_by_name(const char *name)
++bool is_group_local_by_name(const struct sss_nss_ops *ops, const char *name)
+ {
+     struct group grp = { 0 };
+-    struct group *grp_result;
++    int errnop;
+     char buffer[BUFFER_SIZE];
+-    bool is_local = false;
+-    int ret;
++    enum nss_status ret;
+     char *shortname = NULL;
++    int parse_ret;
+ 
+-    ret = sss_parse_internal_fqname(NULL, name, &shortname, NULL);
+-    if (ret != EOK) {
++    parse_ret = sss_parse_internal_fqname(NULL, name, &shortname, NULL);
++    if (parse_ret != EOK) {
+         return false;
+     }
+ 
+-    ret = getgrnam_r(shortname, &grp, buffer, BUFFER_SIZE, &grp_result);
++    ret = ops->getgrnam_r(shortname, &grp, buffer, BUFFER_SIZE, &errnop);
+     talloc_free(shortname);
+-    if (ret == EOK && grp_result != NULL) {
++    if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Group %s is a local group\n", name);
+-        is_local = true;
++        return true;
+     }
+ 
+-    return is_local;
++    return false;
+ }
+ 
+-bool is_group_local_by_gid(uid_t gid)
++bool is_group_local_by_gid(const struct sss_nss_ops *ops, uid_t gid)
+ {
+     struct group grp = { 0 };
+-    struct group *grp_result;
++    int errnop;
+     char buffer[BUFFER_SIZE];
+-    bool is_local = false;
+-    int ret;
++    enum nss_status ret;
+ 
+-    ret = getgrgid_r(gid, &grp, buffer, BUFFER_SIZE, &grp_result);
+-    if (ret == EOK && grp_result != NULL) {
++    ret = ops->getgrgid_r(gid, &grp, buffer, BUFFER_SIZE, &errnop);
++    if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "Group with GID %"SPRIgid" is a local group\n", gid);
+-        is_local = true;
++        return true;
+     }
+ 
+-    return is_local;
++    return false;
+ }
+diff --git a/src/responder/common/negcache_files.h b/src/responder/common/negcache_files.h
+index 01d9f0828..a3e18deb0 100644
+--- a/src/responder/common/negcache_files.h
++++ b/src/responder/common/negcache_files.h
+@@ -22,10 +22,14 @@
+ #ifndef _NEGCACHE_FILES_H_
+ #define _NEGCACHE_FILES_H_
+ 
+-bool is_user_local_by_name(const char *name);
+-bool is_user_local_by_uid(uid_t uid);
++#include <stdbool.h>
+ 
+-bool is_group_local_by_name(const char *name);
+-bool is_group_local_by_gid(uid_t gid);
++struct sss_nss_ops;
++
++bool is_user_local_by_name(const struct sss_nss_ops *ops, const char *name);
++bool is_user_local_by_uid(const struct sss_nss_ops *ops, uid_t uid);
++
++bool is_group_local_by_name(const struct sss_nss_ops *ops, const char *name);
++bool is_group_local_by_gid(const struct sss_nss_ops *ops, uid_t gid);
+ 
+ #endif /* _NEGCACHE_FILES_H_ */
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index a559abe9e..bfc493395 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -75,6 +75,7 @@ SSSD_RESPONDER_IFACE_OBJ = \
+ 
+ SSSD_RESPONDER_OBJ = \
+     ../../../src/responder/common/negcache_files.c \
++    ../../../src/util/nss_dl_load.c \
+     ../../../src/responder/common/negcache.c \
+     ../../../src/responder/common/responder_cmd.c \
+     ../../../src/responder/common/responder_common.c \
+@@ -175,6 +176,7 @@ responder_common_tests_SOURCES =\
+     ../../../src/responder/common/iface/responder_ncache.c \
+     ../../../src/responder/common/iface/responder_iface_generated.c \
+     ../../../src/responder/common/negcache_files.c \
++    ../../../src/util/nss_dl_load.c \
+     ../../../src/responder/common/negcache.c \
+     ../../../src/responder/common/data_provider/rdp_message.c \
+     ../../../src/responder/common/data_provider/rdp_client.c \
+@@ -189,6 +191,7 @@ responder_common_tests_CFLAGS = \
+     $(AM_CFLAGS) \
+     $(NULL)
+ responder_common_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SELINUX_LIBS) \
+@@ -207,6 +210,7 @@ negcache_tests_CFLAGS = \
+     -DBASE_FILE_STEM=\"$(*F)\" \
+     $(NULL)
+ negcache_tests_LDADD = \
++    $(LIBADD_DL) \
+     $(CMOCKA_LIBS) \
+     $(SSSD_LIBS) \
+     $(SELINUX_LIBS) \
+diff --git a/src/tests/cwrap/test_negcache.c b/src/tests/cwrap/test_negcache.c
+index c4f601b34..690e797e2 100644
+--- a/src/tests/cwrap/test_negcache.c
++++ b/src/tests/cwrap/test_negcache.c
+@@ -18,6 +18,10 @@
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+ 
++#include <stdio.h>
++#include <sys/types.h>
++#include <pwd.h>
++
+ #include <stdarg.h>
+ #include <stddef.h>
+ #include <setjmp.h>
+@@ -35,38 +39,40 @@
+ #define TEST_CONF_DB "test_negcache_confdb.ldb"
+ #define TEST_DOM_NAME "test_domain.test"
+ 
+-#define TEST_LOCAL_USER_NAME_1 "foobar"
+-#define TEST_LOCAL_USER_NAME_2 "sssd"
+-
+-#define TEST_LOCAL_USER_UID_1 10001
+-#define TEST_LOCAL_USER_UID_2 123
+-
+-#define TEST_LOCAL_GROUP_NAME_1 "foogroup"
+-#define TEST_LOCAL_GROUP_NAME_2 "sssd"
+-
+-#define TEST_LOCAL_GID_1 10001
+-#define TEST_LOCAL_GID_2 123
+-
+-struct test_user {
++struct user_descriptor_t {
+     const char *name;
+     uid_t uid;
++};
++
++struct group_descriptor_t {
++    const char *name;
+     gid_t gid;
+-} users[] = { { "test_user1", 1001, 50001 },
+-              { "test_user2", 1002, 50002 } };
++};
+ 
+-static void create_users(TALLOC_CTX *mem_ctx,
+-                         struct sss_domain_info *domain)
++struct ncache_test_ctx {
++    struct sss_test_ctx *tctx;
++    struct sss_nc_ctx *ncache;
++    struct user_descriptor_t local_users[2];
++    struct user_descriptor_t non_local_users[2];
++    struct group_descriptor_t local_groups[2];
++    struct group_descriptor_t non_local_groups[2];
++};
++
++static void create_users(struct ncache_test_ctx *test_ctx)
+ {
+     errno_t ret;
+     char *fqname;
++    struct sss_domain_info *domain = test_ctx->tctx->dom;
++    const struct user_descriptor_t *users = test_ctx->non_local_users;
++    const struct group_descriptor_t *groups = test_ctx->non_local_groups;
+ 
+     for (int i = 0; i < 2; i++) {
+-        fqname = sss_create_internal_fqname(mem_ctx,
++        fqname = sss_create_internal_fqname(test_ctx,
+                                             users[i].name,
+                                             domain->name);
+         assert_non_null(fqname);
+ 
+-        ret = sysdb_add_user(domain, users[i].name, users[i].uid, users[i].gid,
++        ret = sysdb_add_user(domain, users[i].name, users[i].uid, groups[i].gid,
+                              fqname, NULL, "/bin/bash", domain->name,
+                              NULL, 30, time(NULL));
+         talloc_free(fqname);
+@@ -74,25 +80,15 @@ static void create_users(TALLOC_CTX *mem_ctx,
+     }
+ }
+ 
+-struct test_group {
+-    const char *name;
+-    gid_t gid;
+-} groups[] = { { "test_group1", 50001 },
+-               { "test_group2", 50002 } };
+-
+-struct ncache_test_ctx {
+-    struct sss_test_ctx *tctx;
+-    struct sss_nc_ctx *ncache;
+-};
+-
+-static void create_groups(TALLOC_CTX *mem_ctx,
+-                          struct sss_domain_info *domain)
++static void create_groups(struct ncache_test_ctx *test_ctx)
+ {
+     errno_t ret;
+     char *fqname;
++    struct sss_domain_info *domain = test_ctx->tctx->dom;
++    const struct group_descriptor_t *groups = test_ctx->non_local_groups;
+ 
+     for (int i = 0; i < 2; i++) {
+-        fqname = sss_create_internal_fqname(mem_ctx,
++        fqname = sss_create_internal_fqname(test_ctx,
+                                             groups[i].name,
+                                             domain->name);
+         assert_non_null(fqname);
+@@ -116,6 +112,114 @@ struct cli_protocol_version *register_cli_protocol_version(void)
+     return responder_test_cli_protocol_version;
+ }
+ 
++static void find_local_users(struct ncache_test_ctx *test_ctx)
++{
++    int i;
++    FILE *passwd_file;
++    const struct passwd *pwd;
++
++    passwd_file = fopen("/etc/passwd", "r");
++    assert_non_null(passwd_file);
++
++    for (i = 0; i < 2; /*no-op*/) {
++        pwd = fgetpwent(passwd_file);
++        assert_non_null(pwd);
++        if (pwd->pw_uid == 0) {
++            /* skip root */
++            continue;
++        }
++        test_ctx->local_users[i].uid = pwd->pw_uid;
++        test_ctx->local_users[i].name = talloc_strdup(test_ctx, pwd->pw_name);
++        assert_non_null(test_ctx->local_users[i].name);
++        ++i;
++    }
++
++    fclose(passwd_file);
++}
++
++static void find_local_groups(struct ncache_test_ctx *test_ctx)
++{
++    int i;
++    FILE *group_file;
++    const struct group *grp;
++
++    group_file = fopen("/etc/group", "r");
++    assert_non_null(group_file);
++
++    for (i = 0; i < 2; /* no-op */) {
++        grp = fgetgrent(group_file);
++        assert_non_null(grp);
++        if (grp->gr_gid == 0) {
++            /* skip root */
++            continue;
++        }
++        test_ctx->local_groups[i].gid = grp->gr_gid;
++        test_ctx->local_groups[i].name = talloc_strdup(test_ctx, grp->gr_name);
++        assert_non_null(test_ctx->local_groups[i].name);
++        ++i;
++    }
++
++    fclose(group_file);
++}
++
++static void find_non_local_users(struct ncache_test_ctx *test_ctx)
++{
++    int i;
++    int k;
++    uid_t uid;
++    char *name;
++
++    for (i = 0, k = 1; (k < 100) && (i < 2); ++k) {
++        uid = 65534-k;
++        if (getpwuid(uid)) {
++            continue;
++        }
++        test_ctx->non_local_users[i].uid = uid;
++        ++i;
++    }
++    assert_int_equal(i, 2);
++
++    for (i = 0, k = 0; (k < 100) && (i < 2); ++k) {
++        name = talloc_asprintf(test_ctx, "nctestuser%d", k);
++        if (getpwnam(name)) {
++            talloc_free(name);
++            continue;
++        }
++        test_ctx->non_local_users[i].name = name;
++        ++i;
++    }
++    assert_int_equal(i, 2);
++}
++
++static void find_non_local_groups(struct ncache_test_ctx *test_ctx)
++{
++    int i = 0;
++    int k;
++    gid_t gid;
++    char *name;
++
++    for (i = 0, k = 1; (k < 100) && (i < 2); ++k) {
++        gid = 65534-k;
++        if (getgrgid(gid)) {
++            continue;
++        }
++        test_ctx->non_local_groups[i].gid = gid;
++        ++i;
++    }
++    assert_int_equal(i, 2);
++
++    for (i = 0, k = 0; (k < 100) && (i < 2); ++k) {
++        name = talloc_asprintf(test_ctx, "nctestgroup%d", k);
++        if (getgrnam(name)) {
++            talloc_free(name);
++            continue;
++        }
++        test_ctx->non_local_groups[i].name = name;
++        ++i;
++    }
++    assert_int_equal(i, 2);
++}
++
+ static int test_ncache_setup(void **state)
+ {
+     struct ncache_test_ctx *test_ctx;
+@@ -125,14 +229,19 @@ static int test_ncache_setup(void **state)
+     test_ctx = talloc_zero(global_talloc_context, struct ncache_test_ctx);
+     assert_non_null(test_ctx);
+ 
++    find_local_users(test_ctx);
++    find_local_groups(test_ctx);
++    find_non_local_users(test_ctx);
++    find_non_local_groups(test_ctx);
++
+     test_dom_suite_setup(TESTS_PATH);
+ 
+     test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB,
+                                          TEST_DOM_NAME, "ipa", NULL);
+     assert_non_null(test_ctx->tctx);
+ 
+-    create_groups(test_ctx, test_ctx->tctx->dom);
+-    create_users(test_ctx, test_ctx->tctx->dom);
++    create_groups(test_ctx);
++    create_users(test_ctx);
+ 
+     check_leaks_push(test_ctx);
+ 
+@@ -213,11 +322,11 @@ static void set_users(struct ncache_test_ctx *test_ctx)
+     int ret;
+ 
+     ret = set_user_in_ncache(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                              users[0].name);
++                             test_ctx->non_local_users[0].name);
+     assert_int_equal(ret, EOK);
+ 
+     ret = set_user_in_ncache(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                             TEST_LOCAL_USER_NAME_1);
++                             test_ctx->local_users[0].name);
+     assert_int_equal(ret, EOK);
+ }
+ 
+@@ -227,19 +336,19 @@ static void check_users(struct ncache_test_ctx *test_ctx,
+     int ret;
+ 
+     ret = check_user_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                users[0].name);
++                                test_ctx->non_local_users[0].name);
+     assert_int_equal(ret, case_a);
+ 
+     ret = check_user_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                users[1].name);
++                                test_ctx->non_local_users[1].name);
+     assert_int_equal(ret, case_b);
+ 
+     ret = check_user_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                TEST_LOCAL_USER_NAME_1);
++                                test_ctx->local_users[0].name);
+     assert_int_equal(ret, case_c);
+ 
+     ret = check_user_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                TEST_LOCAL_USER_NAME_2);
++                                test_ctx->local_users[1].name);
+     assert_int_equal(ret, case_d);
+ }
+ 
+@@ -324,11 +433,11 @@ static void set_uids(struct ncache_test_ctx *test_ctx)
+     int ret;
+ 
+     ret = sss_ncache_set_uid(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                             users[0].uid);
++                             test_ctx->non_local_users[0].uid);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sss_ncache_set_uid(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                             TEST_LOCAL_USER_UID_1);
++                             test_ctx->local_users[0].uid);
+     assert_int_equal(ret, EOK);
+ }
+ 
+@@ -338,19 +447,19 @@ static void check_uids(struct ncache_test_ctx *test_ctx,
+     int ret;
+ 
+     ret = sss_ncache_check_uid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               users[0].uid);
++                               test_ctx->non_local_users[0].uid);
+     assert_int_equal(ret, case_a);
+ 
+     ret = sss_ncache_check_uid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               users[1].uid);
++                               test_ctx->non_local_users[1].uid);
+     assert_int_equal(ret, case_b);
+ 
+     ret = sss_ncache_check_uid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               TEST_LOCAL_USER_UID_1);
++                               test_ctx->local_users[0].uid);
+     assert_int_equal(ret, case_c);
+ 
+     ret = sss_ncache_check_uid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               TEST_LOCAL_USER_UID_2);
++                               test_ctx->local_users[1].uid);
+     assert_int_equal(ret, case_d);
+ }
+ 
+@@ -435,11 +544,11 @@ static void set_groups(struct ncache_test_ctx *test_ctx)
+     int ret;
+ 
+     ret = set_group_in_ncache(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                              groups[0].name);
++                              test_ctx->non_local_groups[0].name);
+     assert_int_equal(ret, EOK);
+ 
+     ret = set_group_in_ncache(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                              TEST_LOCAL_GROUP_NAME_1);
++                              test_ctx->local_groups[0].name);
+     assert_int_equal(ret, EOK);
+ }
+ 
+@@ -449,19 +558,19 @@ static void check_groups(struct ncache_test_ctx *test_ctx,
+     int ret;
+ 
+     ret = check_group_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                groups[0].name);
++                                test_ctx->non_local_groups[0].name);
+     assert_int_equal(ret, case_a);
+ 
+     ret = check_group_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                groups[1].name);
++                                test_ctx->non_local_groups[1].name);
+     assert_int_equal(ret, case_b);
+ 
+     ret = check_group_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                TEST_LOCAL_GROUP_NAME_1);
++                                test_ctx->local_groups[0].name);
+     assert_int_equal(ret, case_c);
+ 
+     ret = check_group_in_ncache(test_ctx->ncache, test_ctx->tctx->dom,
+-                                TEST_LOCAL_GROUP_NAME_2);
++                                test_ctx->local_groups[1].name);
+     assert_int_equal(ret, case_d);
+ }
+ 
+@@ -546,11 +655,11 @@ static void set_gids(struct ncache_test_ctx *test_ctx)
+     int ret;
+ 
+     ret = sss_ncache_set_gid(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                             users[0].gid);
++                             test_ctx->non_local_groups[0].gid);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sss_ncache_set_gid(test_ctx->ncache, false, test_ctx->tctx->dom,
+-                             TEST_LOCAL_GID_1);
++                             test_ctx->local_groups[0].gid);
+     assert_int_equal(ret, EOK);
+ }
+ 
+@@ -560,19 +669,19 @@ static void check_gids(struct ncache_test_ctx *test_ctx,
+     int ret;
+ 
+     ret = sss_ncache_check_gid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               users[0].gid);
++                               test_ctx->non_local_groups[0].gid);
+     assert_int_equal(ret, case_a);
+ 
+     ret = sss_ncache_check_gid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               users[1].gid);
++                               test_ctx->non_local_groups[1].gid);
+     assert_int_equal(ret, case_b);
+ 
+     ret = sss_ncache_check_gid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               TEST_LOCAL_GID_1);
++                               test_ctx->local_groups[0].gid);
+     assert_int_equal(ret, case_c);
+ 
+     ret = sss_ncache_check_gid(test_ctx->ncache, test_ctx->tctx->dom,
+-                               TEST_LOCAL_GID_2);
++                               test_ctx->local_groups[1].gid);
+     assert_int_equal(ret, case_d);
+ }
+ 
+diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py
+index 63f6ea4ed..787255f92 100644
+--- a/src/tests/intg/test_ldap.py
++++ b/src/tests/intg/test_ldap.py
+@@ -43,15 +43,6 @@ from files_ops import passwd_ops_setup, group_ops_setup
+ LDAP_BASE_DN = "dc=example,dc=com"
+ INTERACTIVE_TIMEOUT = 4
+ 
+-PASSWD_USER = dict(name='passwduser', passwd='x', uid=100000, gid=2000,
+-                   gecos='User for tests',
+-                   dir='/home/passwduser',
+-                   shell='/bin/bash')
+-
+-PASSWD_GROUP = dict(name='passwdgroup',
+-                    gid=200000,
+-                    mem=['passwduser'])
+-
+ 
+ @pytest.fixture(scope="module")
+ def ds_inst(request):
+@@ -1860,14 +1851,32 @@ def test_rename_incomplete_group_rdn_changed(ldap_conn, rename_setup_cleanup):
+ 
+ 
+ @pytest.fixture
+-def user_and_group_rfc2307_lcl(passwd_ops_setup, group_ops_setup,
+-                               user_and_group_rfc2307):
+-    pwd_ops = passwd_ops_setup
+-    pwd_ops.useradd(**PASSWD_USER)
+-    grp_ops = group_ops_setup
+-    grp_ops.groupadd(**PASSWD_GROUP)
++def find_local_user_and_group():
++    f = open("/etc/passwd")
++    for line in f:
++        passwd_user = line.split(':')
++        passwd_user[2] = int(passwd_user[2])
++        if passwd_user[2] != 0:
++            break
++    f.close()
++    assert passwd_user[2] != 0
++
++    f = open("/etc/group")
++    for line in f:
++        passwd_group = line.split(':')
++        passwd_group[2] = int(passwd_group[2])
++        if passwd_group[2] != 0:
++            break
++    f.close()
++    assert passwd_group[2] != 0
++
++    return (passwd_user, passwd_group)
+ 
+-    return user_and_group_rfc2307
++
++@pytest.fixture
++def user_and_group_rfc2307_lcl(find_local_user_and_group,
++                               user_and_group_rfc2307):
++    return find_local_user_and_group
+ 
+ 
+ def test_local_negative_timeout_enabled_by_default(ldap_conn,
+@@ -1879,64 +1888,53 @@ def test_local_negative_timeout_enabled_by_default(ldap_conn,
+     # sanity check - try resolving an LDAP user
+     ent.assert_passwd_by_name("user", dict(name="user", uid=1001, gid=2000))
+ 
++    passwd_user, passwd_group = user_and_group_rfc2307_lcl
++
+     # resolve a user who is not in LDAP, but exists locally
+-    res, _ = call_sssd_getpwnam("passwduser")
++    res, _ = call_sssd_getpwnam(passwd_user[0])
+     assert res == NssReturnCode.NOTFOUND
+-    res = pwd.getpwnam("passwduser")
+-    assert res is not None
+     # Do the same by UID
+-    res, _ = call_sssd_getpwuid(100000)
++    res, _ = call_sssd_getpwuid(passwd_user[2])
+     assert res == NssReturnCode.NOTFOUND
+-    res = pwd.getpwuid(100000)
+-    assert res is not None
+ 
+     # Do the same for a group both by name and by ID
+-    res, _ = call_sssd_getgrnam("passwdgroup")
++    res, _ = call_sssd_getgrnam(passwd_group[0])
+     assert res == NssReturnCode.NOTFOUND
+-    res = grp.getgrnam("passwdgroup")
+-    assert res is not None
+-    res, _ = call_sssd_getgrgid(200000)
++    res, _ = call_sssd_getgrgid(passwd_group[2])
+     assert res == NssReturnCode.NOTFOUND
+-    res = grp.getgrgid(200000)
+-    assert res is not None
+ 
+     # add the user and the group to LDAP
+     ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
+-    ent_list.add_user("passwduser", 100000, 2000)
+-    ent_list.add_group("passwdgroup", 200000)
++    ent_list.add_user(passwd_user[0], passwd_user[2], 2000)
++    ent_list.add_group(passwd_group[0], passwd_group[2])
+     create_ldap_entries(ldap_conn, ent_list)
+ 
+-    # Make sure the negative cache expired
++    # Make sure the negative cache would expire if global timeout was used
+     time.sleep(2)
+ 
+     # The user is now negatively cached and can't be resolved by either
+     # name or UID
+-    res, _ = call_sssd_getpwnam("passwduser")
++    res, _ = call_sssd_getpwnam(passwd_group[0])
+     assert res == NssReturnCode.NOTFOUND
+-    res, _ = call_sssd_getpwuid(100000)
++    res, _ = call_sssd_getpwuid(passwd_group[2])
+     assert res == NssReturnCode.NOTFOUND
+ 
+-    res, _ = call_sssd_getgrnam("passwdgroup")
++    res, _ = call_sssd_getgrnam(passwd_group[0])
+     assert res == NssReturnCode.NOTFOUND
+-    res, _ = call_sssd_getgrgid(200000)
++    res, _ = call_sssd_getgrgid(passwd_group[2])
+     assert res == NssReturnCode.NOTFOUND
+ 
+     cleanup_ldap_entries(ldap_conn, ent_list)
+ 
+ 
+ @pytest.fixture
+-def usr_and_grp_rfc2307_no_local_ncache(request, passwd_ops_setup,
+-                                        group_ops_setup, ldap_conn):
++def usr_and_grp_rfc2307_no_local_ncache(request, find_local_user_and_group,
++                                        ldap_conn):
+     """
+     Create an RFC2307 directory fixture with interactive SSSD conf,
+     one user and one group but with the local negative timeout
+     disabled
+     """
+-    pwd_ops = passwd_ops_setup
+-    pwd_ops.useradd(**PASSWD_USER)
+-    grp_ops = group_ops_setup
+-    grp_ops.groupadd(**PASSWD_GROUP)
+-
+     ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
+     ent_list.add_user("user", 1001, 2000)
+     ent_list.add_group("group", 2001)
+@@ -1948,7 +1946,7 @@ def usr_and_grp_rfc2307_no_local_ncache(request, passwd_ops_setup,
+         """)
+     create_conf_fixture(request, conf)
+     create_sssd_fixture(request)
+-    return None
++    return find_local_user_and_group
+ 
+ 
+ def test_local_negative_timeout_disabled(ldap_conn,
+@@ -1960,46 +1958,40 @@ def test_local_negative_timeout_disabled(ldap_conn,
+     # sanity check - try resolving an LDAP user
+     ent.assert_passwd_by_name("user", dict(name="user", uid=1001, gid=2000))
+ 
++    passwd_user, passwd_group = usr_and_grp_rfc2307_no_local_ncache
++
+     # resolve a user who is not in LDAP, but exists locally
+-    res, _ = call_sssd_getpwnam("passwduser")
++    res, _ = call_sssd_getpwnam(passwd_user[0])
+     assert res == NssReturnCode.NOTFOUND
+-    res = pwd.getpwnam("passwduser")
+-    assert res is not None
+     # Do the same by UID
+-    res, _ = call_sssd_getpwuid(100000)
++    res, _ = call_sssd_getpwuid(passwd_user[2])
+     assert res == NssReturnCode.NOTFOUND
+-    res = pwd.getpwuid(100000)
+-    assert res is not None
+ 
+     # Do the same for a group both by name and by ID
+-    res, _ = call_sssd_getgrnam("passwdgroup")
++    res, _ = call_sssd_getgrnam(passwd_group[0])
+     assert res == NssReturnCode.NOTFOUND
+-    res = grp.getgrnam("passwdgroup")
+-    assert res is not None
+-    res, _ = call_sssd_getgrgid(200000)
++    res, _ = call_sssd_getgrgid(passwd_group[2])
+     assert res == NssReturnCode.NOTFOUND
+-    res = grp.getgrgid(200000)
+-    assert res is not None
+ 
+     # add the user and the group to LDAP
+     ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
+-    ent_list.add_user("passwduser", 100000, 2000)
+-    ent_list.add_group("passwdgroup", 200000)
++    ent_list.add_user(passwd_user[0], passwd_user[2], 2000)
++    ent_list.add_group(passwd_group[0], passwd_group[2])
+     create_ldap_entries(ldap_conn, ent_list)
+ 
+     # Make sure the negative cache expired
+     time.sleep(2)
+ 
+     # The user can now be resolved
+-    res, _ = call_sssd_getpwnam("passwduser")
++    res, _ = call_sssd_getpwnam(passwd_user[0])
+     assert res == NssReturnCode.SUCCESS
+     # Do the same by UID
+-    res, _ = call_sssd_getpwuid(100000)
++    res, _ = call_sssd_getpwuid(passwd_user[2])
+     assert res == NssReturnCode.SUCCESS
+ 
+-    res, _ = call_sssd_getgrnam("passwdgroup")
++    res, _ = call_sssd_getgrnam(passwd_group[0])
+     assert res == NssReturnCode.SUCCESS
+-    res, _ = call_sssd_getgrgid(200000)
++    res, _ = call_sssd_getgrgid(passwd_group[2])
+     assert res == NssReturnCode.SUCCESS
+ 
+     cleanup_ldap_entries(ldap_conn, ent_list)
+-- 
+2.19.1
+
diff --git a/SOURCES/0013-negcache_files-got-rid-of-large-array-on-stack.patch b/SOURCES/0013-negcache_files-got-rid-of-large-array-on-stack.patch
new file mode 100644
index 0000000..a405d8f
--- /dev/null
+++ b/SOURCES/0013-negcache_files-got-rid-of-large-array-on-stack.patch
@@ -0,0 +1,89 @@
+From 921a949f6aa8170f851483e4d5763b3e8fb5d5c9 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Fri, 22 Mar 2019 14:21:00 +0100
+Subject: [PATCH 13/15] negcache_files: got rid of large array on stack
+
+Removed large buffer from function stack.
+It is safe to use single (static) global buffer since:
+1) Responders are single threaded
+2) Code doesn't use content of this buffer anyway
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 8e6656c974ac05bb52607014bb4c30b87f4abd8b)
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/common/negcache_files.c | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/src/responder/common/negcache_files.c b/src/responder/common/negcache_files.c
+index 85a7065a4..f22796a0c 100644
+--- a/src/responder/common/negcache_files.c
++++ b/src/responder/common/negcache_files.c
+@@ -24,12 +24,12 @@
+ #include "responder/common/negcache_files.h"
+ 
+ #define BUFFER_SIZE 16384
++static char s_nss_buffer[BUFFER_SIZE];
+ 
+ bool is_user_local_by_name(const struct sss_nss_ops *ops, const char *name)
+ {
+     struct passwd pwd = { 0 };
+     int errnop;
+-    char buffer[BUFFER_SIZE];
+     enum nss_status ret;
+     char *shortname = NULL;
+     int parse_ret;
+@@ -39,7 +39,7 @@ bool is_user_local_by_name(const struct sss_nss_ops *ops, const char *name)
+         return false;
+     }
+ 
+-    ret = ops->getpwnam_r(shortname, &pwd, buffer, BUFFER_SIZE, &errnop);
++    ret = ops->getpwnam_r(shortname, &pwd, s_nss_buffer, BUFFER_SIZE, &errnop);
+     talloc_free(shortname);
+     if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC, "User %s is a local user\n", name);
+@@ -53,10 +53,9 @@ bool is_user_local_by_uid(const struct sss_nss_ops *ops, uid_t uid)
+ {
+     struct passwd pwd = { 0 };
+     int errnop;
+-    char buffer[BUFFER_SIZE];
+     enum nss_status ret;
+ 
+-    ret = ops->getpwuid_r(uid, &pwd, buffer, BUFFER_SIZE, &errnop);
++    ret = ops->getpwuid_r(uid, &pwd, s_nss_buffer, BUFFER_SIZE, &errnop);
+     if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "User with UID %"SPRIuid" is a local user\n", uid);
+@@ -70,7 +69,6 @@ bool is_group_local_by_name(const struct sss_nss_ops *ops, const char *name)
+ {
+     struct group grp = { 0 };
+     int errnop;
+-    char buffer[BUFFER_SIZE];
+     enum nss_status ret;
+     char *shortname = NULL;
+     int parse_ret;
+@@ -80,7 +78,7 @@ bool is_group_local_by_name(const struct sss_nss_ops *ops, const char *name)
+         return false;
+     }
+ 
+-    ret = ops->getgrnam_r(shortname, &grp, buffer, BUFFER_SIZE, &errnop);
++    ret = ops->getgrnam_r(shortname, &grp, s_nss_buffer, BUFFER_SIZE, &errnop);
+     talloc_free(shortname);
+     if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Group %s is a local group\n", name);
+@@ -94,10 +92,9 @@ bool is_group_local_by_gid(const struct sss_nss_ops *ops, uid_t gid)
+ {
+     struct group grp = { 0 };
+     int errnop;
+-    char buffer[BUFFER_SIZE];
+     enum nss_status ret;
+ 
+-    ret = ops->getgrgid_r(gid, &grp, buffer, BUFFER_SIZE, &errnop);
++    ret = ops->getgrgid_r(gid, &grp, s_nss_buffer, BUFFER_SIZE, &errnop);
+     if (ret == NSS_STATUS_SUCCESS) {
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "Group with GID %"SPRIgid" is a local group\n", gid);
+-- 
+2.19.1
+
diff --git a/SOURCES/0014-TESTS-moved-cwrap-test_negcache-to-cmocka-tests.patch b/SOURCES/0014-TESTS-moved-cwrap-test_negcache-to-cmocka-tests.patch
new file mode 100644
index 0000000..92aefef
--- /dev/null
+++ b/SOURCES/0014-TESTS-moved-cwrap-test_negcache-to-cmocka-tests.patch
@@ -0,0 +1,126 @@
+From 861a45d9a866e5a9d87eaad8b8b9734eb6bc59aa Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Fri, 22 Mar 2019 16:33:14 +0100
+Subject: [PATCH 14/15] TESTS: moved cwrap/test_negcache to cmocka tests
+
+Moved cwrap/test_negcache.c to cmocka tests since it doesn't use
+cwrap tools anymore.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 137b684d0a01afa02618b07ba46a44dad017b5b9)
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ Makefile.am                                   | 19 +++++++++
+ .../test_negcache_2.c}                        |  0
+ src/tests/cwrap/Makefile.am                   | 40 -------------------
+ 3 files changed, 19 insertions(+), 40 deletions(-)
+ rename src/tests/{cwrap/test_negcache.c => cmocka/test_negcache_2.c} (100%)
+
+diff --git a/Makefile.am b/Makefile.am
+index 6a67dc7b1..d09f50aa2 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -239,6 +239,7 @@ if HAVE_CMOCKA
+         test-find-uid \
+         test-io \
+         test-negcache \
++        negcache_2-tests \
+         test-authtok \
+         sss_nss_idmap-tests \
+         deskprofile_utils-tests \
+@@ -2603,6 +2604,24 @@ test_negcache_LDADD = \
+     libsss_test_common.la \
+     libsss_idmap.la
+ 
++negcache_2_tests_SOURCES =\
++    $(SSSD_RESPONDER_OBJ) \
++    src/tests/cmocka/test_negcache_2.c \
++    $(NULL)
++negcache_2_tests_CFLAGS = \
++    $(AM_CFLAGS) \
++    -DBASE_FILE_STEM=\"$(*F)\" \
++    $(NULL)
++negcache_2_tests_LDADD = \
++    $(LIBADD_DL) \
++    $(CMOCKA_LIBS) \
++    $(SSSD_LIBS) \
++    $(SYSTEMD_DAEMON_LIBS) \
++    libsss_util.la \
++    libsss_test_common.la \
++    libsss_debug.la \
++    $(NULL)
++
+ test_authtok_SOURCES = \
+     src/tests/cmocka/test_authtok.c \
+     src/util/authtok.c \
+diff --git a/src/tests/cwrap/test_negcache.c b/src/tests/cmocka/test_negcache_2.c
+similarity index 100%
+rename from src/tests/cwrap/test_negcache.c
+rename to src/tests/cmocka/test_negcache_2.c
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index bfc493395..1edefc678 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -73,26 +73,6 @@ SSSD_RESPONDER_IFACE_OBJ = \
+     ../../../src/responder/common/iface/responder_iface_generated.c \
+     $(NULL)
+ 
+-SSSD_RESPONDER_OBJ = \
+-    ../../../src/responder/common/negcache_files.c \
+-    ../../../src/util/nss_dl_load.c \
+-    ../../../src/responder/common/negcache.c \
+-    ../../../src/responder/common/responder_cmd.c \
+-    ../../../src/responder/common/responder_common.c \
+-    ../../../src/responder/common/responder_dp.c \
+-    ../../../src/responder/common/responder_dp_ssh.c \
+-    ../../../src/responder/common/responder_packet.c \
+-    ../../../src/responder/common/responder_get_domains.c \
+-    ../../../src/responder/common/responder_utils.c \
+-    ../../../src/responder/common/data_provider/rdp_message.c \
+-    ../../../src/responder/common/data_provider/rdp_client.c \
+-    ../../../src/monitor/monitor_iface_generated.c \
+-    ../../../src/providers/data_provider_req.c \
+-    ../../../src/util/session_recording.c \
+-    $(SSSD_RESPONDER_IFACE_OBJ) \
+-    $(SSSD_CACHE_REQ_OBJ) \
+-    $(NULL)
+-
+ dist_noinst_DATA = \
+     group \
+     passwd \
+@@ -107,7 +87,6 @@ check_PROGRAMS += \
+     server-tests \
+     usertools-tests \
+     responder_common-tests \
+-    negcache-tests \
+     $(NULL)
+ endif # HAVE_UID_WRAPPER
+ endif # HAVE_NSS_WRAPPER
+@@ -201,23 +180,4 @@ responder_common_tests_LDADD = \
+     $(abs_top_builddir)/libsss_test_common.la \
+     $(NULL)
+ 
+-negcache_tests_SOURCES =\
+-    $(SSSD_RESPONDER_OBJ) \
+-    test_negcache.c \
+-    $(NULL)
+-negcache_tests_CFLAGS = \
+-    $(AM_CFLAGS) \
+-    -DBASE_FILE_STEM=\"$(*F)\" \
+-    $(NULL)
+-negcache_tests_LDADD = \
+-    $(LIBADD_DL) \
+-    $(CMOCKA_LIBS) \
+-    $(SSSD_LIBS) \
+-    $(SELINUX_LIBS) \
+-    $(SYSTEMD_DAEMON_LIBS) \
+-    $(abs_top_builddir)/libsss_util.la \
+-    $(abs_top_builddir)/libsss_debug.la \
+-    $(abs_top_builddir)/libsss_test_common.la \
+-    $(NULL)
+-
+ tests: $(check_PROGRAMS)
+-- 
+2.19.1
+
diff --git a/SOURCES/0015-ci-sssd.supp-getpwuid-leak-suppression.patch b/SOURCES/0015-ci-sssd.supp-getpwuid-leak-suppression.patch
new file mode 100644
index 0000000..d8ac895
--- /dev/null
+++ b/SOURCES/0015-ci-sssd.supp-getpwuid-leak-suppression.patch
@@ -0,0 +1,50 @@
+From 2dbfa995e592329470f57f456a054f845a9a3da3 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Mon, 1 Apr 2019 16:44:26 +0200
+Subject: [PATCH 15/15] ci/sssd.supp: getpwuid() leak suppression
+
+Supresses following error:
+ 4,096 bytes in 1 blocks are definitely lost in loss record 67 of 83
+    at 0x4C2CDCB: malloc (vg_replace_malloc.c:299)
+    by 0xB8F8627: ???
+    by 0xB91EF3F: ???
+    by 0xB90E112: ???
+    by 0x9992974: getpwuid_r@@GLIBC_2.2.5 (in /usr/lib64/libc-2.26.so)
+    by 0x99920D7: getpwuid (in /usr/lib64/libc-2.26.so)
+
+This https://sourceware.org/bugzilla/show_bug.cgi?id=2314#c8 might
+be related.
+
+This problem seems to be afecting Fedora < F28
+
+(cherry picked from commit 9eb8b784d4365b846f1a620f11632099d10de2c8)
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ contrib/ci/sssd.supp | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/contrib/ci/sssd.supp b/contrib/ci/sssd.supp
+index 4303eed22..0bef4fa90 100644
+--- a/contrib/ci/sssd.supp
++++ b/contrib/ci/sssd.supp
+@@ -221,3 +221,16 @@
+    fun:set_default_locale
+    fun:main
+ }
++
++# glibc nsswitch (getpwuid) leak
++# Seems to be affecting Fedora < F28
++{
++   glibc-nss-getpwuid
++   Memcheck:Leak
++   fun:malloc
++   ...
++   fun:getpwuid_r@@GLIBC_2.2.5
++   fun:getpwuid
++   ...
++   fun:main
++}
+-- 
+2.19.1
+
diff --git a/SOURCES/0016-pam-introduce-prompt_config-struct.patch b/SOURCES/0016-pam-introduce-prompt_config-struct.patch
new file mode 100644
index 0000000..5623b8b
--- /dev/null
+++ b/SOURCES/0016-pam-introduce-prompt_config-struct.patch
@@ -0,0 +1,881 @@
+From a5e15f1e5af7d7c41717c18566ea0f2a01c086ec Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 27 Mar 2019 09:02:27 +0100
+Subject: [PATCH 16/21] pam: introduce prompt_config struct
+
+prompt_config is the internal struct to control the prompting of
+pam_sss. To make it easy to change internal details when more options
+are added it should be opaque and only accessed by getters and setter.
+
+Related to https://pagure.io/SSSD/sssd/issue/3264
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit fa8ef7c6db19a160d807f05b08bbc66c0c25ebfe)
+---
+ Makefile.am                            |  17 +
+ src/sss_client/pam_sss_prompt_config.c | 547 +++++++++++++++++++++++++
+ src/sss_client/sss_cli.h               |  29 ++
+ src/tests/cmocka/test_prompt_config.c  | 215 ++++++++++
+ 4 files changed, 808 insertions(+)
+ create mode 100644 src/sss_client/pam_sss_prompt_config.c
+ create mode 100644 src/tests/cmocka/test_prompt_config.c
+
+diff --git a/Makefile.am b/Makefile.am
+index d09f50aa2..f7f55e96a 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -241,6 +241,7 @@ if HAVE_CMOCKA
+         test-negcache \
+         negcache_2-tests \
+         test-authtok \
++        test_prompt_config \
+         sss_nss_idmap-tests \
+         deskprofile_utils-tests \
+         dyndns-tests \
+@@ -2644,6 +2645,21 @@ test_authtok_LDADD = \
+     libsss_debug.la \
+     $(NULL)
+ 
++test_prompt_config_SOURCES = \
++    src/tests/cmocka/test_prompt_config.c \
++    src/sss_client/pam_sss_prompt_config.c \
++    $(NULL)
++test_prompt_config_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(POPT_CFLAGS) \
++    $(NULL)
++test_prompt_config_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(POPT_LIBS) \
++    libsss_debug.la \
++    $(TALLOC_LIBS) \
++    $(NULL)
++
+ sss_nss_idmap_tests_SOURCES = \
+     src/tests/cmocka/sss_nss_idmap-tests.c
+ sss_nss_idmap_tests_CFLAGS = \
+@@ -3820,6 +3836,7 @@ endif
+ pamlib_LTLIBRARIES = pam_sss.la
+ pam_sss_la_SOURCES = \
+     src/sss_client/pam_sss.c \
++    src/sss_client/pam_sss_prompt_config.c \
+     src/sss_client/pam_message.c \
+     src/sss_client/common.c \
+     src/sss_client/sss_cli.h \
+diff --git a/src/sss_client/pam_sss_prompt_config.c b/src/sss_client/pam_sss_prompt_config.c
+new file mode 100644
+index 000000000..35094b406
+--- /dev/null
++++ b/src/sss_client/pam_sss_prompt_config.c
+@@ -0,0 +1,547 @@
++/*
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
++
++    You should have received a copy of the GNU Lesser General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "config.h"
++#include <stdlib.h>
++#include <errno.h>
++
++#include "sss_cli.h"
++
++#include <libintl.h>
++#define _(STRING) dgettext (PACKAGE, STRING)
++
++struct prompt_config_password {
++    char *prompt;
++};
++
++struct prompt_config_2fa {
++    char *prompt_1st;
++    char *prompt_2nd;
++};
++
++struct prompt_config_2fa_single {
++    char *prompt;
++};
++
++struct prompt_config_sc_pin {
++    char *prompt; /* Currently not used */
++};
++
++struct prompt_config {
++    enum prompt_config_type type;
++    union {
++        struct prompt_config_password password;
++        struct prompt_config_2fa two_fa;
++        struct prompt_config_2fa_single two_fa_single;
++        struct prompt_config_sc_pin sc_pin;
++    } data;
++};
++
++enum prompt_config_type pc_get_type(struct prompt_config *pc)
++{
++    if (pc != NULL && pc->type > PC_TYPE_INVALID && pc->type < PC_TYPE_LAST) {
++        return pc->type;
++    }
++    return PC_TYPE_INVALID;
++}
++
++const char *pc_get_password_prompt(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_PASSWORD) {
++        return pc->data.password.prompt;
++    }
++    return NULL;
++}
++
++const char *pc_get_2fa_1st_prompt(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_2FA) {
++        return pc->data.two_fa.prompt_1st;
++    }
++    return NULL;
++}
++
++const char *pc_get_2fa_2nd_prompt(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_2FA) {
++        return pc->data.two_fa.prompt_2nd;
++    }
++    return NULL;
++}
++
++const char *pc_get_2fa_single_prompt(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_2FA_SINGLE) {
++        return pc->data.two_fa_single.prompt;
++    }
++    return NULL;
++}
++
++static void pc_free_password(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_PASSWORD) {
++        free(pc->data.password.prompt);
++    }
++    return;
++}
++
++static void pc_free_2fa(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_2FA) {
++        free(pc->data.two_fa.prompt_1st);
++        free(pc->data.two_fa.prompt_2nd);
++    }
++    return;
++}
++
++static void pc_free_2fa_single(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_2FA_SINGLE) {
++        free(pc->data.two_fa_single.prompt);
++    }
++    return;
++}
++
++static void pc_free_sc_pin(struct prompt_config *pc)
++{
++    if (pc != NULL && pc_get_type(pc) == PC_TYPE_SC_PIN) {
++        free(pc->data.sc_pin.prompt);
++    }
++    return;
++}
++
++void pc_list_free(struct prompt_config **pc_list)
++{
++    size_t c;
++
++    if (pc_list == NULL) {
++        return;
++    }
++
++    for (c = 0; pc_list[c] != NULL; c++) {
++        switch (pc_list[c]->type) {
++        case PC_TYPE_PASSWORD:
++            pc_free_password(pc_list[c]);
++            break;
++        case PC_TYPE_2FA:
++            pc_free_2fa(pc_list[c]);
++            break;
++        case PC_TYPE_2FA_SINGLE:
++            pc_free_2fa_single(pc_list[c]);
++            break;
++        case PC_TYPE_SC_PIN:
++            pc_free_sc_pin(pc_list[c]);
++            break;
++        default:
++            return;
++        }
++        free(pc_list[c]);
++    }
++    free(pc_list);
++}
++
++static errno_t pc_list_add_pc(struct prompt_config ***pc_list,
++                              struct prompt_config *pc)
++{
++    size_t c = 0;
++    struct prompt_config **pcl;
++
++    for (c = 0; *pc_list != NULL && (*pc_list)[c] != NULL; c++); /* just counting */
++
++    pcl = realloc(*pc_list, (c + 2) * sizeof(struct prompt_config *));
++    if (pcl == NULL) {
++        return ENOMEM;
++    }
++    pcl[c] = pc;
++    pcl[c + 1] = NULL;
++
++    *pc_list = pcl;
++
++    return EOK;
++}
++
++#define DEFAULT_PASSWORD_PROMPT _("Password: ")
++#define DEFAULT_2FA_SINGLE_PROMPT _("Password + Token value: ")
++#define DEFAULT_2FA_PROMPT_1ST _("First Factor: ")
++#define DEFAULT_2FA_PROMPT_2ND _("Second Factor: ")
++
++errno_t pc_list_add_password(struct prompt_config ***pc_list,
++                             const char *prompt)
++{
++    struct prompt_config *pc;
++    int ret;
++
++    if (pc_list == NULL) {
++        return EINVAL;
++    }
++
++    pc = calloc(1, sizeof(struct prompt_config));
++    if (pc == NULL) {
++        return ENOMEM;
++    }
++
++    pc->type = PC_TYPE_PASSWORD;
++    pc->data.password.prompt = strdup(prompt != NULL ? prompt
++                                                     : DEFAULT_PASSWORD_PROMPT);
++    if (pc->data.password.prompt == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = pc_list_add_pc(pc_list, pc);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        free(pc->data.password.prompt);
++        free(pc);
++    }
++
++    return ret;
++}
++
++errno_t pc_list_add_2fa(struct prompt_config ***pc_list,
++                        const char *prompt_1st, const char *prompt_2nd)
++{
++    struct prompt_config *pc;
++    int ret;
++
++    if (pc_list == NULL) {
++        return EINVAL;
++    }
++
++    pc = calloc(1, sizeof(struct prompt_config));
++    if (pc == NULL) {
++        return ENOMEM;
++    }
++
++    pc->type = PC_TYPE_2FA;
++    pc->data.two_fa.prompt_1st = strdup(prompt_1st != NULL ? prompt_1st
++                                                   : DEFAULT_2FA_PROMPT_1ST);
++    if (pc->data.two_fa.prompt_1st == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++    pc->data.two_fa.prompt_2nd = strdup(prompt_2nd != NULL ? prompt_2nd
++                                                   : DEFAULT_2FA_PROMPT_2ND);
++    if (pc->data.two_fa.prompt_2nd == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = pc_list_add_pc(pc_list, pc);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        free(pc->data.two_fa.prompt_1st);
++        free(pc->data.two_fa.prompt_2nd);
++        free(pc);
++    }
++
++    return ret;
++}
++
++errno_t pc_list_add_2fa_single(struct prompt_config ***pc_list,
++                               const char *prompt)
++{
++    struct prompt_config *pc;
++    int ret;
++
++    if (pc_list == NULL) {
++        return EINVAL;
++    }
++
++    pc = calloc(1, sizeof(struct prompt_config));
++    if (pc == NULL) {
++        return ENOMEM;
++    }
++
++    pc->type = PC_TYPE_2FA_SINGLE;
++    pc->data.two_fa_single.prompt = strdup(prompt != NULL ? prompt
++                                                   : DEFAULT_2FA_SINGLE_PROMPT);
++    if (pc->data.two_fa_single.prompt == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = pc_list_add_pc(pc_list, pc);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        free(pc->data.two_fa_single.prompt);
++        free(pc);
++    }
++
++    return ret;
++}
++
++errno_t pam_get_response_prompt_config(struct prompt_config **pc_list, int *len,
++                                       uint8_t **data)
++{
++    size_t c;
++    size_t l = 0;
++    uint8_t *d = NULL;
++    uint32_t uint32_val;
++    size_t rp;
++
++    if (pc_list == NULL || *pc_list == NULL) {
++        return ENOENT;
++    }
++
++    l += sizeof(uint32_t);
++    for (c = 0; pc_list[c] != NULL; c++) {
++        l += sizeof(uint32_t);
++        switch (pc_list[c]->type) {
++        case PC_TYPE_PASSWORD:
++            l += sizeof(uint32_t);
++            l += strlen(pc_list[c]->data.password.prompt);
++            break;
++        case PC_TYPE_2FA:
++            l += sizeof(uint32_t);
++            l += strlen(pc_list[c]->data.two_fa.prompt_1st);
++            l += sizeof(uint32_t);
++            l += strlen(pc_list[c]->data.two_fa.prompt_2nd);
++            break;
++        case PC_TYPE_2FA_SINGLE:
++            l += sizeof(uint32_t);
++            l += strlen(pc_list[c]->data.two_fa_single.prompt);
++            break;
++        case PC_TYPE_SC_PIN:
++            break;
++        default:
++            return EINVAL;
++        }
++    }
++
++    d = malloc(l * sizeof(uint8_t));
++    if (d == NULL) {
++        return ENOMEM;
++    }
++
++    rp = 0;
++    uint32_val = c;
++    SAFEALIGN_COPY_UINT32(&d[rp], &uint32_val, &rp);
++
++    for (c = 0; pc_list[c] != NULL; c++) {
++        uint32_val = pc_list[c]->type;
++        SAFEALIGN_COPY_UINT32(&d[rp], &uint32_val, &rp);
++
++        switch (pc_list[c]->type) {
++        case PC_TYPE_PASSWORD:
++            SAFEALIGN_SET_UINT32(&d[rp],
++                                 strlen(pc_list[c]->data.password.prompt), &rp);
++            safealign_memcpy(&d[rp], pc_list[c]->data.password.prompt,
++                             strlen(pc_list[c]->data.password.prompt), &rp);
++            break;
++        case PC_TYPE_2FA:
++            SAFEALIGN_SET_UINT32(&d[rp],
++                                 strlen(pc_list[c]->data.two_fa.prompt_1st),
++                                 &rp);
++            safealign_memcpy(&d[rp], pc_list[c]->data.two_fa.prompt_1st,
++                             strlen(pc_list[c]->data.two_fa.prompt_1st), &rp);
++            SAFEALIGN_SET_UINT32(&d[rp],
++                                 strlen(pc_list[c]->data.two_fa.prompt_2nd),
++                                 &rp);
++            safealign_memcpy(&d[rp], pc_list[c]->data.two_fa.prompt_2nd,
++                             strlen(pc_list[c]->data.two_fa.prompt_2nd), &rp);
++            break;
++        case PC_TYPE_2FA_SINGLE:
++            SAFEALIGN_SET_UINT32(&d[rp],
++                                 strlen(pc_list[c]->data.two_fa_single.prompt),
++                                 &rp);
++            safealign_memcpy(&d[rp], pc_list[c]->data.two_fa_single.prompt,
++                             strlen(pc_list[c]->data.two_fa_single.prompt),
++                             &rp);
++            break;
++        case PC_TYPE_SC_PIN:
++            break;
++        default:
++            free(d);
++            return EINVAL;
++        }
++    }
++
++    if (rp != l) {
++        free(d);
++        return EFAULT;
++    }
++
++    *data = d;
++    *len = l;
++
++    return EOK;
++}
++
++errno_t pc_list_from_response(int size, uint8_t *buf,
++                              struct prompt_config ***pc_list)
++{
++    int ret;
++    uint32_t count;
++    uint32_t type;
++    uint32_t l;
++    size_t rp;
++    size_t c;
++    struct prompt_config **pl = NULL;
++    char *str;
++    char *str2;
++
++    if (buf == NULL || size < 3 * sizeof(uint32_t)) {
++        return EINVAL;
++    }
++
++    rp = 0;
++    SAFEALIGN_COPY_UINT32_CHECK(&count, buf + rp, size, &rp);
++
++    for (c = 0; c < count; c++) {
++        /* Since we already know size < 3 * sizeof(uint32_t) this check should
++         * be safe and without over- or underflow. */
++        if (rp > size - sizeof(uint32_t)) {
++            ret = EINVAL;
++            goto done;
++        }
++        SAFEALIGN_COPY_UINT32(&type, buf + rp, &rp);
++
++        switch (type) {
++        case PC_TYPE_PASSWORD:
++            if (rp > size - sizeof(uint32_t)) {
++                ret = EINVAL;
++                goto done;
++            }
++            SAFEALIGN_COPY_UINT32(&l, buf + rp, &rp);
++
++            if (l > size || rp > size - l) {
++                ret = EINVAL;
++                goto done;
++            }
++            str = strndup((char *) buf + rp, l);
++            if (str == NULL) {
++                ret = ENOMEM;
++                goto done;
++            }
++            rp += l;
++
++            ret = pc_list_add_password(&pl, str);
++            free(str);
++            if (ret != EOK) {
++                goto done;
++            }
++            break;
++        case PC_TYPE_2FA:
++            if (rp > size - sizeof(uint32_t)) {
++                ret = EINVAL;
++                goto done;
++            }
++            SAFEALIGN_COPY_UINT32(&l, buf + rp, &rp);
++
++            if (l > size || rp > size - l) {
++                ret = EINVAL;
++                goto done;
++            }
++            str = strndup((char *) buf + rp, l);
++            if (str == NULL) {
++                ret = ENOMEM;
++                goto done;
++            }
++            rp += l;
++
++            if (rp > size - sizeof(uint32_t)) {
++                free(str);
++                ret = EINVAL;
++                goto done;
++            }
++            SAFEALIGN_COPY_UINT32(&l, buf + rp, &rp);
++
++            if (l > size || rp > size - l) {
++                free(str);
++                ret = EINVAL;
++                goto done;
++            }
++            str2 = strndup((char *) buf + rp, l);
++            if (str2 == NULL) {
++                free(str);
++                ret = ENOMEM;
++                goto done;
++            }
++            rp += l;
++
++            ret = pc_list_add_2fa(&pl, str, str2);
++            free(str);
++            free(str2);
++            if (ret != EOK) {
++                goto done;
++            }
++            break;
++        case PC_TYPE_2FA_SINGLE:
++            if (rp > size - sizeof(uint32_t)) {
++                ret = EINVAL;
++                goto done;
++            }
++            SAFEALIGN_COPY_UINT32(&l, buf + rp, &rp);
++
++            if (l > size || rp > size - l) {
++                ret = EINVAL;
++                goto done;
++            }
++            str = strndup((char *) buf + rp, l);
++            if (str == NULL) {
++                ret = ENOMEM;
++                goto done;
++            }
++            rp += l;
++
++            ret = pc_list_add_2fa_single(&pl, str);
++            free(str);
++            if (ret != EOK) {
++                goto done;
++            }
++            break;
++        case PC_TYPE_SC_PIN:
++            break;
++        default:
++            ret = EINVAL;
++            goto done;
++        }
++    }
++
++    *pc_list = pl;
++
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        pc_list_free(pl);
++    }
++
++    return ret;
++}
+diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
+index 24d28ed4b..7e748c281 100644
+--- a/src/sss_client/sss_cli.h
++++ b/src/sss_client/sss_cli.h
+@@ -561,6 +561,35 @@ enum user_info_type {
+  * @}
+  */ /* end of group sss_pam_cli */
+ 
++
++enum prompt_config_type {
++    PC_TYPE_INVALID = 0,
++    PC_TYPE_PASSWORD,
++    PC_TYPE_2FA,
++    PC_TYPE_2FA_SINGLE,
++    PC_TYPE_SC_PIN,
++    PC_TYPE_LAST
++};
++
++struct prompt_config;
++
++enum prompt_config_type pc_get_type(struct prompt_config *pc);
++const char *pc_get_password_prompt(struct prompt_config *pc);
++const char *pc_get_2fa_1st_prompt(struct prompt_config *pc);
++const char *pc_get_2fa_2nd_prompt(struct prompt_config *pc);
++const char *pc_get_2fa_single_prompt(struct prompt_config *pc);
++void pc_list_free(struct prompt_config **pc_list);
++errno_t pc_list_add_password(struct prompt_config ***pc_list,
++                             const char *prompt);
++errno_t pc_list_add_2fa(struct prompt_config ***pc_list,
++                        const char *prompt_1st, const char *prompt_2nd);
++errno_t pc_list_add_2fa_single(struct prompt_config ***pc_list,
++                               const char *prompt);
++errno_t pam_get_response_prompt_config(struct prompt_config **pc_list, int *len,
++                                       uint8_t **data);
++errno_t pc_list_from_response(int size, uint8_t *buf,
++                              struct prompt_config ***pc_list);
++
+ enum sss_netgr_rep_type {
+     SSS_NETGR_REP_TRIPLE = 1,
+     SSS_NETGR_REP_GROUP
+diff --git a/src/tests/cmocka/test_prompt_config.c b/src/tests/cmocka/test_prompt_config.c
+new file mode 100644
+index 000000000..0b761ae4c
+--- /dev/null
++++ b/src/tests/cmocka/test_prompt_config.c
+@@ -0,0 +1,215 @@
++/*
++    SSSD
++
++    prompt config - Utilities tests
++
++    Authors:
++        Sumit bose <sbose@redhat.com>
++
++    Copyright (C) 2019 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 <string.h>
++#include <popt.h>
++
++#include "tests/cmocka/common_mock.h"
++
++#include "sss_client/sss_cli.h"
++
++void test_pc_list_add_password(void **state)
++{
++    int ret;
++    struct prompt_config **pc_list = NULL;
++
++    ret = pc_list_add_password(&pc_list, "Hello");
++    assert_int_equal(ret, EOK);
++    assert_non_null(pc_list);
++    assert_non_null(pc_list[0]);
++    assert_int_equal(PC_TYPE_PASSWORD, pc_get_type(pc_list[0]));
++    assert_string_equal("Hello", pc_get_password_prompt(pc_list[0]));
++    assert_null(pc_list[1]);
++
++    ret = pc_list_add_password(&pc_list, "Hello2");
++    assert_int_equal(ret, EOK);
++    assert_non_null(pc_list);
++    assert_non_null(pc_list[0]);
++    assert_int_equal(PC_TYPE_PASSWORD, pc_get_type(pc_list[0]));
++    assert_string_equal("Hello", pc_get_password_prompt(pc_list[0]));
++    assert_non_null(pc_list[1]);
++    assert_int_equal(PC_TYPE_PASSWORD, pc_get_type(pc_list[1]));
++    assert_string_equal("Hello2", pc_get_password_prompt(pc_list[1]));
++    assert_null(pc_list[2]);
++
++    pc_list_free(pc_list);
++}
++
++void test_pc_list_add_2fa_single(void **state)
++{
++    int ret;
++    struct prompt_config **pc_list = NULL;
++
++    ret = pc_list_add_2fa_single(&pc_list, "Hello");
++    assert_int_equal(ret, EOK);
++    assert_non_null(pc_list);
++    assert_non_null(pc_list[0]);
++    assert_int_equal(PC_TYPE_2FA_SINGLE, pc_get_type(pc_list[0]));
++    assert_string_equal("Hello", pc_get_2fa_single_prompt(pc_list[0]));
++    assert_null(pc_list[1]);
++
++    ret = pc_list_add_2fa_single(&pc_list, "Hello2");
++    assert_int_equal(ret, EOK);
++    assert_non_null(pc_list);
++    assert_non_null(pc_list[0]);
++    assert_int_equal(PC_TYPE_2FA_SINGLE, pc_get_type(pc_list[0]));
++    assert_string_equal("Hello", pc_get_2fa_single_prompt(pc_list[0]));
++    assert_non_null(pc_list[1]);
++    assert_int_equal(PC_TYPE_2FA_SINGLE, pc_get_type(pc_list[1]));
++    assert_string_equal("Hello2", pc_get_2fa_single_prompt(pc_list[1]));
++    assert_null(pc_list[2]);
++
++    pc_list_free(pc_list);
++}
++
++void test_pc_list_add_2fa(void **state)
++{
++    int ret;
++    struct prompt_config **pc_list = NULL;
++
++    ret = pc_list_add_2fa(&pc_list, "Hello", "Good Bye");
++    assert_int_equal(ret, EOK);
++    assert_non_null(pc_list);
++    assert_non_null(pc_list[0]);
++    assert_int_equal(PC_TYPE_2FA, pc_get_type(pc_list[0]));
++    assert_string_equal("Hello", pc_get_2fa_1st_prompt(pc_list[0]));
++    assert_string_equal("Good Bye", pc_get_2fa_2nd_prompt(pc_list[0]));
++    assert_null(pc_list[1]);
++
++    pc_list_free(pc_list);
++}
++
++void test_pam_get_response_prompt_config(void **state)
++{
++    int ret;
++    struct prompt_config **pc_list = NULL;
++    int len;
++    uint8_t *data;
++
++    ret = pc_list_add_password(&pc_list, "password");
++    assert_int_equal(ret, EOK);
++
++    ret = pc_list_add_2fa(&pc_list, "first", "second");
++    assert_int_equal(ret, EOK);
++
++    ret = pc_list_add_2fa_single(&pc_list, "single");
++    assert_int_equal(ret, EOK);
++
++    ret = pam_get_response_prompt_config(pc_list, &len, &data);
++    pc_list_free(pc_list);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(len, 57);
++
++#if __BYTE_ORDER == __LITTLE_ENDIAN
++    assert_memory_equal(data, "\3\0\0\0\1\0\0\0\10\0\0\0" "password\2\0\0\0\5\0\0\0" "first\6\0\0\0" "second\3\0\0\0\6\0\0\0" "single", len);
++#else
++    assert_memory_equal(data, "\0\0\0\3\0\0\0\1\0\0\0\10" "password\0\0\0\2\0\0\0\5" "first\0\0\0\6" "second\0\0\0\3\0\0\0\6" "single", len);
++#endif
++
++    free(data);
++}
++
++void test_pc_list_from_response(void **state)
++{
++    int ret;
++    struct prompt_config **pc_list = NULL;
++    int len;
++    uint8_t *data;
++
++    ret = pc_list_add_password(&pc_list, "password");
++    assert_int_equal(ret, EOK);
++
++    ret = pc_list_add_2fa(&pc_list, "first", "second");
++    assert_int_equal(ret, EOK);
++
++    ret = pc_list_add_2fa_single(&pc_list, "single");
++    assert_int_equal(ret, EOK);
++
++    ret = pam_get_response_prompt_config(pc_list, &len, &data);
++    pc_list_free(pc_list);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(len, 57);
++
++    pc_list = NULL;
++
++    ret = pc_list_from_response(len, data, &pc_list);
++    free(data);
++    assert_int_equal(ret, EOK);
++    assert_non_null(pc_list);
++
++    assert_non_null(pc_list[0]);
++    assert_int_equal(PC_TYPE_PASSWORD, pc_get_type(pc_list[0]));
++    assert_string_equal("password", pc_get_password_prompt(pc_list[0]));
++
++    assert_non_null(pc_list[1]);
++    assert_int_equal(PC_TYPE_2FA, pc_get_type(pc_list[1]));
++    assert_string_equal("first", pc_get_2fa_1st_prompt(pc_list[1]));
++    assert_string_equal("second", pc_get_2fa_2nd_prompt(pc_list[1]));
++
++    assert_non_null(pc_list[2]);
++    assert_int_equal(PC_TYPE_2FA_SINGLE, pc_get_type(pc_list[2]));
++    assert_string_equal("single", pc_get_2fa_single_prompt(pc_list[2]));
++
++    assert_null(pc_list[3]);
++
++    pc_list_free(pc_list);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const struct CMUnitTest tests[] = {
++        cmocka_unit_test(test_pc_list_add_password),
++        cmocka_unit_test(test_pc_list_add_2fa_single),
++        cmocka_unit_test(test_pc_list_add_2fa),
++        cmocka_unit_test(test_pam_get_response_prompt_config),
++        cmocka_unit_test(test_pc_list_from_response),
++    };
++
++    /* Set debug level to invalid value so we can decide if -d 0 was used. */
++    debug_level = SSSDBG_INVALID;
++
++    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
++    while((opt = poptGetNextOpt(pc)) != -1) {
++        switch(opt) {
++        default:
++            fprintf(stderr, "\nInvalid option %s: %s\n\n",
++                    poptBadOption(pc, 0), poptStrerror(opt));
++            poptPrintUsage(pc, stderr, 0);
++            return 1;
++        }
++    }
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    return cmocka_run_group_tests(tests, NULL, NULL);
++}
+-- 
+2.19.1
+
diff --git a/SOURCES/0017-authtok-add-dedicated-type-for-2fa-with-single-strin.patch b/SOURCES/0017-authtok-add-dedicated-type-for-2fa-with-single-strin.patch
new file mode 100644
index 0000000..7b685a4
--- /dev/null
+++ b/SOURCES/0017-authtok-add-dedicated-type-for-2fa-with-single-strin.patch
@@ -0,0 +1,324 @@
+From fc57f57b805a5b91348a8355e74ceb4444881729 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 27 Mar 2019 09:04:53 +0100
+Subject: [PATCH 17/21] authtok: add dedicated type for 2fa with single string
+
+Currently the password type is used to send two-factor authentication
+credentials entered in a single string to the backend, This is
+unreliable and only works properly if password authentication is not
+available for the user as well.
+
+To support 2FA credentials in a single string better a new authtok type
+is added.
+
+Related to https://pagure.io/SSSD/sssd/issue/3264
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit ac4b33f765ac322949ac7c2f24985d3b9c178168)
+---
+ src/providers/krb5/krb5_auth.c          |  1 +
+ src/providers/krb5/krb5_child.c         | 13 +++++++
+ src/providers/krb5/krb5_child_handler.c |  4 +++
+ src/responder/pam/pamsrv_cmd.c          |  1 +
+ src/sss_client/sss_cli.h                |  3 ++
+ src/tests/cmocka/test_authtok.c         | 45 +++++++++++++++++++++++++
+ src/util/authtok.c                      | 42 +++++++++++++++++++++++
+ src/util/authtok.h                      | 35 +++++++++++++++++++
+ 8 files changed, 144 insertions(+)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index d40d2afed..9a9250434 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -495,6 +495,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+         case SSS_PAM_CHAUTHTOK:
+             if (authtok_type != SSS_AUTHTOK_TYPE_PASSWORD
+                     && authtok_type != SSS_AUTHTOK_TYPE_2FA
++                    && authtok_type != SSS_AUTHTOK_TYPE_2FA_SINGLE
+                     && authtok_type != SSS_AUTHTOK_TYPE_SC_PIN
+                     && authtok_type != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
+                 /* handle empty password gracefully */
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index a578930a9..a86d9a7ae 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -503,6 +503,15 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx,
+             return ret;
+         }
+ 
++        return tokeninfo_matches_pwd(mem_ctx, ti, pwd, len, out_token, out_pin);
++        break;
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
++        ret = sss_authtok_get_2fa_single(auth_tok, &pwd, &len);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_password failed.\n");
++            return ret;
++        }
++
+         return tokeninfo_matches_pwd(mem_ctx, ti, pwd, len, out_token, out_pin);
+         break;
+     case SSS_AUTHTOK_TYPE_2FA:
+@@ -2091,6 +2100,7 @@ static errno_t tgt_req_child(struct krb5_req *kr)
+     /* No password is needed for pre-auth or if we have 2FA or SC */
+     if (kr->pd->cmd != SSS_PAM_PREAUTH
+             && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_2FA
++            && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_2FA_SINGLE
+             && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
+             && sss_authtok_get_type(kr->pd->authtok)
+                                                 != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
+@@ -2349,6 +2359,9 @@ static errno_t unpack_authtok(struct sss_auth_token *tok,
+     case SSS_AUTHTOK_TYPE_CCFILE:
+         ret = sss_authtok_set_ccfile(tok, (char *)(buf + *p), 0);
+         break;
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
++        ret = sss_authtok_set_2fa_single(tok, (char *)(buf + *p), 0);
++        break;
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
+diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
+index 352ff980d..b7fb54499 100644
+--- a/src/providers/krb5/krb5_child_handler.c
++++ b/src/providers/krb5/krb5_child_handler.c
+@@ -79,6 +79,10 @@ static errno_t pack_authtok(struct io_buffer *buf, size_t *rp,
+         ret = sss_authtok_get_ccfile(tok, &data, &len);
+         auth_token_length = len + 1;
+         break;
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
++        ret = sss_authtok_get_2fa_single(tok, &data, &len);
++        auth_token_length = len + 1;
++        break;
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 94867a0fe..6f3a7e56b 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -160,6 +160,7 @@ static int extract_authtok_v2(struct sss_auth_token *tok,
+         }
+         break;
+     case SSS_AUTHTOK_TYPE_2FA:
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
+         ret = sss_authtok_set(tok, auth_token_type,
+diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
+index 7e748c281..23ef21608 100644
+--- a/src/sss_client/sss_cli.h
++++ b/src/sss_client/sss_cli.h
+@@ -340,6 +340,9 @@ enum sss_authtok_type {
+                                           * Smart Card authentication is used
+                                           * and that the PIN will be entered
+                                           * at the card reader. */
++    SSS_AUTHTOK_TYPE_2FA_SINGLE = 0x0006, /**< Authentication token has two
++                                           * factors in a single string, it may
++                                           * or may no contain a trailing \\0 */
+ };
+ 
+ /**
+diff --git a/src/tests/cmocka/test_authtok.c b/src/tests/cmocka/test_authtok.c
+index 9422f96bc..84e209783 100644
+--- a/src/tests/cmocka/test_authtok.c
++++ b/src/tests/cmocka/test_authtok.c
+@@ -652,6 +652,49 @@ void test_sss_authtok_sc_pin(void **state)
+     assert_int_equal(ret, EFAULT);
+ }
+ 
++/* Test when type has value SSS_AUTHTOK_TYPE_2FA_SINGLE */
++static void test_sss_authtok_2fa_single(void **state)
++{
++    size_t len;
++    errno_t ret;
++    char *data;
++    size_t ret_len;
++    const char *pwd;
++    struct test_state *ts;
++    enum sss_authtok_type type;
++
++    ts = talloc_get_type_abort(*state, struct test_state);
++    data = talloc_strdup(ts, "1stfacto2ndfactor");
++    assert_non_null(data);
++
++    len = strlen(data) + 1;
++    type = SSS_AUTHTOK_TYPE_2FA_SINGLE;
++    ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
++
++    assert_int_equal(ret, EOK);
++    assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
++    assert_int_equal(len, sss_authtok_get_size(ts->authtoken));
++    assert_string_equal(data, sss_authtok_get_data(ts->authtoken));
++
++    ret = sss_authtok_get_2fa_single(ts->authtoken, &pwd, &ret_len);
++
++    assert_int_equal(ret, EOK);
++    assert_string_equal(data, pwd);
++    assert_int_equal(len - 1, ret_len);
++
++    ret = sss_authtok_set_2fa_single(ts->authtoken, data, len);
++    assert_int_equal(ret, EOK);
++
++    ret = sss_authtok_get_2fa_single(ts->authtoken, &pwd, &ret_len);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(data, pwd);
++    assert_int_equal(len - 1, ret_len);
++
++    talloc_free(data);
++    sss_authtok_set_empty(ts->authtoken);
++}
++
++
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -687,6 +730,8 @@ int main(int argc, const char *argv[])
+                                         setup, teardown),
+         cmocka_unit_test_setup_teardown(test_sss_authtok_sc_blobs,
+                                         setup, teardown),
++        cmocka_unit_test_setup_teardown(test_sss_authtok_2fa_single,
++                                        setup, teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can decide if -d 0 was used. */
+diff --git a/src/util/authtok.c b/src/util/authtok.c
+index c2f78be32..0cac24598 100644
+--- a/src/util/authtok.c
++++ b/src/util/authtok.c
+@@ -41,6 +41,7 @@ size_t sss_authtok_get_size(struct sss_auth_token *tok)
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
+         return tok->length;
+     case SSS_AUTHTOK_TYPE_EMPTY:
+         return 0;
+@@ -76,6 +77,7 @@ errno_t sss_authtok_get_password(struct sss_auth_token *tok,
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
+         return EACCES;
+     }
+ 
+@@ -101,6 +103,33 @@ errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok,
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
++        return EACCES;
++    }
++
++    return EINVAL;
++}
++
++errno_t sss_authtok_get_2fa_single(struct sss_auth_token *tok,
++                                   const char **str, size_t *len)
++{
++    if (!tok) {
++        return EINVAL;
++    }
++    switch (tok->type) {
++    case SSS_AUTHTOK_TYPE_EMPTY:
++        return ENOENT;
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
++        *str = (const char *)tok->data;
++        if (len) {
++            *len = tok->length - 1;
++        }
++        return EOK;
++    case SSS_AUTHTOK_TYPE_PASSWORD:
++    case SSS_AUTHTOK_TYPE_2FA:
++    case SSS_AUTHTOK_TYPE_SC_PIN:
++    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
++    case SSS_AUTHTOK_TYPE_CCFILE:
+         return EACCES;
+     }
+ 
+@@ -151,6 +180,7 @@ void sss_authtok_set_empty(struct sss_auth_token *tok)
+     case SSS_AUTHTOK_TYPE_PASSWORD:
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_PIN:
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
+         safezero(tok->data, tok->length);
+         break;
+     case SSS_AUTHTOK_TYPE_CCFILE:
+@@ -181,6 +211,15 @@ errno_t sss_authtok_set_ccfile(struct sss_auth_token *tok,
+                                   "ccfile", ccfile, len);
+ }
+ 
++errno_t sss_authtok_set_2fa_single(struct sss_auth_token *tok,
++                                   const char *str, size_t len)
++{
++    sss_authtok_set_empty(tok);
++
++    return sss_authtok_set_string(tok, SSS_AUTHTOK_TYPE_2FA_SINGLE,
++                                  "2fa_single", str, len);
++}
++
+ static errno_t sss_authtok_set_2fa_from_blob(struct sss_auth_token *tok,
+                                              const uint8_t *data, size_t len);
+ 
+@@ -199,6 +238,8 @@ errno_t sss_authtok_set(struct sss_auth_token *tok,
+         return sss_authtok_set_sc_from_blob(tok, data, len);
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
+         return sss_authtok_set_sc_from_blob(tok, data, len);
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
++        return sss_authtok_set_2fa_single(tok, (const char *) data, len);
+     case SSS_AUTHTOK_TYPE_EMPTY:
+         sss_authtok_set_empty(tok);
+         return EOK;
+@@ -566,6 +607,7 @@ errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **_pin,
+     case SSS_AUTHTOK_TYPE_CCFILE:
+     case SSS_AUTHTOK_TYPE_2FA:
+     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
++    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
+         return EACCES;
+     }
+ 
+diff --git a/src/util/authtok.h b/src/util/authtok.h
+index a55e89fd2..dae3ff6b1 100644
+--- a/src/util/authtok.h
++++ b/src/util/authtok.h
+@@ -348,4 +348,39 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok,
+                            const char **_token_name, size_t *_token_name_len,
+                            const char **_module_name, size_t *_module_name_len,
+                            const char **_key_id, size_t *_key_id_len);
++
++
++/**
++ * @brief Returns a const string if the auth token is of type
++          SSS_AUTHTOK_TYPE_2FA_SINGLE, otherwise it returns an error
++ *
++ * @param tok    A pointer to an sss_auth_token
++ * @param pwd    A pointer to a const char *, that will point to a null
++ *               terminated string
++ * @param len    The length of the credential string
++ *
++ * @return       EOK on success
++ *               ENOENT if the token is empty
++ *               EACCESS if the token is not a password token
++ */
++errno_t sss_authtok_get_2fa_single(struct sss_auth_token *tok,
++                                   const char **str, size_t *len);
++
++/**
++ * @brief Set a 2FA credentials in a single strings  into an auth token,
++ *        replacing any previous data
++ *
++ * @param tok        A pointer to an sss_auth_token structure to change, also
++ *                   used as a memory context to allocate the internal data.
++ * @param password   A string where the two authentication factors are
++ *                   concatenated together
++ * @param len        The length of the string or, if 0 is passed,
++ *                   then strlen(password) will be used internally.
++ *
++ * @return       EOK on success
++ *               ENOMEM on error
++ */
++errno_t sss_authtok_set_2fa_single(struct sss_auth_token *tok,
++                                   const char *str, size_t len);
++
+ #endif /*  __AUTHTOK_H__ */
+-- 
+2.19.1
+
diff --git a/SOURCES/0018-pam_sss-use-configured-prompting.patch b/SOURCES/0018-pam_sss-use-configured-prompting.patch
new file mode 100644
index 0000000..b2237e9
--- /dev/null
+++ b/SOURCES/0018-pam_sss-use-configured-prompting.patch
@@ -0,0 +1,232 @@
+From 6b7ce87976ebba7b3c1aea24dbf91486ec5de2ed Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 27 Mar 2019 09:48:42 +0100
+Subject: [PATCH 18/21] pam_sss: use configured prompting
+
+If the responds of SSSD's PAM responder contains a prompt_config
+structure use the content to prompt the user for credentials.
+
+Related to https://pagure.io/SSSD/sssd/issue/3264
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked with fixes from commit fc26b4a82d4a92b29cf321fba8dbec52c3bff8d6)
+---
+ src/sss_client/pam_message.h |   2 +
+ src/sss_client/pam_sss.c     | 136 +++++++++++++++++++++++++++++------
+ src/sss_client/sss_cli.h     |   3 +
+ 3 files changed, 119 insertions(+), 22 deletions(-)
+
+diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
+index 11526a80a..c87162479 100644
+--- a/src/sss_client/pam_message.h
++++ b/src/sss_client/pam_message.h
+@@ -64,6 +64,8 @@ struct pam_items {
+     bool user_name_hint;
+     struct cert_auth_info *cert_list;
+     struct cert_auth_info *selected_cert;
++
++    struct prompt_config **pc;
+ };
+ 
+ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer);
+diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
+index 59081cc67..ab9b7478e 100644
+--- a/src/sss_client/pam_sss.c
++++ b/src/sss_client/pam_sss.c
+@@ -205,6 +205,9 @@ static void overwrite_and_free_pam_items(struct pam_items *pi)
+     free_cert_list(pi->cert_list);
+     pi->cert_list = NULL;
+     pi->selected_cert = NULL;
++
++    pc_list_free(pi->pc);
++    pi->pc = NULL;
+ }
+ 
+ static int null_strcmp(const char *s1, const char *s2) {
+@@ -1163,6 +1166,16 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
+                 D(("Password prompting available."));
+                 pi->password_prompting = true;
+                 break;
++            case SSS_PAM_PROMPT_CONFIG:
++                if (pi->pc == NULL) {
++                    ret = pc_list_from_response(len, &buf[p], &pi->pc);
++                    if (ret != EOK) {
++                        D(("Failed to parse prompting data, using defaults"));
++                        pc_list_free(pi->pc);
++                        pi->pc = NULL;
++                    }
++                }
++                break;
+             default:
+                 D(("Unknown response type [%d]", type));
+         }
+@@ -1256,6 +1269,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
+     pi->cert_list = NULL;
+     pi->selected_cert = NULL;
+ 
++    pi->pc = NULL;
++
+     return PAM_SUCCESS;
+ }
+ 
+@@ -1558,6 +1573,37 @@ done:
+     return ret;
+ }
+ 
++static int prompt_2fa_single(pam_handle_t *pamh, struct pam_items *pi,
++                             const char *prompt)
++{
++    int ret;
++    char *answer = NULL;
++
++    ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
++    if (ret != PAM_SUCCESS) {
++        D(("do_pam_conversation failed."));
++        return ret;
++    }
++
++    if (answer == NULL) {
++        pi->pam_authtok = NULL;
++        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
++        pi->pam_authtok_size=0;
++    } else {
++        pi->pam_authtok = strdup(answer);
++        _pam_overwrite((void *)answer);
++        free(answer);
++        answer=NULL;
++        if (pi->pam_authtok == NULL) {
++            return PAM_BUF_ERR;
++        }
++        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_2FA_SINGLE;
++        pi->pam_authtok_size=strlen(pi->pam_authtok);
++    }
++
++    return PAM_SUCCESS;
++}
++
+ #define SC_PROMPT_FMT "PIN for %s"
+ 
+ #ifndef discard_const
+@@ -2014,6 +2060,48 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
+     return;
+ }
+ 
++static int prompt_by_config(pam_handle_t *pamh, struct pam_items *pi)
++{
++    size_t c;
++    int ret;
++
++    if (pi->pc == NULL || *pi->pc == NULL) {
++        return EINVAL;
++    }
++
++    for (c = 0; pi->pc[c] != NULL; c++) {
++        switch (pc_get_type(pi->pc[c])) {
++        case PC_TYPE_PASSWORD:
++            ret = prompt_password(pamh, pi, pc_get_password_prompt(pi->pc[c]));
++            break;
++        case PC_TYPE_2FA:
++            ret = prompt_2fa(pamh, pi, pc_get_2fa_1st_prompt(pi->pc[c]),
++                             pc_get_2fa_2nd_prompt(pi->pc[c]));
++            break;
++        case PC_TYPE_2FA_SINGLE:
++            ret = prompt_2fa_single(pamh, pi,
++                                    pc_get_2fa_single_prompt(pi->pc[c]));
++            break;
++        case PC_TYPE_SC_PIN:
++            ret = prompt_sc_pin(pamh, pi);
++            /* Todo: add extra string option */
++            break;
++        default:
++            ret = EINVAL;
++        }
++
++        /* If not credential where given try the next type otherwise we are
++         * done. */
++        if (ret == PAM_SUCCESS && pi->pam_authtok_size == 0) {
++            continue;
++        }
++
++        break;
++    }
++
++    return ret;
++}
++
+ static int get_authtok_for_authentication(pam_handle_t *pamh,
+                                           struct pam_items *pi,
+                                           uint32_t flags)
+@@ -2032,30 +2120,34 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
+         }
+         pi->pam_authtok_size = strlen(pi->pam_authtok);
+     } else {
+-        if (flags & FLAGS_USE_2FA
+-                || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
+-                        && pi->otp_challenge != NULL)) {
+-            if (pi->password_prompting) {
+-                ret = prompt_2fa(pamh, pi, _("First Factor: "),
+-                                 _("Second Factor (optional): "));
+-            } else {
+-                ret = prompt_2fa(pamh, pi, _("First Factor: "),
+-                                 _("Second Factor: "));
+-            }
+-        } else if (pi->cert_list != NULL) {
+-            if (pi->cert_list->next == NULL) {
+-                /* Only one certificate */
+-                pi->selected_cert = pi->cert_list;
+-            } else {
+-                ret = prompt_multi_cert(pamh, pi);
+-                if (ret != 0) {
+-                    D(("Failed to select certificate"));
+-                    return PAM_AUTHTOK_ERR;
++        if (pi->pc != NULL) {
++            ret = prompt_by_config(pamh, pi);
++        } else {
++            if (flags & FLAGS_USE_2FA
++                    || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
++                            && pi->otp_challenge != NULL)) {
++                if (pi->password_prompting) {
++                    ret = prompt_2fa(pamh, pi, _("First Factor: "),
++                                     _("Second Factor (optional): "));
++                } else {
++                    ret = prompt_2fa(pamh, pi, _("First Factor: "),
++                                     _("Second Factor: "));
+                 }
++            } else if (pi->cert_list != NULL) {
++                if (pi->cert_list->next == NULL) {
++                    /* Only one certificate */
++                    pi->selected_cert = pi->cert_list;
++                } else {
++                    ret = prompt_multi_cert(pamh, pi);
++                    if (ret != 0) {
++                        D(("Failed to select certificate"));
++                        return PAM_AUTHTOK_ERR;
++                    }
++                }
++                ret = prompt_sc_pin(pamh, pi);
++            } else {
++                ret = prompt_password(pamh, pi, _("Password: "));
+             }
+-            ret = prompt_sc_pin(pamh, pi);
+-        } else {
+-            ret = prompt_password(pamh, pi, _("Password: "));
+         }
+         if (ret != PAM_SUCCESS) {
+             D(("failed to get password from user"));
+diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
+index 23ef21608..24b24a91b 100644
+--- a/src/sss_client/sss_cli.h
++++ b/src/sss_client/sss_cli.h
+@@ -469,6 +469,9 @@ enum response_type {
+     SSS_PAM_CERT_INFO_WITH_HINT, /**< Same as SSS_PAM_CERT_INFO but user name
+                                   * might be missing and should be prompted
+                                   * for. */
++    SSS_PAM_PROMPT_CONFIG, /**< Contains data which controls which credentials
++                            * are expected and how the user is prompted for
++                            * them. */
+ };
+ 
+ /**
+-- 
+2.19.1
+
diff --git a/SOURCES/0019-PAM-add-initial-prompting-configuration.patch b/SOURCES/0019-PAM-add-initial-prompting-configuration.patch
new file mode 100644
index 0000000..7c65b56
--- /dev/null
+++ b/SOURCES/0019-PAM-add-initial-prompting-configuration.patch
@@ -0,0 +1,511 @@
+From 45580b2c90d7c19f1d8df57ce7b3e9f3e0acc244 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 27 Mar 2019 21:05:06 +0100
+Subject: [PATCH 19/21] PAM: add initial prompting configuration
+
+Add new section for sssd.conf to allow more flexible prompting during
+authentication.
+
+Related to https://pagure.io/SSSD/sssd/issue/3264
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked with fixes from commit a4d178593bec65a4c7534b841cedfbb74c56f49f)
+---
+ Makefile.am                              |   7 +
+ src/confdb/confdb.h                      |  10 +
+ src/man/sssd.conf.5.xml                  |  66 ++++++
+ src/responder/pam/pam_prompting_config.c | 275 +++++++++++++++++++++++
+ src/responder/pam/pamsrv.c               |  16 +-
+ src/responder/pam/pamsrv.h               |   6 +
+ src/responder/pam/pamsrv_cmd.c           |   8 +
+ 7 files changed, 387 insertions(+), 1 deletion(-)
+ create mode 100644 src/responder/pam/pam_prompting_config.c
+
+diff --git a/Makefile.am b/Makefile.am
+index f7f55e96a..e22423071 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1397,8 +1397,13 @@ sssd_pam_SOURCES = \
+     src/responder/pam/pamsrv_cmd.c \
+     src/responder/pam/pamsrv_p11.c \
+     src/responder/pam/pamsrv_dp.c \
++    src/responder/pam/pam_prompting_config.c \
++    src/sss_client/pam_sss_prompt_config.c \
+     src/responder/pam/pam_helpers.c \
+     $(SSSD_RESPONDER_OBJ)
++sssd_pam_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(NULL)
+ sssd_pam_LDADD = \
+     $(LIBADD_DL) \
+     $(TDB_LIBS) \
+@@ -2446,6 +2451,8 @@ pam_srv_tests_SOURCES = \
+     src/responder/pam/pam_helpers.c \
+     src/responder/pam/pamsrv_dp.c \
+     src/responder/pam/pam_LOCAL_domain.c \
++    src/responder/pam/pam_prompting_config.c \
++    src/sss_client/pam_sss_prompt_config.c \
+     $(NULL)
+ pam_srv_tests_CFLAGS = \
+     -U SSSD_LIBEXEC_PATH -DSSSD_LIBEXEC_PATH=\"$(abs_builddir)\" \
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index e8091fcd9..0251ab606 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -266,6 +266,16 @@
+ #define CONFDB_KCM_SOCKET "socket_path"
+ #define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
+ 
++/* Prompting */
++#define CONFDB_PC_CONF_ENTRY "config/prompting"
++#define CONFDB_PC_TYPE_PASSWORD "password"
++#define CONFDB_PC_PASSWORD_PROMPT "password_prompt"
++#define CONFDB_PC_TYPE_2FA "2fa"
++#define CONFDB_PC_2FA_SINGLE_PROMPT "single_prompt"
++#define CONFDB_PC_2FA_1ST_PROMPT "first_prompt"
++#define CONFDB_PC_2FA_2ND_PROMPT "second_prompt"
++#define CONFDB_PC_TYPE_CERT_AUTH "cert_auth"
++
+ struct confdb_ctx;
+ struct config_file_ctx;
+ 
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 3d017f638..274809e24 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -3364,6 +3364,72 @@ ldap_user_extra_attrs = phone:telephoneNumber
+         </para>
+     </refsect1>
+ 
++    <refsect1 id='prompting_configuration'>
++        <title>PROMPTING CONFIGURATION SECTION</title>
++        <para>
++            If a special file
++            (<filename>/var/lib/sss/pubconf/pam_preauth_available</filename>)
++            exists SSSD's PAM module pam_sss will ask SSSD to figure out which
++            authentication methods are available for the user trying to log in.
++            Based on the results pam_sss will prompt the user for appropriate
++            credentials.
++        </para>
++        <para>
++            With the growing number of authentication methods and the
++            possibility that there are multiple ones for a single user the
++            heuristic used by pam_sss to select the prompting might not be
++            suitable for all use cases. To following options should provide a
++            better flexibility here.
++        </para>
++        <para>
++            Each supported authentication method has it's own configuration
++            sub-section under <quote>[prompting/...]</quote>. Currently there
++            are:
++        <variablelist>
++            <varlistentry>
++                <term>[prompting/password]</term>
++                <listitem>
++                    <para>to configure password prompting, allowed options are:
++                    <variablelist><varlistentry><term>password_prompt</term>
++                        <listitem><para>to change the string of the password
++                        prompt</para></listitem></varlistentry></variablelist>
++                    </para>
++                </listitem>
++            </varlistentry>
++        </variablelist>
++        <variablelist>
++            <varlistentry>
++                <term>[prompting/2fa]</term>
++                <listitem>
++                    <para>to configure two-factor authentication prompting,
++                    allowed options are:
++                    <variablelist><varlistentry><term>first_prompt</term>
++                        <listitem><para>to change the string of the prompt for
++                        the first factor </para></listitem>
++                        </varlistentry>
++                        <varlistentry><term>second_prompt</term>
++                        <listitem><para>to change the string of the prompt for
++                        the second factor </para></listitem>
++                        </varlistentry>
++                        <varlistentry><term>single_prompt</term>
++                        <listitem><para>boolean value, if True there will be
++                        only a single prompt using the value of first_prompt
++                        where it is expected that both factor are entered as a
++                        single string</para></listitem>
++                        </varlistentry>
++                    </variablelist>
++                    </para>
++                </listitem>
++            </varlistentry>
++        </variablelist>
++        </para>
++        <para>
++            It is possible to add a sub-section for specific PAM services like
++            e.g. <quote>[prompting/password/sshd]</quote> to individual change
++            the prompting for this service.
++        </para>
++    </refsect1>
++
+     <refsect1 id='example'>
+         <title>EXAMPLES</title>
+         <para>
+diff --git a/src/responder/pam/pam_prompting_config.c b/src/responder/pam/pam_prompting_config.c
+new file mode 100644
+index 000000000..c3ee41d4b
+--- /dev/null
++++ b/src/responder/pam/pam_prompting_config.c
+@@ -0,0 +1,275 @@
++/*
++   SSSD
++
++   PAM Responder - helpers for PAM prompting configuration
++
++   Copyright (C) Sumit Bose <sbose@redhat.com> 2019
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "util/util.h"
++#include "providers/data_provider.h"
++#include "confdb/confdb.h"
++#include "sss_client/sss_cli.h"
++#include "responder/pam/pamsrv.h"
++
++typedef errno_t (pam_set_prompting_fn_t)(TALLOC_CTX *, struct confdb_ctx *,
++                                         const char *,
++                                         struct prompt_config ***);
++
++
++static errno_t pam_set_password_prompting_options(TALLOC_CTX *tmp_ctx,
++                                                struct confdb_ctx *cdb,
++                                                const char *section,
++                                                struct prompt_config ***pc_list)
++{
++    int ret;
++    char *value = NULL;
++
++    ret = confdb_get_string(cdb, tmp_ctx, section, CONFDB_PC_PASSWORD_PROMPT,
++                            NULL, &value);
++    if (ret == EOK && value != NULL) {
++        ret = pc_list_add_password(pc_list, value);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "pc_list_add_password failed.\n");
++        }
++        return ret;
++    }
++
++    return ENOENT;
++}
++
++static errno_t pam_set_2fa_prompting_options(TALLOC_CTX *tmp_ctx,
++                                             struct confdb_ctx *cdb,
++                                             const char *section,
++                                             struct prompt_config ***pc_list)
++{
++    bool single_2fa_prompt = false;
++    char *first_prompt = NULL;
++    char *second_prompt = NULL;
++    int ret;
++
++
++    ret = confdb_get_bool(cdb, section, CONFDB_PC_2FA_SINGLE_PROMPT, false,
++                          &single_2fa_prompt);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "confdb_get_bool failed, using defaults");
++    }
++    ret = confdb_get_string(cdb, tmp_ctx, section, CONFDB_PC_2FA_1ST_PROMPT,
++                            NULL, &first_prompt);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "confdb_get_string failed, using defaults");
++    }
++
++    if (single_2fa_prompt) {
++        ret = pc_list_add_2fa_single(pc_list, first_prompt);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "pc_list_add_2fa_single failed.\n");
++        }
++        return ret;
++    } else {
++        ret = confdb_get_string(cdb, tmp_ctx, section, CONFDB_PC_2FA_2ND_PROMPT,
++                                NULL, &second_prompt);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "confdb_get_string failed, using defaults");
++        }
++
++        ret = pc_list_add_2fa(pc_list, first_prompt, second_prompt);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "pc_list_add_2fa failed.\n");
++        }
++        return ret;
++    }
++
++    return ENOENT;
++}
++
++static errno_t pam_set_prompting_options(struct confdb_ctx *cdb,
++                                         const char *service_name,
++                                         char **sections,
++                                         int num_sections,
++                                         const char *section_path,
++                                         pam_set_prompting_fn_t *setter,
++                                         struct prompt_config ***pc_list)
++{
++    char *dummy;
++    size_t c;
++    bool global = false;
++    bool specific = false;
++    char *section = NULL;
++    int ret;
++    char *last;
++    TALLOC_CTX *tmp_ctx = NULL;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++
++    dummy = talloc_asprintf(tmp_ctx, "%s/%s", section_path,
++                                              service_name);
++    for (c = 0; c < num_sections; c++) {
++        if (strcmp(sections[c], CONFDB_PC_TYPE_PASSWORD) == 0) {
++            global = true;
++        }
++        if (dummy != NULL && strcmp(sections[c], dummy) == 0) {
++            specific = true;
++        }
++    }
++
++    section = talloc_asprintf(tmp_ctx, "%s/%s", CONFDB_PC_CONF_ENTRY, dummy);
++    if (section == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = ENOENT;
++    if (specific) {
++        ret = setter(tmp_ctx, cdb, section, pc_list);
++    }
++    if (global && ret == ENOENT) {
++        last = strrchr(section, '/');
++        if (last != NULL) {
++            *last = '\0';
++            ret = setter(tmp_ctx, cdb, section, pc_list);
++        }
++    }
++    if (ret != EOK && ret != ENOENT) {
++        DEBUG(SSSDBG_OP_FAILURE, "setter failed.\n");
++        goto done;
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
++errno_t pam_eval_prompting_config(struct pam_ctx *pctx, struct pam_data *pd)
++{
++    int ret;
++    struct response_data *resp;
++    bool password_auth = false;
++    bool otp_auth = false;
++    bool cert_auth = false;
++    struct prompt_config **pc_list = NULL;
++    int resp_len;
++    uint8_t *resp_data = NULL;
++
++    if (pctx->num_prompting_config_sections == 0) {
++        DEBUG(SSSDBG_TRACE_ALL, "No prompting configuration found.\n");
++        return EOK;
++    }
++
++    resp = pd->resp_list;
++    while (resp != NULL) {
++        switch (resp->type) {
++        case SSS_PAM_OTP_INFO:
++            otp_auth = true;
++            break;
++        case SSS_PAM_CERT_INFO:
++            cert_auth = true;
++            break;
++        case SSS_PASSWORD_PROMPTING:
++            password_auth = true;
++            break;
++        case SSS_CERT_AUTH_PROMPTING:
++            /* currently not used */
++            break;
++        default:
++            break;
++        }
++        resp = resp->next;
++    }
++
++    if (!password_auth && !otp_auth && !cert_auth) {
++        /* If the backend cannot determine which authentication types are
++         * available the default would be to prompt for a password. */
++        password_auth = true;
++    }
++
++    DEBUG(SSSDBG_TRACE_ALL, "Authentication types for user [%s] and service "
++                            "[%s]:%s%s%s\n", pd->user, pd->service,
++                            password_auth ? " password": "",
++                            otp_auth ? " two-factor" : "",
++                            cert_auth ? " smartcard" : "");
++
++    if (cert_auth) {
++        /* If certificate based authentication is possilbe, i.e. a Smartcard
++         * or similar with the mapped certificate is available we currently
++         * prefer this authentication type unconditionally. If other types
++         * should be used the Smartcard can be removed during authentication.
++         * Since there currently are no specific options for cert_auth we are
++         * done. */
++        ret = EOK;
++        goto done;
++    }
++
++    /* If OTP and password auth are possible we currently prefer OTP. */
++    if (otp_auth) {
++        ret = pam_set_prompting_options(pctx->rctx->cdb, pd->service,
++                                        pctx->prompting_config_sections,
++                                        pctx->num_prompting_config_sections,
++                                        CONFDB_PC_TYPE_2FA,
++                                        pam_set_2fa_prompting_options,
++                                        &pc_list);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "pam_set_prompting_options failed.\n");
++            goto done;
++        }
++    }
++
++    if (password_auth) {
++        ret = pam_set_prompting_options(pctx->rctx->cdb, pd->service,
++                                        pctx->prompting_config_sections,
++                                        pctx->num_prompting_config_sections,
++                                        CONFDB_PC_TYPE_PASSWORD,
++                                        pam_set_password_prompting_options,
++                                        &pc_list);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "pam_set_prompting_options failed.\n");
++            goto done;
++        }
++    }
++
++    if (pc_list != NULL) {
++        ret = pam_get_response_prompt_config(pc_list, &resp_len, &resp_data);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "pam_get_response_prompt_config failed.\n");
++            goto done;
++        }
++
++        ret = pam_add_response(pd, SSS_PAM_PROMPT_CONFIG, resp_len, resp_data);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "pam_add_response failed.\n");
++            goto done;
++        }
++    }
++
++    ret = EOK;
++done:
++    free(resp_data);
++    pc_list_free(pc_list);
++
++    return ret;
++}
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index 4ddd1d0b3..fb799d28b 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -315,6 +315,16 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
++    /* Check if there is a prompting configuration */
++    pctx->prompting_config_sections = NULL;
++    pctx->num_prompting_config_sections = 0;
++    ret = confdb_get_sub_sections(pctx, pctx->rctx->cdb, CONFDB_PC_CONF_ENTRY,
++                                  &pctx->prompting_config_sections,
++                                  &pctx->num_prompting_config_sections);
++    if (ret != EOK && ret != ENOENT) {
++        DEBUG(SSSDBG_OP_FAILURE, "confdb_get_sub_sections failed, not fatal.\n");
++    }
++
+     /* Check if certificate based authentication is enabled */
+     ret = confdb_get_bool(pctx->rctx->cdb,
+                           CONFDB_PAM_CONF_ENTRY,
+@@ -346,11 +356,15 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+ 
++    }
++
++    if (pctx->cert_auth || pctx->num_prompting_config_sections != 0) {
+         ret = create_preauth_indicator();
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+                   "Failed to create pre-authentication indicator file, "
+-                  "Smartcard authentication might not work as expected.\n");
++                  "Smartcard authentication or configured prompting might "
++                  "not work as expected.\n");
+         }
+     }
+ 
+diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
+index 3325d9b9f..319362a95 100644
+--- a/src/responder/pam/pamsrv.h
++++ b/src/responder/pam/pamsrv.h
+@@ -52,6 +52,9 @@ struct pam_ctx {
+     char *nss_db;
+     struct sss_certmap_ctx *sss_certmap_ctx;
+     char **smartcard_services;
++
++    char **prompting_config_sections;
++    int num_prompting_config_sections;
+ };
+ 
+ struct pam_auth_dp_req {
+@@ -130,4 +133,7 @@ pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+ errno_t filter_responses(struct confdb_ctx *cdb,
+                          struct response_data *resp_list,
+                          struct pam_data *pd);
++
++errno_t pam_eval_prompting_config(struct pam_ctx *pctx, struct pam_data *pd);
++
+ #endif /* __PAMSRV_H__ */
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 6f3a7e56b..6b2dc5bdc 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -1003,6 +1003,14 @@ static void pam_reply(struct pam_auth_req *preq)
+         }
+     }
+ 
++    if (pd->cmd == SSS_PAM_PREAUTH) {
++        ret = pam_eval_prompting_config(pctx, pd);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "Failed to add prompting information, "
++                                     "using defaults.\n");
++        }
++    }
++
+     /*
+      * Export non-overridden shell to tlog-rec-session when opening the session
+      */
+-- 
+2.19.1
+
diff --git a/SOURCES/0020-getsockopt_wrapper-add-support-for-PAM-clients.patch b/SOURCES/0020-getsockopt_wrapper-add-support-for-PAM-clients.patch
new file mode 100644
index 0000000..6e1fd70
--- /dev/null
+++ b/SOURCES/0020-getsockopt_wrapper-add-support-for-PAM-clients.patch
@@ -0,0 +1,80 @@
+From c8d517bacd47f3d5c706a53561924ac20d0b3321 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 7 Sep 2018 22:19:26 +0200
+Subject: [PATCH 20/21] getsockopt_wrapper: add support for PAM clients
+
+PAM clients expect that the private socket of the PAM responder is
+handled by root. With this patch getsockopt_wrapper can return the
+expected UID and GID to PAM clients.
+
+Related to https://pagure.io/SSSD/sssd/issue/3500
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked with fixes from commit d332c8a0e7a4c7f0b3ee1b2110145a23cbd61c2a)
+---
+ src/tests/intg/getsockopt_wrapper.c | 35 +++++++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+diff --git a/src/tests/intg/getsockopt_wrapper.c b/src/tests/intg/getsockopt_wrapper.c
+index 77c832329..eb8fa56dd 100644
+--- a/src/tests/intg/getsockopt_wrapper.c
++++ b/src/tests/intg/getsockopt_wrapper.c
+@@ -9,6 +9,7 @@
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <dlfcn.h>
++#include <stdlib.h>
+ 
+ static bool is_dbus_socket(int fd)
+ {
+@@ -27,6 +28,38 @@ static bool is_dbus_socket(int fd)
+     return NULL != strstr(unix_socket->sun_path, "system_bus_socket");
+ }
+ 
++static bool peer_is_private_pam(int fd)
++{
++    int ret;
++    struct sockaddr_storage addr = { 0 };
++    socklen_t addrlen = sizeof(addr);
++    struct sockaddr_un *unix_socket;
++
++    ret = getpeername(fd, (struct sockaddr *)&addr, &addrlen);
++    if (ret != 0) return false;
++
++    if (addr.ss_family != AF_UNIX) return false;
++
++    unix_socket = (struct sockaddr_un *)&addr;
++
++    return NULL != strstr(unix_socket->sun_path, "private/pam");
++}
++
++static void fake_peer_uid_gid(uid_t *uid, gid_t *gid)
++{
++    char *val;
++
++    val = getenv("SSSD_INTG_PEER_UID");
++    if (val != NULL) {
++        *uid = atoi(val);
++    }
++
++    val = getenv("SSSD_INTG_PEER_GID");
++    if (val != NULL) {
++        *gid = atoi(val);
++    }
++}
++
+ typedef typeof(getsockopt) getsockopt_fn_t;
+ 
+ static getsockopt_fn_t *orig_getsockopt = NULL;
+@@ -52,6 +85,8 @@ int getsockopt(int sockfd, int level, int optname,
+         cr = optval;
+         if (cr->uid != 0 && is_dbus_socket(sockfd)) {
+             cr->uid = 0;
++        } else if (peer_is_private_pam(sockfd)) {
++            fake_peer_uid_gid(&cr->uid, &cr->gid);
+         }
+     }
+ 
+-- 
+2.19.1
+
diff --git a/SOURCES/0021-intg-add-test-for-password-prompt-configuration.patch b/SOURCES/0021-intg-add-test-for-password-prompt-configuration.patch
new file mode 100644
index 0000000..d98cc65
--- /dev/null
+++ b/SOURCES/0021-intg-add-test-for-password-prompt-configuration.patch
@@ -0,0 +1,261 @@
+From abfba08af067f70b736108310c3e55534ef7085e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 29 Mar 2019 10:38:50 +0100
+Subject: [PATCH 21/21] intg: add test for password prompt configuration
+
+Related to Related to https://pagure.io/SSSD/sssd/issue/3264
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked with fixes from commit 45efba71befd96c8e9fe0a51fc300cafa93bd703)
+---
+ src/tests/intg/Makefile.am           |  32 +++++-
+ src/tests/intg/test_pam_responder.py | 154 ++++++++++++++++++++++++++-
+ 2 files changed, 184 insertions(+), 2 deletions(-)
+
+diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
+index 91dc86a4f..884c903b6 100644
+--- a/src/tests/intg/Makefile.am
++++ b/src/tests/intg/Makefile.am
+@@ -105,13 +105,36 @@ passwd: root
+ group:
+ 	echo "root:x:0:" > $@
+ 
++PAM_SERVICE_DIR=pam_service_dir
++pam_sss_service:
++	$(MKDIR_P) $(PAM_SERVICE_DIR)
++	echo "auth     required       $(DESTDIR)$(pammoddir)/pam_sss.so"  > $(PAM_SERVICE_DIR)/$@
++	echo "account  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
++	echo "password required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
++	echo "session  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
++
++pam_sss_alt_service:
++	$(MKDIR_P) $(PAM_SERVICE_DIR)
++	echo "auth     required       $(DESTDIR)$(pammoddir)/pam_sss.so"  > $(PAM_SERVICE_DIR)/$@
++	echo "account  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
++	echo "password required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
++	echo "session  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
++
+ CLEANFILES=config.py config.pyc passwd group
+ 
+ clean-local:
+ 	rm -Rf root
+ 	rm -f $(builddir)/cwrap-dbus-system.conf
+ 
+-intgcheck-installed: config.py passwd group
++if HAVE_NSS
++PAM_CERT_DB_PATH="sql:$(DESTDIR)$(sysconfdir)/pki/nssdb"
++SOFTHSM2_CONF=""
++else
++PAM_CERT_DB_PATH="$(abs_builddir)/../test_CA/SSSD_test_CA.pem"
++SOFTHSM2_CONF="$(abs_builddir)/../test_CA/softhsm2_one.conf"
++endif
++
++intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service
+ 	pipepath="$(DESTDIR)$(pipepath)"; \
+ 	if test $${#pipepath} -gt 80; then \
+ 	    echo "error: Pipe directory path too long," \
+@@ -126,16 +149,23 @@ intgcheck-installed: config.py passwd group
+ 	PATH="$$(dirname -- $(SLAPD)):$$PATH" \
+ 	PATH="$(DESTDIR)$(sbindir):$(DESTDIR)$(bindir):$$PATH" \
+ 	PATH="$$PATH:$(abs_builddir):$(abs_srcdir)" \
++	LANG=C \
+ 	PYTHONPATH="$(abs_builddir):$(abs_srcdir)" \
+ 	LDB_MODULES_PATH="$(DESTDIR)$(ldblibdir)" \
+ 	NON_WRAPPED_UID=$$(id -u) \
+ 	LD_PRELOAD="$(libdir)/getsockopt_wrapper.so:$$nss_wrapper:$$uid_wrapper" \
++	LD_LIBRARY_PATH="$$LD_LIBRARY_PATH:$(DESTDIR)$(nsslibdir)" \
+ 	NSS_WRAPPER_PASSWD="$(abs_builddir)/passwd" \
+ 	NSS_WRAPPER_GROUP="$(abs_builddir)/group" \
+ 	NSS_WRAPPER_MODULE_SO_PATH="$(DESTDIR)$(nsslibdir)/libnss_sss.so.2" \
+ 	NSS_WRAPPER_MODULE_FN_PREFIX="sss" \
+ 	UID_WRAPPER=1 \
+ 	UID_WRAPPER_ROOT=1 \
++	PAM_WRAPPER=0 \
++	PAM_WRAPPER_SERVICE_DIR="$(abs_builddir)/$(PAM_SERVICE_DIR)" \
++	PAM_WRAPPER_PATH=$$(pkg-config --libs pam_wrapper) \
++	PAM_CERT_DB_PATH=$(PAM_CERT_DB_PATH) \
++	SOFTHSM2_CONF=$(SOFTHSM2_CONF) \
+ 	DBUS_SOCK_DIR="$(DESTDIR)$(runstatedir)/dbus/" \
+ 	DBUS_SESSION_BUS_ADDRESS="unix:path=$$DBUS_SOCK_DIR/fake_socket" \
+ 	DBUS_SYSTEM_BUS_ADDRESS="unix:path=$$DBUS_SOCK_DIR/system_bus_socket" \
+diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
+index cf6fff2db..7e5828dde 100644
+--- a/src/tests/intg/test_pam_responder.py
++++ b/src/tests/intg/test_pam_responder.py
+@@ -30,9 +30,84 @@ import time
+ import pytest
+ 
+ import config
+-
++import shutil
+ from util import unindent
+ 
++import intg.ds_openldap
++
++import pytest
++
++from intg.util import unindent
++from intg.files_ops import passwd_ops_setup
++
++LDAP_BASE_DN = "dc=example,dc=com"
++
++
++@pytest.fixture(scope="module")
++def ad_inst(request):
++    """Fake AD server instance fixture"""
++    instance = intg.ds_openldap.FakeAD(
++        config.PREFIX, 10389, LDAP_BASE_DN,
++        "cn=admin", "Secret123"
++    )
++
++    try:
++        instance.setup()
++    except:
++        instance.teardown()
++        raise
++    request.addfinalizer(instance.teardown)
++    return instance
++
++
++@pytest.fixture(scope="module")
++def ldap_conn(request, ad_inst):
++    """LDAP server connection fixture"""
++    ldap_conn = ad_inst.bind()
++    ldap_conn.ad_inst = ad_inst
++    request.addfinalizer(ldap_conn.unbind_s)
++    return ldap_conn
++
++
++def format_basic_conf(ldap_conn):
++    """Format a basic SSSD configuration"""
++    return unindent("""\
++        [sssd]
++        domains = FakeAD
++        services = pam, nss
++
++        [nss]
++
++        [pam]
++        debug_level = 10
++
++        [domain/FakeAD]
++        debug_level = 10
++        ldap_search_base = {ldap_conn.ad_inst.base_dn}
++        ldap_referrals = false
++
++        id_provider = ldap
++        auth_provider = ldap
++        chpass_provider = ldap
++        access_provider = ldap
++
++        ldap_uri = {ldap_conn.ad_inst.ldap_url}
++        ldap_default_bind_dn = {ldap_conn.ad_inst.admin_dn}
++        ldap_default_authtok_type = password
++        ldap_default_authtok = {ldap_conn.ad_inst.admin_pw}
++
++        ldap_schema = ad
++        ldap_id_mapping = true
++        ldap_idmap_default_domain_sid = S-1-5-21-1305200397-2901131868-73388776
++        case_sensitive = False
++
++        [prompting/password]
++        password_prompt = My global prompt
++
++        [prompting/password/pam_sss_alt_service]
++        password_prompt = My alt service prompt
++    """).format(**locals())
++
+ 
+ def format_pam_cert_auth_conf():
+     """Format a basic SSSD configuration"""
+@@ -79,6 +154,8 @@ def create_conf_fixture(request, contents):
+ 
+ def create_sssd_process():
+     """Start the SSSD process"""
++    os.environ["SSS_FILES_PASSWD"] = os.environ["NSS_WRAPPER_PASSWD"]
++    os.environ["SSS_FILES_GROUP"] = os.environ["NSS_WRAPPER_GROUP"]
+     if subprocess.call(["sssd", "-D", "-f"]) != 0:
+         raise Exception("sssd start failed")
+ 
+@@ -129,3 +206,78 @@ def test_preauth_indicator(simple_pam_cert_auth):
+     """Check if preauth indicator file is created"""
+     statinfo = os.stat(config.PUBCONF_PATH + "/pam_preauth_available")
+     assert stat.S_ISREG(statinfo.st_mode)
++
++
++@pytest.fixture
++def pam_prompting_config(request, ldap_conn):
++    """Setup SSSD with PAM prompting config"""
++    conf = format_basic_conf(ldap_conn)
++    create_conf_fixture(request, conf)
++    create_sssd_fixture(request)
++    return None
++
++
++def test_password_prompting_config_global(ldap_conn, pam_prompting_config,
++                                          env_for_sssctl):
++    """Check global change of the password prompt"""
++
++    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1_dom1-19661",
++                               "--action=auth", "--service=pam_sss_service"],
++                              universal_newlines=True,
++                              env=env_for_sssctl, stdin=subprocess.PIPE,
++                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
++
++    try:
++        out, err = sssctl.communicate(input="111")
++    except:
++        sssctl.kill()
++        out, err = sssctl.communicate()
++
++    sssctl.stdin.close()
++    sssctl.stdout.close()
++
++    if sssctl.wait() != 0:
++        raise Exception("sssctl failed")
++
++    assert err.find("My global prompt") != -1
++
++
++def test_password_prompting_config_srv(ldap_conn, pam_prompting_config,
++                                       env_for_sssctl):
++    """Check change of the password prompt for dedicated service"""
++
++    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1_dom1-19661",
++                               "--action=auth",
++                               "--service=pam_sss_alt_service"],
++                              universal_newlines=True,
++                              env=env_for_sssctl, stdin=subprocess.PIPE,
++                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
++
++    try:
++        out, err = sssctl.communicate(input="111")
++    except:
++        sssctl.kill()
++        out, err = sssctl.communicate()
++
++    sssctl.stdin.close()
++    sssctl.stdout.close()
++
++    if sssctl.wait() != 0:
++        raise Exception("sssctl failed")
++
++    assert err.find("My alt service prompt") != -1
++
++
++@pytest.fixture
++def env_for_sssctl(request):
++    pwrap_runtimedir = os.getenv("PAM_WRAPPER_SERVICE_DIR")
++    if pwrap_runtimedir is None:
++        raise ValueError("The PAM_WRAPPER_SERVICE_DIR variable is unset\n")
++
++    env_for_sssctl = os.environ.copy()
++    env_for_sssctl['PAM_WRAPPER'] = "1"
++    env_for_sssctl['SSSD_INTG_PEER_UID'] = "0"
++    env_for_sssctl['SSSD_INTG_PEER_GID'] = "0"
++    env_for_sssctl['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
++
++    return env_for_sssctl
+-- 
+2.19.1
+
diff --git a/SOURCES/0022-krb5-Write-multiple-dnsnames-into-kdc-info-file.patch b/SOURCES/0022-krb5-Write-multiple-dnsnames-into-kdc-info-file.patch
new file mode 100644
index 0000000..3a2fcf6
--- /dev/null
+++ b/SOURCES/0022-krb5-Write-multiple-dnsnames-into-kdc-info-file.patch
@@ -0,0 +1,432 @@
+From f61c92c399531a5530dbb57a36b4e0db46c72b5b Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Wed, 13 Mar 2019 08:37:36 +0100
+Subject: [PATCH 22/23] krb5: Write multiple dnsnames into kdc info file
+
+Multiple servers should be written to kdc info file. In
+this PR we iterate trough server list and we write
+list of primary servers followed by backup servers.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3974
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 208a79a83c76b6693bdf927c3d7d6267e3218b0b)
+---
+ src/providers/ad/ad_common.c       |  39 +++++----
+ src/providers/fail_over.c          |  27 ++++++
+ src/providers/fail_over.h          |   9 ++
+ src/providers/ipa/ipa_common.c     |  25 +-----
+ src/providers/ipa/ipa_subdomains.c |   4 +-
+ src/providers/krb5/krb5_common.c   | 131 ++++++++++++++++++++---------
+ src/providers/krb5/krb5_common.h   |   7 +-
+ 7 files changed, 158 insertions(+), 84 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index 0d154ca57..b7f34daa9 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -24,6 +24,7 @@
+ #include "providers/ad/ad_common.h"
+ #include "providers/ad/ad_opts.h"
+ #include "providers/be_dyndns.h"
++#include "providers/fail_over.h"
+ 
+ struct ad_server_data {
+     bool gc;
+@@ -839,6 +840,20 @@ done:
+     return ret;
+ }
+ 
++static bool
++ad_krb5info_file_filter(struct fo_server *server)
++{
++    struct ad_server_data *sdata = NULL;
++    if (server == NULL) return true;
++
++    sdata = fo_get_server_user_data(server);
++    if (sdata && sdata->gc) {
++        /* Only write kdcinfo files for local servers */
++        return true;
++    }
++    return false;
++}
++
+ static void
+ ad_resolve_callback(void *private_data, struct fo_server *server)
+ {
+@@ -848,7 +863,6 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
+     struct resolv_hostent *srvaddr;
+     struct sockaddr_storage *sockaddr;
+     char *address;
+-    char *safe_addr_list[2] = { NULL, NULL };
+     char *new_uri;
+     int new_port;
+     const char *srv_name;
+@@ -953,25 +967,14 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
+         goto done;
+     }
+ 
+-    /* Only write kdcinfo files for local servers */
+-    if ((sdata == NULL || sdata->gc == false) &&
+-        service->krb5_service->write_kdcinfo) {
+-        /* Write krb5 info files */
+-        safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
+-                                                  srvaddr->family,
+-                                                  address);
+-        if (safe_addr_list[0] == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
+-            ret = ENOMEM;
+-            goto done;
+-        }
+-
+-        ret = write_krb5info_file(service->krb5_service,
+-                                  safe_addr_list,
+-                                  SSS_KRB5KDC_FO_SRV);
++    if (service->krb5_service->write_kdcinfo) {
++        ret = write_krb5info_file_from_fo_server(service->krb5_service,
++                                                 server,
++                                                 SSS_KRB5KDC_FO_SRV,
++                                                 ad_krb5info_file_filter);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+-                "write_krb5info_file failed, authentication might fail.\n");
++                  "write_krb5info_file failed, authentication might fail.\n");
+         }
+     }
+ 
+diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
+index 168e59d6f..dc5c7c7d8 100644
+--- a/src/providers/fail_over.c
++++ b/src/providers/fail_over.c
+@@ -1637,6 +1637,33 @@ fo_get_server_hostname_last_change(struct fo_server *server)
+     return server->common->last_status_change.tv_sec;
+ }
+ 
++struct fo_server *fo_server_first(struct fo_server *server)
++{
++    if (!server) return NULL;
++
++    while (server->prev) { server = server->prev; }
++    return server;
++}
++
++struct fo_server *fo_server_next(struct fo_server *server)
++{
++    if (!server) return NULL;
++
++    return server->next;
++}
++
++size_t fo_server_count(struct fo_server *server)
++{
++    struct fo_server *item = fo_server_first(server);
++    size_t size = 0;
++
++    while (item) {
++        ++size;
++        item = item->next;
++    }
++    return size;
++}
++
+ time_t fo_get_service_retry_timeout(struct fo_service *svc)
+ {
+     if (svc == NULL || svc->ctx == NULL || svc->ctx->opts == NULL) {
+diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
+index d70212fb7..bc8142710 100644
+--- a/src/providers/fail_over.h
++++ b/src/providers/fail_over.h
+@@ -216,6 +216,15 @@ const char **fo_svc_server_list(TALLOC_CTX *mem_ctx,
+                                 struct fo_service *service,
+                                 size_t *_count);
+ 
++/*
++ * Folowing functions allow to iterate trough list of servers.
++ */
++struct fo_server *fo_server_first(struct fo_server *server);
++
++struct fo_server *fo_server_next(struct fo_server *server);
++
++size_t fo_server_count(struct fo_server *server);
++
+ /*
+  * pvt will be talloc_stealed to ctx
+  */
+diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
+index 17d14e6b0..1ed2e2203 100644
+--- a/src/providers/ipa/ipa_common.c
++++ b/src/providers/ipa/ipa_common.c
+@@ -819,8 +819,6 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
+     struct ipa_service *service;
+     struct resolv_hostent *srvaddr;
+     struct sockaddr_storage *sockaddr;
+-    char *address;
+-    char *safe_addr_list[2] = { NULL, NULL };
+     char *new_uri;
+     const char *srv_name;
+     int ret;
+@@ -854,13 +852,6 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
+         return;
+     }
+ 
+-    address = resolv_get_string_address(tmp_ctx, srvaddr);
+-    if (address == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "resolv_get_string_address failed.\n");
+-        talloc_free(tmp_ctx);
+-        return;
+-    }
+-
+     srv_name = fo_get_server_name(server);
+     if (srv_name == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Could not get server host name\n");
+@@ -883,18 +874,10 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
+     service->sdap->sockaddr = talloc_steal(service, sockaddr);
+ 
+     if (service->krb5_service->write_kdcinfo) {
+-        safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
+-                                             srvaddr->family,
+-                                             address);
+-        if (safe_addr_list[0] == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
+-            talloc_free(tmp_ctx);
+-            return;
+-        }
+-
+-        ret = write_krb5info_file(service->krb5_service,
+-                                  safe_addr_list,
+-                                  SSS_KRB5KDC_FO_SRV);
++        ret = write_krb5info_file_from_fo_server(service->krb5_service,
++                                                 server,
++                                                 SSS_KRB5KDC_FO_SRV,
++                                                 NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+                   "write_krb5info_file failed, authentication might fail.\n");
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index d86ca4cc5..da1279e3e 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -2545,7 +2545,7 @@ static errno_t ipa_subdomains_write_kdcinfo_write_step(struct sss_domain_info *d
+     errno_t ret;
+     char *address = NULL;
+     char *safe_address = NULL;
+-    char **safe_addr_list;
++    const char **safe_addr_list;
+     int addr_index = 0;
+     TALLOC_CTX *tmp_ctx = NULL;
+ 
+@@ -2554,7 +2554,7 @@ static errno_t ipa_subdomains_write_kdcinfo_write_step(struct sss_domain_info *d
+         return ENOMEM;
+     }
+ 
+-    safe_addr_list = talloc_zero_array(tmp_ctx, char *, rhp_len+1);
++    safe_addr_list = talloc_zero_array(tmp_ctx, const char *, rhp_len+1);
+     if (safe_addr_list == NULL) {
+         ret = ENOMEM;
+         goto done;
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index 2b003e164..1e33fc0f5 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -33,6 +33,7 @@
+ #include "providers/krb5/krb5_common.h"
+ #include "providers/krb5/krb5_opts.h"
+ #include "providers/krb5/krb5_utils.h"
++#include "providers/fail_over.h"
+ 
+ #ifdef HAVE_KRB5_CC_COLLECTION
+ /* krb5 profile functions */
+@@ -592,7 +593,7 @@ done:
+ }
+ 
+ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+-                            char **server_list,
++                            const char **server_list,
+                             const char *service)
+ {
+     int i;
+@@ -635,73 +636,119 @@ done:
+     return ret;
+ }
+ 
+-static void krb5_resolve_callback(void *private_data, struct fo_server *server)
++static const char* fo_server_address_or_name(TALLOC_CTX *tmp_ctx, struct fo_server *server)
+ {
+-    struct krb5_service *krb5_service;
+     struct resolv_hostent *srvaddr;
+     char *address;
+-    char *safe_addr_list[2] = { NULL, NULL };
+-    int ret;
++
++    if (!server) return NULL;
++
++    srvaddr = fo_get_server_hostent(server);
++    if (srvaddr) {
++        address = resolv_get_string_address(tmp_ctx, srvaddr);
++        if (address) {
++            return sss_escape_ip_address(tmp_ctx,
++                                         srvaddr->family,
++                                         address);
++        }
++    }
++
++    return fo_get_server_name(server);
++}
++
++errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
++                                           struct fo_server *server,
++                                           const char *service,
++                                           bool (*filter)(struct fo_server *))
++{
+     TALLOC_CTX *tmp_ctx = NULL;
++    const char **server_list;
++    size_t server_idx;
++    struct fo_server *item;
++    int primary;
++    const char *address;
++    errno_t ret;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed\n");
+-        return;
++        return ENOMEM;
+     }
+ 
+-    krb5_service = talloc_get_type(private_data, struct krb5_service);
+-    if (!krb5_service) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Bad private_data\n");
++    server_idx = 0;
++    server_list = talloc_zero_array(tmp_ctx,
++                                    const char *,
++                                    fo_server_count(server) + 1);
++    if (server_list == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array failed\n");
+         talloc_free(tmp_ctx);
+-        return;
++        return ENOMEM;
+     }
+ 
+-    srvaddr = fo_get_server_hostent(server);
+-    if (!srvaddr) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "FATAL: No hostent available for server (%s)\n",
+-                  fo_get_server_str_name(server));
+-        talloc_free(tmp_ctx);
+-        return;
++    if (filter == NULL || filter(server) == false) {
++        address = fo_server_address_or_name(tmp_ctx, server);
++        if (address) {
++            server_list[server_idx++] = address;
++        } else {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Server without name and address found in list.\n");
++        }
+     }
+ 
+-    address = resolv_get_string_address(tmp_ctx, srvaddr);
+-    if (address == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "resolv_get_string_address failed.\n");
+-        talloc_free(tmp_ctx);
+-        return;
++    for (primary = 1; primary >= 0; --primary) {
++        for (item = fo_server_next(server) ? fo_server_next(server) : fo_server_first(server);
++             item != server;
++             item = fo_server_next(item) ? fo_server_next(item) : fo_server_first(item)) {
++
++            if (primary && !fo_is_server_primary(item)) continue;
++            if (!primary && fo_is_server_primary(item)) continue;
++            if (filter != NULL && filter(item)) continue;
++
++            address = fo_server_address_or_name(tmp_ctx, item);
++            if (address == NULL) {
++                DEBUG(SSSDBG_CRIT_FAILURE,
++                      "Server without name and address found in list.\n");
++                continue;
++            }
++
++            server_list[server_idx++] = address;
++        }
+     }
++    if (server_list[0] == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "There is no server that can be written into kdc info file.\n");
++        ret = EINVAL;
++    } else {
++        ret = write_krb5info_file(krb5_service,
++                                  server_list,
++                                  service);
++    }
++    talloc_free(tmp_ctx);
++    return ret;
++}
+ 
+-    safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
+-                                              srvaddr->family,
+-                                              address);
+-    if (safe_addr_list[0] == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
+-        talloc_free(tmp_ctx);
++
++static void krb5_resolve_callback(void *private_data, struct fo_server *server)
++{
++    struct krb5_service *krb5_service;
++    int ret;
++
++    krb5_service = talloc_get_type(private_data, struct krb5_service);
++    if (!krb5_service) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Bad private_data\n");
+         return;
+     }
+ 
+     if (krb5_service->write_kdcinfo) {
+-        safe_addr_list[0] = talloc_asprintf_append(safe_addr_list[0], ":%d",
+-                                                   fo_get_server_port(server));
+-        if (safe_addr_list[0] == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append failed.\n");
+-            talloc_free(tmp_ctx);
+-            return;
+-        }
+-
+-        ret = write_krb5info_file(krb5_service,
+-                                  safe_addr_list,
+-                                  krb5_service->name);
++        ret = write_krb5info_file_from_fo_server(krb5_service,
++                                                 server,
++                                                 krb5_service->name,
++                                                 NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+                   "write_krb5info_file failed, authentication might fail.\n");
+         }
+     }
+-
+-    talloc_free(tmp_ctx);
+-    return;
+ }
+ 
+ static errno_t _krb5_servers_init(struct be_ctx *ctx,
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index bf36a551a..be541626b 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -161,9 +161,14 @@ errno_t sss_krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb,
+                              const char *conf_path, struct dp_option **_opts);
+ 
+ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+-                            char **server_list,
++                            const char **server_list,
+                             const char *service);
+ 
++errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
++                                           struct fo_server *server,
++                                           const char *service,
++                                           bool (*filter)(struct fo_server *));
++
+ struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
+                                       struct be_ctx *be_ctx,
+                                       const char *service_name,
+-- 
+2.19.1
+
diff --git a/SOURCES/0023-krb5-Lookahead-resolving-of-host-names.patch b/SOURCES/0023-krb5-Lookahead-resolving-of-host-names.patch
new file mode 100644
index 0000000..42ba03b
--- /dev/null
+++ b/SOURCES/0023-krb5-Lookahead-resolving-of-host-names.patch
@@ -0,0 +1,650 @@
+From 385c8c7e0e6f184dd61953745bfe04a5a79a951a Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Fri, 15 Mar 2019 10:27:50 +0100
+Subject: [PATCH 23/23] krb5: Lookahead resolving of host names
+
+The caller that initializes
+the fail over service (maybe with be_fo_add_service) should provide
+a hint with the value of the lookahead option. Then, if a request for
+server resolution is triggered, the fail over code would resolve a server
+and afterwards check if enough fo_server entries with a valid hostname
+in the struct server_common structure. If not, the request would
+check if any of the fo_server structures represents a SRV query and
+try to resolve the query to receive more host names.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3975
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit e8d806d9bbb1ba288ed6a83158113f4d8f8a8929)
+---
+ Makefile.am                               |  1 +
+ src/man/sssd-krb5.5.xml                   | 34 +++++++++++
+ src/providers/ad/ad_common.c              | 10 +++-
+ src/providers/ad/ad_common.h              |  2 +
+ src/providers/ad/ad_init.c                |  2 +
+ src/providers/ad/ad_opts.c                |  2 +
+ src/providers/ad/ad_subdomains.c          | 12 +++-
+ src/providers/ipa/ipa_common.c            | 14 +++--
+ src/providers/ipa/ipa_opts.c              |  2 +
+ src/providers/ipa/ipa_subdomains.c        |  4 +-
+ src/providers/ipa/ipa_subdomains_server.c |  7 +++
+ src/providers/krb5/krb5_common.c          | 71 ++++++++++++++++++++++-
+ src/providers/krb5/krb5_common.h          | 13 ++++-
+ src/providers/krb5/krb5_init.c            | 19 +++++-
+ src/providers/krb5/krb5_opts.c            |  1 +
+ src/providers/ldap/ldap_common.c          |  9 +++
+ src/providers/ldap/ldap_opts.c            |  1 +
+ src/providers/ldap/sdap.h                 |  1 +
+ 18 files changed, 193 insertions(+), 12 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index e22423071..0c24ae664 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3339,6 +3339,7 @@ test_ad_subdom_LDADD = \
+     libsss_idmap.la \
+     libsss_test_common.la \
+     libdlopen_test_providers.la \
++    libsss_krb5_common.la \
+     $(NULL)
+ 
+ test_ipa_subdom_util_SOURCES = \
+diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml
+index 60b7dfb50..5a0bb5e9c 100644
+--- a/src/man/sssd-krb5.5.xml
++++ b/src/man/sssd-krb5.5.xml
+@@ -501,6 +501,40 @@
+                     </listitem>
+                 </varlistentry>
+ 
++                <varlistentry>
++                    <term>krb5_kdcinfo_lookahead (string)</term>
++                    <listitem>
++                        <para>
++                            When krb5_use_kdcinfo is set to true, you can limit the amount
++                            of servers handed to
++                            <citerefentry>
++                                <refentrytitle>sssd_krb5_locator_plugin</refentrytitle>
++                                <manvolnum>8</manvolnum>
++                            </citerefentry>.
++                            This might be helpful when there are too many servers
++                            discovered using SRV record.
++                        </para>
++                        <para>
++                            The krb5_kdcinfo_lookahead option contains two
++                            numbers seperated by a colon. The first number represents
++                            number of primary servers used and the second number
++                            specifies the number of backup servers.
++                        </para>
++                        <para>
++                            For example <emphasis>10:0</emphasis> means that up to
++                            10 primary servers will be handed to
++                            <citerefentry>
++                                <refentrytitle>sssd_krb5_locator_plugin</refentrytitle>
++                                <manvolnum>8</manvolnum>
++                            </citerefentry>.
++                            but no backup servers.
++                        </para>
++                        <para>
++                            Default: 3:1
++                        </para>
++                    </listitem>
++                </varlistentry>
++
+                 <varlistentry>
+                     <term>krb5_use_enterprise_principal (boolean)</term>
+                     <listitem>
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index b7f34daa9..4d1800806 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -729,6 +729,8 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+                  const char *ad_gc_service,
+                  const char *ad_domain,
+                  bool use_kdcinfo,
++                 size_t n_lookahead_primary,
++                 size_t n_lookahead_backup,
+                  struct ad_service **_service)
+ {
+     errno_t ret;
+@@ -760,7 +762,9 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+ 
+     service->krb5_service = krb5_service_new(service, bectx,
+                                              ad_service, krb5_realm,
+-                                             use_kdcinfo);
++                                             use_kdcinfo,
++                                             n_lookahead_primary,
++                                             n_lookahead_backup);
+     if (!service->krb5_service) {
+         ret = ENOMEM;
+         goto done;
+@@ -1292,6 +1296,10 @@ ad_get_auth_options(TALLOC_CTX *mem_ctx,
+     DEBUG(SSSDBG_CONF_SETTINGS, "Option %s set to %s\n",
+           krb5_options[KRB5_USE_KDCINFO].opt_name,
+           ad_opts->service->krb5_service->write_kdcinfo ? "true" : "false");
++    sss_krb5_parse_lookahead(
++        dp_opt_get_string(krb5_options, KRB5_KDCINFO_LOOKAHEAD),
++        &ad_opts->service->krb5_service->lookahead_primary,
++        &ad_opts->service->krb5_service->lookahead_backup);
+ 
+     *_opts = talloc_steal(mem_ctx, krb5_options);
+ 
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index 529753a8a..638465958 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -147,6 +147,8 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
+                  const char *ad_gc_service,
+                  const char *ad_domain,
+                  bool use_kdcinfo,
++                 size_t n_lookahead_primary,
++                 size_t n_lookahead_backup,
+                  struct ad_service **_service);
+ 
+ errno_t
+diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
+index 637efb761..612d4587e 100644
+--- a/src/providers/ad/ad_init.c
++++ b/src/providers/ad/ad_init.c
+@@ -160,6 +160,8 @@ static errno_t ad_init_options(TALLOC_CTX *mem_ctx,
+                            ad_realm, AD_SERVICE_NAME, AD_GC_SERVICE_NAME,
+                            dp_opt_get_string(ad_options->basic, AD_DOMAIN),
+                            false, /* will be set in ad_get_auth_options() */
++                           (size_t) -1,
++                           (size_t) -1,
+                            &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init AD failover service: "
+diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
+index c408295f3..652d8bb27 100644
+--- a/src/providers/ad/ad_opts.c
++++ b/src/providers/ad/ad_opts.c
+@@ -111,6 +111,7 @@ struct dp_option ad_def_ldap_opts[] = {
+     { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "krb5_use_kdcinfo", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
++    { "krb5_kdcinfo_lookahead", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_pwd_policy", DP_OPT_STRING, { "none" }, NULL_STRING },
+     { "ldap_referrals", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },
+@@ -175,6 +176,7 @@ struct dp_option ad_def_krb5_opts[] = {
+     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "krb5_use_kdcinfo", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
++    { "krb5_kdcinfo_lookahead", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "krb5_map_user", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 4fc4be094..b4ad347e4 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -280,6 +280,8 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+     const char *keytab;
+     char *subdom_conf_path;
+     bool use_kdcinfo = false;
++    size_t n_lookahead_primary = SSS_KRB5_LOOKAHEAD_PRIMARY_DEFAULT;
++    size_t n_lookahead_backup = SSS_KRB5_LOOKAHEAD_BACKUP_DEFAULT;
+ 
+     realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM);
+     hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME);
+@@ -331,6 +333,11 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+             && id_ctx->ad_options->auth_ctx->opts != NULL) {
+         use_kdcinfo = dp_opt_get_bool(id_ctx->ad_options->auth_ctx->opts,
+                                       KRB5_USE_KDCINFO);
++        sss_krb5_parse_lookahead(
++            dp_opt_get_string(id_ctx->ad_options->auth_ctx->opts,
++                              KRB5_KDCINFO_LOOKAHEAD),
++            &n_lookahead_primary,
++            &n_lookahead_backup);
+     }
+ 
+     DEBUG(SSSDBG_TRACE_ALL,
+@@ -339,7 +346,10 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+ 
+     ret = ad_failover_init(ad_options, be_ctx, servers, backup_servers,
+                            subdom->realm, service_name, gc_service_name,
+-                           subdom->name, use_kdcinfo, &ad_options->service);
++                           subdom->name, use_kdcinfo,
++                           n_lookahead_primary,
++                           n_lookahead_backup,
++                           &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
+         talloc_free(ad_options);
+diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
+index 1ed2e2203..871fb9bbc 100644
+--- a/src/providers/ipa/ipa_common.c
++++ b/src/providers/ipa/ipa_common.c
+@@ -801,6 +801,12 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts,
+     DEBUG(SSSDBG_CONF_SETTINGS, "Option %s set to %s\n",
+           ipa_opts->auth[KRB5_USE_KDCINFO].opt_name,
+           ipa_opts->service->krb5_service->write_kdcinfo ? "true" : "false");
++    if (ipa_opts->service->krb5_service->write_kdcinfo) {
++        sss_krb5_parse_lookahead(
++            dp_opt_get_string(ipa_opts->auth, KRB5_KDCINFO_LOOKAHEAD),
++            &ipa_opts->service->krb5_service->lookahead_primary,
++            &ipa_opts->service->krb5_service->lookahead_backup);
++    }
+ 
+     *_opts = ipa_opts->auth;
+     ret = EOK;
+@@ -1022,10 +1028,10 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+ 
+     service->krb5_service = krb5_service_new(service, ctx,
+                                              "IPA", realm,
+-                                             true); /* The configured value
+-                                                     * will be set later when
+-                                                     * the auth provider is set up
+-                                                     */
++                                             true,   /* The configured value */
++                                             0,      /* will be set later when */
++                                             0);     /* the auth provider is set up */
++
+     if (!service->krb5_service) {
+         ret = ENOMEM;
+         goto done;
+diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
+index 373dc0e53..600b9ec4b 100644
+--- a/src/providers/ipa/ipa_opts.c
++++ b/src/providers/ipa/ipa_opts.c
+@@ -121,6 +121,7 @@ struct dp_option ipa_def_ldap_opts[] = {
+     { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "krb5_use_kdcinfo", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
++    { "krb5_kdcinfo_lookahead", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING },
+     { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },
+@@ -320,6 +321,7 @@ struct dp_option ipa_def_krb5_opts[] = {
+     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "krb5_use_kdcinfo", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
++    { "krb5_kdcinfo_lookahead", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "krb5_map_user", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index da1279e3e..94365aaca 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -692,7 +692,9 @@ ipa_subdom_get_k5_svc(struct ipa_subdomains_ctx *ctx,
+                                         ctx->be_ctx,
+                                         "IPA",
+                                         dom->realm,
+-                                        use_kdcinfo);
++                                        use_kdcinfo,
++                                        (size_t) -1,
++                                        (size_t) -1);
+     if (k5svc_ent->k5svc == NULL) {
+         talloc_free(k5svc_ent);
+         return NULL;
+diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
+index 43a3053cb..dd0933642 100644
+--- a/src/providers/ipa/ipa_subdomains_server.c
++++ b/src/providers/ipa/ipa_subdomains_server.c
+@@ -225,6 +225,8 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+     errno_t ret;
+     const char *extra_attrs;
+     bool use_kdcinfo = false;
++    size_t n_lookahead_primary = (size_t)-1;
++    size_t n_lookahead_backup = (size_t)-1;
+ 
+     ad_domain = subdom->name;
+     DEBUG(SSSDBG_TRACE_LIBS, "Setting up AD subdomain %s\n", subdom->name);
+@@ -284,6 +286,10 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+     if (id_ctx->ipa_options != NULL && id_ctx->ipa_options->auth != NULL) {
+         use_kdcinfo = dp_opt_get_bool(id_ctx->ipa_options->auth,
+                                       KRB5_USE_KDCINFO);
++        sss_krb5_parse_lookahead(
++            dp_opt_get_string(id_ctx->ipa_options->auth, KRB5_KDCINFO_LOOKAHEAD),
++            &n_lookahead_primary,
++            &n_lookahead_backup);
+     }
+ 
+     DEBUG(SSSDBG_TRACE_ALL,
+@@ -297,6 +303,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+                            subdom->realm,
+                            service_name, gc_service_name,
+                            subdom->name, use_kdcinfo,
++                           n_lookahead_primary, n_lookahead_backup,
+                            &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index 1e33fc0f5..e56820b8d 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -390,6 +390,39 @@ done:
+     return ret;
+ }
+ 
++void sss_krb5_parse_lookahead(const char *param, size_t *primary, size_t *backup)
++{
++    int ret;
++
++    if (primary == NULL || backup == NULL) {
++        return;
++    }
++
++    *primary = SSS_KRB5_LOOKAHEAD_PRIMARY_DEFAULT;
++    *backup = SSS_KRB5_LOOKAHEAD_BACKUP_DEFAULT;
++
++    if (param == NULL) {
++        return;
++    }
++
++    if (strchr(param, ':')) {
++        ret = sscanf(param, "%zu:%zu", primary, backup);
++        if (ret != 2) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not parse krb5_kdcinfo_lookahead!\n");
++        }
++    } else {
++        ret = sscanf(param, "%zu", primary);
++        if (ret != 1) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not parse krb5_kdcinfo_lookahead!\n");
++        }
++    }
++
++    DEBUG(SSSDBG_CONF_SETTINGS,
++          "Option krb5_kdcinfo_lookahead set to %zu:%zu",
++          *primary, *backup);
++}
++
++
+ static int remove_info_files_destructor(void *p)
+ {
+     int ret;
+@@ -668,6 +701,13 @@ errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
+     int primary;
+     const char *address;
+     errno_t ret;
++    size_t n_lookahead_primary;
++    size_t n_lookahead_backup;
++
++    if (krb5_service == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "The krb5_service must not be NULL!\n");
++        return EINVAL;
++    }
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -675,6 +715,9 @@ errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
+         return ENOMEM;
+     }
+ 
++    n_lookahead_primary = krb5_service->lookahead_primary;
++    n_lookahead_backup = krb5_service->lookahead_backup;
++
+     server_idx = 0;
+     server_list = talloc_zero_array(tmp_ctx,
+                                     const char *,
+@@ -689,6 +732,15 @@ errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
+         address = fo_server_address_or_name(tmp_ctx, server);
+         if (address) {
+             server_list[server_idx++] = address;
++            if (fo_is_server_primary(server)) {
++                if (n_lookahead_primary > 0) {
++                    n_lookahead_primary--;
++                }
++            } else {
++                if (n_lookahead_backup > 0) {
++                    n_lookahead_backup--;
++                }
++            }
+         } else {
+             DEBUG(SSSDBG_CRIT_FAILURE,
+                   "Server without name and address found in list.\n");
+@@ -700,6 +752,8 @@ errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
+              item != server;
+              item = fo_server_next(item) ? fo_server_next(item) : fo_server_first(item)) {
+ 
++            if (primary && n_lookahead_primary == 0) break;
++            if (!primary && n_lookahead_backup == 0) break;
+             if (primary && !fo_is_server_primary(item)) continue;
+             if (!primary && fo_is_server_primary(item)) continue;
+             if (filter != NULL && filter(item)) continue;
+@@ -712,6 +766,11 @@ errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
+             }
+ 
+             server_list[server_idx++] = address;
++            if (primary) {
++                n_lookahead_primary--;
++            } else {
++                n_lookahead_backup--;
++            }
+         }
+     }
+     if (server_list[0] == NULL) {
+@@ -901,7 +960,9 @@ struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
+                                       struct be_ctx *be_ctx,
+                                       const char *service_name,
+                                       const char *realm,
+-                                      bool use_kdcinfo)
++                                      bool use_kdcinfo,
++                                      size_t n_lookahead_primary,
++                                      size_t n_lookahead_backup)
+ {
+     struct krb5_service *service;
+ 
+@@ -927,6 +988,9 @@ struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
+           realm,
+           use_kdcinfo ? "true" : "false");
+     service->write_kdcinfo = use_kdcinfo;
++    service->lookahead_primary = n_lookahead_primary;
++    service->lookahead_backup = n_lookahead_backup;
++
+     service->be_ctx = be_ctx;
+     return service;
+ }
+@@ -937,6 +1001,8 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *backup_servers,
+                       const char *realm,
+                       bool use_kdcinfo,
++                      size_t n_lookahead_primary,
++                      size_t n_lookahead_backup,
+                       struct krb5_service **_service)
+ {
+     TALLOC_CTX *tmp_ctx;
+@@ -948,7 +1014,8 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         return ENOMEM;
+     }
+ 
+-    service = krb5_service_new(tmp_ctx, ctx, service_name, realm, use_kdcinfo);
++    service = krb5_service_new(tmp_ctx, ctx, service_name, realm, use_kdcinfo,
++                               n_lookahead_primary, n_lookahead_backup);
+     if (!service) {
+         ret = ENOMEM;
+         goto done;
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index be541626b..441c52b34 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -38,6 +38,8 @@
+ 
+ #define SSS_KRB5KDC_FO_SRV "KERBEROS"
+ #define SSS_KRB5KPASSWD_FO_SRV "KPASSWD"
++#define SSS_KRB5_LOOKAHEAD_PRIMARY_DEFAULT 3
++#define SSS_KRB5_LOOKAHEAD_BACKUP_DEFAULT 1
+ 
+ enum krb5_opts {
+     KRB5_KDC = 0,
+@@ -59,6 +61,7 @@ enum krb5_opts {
+     KRB5_CANONICALIZE,
+     KRB5_USE_ENTERPRISE_PRINCIPAL,
+     KRB5_USE_KDCINFO,
++    KRB5_KDCINFO_LOOKAHEAD,
+     KRB5_MAP_USER,
+ 
+     KRB5_OPTS
+@@ -71,6 +74,8 @@ struct krb5_service {
+     char *name;
+     char *realm;
+     bool write_kdcinfo;
++    size_t lookahead_primary;
++    size_t lookahead_backup;
+     bool removal_callback_available;
+ };
+ 
+@@ -160,6 +165,8 @@ errno_t krb5_try_kdcip(struct confdb_ctx *cdb, const char *conf_path,
+ errno_t sss_krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb,
+                              const char *conf_path, struct dp_option **_opts);
+ 
++void sss_krb5_parse_lookahead(const char *param, size_t *primary, size_t *backup);
++
+ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+                             const char **server_list,
+                             const char *service);
+@@ -173,7 +180,9 @@ struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
+                                       struct be_ctx *be_ctx,
+                                       const char *service_name,
+                                       const char *realm,
+-                                      bool use_kdcinfo);
++                                      bool use_kdcinfo,
++                                      size_t n_lookahead_primary,
++                                      size_t n_lookahead_backup);
+ 
+ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *service_name,
+@@ -181,6 +190,8 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *backup_servers,
+                       const char *realm,
+                       bool use_kdcinfo,
++                      size_t n_lookahead_primary,
++                      size_t n_lookahead_backup,
+                       struct krb5_service **_service);
+ 
+ void remove_krb5_info_files_callback(void *pvt);
+diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c
+index 66ae68fb4..3f4c1b361 100644
+--- a/src/providers/krb5/krb5_init.c
++++ b/src/providers/krb5/krb5_init.c
+@@ -40,6 +40,8 @@ static errno_t krb5_init_kpasswd(struct krb5_ctx *ctx,
+     const char *backup_servers;
+     const char *kdc_servers;
+     bool use_kdcinfo;
++    size_t n_lookahead_primary;
++    size_t n_lookahead_backup;
+     errno_t ret;
+ 
+     realm = dp_opt_get_string(ctx->opts, KRB5_REALM);
+@@ -52,6 +54,9 @@ static errno_t krb5_init_kpasswd(struct krb5_ctx *ctx,
+     primary_servers = dp_opt_get_string(ctx->opts, KRB5_KPASSWD);
+     backup_servers = dp_opt_get_string(ctx->opts, KRB5_BACKUP_KPASSWD);
+     use_kdcinfo = dp_opt_get_bool(ctx->opts, KRB5_USE_KDCINFO);
++    sss_krb5_parse_lookahead(dp_opt_get_string(ctx->opts, KRB5_KDCINFO_LOOKAHEAD),
++                             &n_lookahead_primary, &n_lookahead_backup);
++
+ 
+     if (primary_servers == NULL && backup_servers != NULL) {
+         DEBUG(SSSDBG_CONF_SETTINGS, "kpasswd server wasn't specified but "
+@@ -67,7 +72,10 @@ static errno_t krb5_init_kpasswd(struct krb5_ctx *ctx,
+     } else {
+         ret = krb5_service_init(ctx, be_ctx, SSS_KRB5KPASSWD_FO_SRV,
+                                 primary_servers, backup_servers, realm,
+-                                use_kdcinfo, &ctx->kpasswd_service);
++                                use_kdcinfo,
++                                n_lookahead_primary,
++                                n_lookahead_backup,
++                                &ctx->kpasswd_service);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+                   "Failed to init KRB5KPASSWD failover service!\n");
+@@ -84,6 +92,8 @@ static errno_t krb5_init_kdc(struct krb5_ctx *ctx, struct be_ctx *be_ctx)
+     const char *backup_servers;
+     const char *realm;
+     bool use_kdcinfo;
++    size_t n_lookahead_primary;
++    size_t n_lookahead_backup;
+     errno_t ret;
+ 
+     realm = dp_opt_get_string(ctx->opts, KRB5_REALM);
+@@ -96,10 +106,15 @@ static errno_t krb5_init_kdc(struct krb5_ctx *ctx, struct be_ctx *be_ctx)
+     backup_servers = dp_opt_get_string(ctx->opts, KRB5_BACKUP_KDC);
+ 
+     use_kdcinfo = dp_opt_get_bool(ctx->opts, KRB5_USE_KDCINFO);
++    sss_krb5_parse_lookahead(dp_opt_get_string(ctx->opts, KRB5_KDCINFO_LOOKAHEAD),
++                             &n_lookahead_primary, &n_lookahead_backup);
+ 
+     ret = krb5_service_init(ctx, be_ctx, SSS_KRB5KDC_FO_SRV,
+                             primary_servers, backup_servers, realm,
+-                            use_kdcinfo, &ctx->service);
++                            use_kdcinfo,
++                            n_lookahead_primary,
++                            n_lookahead_backup,
++                            &ctx->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init KRB5 failover service!\n");
+         return ret;
+diff --git a/src/providers/krb5/krb5_opts.c b/src/providers/krb5/krb5_opts.c
+index 6bec52767..05395e0f4 100644
+--- a/src/providers/krb5/krb5_opts.c
++++ b/src/providers/krb5/krb5_opts.c
+@@ -42,6 +42,7 @@ struct dp_option default_krb5_opts[] = {
+     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+     { "krb5_use_kdcinfo", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
++    { "krb5_kdcinfo_lookahead", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "krb5_map_user", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
+index 9cd8ec09c..4c49f08c5 100644
+--- a/src/providers/ldap/ldap_common.c
++++ b/src/providers/ldap/ldap_common.c
+@@ -335,6 +335,8 @@ int sdap_gssapi_init(TALLOC_CTX *mem_ctx,
+     const char *krb5_opt_realm;
+     struct krb5_service *service = NULL;
+     TALLOC_CTX *tmp_ctx;
++    size_t n_lookahead_primary;
++    size_t n_lookahead_backup;
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) return ENOMEM;
+@@ -361,11 +363,18 @@ int sdap_gssapi_init(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
++    sss_krb5_parse_lookahead(
++        dp_opt_get_string(opts, SDAP_KRB5_KDCINFO_LOOKAHEAD),
++        &n_lookahead_primary,
++        &n_lookahead_backup);
++
+     ret = krb5_service_init(mem_ctx, bectx,
+                             SSS_KRB5KDC_FO_SRV, krb5_servers,
+                             krb5_backup_servers, krb5_realm,
+                             dp_opt_get_bool(opts,
+                                             SDAP_KRB5_USE_KDCINFO),
++                            n_lookahead_primary,
++                            n_lookahead_backup,
+                             &service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init KRB5 failover service!\n");
+diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
+index f7574fac2..613fe7463 100644
+--- a/src/providers/ldap/ldap_opts.c
++++ b/src/providers/ldap/ldap_opts.c
+@@ -82,6 +82,7 @@ struct dp_option default_basic_opts[] = {
+     { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "krb5_use_kdcinfo", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
++    { "krb5_kdcinfo_lookahead", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_pwd_policy", DP_OPT_STRING, { "none" }, NULL_STRING },
+     { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index 0f79ae9de..48061d389 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -199,6 +199,7 @@ enum sdap_basic_opt {
+     SDAP_KRB5_REALM,
+     SDAP_KRB5_CANONICALIZE,
+     SDAP_KRB5_USE_KDCINFO,
++    SDAP_KRB5_KDCINFO_LOOKAHEAD,
+     SDAP_PWD_POLICY,
+     SDAP_REFERRALS,
+     SDAP_ACCOUNT_CACHE_EXPIRATION,
+-- 
+2.19.1
+
diff --git a/SOURCES/0024-SDAP-Add-sdap_has_deref_support_ex.patch b/SOURCES/0024-SDAP-Add-sdap_has_deref_support_ex.patch
new file mode 100644
index 0000000..d6f73a2
--- /dev/null
+++ b/SOURCES/0024-SDAP-Add-sdap_has_deref_support_ex.patch
@@ -0,0 +1,114 @@
+From eaceb6a212c989613c228fcbf939cf00427fb543 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 12 Mar 2019 12:48:29 +0100
+Subject: [PATCH 24/25] SDAP: Add sdap_has_deref_support_ex()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3979
+
+In some cases, it makes sense for performance reasons to disable
+dereference when processing user groups. But since processing of HBAC host
+groups is not much of a performance sensitive operation, we can get away
+with ignoring the client side setting and always using the dereference
+branch if the server supports the dereference call.
+
+This patch extends the sdap_has_deref_support call with a flag that
+allows the caller to bypass the client side check.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 1eb3ae1c46314ccc9151dc271966584b3d0f39f5)
+---
+ src/providers/ldap/sdap_async.c     | 19 ++++++++++++++-----
+ src/providers/ldap/sdap_async.h     |  6 +++++-
+ src/tests/cmocka/common_mock_sdap.c | 10 +++++++++-
+ 3 files changed, 28 insertions(+), 7 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
+index c9c633b44..822baf06a 100644
+--- a/src/providers/ldap/sdap_async.c
++++ b/src/providers/ldap/sdap_async.c
+@@ -2959,7 +2959,9 @@ int sdap_deref_search_recv(struct tevent_req *req,
+     return EOK;
+ }
+ 
+-bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts)
++bool sdap_has_deref_support_ex(struct sdap_handle *sh,
++                               struct sdap_options *opts,
++                               bool ignore_client)
+ {
+     const char *deref_oids[][2] = { { LDAP_SERVER_ASQ_OID, "ASQ" },
+                                     { LDAP_CONTROL_X_DEREF, "OpenLDAP" },
+@@ -2972,18 +2974,25 @@ bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts)
+         return false;
+     }
+ 
+-    deref_threshold = dp_opt_get_int(opts->basic, SDAP_DEREF_THRESHOLD);
+-    if (deref_threshold == 0) {
+-        return false;
++    if (ignore_client == false) {
++        deref_threshold = dp_opt_get_int(opts->basic, SDAP_DEREF_THRESHOLD);
++        if (deref_threshold == 0) {
++            return false;
++        }
+     }
+ 
+     for (i=0; deref_oids[i][0]; i++) {
+         if (sdap_is_control_supported(sh, deref_oids[i][0])) {
+             DEBUG(SSSDBG_TRACE_FUNC, "The server supports deref method %s\n",
+-                      deref_oids[i][1]);
++                  deref_oids[i][1]);
+             return true;
+         }
+     }
+ 
+     return false;
+ }
++
++bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts)
++{
++    return sdap_has_deref_support_ex(sh, opts, false);
++}
+diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
+index cdf4e9e46..34940ad75 100644
+--- a/src/providers/ldap/sdap_async.h
++++ b/src/providers/ldap/sdap_async.h
+@@ -252,7 +252,11 @@ int sdap_get_generic_recv(struct tevent_req *req,
+                          TALLOC_CTX *mem_ctx, size_t *reply_count,
+                          struct sysdb_attrs ***reply_list);
+ 
+-bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts);
++bool sdap_has_deref_support_ex(struct sdap_handle *sh,
++                               struct sdap_options *opts,
++                               bool ignore_client);
++bool sdap_has_deref_support(struct sdap_handle *sh,
++                            struct sdap_options *opts);
+ 
+ enum sdap_deref_flags {
+     SDAP_DEREF_FLG_SILENT = 1 << 0,     /* Do not warn if dereference fails */
+diff --git a/src/tests/cmocka/common_mock_sdap.c b/src/tests/cmocka/common_mock_sdap.c
+index fa4787c4b..9bbaaf4fb 100644
+--- a/src/tests/cmocka/common_mock_sdap.c
++++ b/src/tests/cmocka/common_mock_sdap.c
+@@ -76,7 +76,15 @@ struct sdap_handle *mock_sdap_handle(TALLOC_CTX *mem_ctx)
+  * their mock equivalent shall be used.
+  */
+ 
+-bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts)
++bool sdap_has_deref_support_ex(struct sdap_handle *sh,
++                               struct sdap_options *opts,
++                               bool ignore_client)
++{
++    return sss_mock_type(bool);
++}
++
++bool sdap_has_deref_support(struct sdap_handle *sh,
++                            struct sdap_options *opts)
+ {
+     return sss_mock_type(bool);
+ }
+-- 
+2.19.1
+
diff --git a/SOURCES/0025-IPA-Use-dereference-for-host-groups-even-if-the-conf.patch b/SOURCES/0025-IPA-Use-dereference-for-host-groups-even-if-the-conf.patch
new file mode 100644
index 0000000..45a69ba
--- /dev/null
+++ b/SOURCES/0025-IPA-Use-dereference-for-host-groups-even-if-the-conf.patch
@@ -0,0 +1,63 @@
+From 2c97edb4bd965499fe4cc39710de1a565c1b40d3 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 12 Mar 2019 12:48:48 +0100
+Subject: [PATCH 25/25] IPA: Use dereference for host groups even if the
+ configuration disables dereference
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3979
+
+In some cases, it makes sense for performance reasons to disable
+dereference when processing user groups. But since processing of HBAC host
+groups is not much of a performance sensitive operation, we can get away
+with ignoring the client side setting and always using the dereference
+branch if the server supports the dereference call.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 9d63616000c0c886a6da87708a460218a9e24474)
+---
+ src/man/sssd-ldap.5.xml       | 11 +++++++++--
+ src/providers/ipa/ipa_hosts.c |  2 +-
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index 5b858be62..25acc19e6 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1601,8 +1601,15 @@
+                             they are looked up individually.
+                         </para>
+                         <para>
+-                            You can turn off dereference lookups completely by
+-                            setting the value to 0.
++                            You can turn off dereference lookups completely
++                            by setting the value to 0. Please note that
++                            there are some codepaths in SSSD, like the IPA
++                            HBAC provider, that are only implemented using
++                            the dereference call, so even with dereference
++                            explicitly disabled, those parts will still
++                            use dereference if the server supports it
++                            and advertises the dereference control in the
++                            rootDSE object.
+                         </para>
+                         <para>
+                             A dereference lookup is a means of fetching all
+diff --git a/src/providers/ipa/ipa_hosts.c b/src/providers/ipa/ipa_hosts.c
+index 288bfb865..e209bca67 100644
+--- a/src/providers/ipa/ipa_hosts.c
++++ b/src/providers/ipa/ipa_hosts.c
+@@ -157,7 +157,7 @@ ipa_host_info_done(struct tevent_req *subreq)
+                 return;
+             }
+ 
+-            if (!sdap_has_deref_support(state->sh, state->opts)) {
++            if (!sdap_has_deref_support_ex(state->sh, state->opts, true)) {
+                 DEBUG(SSSDBG_CRIT_FAILURE, "Server does not support deref\n");
+                 tevent_req_error(req, EIO);
+                 return;
+-- 
+2.19.1
+
diff --git a/SOURCES/0026-PAM-Also-cache-SSS_PAM_PREAUTH.patch b/SOURCES/0026-PAM-Also-cache-SSS_PAM_PREAUTH.patch
new file mode 100644
index 0000000..5253c3d
--- /dev/null
+++ b/SOURCES/0026-PAM-Also-cache-SSS_PAM_PREAUTH.patch
@@ -0,0 +1,115 @@
+From 0a637fff4fe575916bdae0eb17b7c36e8427308a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 17 Apr 2019 15:07:43 +0200
+Subject: [PATCH] PAM: Also cache SSS_PAM_PREAUTH
+
+Related: https://pagure.io/SSSD/sssd/issue/3960
+
+Even if cached_auth_timeout was set, the pam responder would still
+forward the preauthentication requests to the back end. This could
+trigger unwanted traffic towards the KDCs.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit c911562d1bea8ae44e45e564c9df5df43d87b035)
+---
+ src/man/sssd.conf.5.xml        |  4 +++-
+ src/responder/pam/pamsrv_cmd.c | 40 +++++++++++++++-------------------
+ 2 files changed, 21 insertions(+), 23 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 274809e24..1ab7af00b 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2960,7 +2960,9 @@ subdomain_inherit = ldap_purge_cache_timeout
+                             Specifies time in seconds since last successful
+                             online authentication for which user will be
+                             authenticated using cached credentials while
+-                            SSSD is in the online mode.
++                            SSSD is in the online mode. If the credentials
++                            are incorrect, SSSD falls back to online
++                            authentication.
+                         </para>
+                         <para>
+                             This option's value is inherited by all trusted
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 6b2dc5bdc..00302be75 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -803,8 +803,9 @@ static void pam_reply(struct pam_auth_req *preq)
+         pam_verbosity = DEFAULT_PAM_VERBOSITY;
+     }
+ 
+-    DEBUG(SSSDBG_FUNC_DATA,
+-          "pam_reply called with result [%d]: %s.\n",
++    DEBUG(SSSDBG_TRACE_ALL,
++          "pam_reply initially called with result [%d]: %s. "
++          "this result might be changed during processing\n",
+           pd->pam_status, pam_strerror(NULL, pd->pam_status));
+ 
+     if (pd->cmd == SSS_PAM_AUTHENTICATE
+@@ -886,6 +887,7 @@ static void pam_reply(struct pam_auth_req *preq)
+             break;
+ /* TODO: we need the pam session cookie here to make sure that cached
+  * authentication was successful */
++        case SSS_PAM_PREAUTH:
+         case SSS_PAM_SETCRED:
+         case SSS_PAM_ACCT_MGMT:
+         case SSS_PAM_OPEN_SESSION:
+@@ -1067,6 +1069,8 @@ static void pam_reply(struct pam_auth_req *preq)
+     }
+ 
+ done:
++    DEBUG(SSSDBG_FUNC_DATA, "Returning [%d]: %s to the client\n",
++          pd->pam_status, pam_strerror(NULL, pd->pam_status));
+     sss_cmd_done(cctx, preq);
+ }
+ 
+@@ -1949,21 +1953,6 @@ done:
+     return ret;
+ }
+ 
+-static bool pam_is_cmd_cachable(int cmd)
+-{
+-    bool is_cachable;
+-
+-    switch(cmd) {
+-    case SSS_PAM_AUTHENTICATE:
+-        is_cachable = true;
+-        break;
+-    default:
+-        is_cachable = false;
+-    }
+-
+-    return is_cachable;
+-}
+-
+ static bool pam_is_authtok_cachable(struct sss_auth_token *authtok)
+ {
+     enum sss_authtok_type type;
+@@ -1988,11 +1977,18 @@ static bool pam_can_user_cache_auth(struct sss_domain_info *domain,
+     errno_t ret;
+     bool result = false;
+ 
+-    if (!cached_auth_failed /* don't try cached auth again */
+-            && domain->cache_credentials
+-            && domain->cached_auth_timeout > 0
+-            && pam_is_authtok_cachable(authtok)
+-            && pam_is_cmd_cachable(pam_cmd)) {
++    if (cached_auth_failed) {
++        /* Do not retry indefinitely */
++        return false;
++    }
++
++    if (!domain->cache_credentials || domain->cached_auth_timeout <= 0) {
++        return false;
++    }
++
++    if (pam_cmd == SSS_PAM_PREAUTH
++        || (pam_cmd == SSS_PAM_AUTHENTICATE
++            && pam_is_authtok_cachable(authtok))) {
+ 
+         ret = pam_is_last_online_login_fresh(domain, user,
+                                              domain->cached_auth_timeout,
+-- 
+2.19.2
+
diff --git a/SOURCES/0027-winbind-idmap-plugin-update-struct-idmap_domain-to-l.patch b/SOURCES/0027-winbind-idmap-plugin-update-struct-idmap_domain-to-l.patch
new file mode 100644
index 0000000..d32bc45
--- /dev/null
+++ b/SOURCES/0027-winbind-idmap-plugin-update-struct-idmap_domain-to-l.patch
@@ -0,0 +1,94 @@
+From e6734785fd1970c4b63d0dd021074003e35d7137 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 5 Apr 2019 18:05:08 +0200
+Subject: [PATCH] winbind idmap plugin: update struct idmap_domain to latest
+ version
+
+While updating to interface version 6 we forgot to add the query_user
+member.
+
+Recent version of Samba added a new member dom_sid. Unfortunately the
+interface version was not update for this change so we have to enable
+the member based on the Samba version.
+
+Related to https://pagure.io/SSSD/sssd/issue/4005
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 30734e5f213f4bd2984e632d497d7cbfc16495db)
+---
+ src/external/samba.m4                         | 13 +++++++++++++
+ src/lib/winbind_idmap_sss/winbind_idmap_sss.c |  4 ++++
+ src/lib/winbind_idmap_sss/winbind_idmap_sss.h | 15 +++++++++++++++
+ 3 files changed, 32 insertions(+)
+
+diff --git a/src/external/samba.m4 b/src/external/samba.m4
+index 7a8c1eb7b..e68f064b3 100644
+--- a/src/external/samba.m4
++++ b/src/external/samba.m4
+@@ -121,6 +121,19 @@ int main(void)
+     AC_MSG_NOTICE([Samba's idmap interface version: $idmap_version])
+     AC_DEFINE_UNQUOTED(SMB_IDMAP_INTERFACE_VERSION, $idmap_version,
+                        [Detected version of Samba's idmap plugin interface])
++
++    samba_major_version=`echo -e '#include <samba/version.h>\nSAMBA_VERSION_MAJOR' | $CPP $SMBCLIENT_CFLAGS -P -`
++    samba_minor_version=`echo -e '#include <samba/version.h>\nSAMBA_VERSION_MINOR' | $CPP $SMBCLIENT_CFLAGS -P -`
++    samba_release_version=`echo -e '#include <samba/version.h>\nSAMBA_VERSION_RELEASE' | $CPP $SMBCLIENT_CFLAGS -P -`
++    AC_MSG_NOTICE([Samba version: $samba_major_version $samba_minor_version $samba_release_version])
++    if test $samba_major_version -ge 4 -a $samba_minor_version -ge 8 ; then
++        AC_DEFINE_UNQUOTED(SMB_IDMAP_DOMAIN_HAS_DOM_SID, 1,
++                           [Samba's struct idmap_domain has dom_sid member])
++        AC_MSG_NOTICE([Samba's struct idmap_domain has dom_sid member])
++    else
++        AC_MSG_NOTICE([Samba's struct idmap_domain does not have dom_sid member])
++    fi
++
+ fi
+ 
+ SAVE_CFLAGS=$CFLAGS
+diff --git a/src/lib/winbind_idmap_sss/winbind_idmap_sss.c b/src/lib/winbind_idmap_sss/winbind_idmap_sss.c
+index 0d9109455..58375322a 100644
+--- a/src/lib/winbind_idmap_sss/winbind_idmap_sss.c
++++ b/src/lib/winbind_idmap_sss/winbind_idmap_sss.c
+@@ -55,6 +55,10 @@ static NTSTATUS idmap_sss_initialize(struct idmap_domain *dom)
+         return NT_STATUS_NO_MEMORY;
+     }
+ 
++#if SMB_IDMAP_INTERFACE_VERSION == 6
++    dom->query_user = NULL;
++#endif
++
+     dom->private_data = ctx;
+ 
+     return NT_STATUS_OK;
+diff --git a/src/lib/winbind_idmap_sss/winbind_idmap_sss.h b/src/lib/winbind_idmap_sss/winbind_idmap_sss.h
+index 868049fff..78800838e 100644
+--- a/src/lib/winbind_idmap_sss/winbind_idmap_sss.h
++++ b/src/lib/winbind_idmap_sss/winbind_idmap_sss.h
+@@ -70,9 +70,24 @@ struct id_map {
+ #error Missing Samba idmap interface version
+ #endif
+ 
++#if SMB_IDMAP_INTERFACE_VERSION == 6
++struct wbint_userinfo;
++#endif
++
+ struct idmap_domain {
+     const char *name;
++#if SMB_IDMAP_INTERFACE_VERSION == 6 && defined(SMB_IDMAP_DOMAIN_HAS_DOM_SID)
++    /*
++     * dom_sid is currently only initialized in the unixids_to_sids request,
++     * so don't rely on this being filled out everywhere!
++     */
++    struct dom_sid dom_sid;
++#endif
+     struct idmap_methods *methods;
++#if SMB_IDMAP_INTERFACE_VERSION == 6
++    NTSTATUS (*query_user)(struct idmap_domain *domain,
++                           struct wbint_userinfo *info);
++#endif
+     uint32_t low_id;
+     uint32_t high_id;
+     bool read_only;
+-- 
+2.19.1
+
diff --git a/SOURCES/0028-DP-add-NULL-check-to-be_ptask_-enable-disable.patch b/SOURCES/0028-DP-add-NULL-check-to-be_ptask_-enable-disable.patch
new file mode 100644
index 0000000..6081663
--- /dev/null
+++ b/SOURCES/0028-DP-add-NULL-check-to-be_ptask_-enable-disable.patch
@@ -0,0 +1,77 @@
+From cb94d00f31d1d6b6fcaa69dbaa928031d2e7c092 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 24 May 2019 09:18:25 +0200
+Subject: [PATCH 28/29] DP: add NULL check to be_ptask_{enable|disable}
+
+Currently the files and the proxy provider do not provide a check online
+method (DPM_CHECK_ONLINE). The files provider because it can never go
+offline. The proxy provider because there is no generic way to check
+since the nature of the actual provider is unknown.
+
+Since the method is missing check_if_online() jumps into the error
+handling block were we try to reset the offline state
+unconditionally. If there is no check_if_online_ptask, which never
+exists for the files provider and will not be available in the proxy
+provider as long as the backend is online, be_ptask_{enable|disable}
+will be called with a NULL pointer.
+
+Related to https://pagure.io/SSSD/sssd/issue/4014
+
+Reviewed-by: Tomas Halman <thalman@redhat.com>
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+(cherry picked from commit 2720d97ce2559a3a382caf8f669820f64d6097fe)
+---
+ src/providers/be_ptask.c | 29 +++++++++++++++++------------
+ 1 file changed, 17 insertions(+), 12 deletions(-)
+
+diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c
+index dc3c57db5..c43351755 100644
+--- a/src/providers/be_ptask.c
++++ b/src/providers/be_ptask.c
+@@ -352,26 +352,31 @@ done:
+ 
+ void be_ptask_enable(struct be_ptask *task)
+ {
+-    if (task->enabled) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: already enabled\n",
+-                                     task->name);
+-        return;
+-    }
++    if (task != NULL) {
++        if (task->enabled) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: already enabled\n",
++                                         task->name);
++            return;
++        }
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: enabling task\n", task->name);
++        DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: enabling task\n", task->name);
+ 
+-    task->enabled = true;
+-    be_ptask_schedule(task, BE_PTASK_ENABLED_DELAY, BE_PTASK_SCHEDULE_FROM_NOW);
++        task->enabled = true;
++        be_ptask_schedule(task, BE_PTASK_ENABLED_DELAY,
++                          BE_PTASK_SCHEDULE_FROM_NOW);
++    }
+ }
+ 
+ /* Disable the task, but if a request already in progress, let it finish. */
+ void be_ptask_disable(struct be_ptask *task)
+ {
+-    DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabling task\n", task->name);
++    if (task != NULL) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabling task\n", task->name);
+ 
+-    talloc_zfree(task->timer);
+-    task->enabled = false;
+-    task->period = task->orig_period;
++        talloc_zfree(task->timer);
++        task->enabled = false;
++        task->period = task->orig_period;
++    }
+ }
+ 
+ void be_ptask_destroy(struct be_ptask **task)
+-- 
+2.20.1
+
diff --git a/SOURCES/0029-LDAP-Return-the-error-message-from-the-extended-oper.patch b/SOURCES/0029-LDAP-Return-the-error-message-from-the-extended-oper.patch
new file mode 100644
index 0000000..8661da8
--- /dev/null
+++ b/SOURCES/0029-LDAP-Return-the-error-message-from-the-extended-oper.patch
@@ -0,0 +1,57 @@
+From 4ab1b754a2659d8e75ae734987ed93f3e1ed047f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 15 May 2019 21:20:26 +0200
+Subject: [PATCH 29/29] LDAP: Return the error message from the extended
+ operation password change also on failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves: https://pagure.io/SSSD/sssd/issue/4015
+
+If password change fails, the tevent request would call
+TEVENT_REQ_RETURN_ON_ERROR before returning the error message that comes
+from the server, so the server message would not be propagated to the caller.
+
+This regressed in cf1d7ff
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 9a4d5f0601b432b87c3bf93f7126d07e65993e0d)
+---
+ src/providers/ldap/ldap_auth.c  | 5 +++--
+ src/providers/ldap/sdap_async.c | 1 +
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
+index 86724e388..4f416c1aa 100644
+--- a/src/providers/ldap/ldap_auth.c
++++ b/src/providers/ldap/ldap_auth.c
+@@ -1212,10 +1212,11 @@ sdap_pam_change_password_recv(TALLOC_CTX *mem_ctx,
+     struct sdap_pam_change_password_state *state;
+     state = tevent_req_data(req, struct sdap_pam_change_password_state);
+ 
+-    TEVENT_REQ_RETURN_ON_ERROR(req);
+-
++    /* We want to return the error message even on failure */
+     *_user_error_message = talloc_steal(mem_ctx, state->user_error_message);
+ 
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
+     return EOK;
+ }
+ 
+diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
+index 822baf06a..7e78e6b6e 100644
+--- a/src/providers/ldap/sdap_async.c
++++ b/src/providers/ldap/sdap_async.c
+@@ -696,6 +696,7 @@ errno_t sdap_exop_modify_passwd_recv(struct tevent_req *req,
+     struct sdap_exop_modify_passwd_state *state = tevent_req_data(req,
+                                          struct sdap_exop_modify_passwd_state);
+ 
++    /* We want to return the error message even on failure */
+     *user_error_message = talloc_steal(mem_ctx, state->user_error_message);
+ 
+     TEVENT_REQ_RETURN_ON_ERROR(req);
+-- 
+2.20.1
+
diff --git a/SOURCES/0030-SDAP-allow-GSS-SPNEGO-for-LDAP-SASL-bind-as-well.patch b/SOURCES/0030-SDAP-allow-GSS-SPNEGO-for-LDAP-SASL-bind-as-well.patch
new file mode 100644
index 0000000..6a809bf
--- /dev/null
+++ b/SOURCES/0030-SDAP-allow-GSS-SPNEGO-for-LDAP-SASL-bind-as-well.patch
@@ -0,0 +1,272 @@
+From f5d031ba41b1c297f95df61f013f1c7ef8bca275 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Sun, 12 May 2019 16:38:43 +0200
+Subject: [PATCH 30/31] SDAP: allow GSS-SPNEGO for LDAP SASL bind as well
+
+From the LDAP client perspective GSS-SPNEGO and GSSAPI are quite
+similar. To support GSS-SPNEGO SSSD must make sure that a Kerberos
+ticket is available before the LDAP SASL bind is started.
+
+Related to https://pagure.io/SSSD/sssd/issue/4006
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 3b89934e831fa4e575e398fee6e4c3d4d24854eb)
+---
+ src/man/sssd-ldap.5.xml                    | 29 ++++++++++++----------
+ src/providers/ad/ad_common.c               |  6 ++---
+ src/providers/ad/ad_init.c                 |  2 +-
+ src/providers/ldap/ldap_auth.c             | 10 ++++----
+ src/providers/ldap/ldap_common.h           |  2 +-
+ src/providers/ldap/ldap_init.c             |  2 +-
+ src/providers/ldap/sdap.c                  |  9 +++++++
+ src/providers/ldap/sdap.h                  |  2 ++
+ src/providers/ldap/sdap_async_connection.c |  8 +++---
+ 9 files changed, 42 insertions(+), 28 deletions(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index 25acc19e6..17c5523c0 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1805,8 +1805,8 @@
+                     <term>ldap_sasl_mech (string)</term>
+                     <listitem>
+                         <para>
+-                            Specify the SASL mechanism to use.
+-                            Currently only GSSAPI is tested and supported.
++                            Specify the SASL mechanism to use.  Currently only
++                            GSSAPI and GSS-SPNEGO are tested and supported.
+                         </para>
+                         <para>
+                             Default: not set
+@@ -1818,13 +1818,14 @@
+                     <term>ldap_sasl_authid (string)</term>
+                     <listitem>
+                         <para>
+-                            Specify the SASL authorization id to use.
+-                            When GSSAPI is used, this represents the Kerberos
+-                            principal used for authentication to the directory.
+-                            This option can either contain the full principal (for
+-                            example host/myhost@EXAMPLE.COM) or just the principal name
+-                            (for example host/myhost). By default, the value is not set
+-                            and the following principals are used:
++                            Specify the SASL authorization id to use.  When
++                            GSSAPI/GSS-SPNEGO are used, this represents the
++                            Kerberos principal used for authentication to the
++                            directory.  This option can either contain the full
++                            principal (for example host/myhost@EXAMPLE.COM) or
++                            just the principal name (for example host/myhost).
++                            By default, the value is not set and the following
++                            principals are used:
+                             <programlisting>
+ hostname@REALM
+ netbiosname$@REALM
+@@ -1875,7 +1876,8 @@ host/*
+                     <term>ldap_krb5_keytab (string)</term>
+                     <listitem>
+                         <para>
+-                            Specify the keytab to use when using SASL/GSSAPI.
++                            Specify the keytab to use when using
++                            SASL/GSSAPI/GSS-SPNEGO.
+                         </para>
+                         <para>
+                             Default: System keytab, normally <filename>/etc/krb5.keytab</filename>
+@@ -1890,7 +1892,7 @@ host/*
+                             Specifies that the id_provider should init
+                             Kerberos credentials (TGT).
+                             This action is performed only if SASL is used and
+-                            the mechanism selected is GSSAPI.
++                            the mechanism selected is GSSAPI or GSS-SPNEGO.
+                         </para>
+                         <para>
+                             Default: true
+@@ -1903,7 +1905,7 @@ host/*
+                     <listitem>
+                         <para>
+                             Specifies the lifetime in seconds of the TGT if
+-                            GSSAPI is used.
++                            GSSAPI or GSS-SPNEGO is used.
+                         </para>
+                         <para>
+                             Default: 86400 (24 hours)
+@@ -1944,7 +1946,8 @@ host/*
+                     <term>krb5_realm (string)</term>
+                     <listitem>
+                         <para>
+-                            Specify the Kerberos REALM (for SASL/GSSAPI auth).
++                            Specify the Kerberos REALM (for
++                            SASL/GSSAPI/GSS-SPNEGO auth).
+                         </para>
+                         <para>
+                             Default: System defaults, see <filename>/etc/krb5.conf</filename>
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index 4d1800806..19d4b3d5a 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -577,7 +577,7 @@ _ad_servers_init(struct ad_service *service,
+         if (resolv_is_address(list[j])) {
+             DEBUG(SSSDBG_IMPORTANT_INFO,
+                   "ad_server [%s] is detected as IP address, "
+-                  "this can cause GSSAPI problems\n", list[j]);
++                  "this can cause GSSAPI/GSS-SPNEGO problems\n", list[j]);
+         }
+     }
+ 
+@@ -1012,7 +1012,7 @@ ad_set_sdap_options(struct ad_options *ad_opts,
+         goto done;
+     }
+ 
+-    /* Set the Kerberos Realm for GSSAPI */
++    /* Set the Kerberos Realm for GSSAPI or GSS-SPNEGO */
+     krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
+     if (!krb5_realm) {
+         /* Should be impossible, this is set in ad_get_common_options() */
+@@ -1269,7 +1269,7 @@ ad_get_auth_options(TALLOC_CTX *mem_ctx,
+            ad_servers);
+ 
+     /* Set krb5 realm */
+-    /* Set the Kerberos Realm for GSSAPI */
++    /* Set the Kerberos Realm for GSSAPI/GSS-SPNEGO */
+     krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
+     if (!krb5_realm) {
+         /* Should be impossible, this is set in ad_get_common_options() */
+diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
+index 612d4587e..302bcae7d 100644
+--- a/src/providers/ad/ad_init.c
++++ b/src/providers/ad/ad_init.c
+@@ -56,7 +56,7 @@ static int ad_sasl_getopt(void *context, const char *plugin_name,
+     if (!plugin_name || !result) {
+         return SASL_FAIL;
+     }
+-    if (strcmp(plugin_name, "GSSAPI") != 0) {
++    if (!sdap_sasl_mech_needs_kinit(plugin_name)) {
+         return SASL_FAIL;
+     }
+     if (strcmp(option, "ad_compat") != 0) {
+diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
+index de22689ae..86724e388 100644
+--- a/src/providers/ldap/ldap_auth.c
++++ b/src/providers/ldap/ldap_auth.c
+@@ -715,9 +715,9 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
+          * we don't need to authenticate the connection, because we're not
+          * looking up any information using the connection. This might be
+          * needed e.g. in case both ID and AUTH providers are set to LDAP
+-         * and the server is AD, because otherwise the connection would
+-         * both do a startTLS and later bind using GSSAPI which doesn't work
+-         * well with AD.
++         * and the server is AD, because otherwise the connection would both
++         * do a startTLS and later bind using GSSAPI or GSS-SPNEGO which
++         * doesn't work well with AD.
+          */
+         skip_conn_auth = true;
+     }
+@@ -725,8 +725,8 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
+     if (skip_conn_auth == false) {
+         sasl_mech = dp_opt_get_string(state->ctx->opts->basic,
+                                       SDAP_SASL_MECH);
+-        if (sasl_mech && strcasecmp(sasl_mech, "GSSAPI") == 0) {
+-            /* Don't force TLS on if we're told to use GSSAPI */
++        if (sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) {
++            /* Don't force TLS on if we're told to use GSSAPI or GSS-SPNEGO */
+             use_tls = false;
+         }
+     }
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index 6647241b4..04548a388 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -65,7 +65,7 @@ struct sdap_id_ctx {
+     struct be_ctx *be;
+     struct sdap_options *opts;
+ 
+-    /* If using GSSAPI */
++    /* If using GSSAPI or GSS-SPNEGO */
+     struct krb5_service *krb5_service;
+     /* connection to a server */
+     struct sdap_id_conn_ctx *conn;
+diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
+index 44b3e9ab3..352f0b656 100644
+--- a/src/providers/ldap/ldap_init.c
++++ b/src/providers/ldap/ldap_init.c
+@@ -365,7 +365,7 @@ static bool should_call_gssapi_init(struct sdap_options *opts)
+         return false;
+     }
+ 
+-    if (strcasecmp(sasl_mech, "GSSAPI") != 0) {
++    if (!sdap_sasl_mech_needs_kinit(sasl_mech)) {
+         return false;
+     }
+ 
+diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
+index 5c9d0a45d..5591a6718 100644
+--- a/src/providers/ldap/sdap.c
++++ b/src/providers/ldap/sdap.c
+@@ -904,6 +904,15 @@ errno_t setup_tls_config(struct dp_option *basic_opts)
+     return EOK;
+ }
+ 
++bool sdap_sasl_mech_needs_kinit(const char *sasl_mech)
++{
++    if (strcasecmp(sasl_mech, "GSSAPI") == 0
++            || strcasecmp(sasl_mech, "GSS-SPNEGO") == 0) {
++        return true;
++    }
++
++    return false;
++}
+ 
+ bool sdap_check_sup_list(struct sup_list *l, const char *val)
+ {
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index 48061d389..dddcf5faf 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -619,6 +619,8 @@ bool sdap_check_sup_list(struct sup_list *l, const char *val);
+ #define sdap_is_extension_supported(sh, ext_oid) \
+     sdap_check_sup_list(&((sh)->supported_extensions), ext_oid)
+ 
++bool sdap_sasl_mech_needs_kinit(const char *mech);
++
+ int build_attrs_from_map(TALLOC_CTX *memctx,
+                          struct sdap_attr_map *map,
+                          size_t size,
+diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
+index 8aacd6705..6bc271a91 100644
+--- a/src/providers/ldap/sdap_async_connection.c
++++ b/src/providers/ldap/sdap_async_connection.c
+@@ -1605,14 +1605,14 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
+     sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
+ 
+     if (state->do_auth && sasl_mech && state->use_rootdse) {
+-        /* check if server claims to support GSSAPI */
++        /* check if server claims to support the configured SASL MECH */
+         if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
+             tevent_req_error(req, ENOTSUP);
+             return;
+         }
+     }
+ 
+-    if (state->do_auth && sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
++    if (state->do_auth && sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) {
+         if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
+             sdap_cli_kinit_step(req);
+             return;
+@@ -1690,14 +1690,14 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq)
+     sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
+ 
+     if (state->do_auth && sasl_mech && state->rootdse) {
+-        /* check if server claims to support GSSAPI */
++        /* check if server claims to support the configured SASL MECH */
+         if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
+             tevent_req_error(req, ENOTSUP);
+             return;
+         }
+     }
+ 
+-    if (state->do_auth && sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
++    if (state->do_auth && sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) {
+         if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
+             sdap_cli_kinit_step(req);
+             return;
+-- 
+2.20.1
+
diff --git a/SOURCES/0031-sdap-inherit-SDAP_SASL_MECH-if-not-set-explicitly.patch b/SOURCES/0031-sdap-inherit-SDAP_SASL_MECH-if-not-set-explicitly.patch
new file mode 100644
index 0000000..25394a1
--- /dev/null
+++ b/SOURCES/0031-sdap-inherit-SDAP_SASL_MECH-if-not-set-explicitly.patch
@@ -0,0 +1,209 @@
+From 373b1136ccb3bf54f32d47473e8120d0258f8405 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 21 May 2019 10:22:04 +0200
+Subject: [PATCH 31/31] sdap: inherit SDAP_SASL_MECH if not set explicitly
+
+If ldap_sasl_mech is set for the configured domain in sssd.conf the
+value is inherited automatically to all sub-domains. The can be
+overwritten by setting ldap_sasl_mech for a given sub-domain explicitly
+in sssd.conf.
+
+Related to https://pagure.io/SSSD/sssd/issue/4006
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 070f22f896b909c140ed7598aed2393d61a834ae)
+---
+ src/config/cfg_rules.ini                  |  1 +
+ src/man/sssd-ldap.5.xml                   | 10 ++++++
+ src/man/sssd.conf.5.xml                   |  1 +
+ src/providers/ad/ad_common.c              | 38 +++++++++++++++++++++++
+ src/providers/ad/ad_common.h              |  5 +++
+ src/providers/ad/ad_subdomains.c          | 18 ++++++++++-
+ src/providers/ipa/ipa_subdomains_server.c | 19 +++++++++++-
+ 7 files changed, 90 insertions(+), 2 deletions(-)
+
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 603211711..3976ec4e1 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -753,6 +753,7 @@ option = ldap_user_search_base
+ option = ldap_group_search_base
+ option = ldap_netgroup_search_base
+ option = ldap_service_search_base
++option = ldap_sasl_mech
+ option = ad_server
+ option = ad_backup_server
+ option = ad_site
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index 17c5523c0..fadd05cb7 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1808,6 +1808,16 @@
+                             Specify the SASL mechanism to use.  Currently only
+                             GSSAPI and GSS-SPNEGO are tested and supported.
+                         </para>
++                        <para>
++                            If the backend supports sub-domains the value of
++                            ldap_sasl_mech is automatically inherited to the
++                            sub-domains. If a different value is needed for a
++                            sub-domain it can be overwritten by setting
++                            ldap_sasl_mech for this sub-domain explicitly.
++                            Please see TRUSTED DOMAIN SECTION in
++                            <citerefentry><refentrytitle>sssd.conf</refentrytitle>
++                            <manvolnum>5</manvolnum></citerefentry> for details.
++                        </para>
+                         <para>
+                             Default: not set
+                         </para>
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 1ab7af00b..3f05b3942 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -3356,6 +3356,7 @@ ldap_user_extra_attrs = phone:telephoneNumber
+             <para>ldap_group_search_base,</para>
+             <para>ldap_netgroup_search_base,</para>
+             <para>ldap_service_search_base,</para>
++            <para>ldap_sasl_mech,</para>
+             <para>ad_server,</para>
+             <para>ad_backup_server,</para>
+             <para>ad_site,</para>
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index 19d4b3d5a..1b8b1df19 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -1455,3 +1455,41 @@ ad_user_conn_list(TALLOC_CTX *mem_ctx,
+ 
+     return clist;
+ }
++
++errno_t ad_inherit_opts_if_needed(struct dp_option *parent_opts,
++                                  struct dp_option *suddom_opts,
++                                  struct confdb_ctx *cdb,
++                                  const char *subdom_conf_path,
++                                  int opt_id)
++{
++    int ret;
++    const char *parent_val = NULL;
++    char *dummy = NULL;
++    char *option_list[2] = { NULL, NULL };
++
++    parent_val = dp_opt_get_cstring(parent_opts, opt_id);
++    if (parent_val != NULL) {
++        ret = confdb_get_string(cdb, NULL, subdom_conf_path,
++                                parent_opts[opt_id].opt_name, NULL, &dummy);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "confdb_get_string failed.\n");
++            goto done;
++        }
++
++        if (dummy == NULL) {
++            DEBUG(SSSDBG_CONF_SETTINGS,
++                  "Option [%s] is set in parent domain but not set for "
++                  "sub-domain trying to set it to [%s].\n",
++                  parent_opts[opt_id].opt_name, parent_val);
++            option_list[0] = discard_const(parent_opts[opt_id].opt_name);
++            dp_option_inherit(option_list, opt_id, parent_opts, suddom_opts);
++        }
++    }
++
++    ret = EOK;
++
++done:
++    talloc_free(dummy);
++
++    return ret;
++}
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index 638465958..2f624df3d 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -216,4 +216,9 @@ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
+                                  char **_site,
+                                  char **_forest);
+ 
++errno_t ad_inherit_opts_if_needed(struct dp_option *parent_opts,
++                                  struct dp_option *suddom_opts,
++                                  struct confdb_ctx *cdb,
++                                  const char *subdom_conf_path,
++                                  int opt_id);
+ #endif /* AD_COMMON_H_ */
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index b4ad347e4..b4e09fb7e 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -305,13 +305,29 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+                                               realm,
+                                               subdom,
+                                               hostname, keytab);
+-    talloc_free(subdom_conf_path);
+     if (ad_options == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
+         talloc_free(ad_options);
++        talloc_free(subdom_conf_path);
+         return ENOMEM;
+     }
+ 
++    ret = ad_inherit_opts_if_needed(id_ctx->sdap_id_ctx->opts->basic,
++                                    ad_options->id->basic,
++                                    be_ctx->cdb, subdom_conf_path,
++                                    SDAP_SASL_MECH);
++    talloc_free(subdom_conf_path);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to inherit option [%s] to sub-domain [%s]. "
++              "This error is ignored but might cause issues or unexpected "
++              "behavior later on.\n",
++              id_ctx->ad_options->id->basic[SDAP_SASL_MECH].opt_name,
++              subdom->name);
++
++        return ret;
++    }
++
+     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
+ 
+     gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->name);
+diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
+index 1d480e52b..d0e89a4f9 100644
+--- a/src/providers/ipa/ipa_subdomains_server.c
++++ b/src/providers/ipa/ipa_subdomains_server.c
+@@ -172,6 +172,7 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx,
+     const char *forest;
+     const char *forest_realm;
+     char *subdom_conf_path;
++    int ret;
+ 
+     /* Trusts are only established with forest roots */
+     direction = subdom->forest_root->trust_direction;
+@@ -196,12 +197,28 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx,
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported trust direction!\n");
+         ad_options = NULL;
+     }
+-    talloc_free(subdom_conf_path);
+ 
+     if (ad_options == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
++        talloc_free(subdom_conf_path);
+         return NULL;
+     }
++
++    ret = ad_inherit_opts_if_needed(id_ctx->ipa_options->id->basic,
++                                    ad_options->id->basic, be_ctx->cdb,
++                                    subdom_conf_path, SDAP_SASL_MECH);
++    talloc_free(subdom_conf_path);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to inherit option [%s] to sub-domain [%s]. "
++              "This error is ignored but might cause issues or unexpected "
++              "behavior later on.\n",
++              id_ctx->ipa_options->id->basic[SDAP_SASL_MECH].opt_name,
++              subdom->name);
++
++        return NULL;
++    }
++
+     return ad_options;
+ }
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0032-Translation-Update-japanese-translation.patch b/SOURCES/0032-Translation-Update-japanese-translation.patch
new file mode 100644
index 0000000..fd67828
--- /dev/null
+++ b/SOURCES/0032-Translation-Update-japanese-translation.patch
@@ -0,0 +1,2750 @@
+From 74f29a0e83d3995de770500b270a3b0d02fa079c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Thu, 6 Jun 2019 03:27:05 +0200
+Subject: [PATCH 32/33] Translation: Update japanese translation
+
+---
+ po/ja.po | 1350 ++++++++++++++++++++++++++----------------------------
+ 1 file changed, 647 insertions(+), 703 deletions(-)
+
+diff --git a/po/ja.po b/po/ja.po
+index d8ca6e838..396b693c2 100644
+--- a/po/ja.po
++++ b/po/ja.po
+@@ -1,23 +1,24 @@
+ # SOME DESCRIPTIVE TITLE.
+ # Copyright (C) YEAR Red Hat, Inc.
+ # This file is distributed under the same license as the PACKAGE package.
+-#
++# 
+ # Translators:
+ # Tomoyuki KATO <tomo@dream.daynight.jp>, 2012-2013
+ # Noriko Mizumoto <noriko.mizumoto@gmail.com>, 2016. #zanata
++# Keiko Moriguchi <kemorigu@redhat.com>, 2019. #zanata
+ msgid ""
+ msgstr ""
+ "Project-Id-Version: PACKAGE VERSION\n"
+ "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"
+-"POT-Creation-Date: 2019-03-20 22:07+0100\n"
+-"PO-Revision-Date: 2016-08-18 08:06+0000\n"
+-"Last-Translator: Noriko Mizumoto <noriko.mizumoto@gmail.com>\n"
+-"Language-Team: Japanese (http://www.transifex.com/projects/p/sssd/language/"
+-"ja/)\n"
+-"Language: ja\n"
++"POT-Creation-Date: 2019-02-27 19:55+0100\n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
++"PO-Revision-Date: 2019-05-28 11:45+0000\n"
++"Last-Translator: Keiko Moriguchi <kemorigu@redhat.com>\n"
++"Language-Team: Japanese (http://www.transifex.com/projects/p/sssd/language/"
++"ja/)\n"
++"Language: ja\n"
+ "Plural-Forms: nplurals=1; plural=0;\n"
+ "X-Generator: Zanata 4.6.2\n"
+ 
+@@ -40,7 +41,7 @@ msgstr "デバッグメッセージをログファイルに書き込む"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:48
+ msgid "Watchdog timeout before restarting service"
+-msgstr ""
++msgstr "サービス再起動前の Watchdog タイムアウト"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:49
+ msgid "Command to start service"
+@@ -60,11 +61,11 @@ msgstr "クライアントの自動切断までのアイドル時間"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:53
+ msgid "Idle time before automatic shutdown of the responder"
+-msgstr ""
++msgstr "レスポンダーの自動シャットダウンまでのアイドル時間"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:54
+ msgid "Always query all the caches before querying the Data Providers"
+-msgstr ""
++msgstr "データプロバイダーをクエリーする前に、常にすべてのキャッシュをクエリーします"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:57
+ msgid "SSSD Services to start"
+@@ -79,12 +80,12 @@ msgid "Timeout for messages sent over the SBUS"
+ msgstr "SBUS 経由のメッセージ送信のタイムアウト"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:60
+-#: src/config/SSSDConfig/__init__.py.in:198
++#: src/config/SSSDConfig/__init__.py.in:199
+ msgid "Regex to parse username and domain"
+ msgstr "ユーザー名とドメインを構文解析する正規表現"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:61
+-#: src/config/SSSDConfig/__init__.py.in:197
++#: src/config/SSSDConfig/__init__.py.in:198
+ msgid "Printf-compatible format for displaying fully-qualified names"
+ msgstr "完全修飾名を表示するための printf 互換の形式"
+ 
+@@ -92,9 +93,7 @@ msgstr "完全修飾名を表示するための printf 互換の形式"
+ msgid ""
+ "Directory on the filesystem where SSSD should store Kerberos replay cache "
+ "files."
+-msgstr ""
+-"SSSD が Kerberos リプレイキャッシュファイルを保存するファイルシステムのディレ"
+-"クトリです。"
++msgstr "SSSD が Kerberos リプレイキャッシュファイルを保存するファイルシステムのディレクトリです。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:63
+ msgid "Domain to add to names without a domain component."
+@@ -102,27 +101,27 @@ msgstr "domain 要素なしで追加するドメインの名前。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:64
+ msgid "The user to drop privileges to"
+-msgstr ""
++msgstr "ユーザーが特権を停止します"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:65
+ msgid "Tune certificate verification"
+-msgstr ""
++msgstr "証明書検証の調整"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:66
+ msgid "All spaces in group or user names will be replaced with this character"
+-msgstr ""
++msgstr "グループ名またはユーザー名のすべてのスペースは、この文字に置き換えられます"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:67
+ msgid "Tune sssd to honor or ignore netlink state changes"
+-msgstr ""
++msgstr "SSSD を調整し、netlink の状態変更を尊重するか、または無視します"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:68
+ msgid "Enable or disable the implicit files domain"
+-msgstr ""
++msgstr "暗黙のファイルドメインを有効化または無効化する"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:69
+ msgid "A specific order of the domains to be looked up"
+-msgstr ""
++msgstr "検索するドメインの特定の順番"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:72
+ msgid "Enumeration cache timeout length (seconds)"
+@@ -133,13 +132,13 @@ msgid "Entry cache background update timeout length (seconds)"
+ msgstr "エントリーキャッシュのバックグラウンド更新のタイムアウト時間(秒)"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:74
+-#: src/config/SSSDConfig/__init__.py.in:114
++#: src/config/SSSDConfig/__init__.py.in:116
+ msgid "Negative cache timeout length (seconds)"
+ msgstr "ネガティブキャッシュのタイムアウト(秒)"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:75
+ msgid "Files negative cache timeout length (seconds)"
+-msgstr ""
++msgstr "ファイルネガティブキャッシュのタイムアウト時間(秒)"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:76
+ msgid "Users that SSSD should explicitly ignore"
+@@ -164,9 +163,7 @@ msgstr "識別プロバイダーからのホームディレクトリーの値を
+ #: src/config/SSSDConfig/__init__.py.in:81
+ msgid ""
+ "Substitute empty homedir value from the identity provider with this value"
+-msgstr ""
+-"アイデンティティプロバイダーからの空のホームディレクトリーをこの値で置き換え"
+-"ます"
++msgstr "アイデンティティプロバイダーからの空のホームディレクトリーをこの値で置き換えます"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:82
+ msgid "Override shell value from the identity provider with this value"
+@@ -185,9 +182,7 @@ msgstr "拒否されてフォールバックシェルで置き換えられるシ
+ msgid ""
+ "If a shell stored in central directory is allowed but not available, use "
+ "this fallback"
+-msgstr ""
+-"中央ディレクトリーに保存されたシェルが許可されるが、利用できない場合、この"
+-"フォールバックを使用する"
++msgstr "中央ディレクトリーに保存されたシェルが許可されるが、利用できない場合、このフォールバックを使用する"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:86
+ msgid "Shell to use if the provider does not list one"
+@@ -199,7 +194,7 @@ msgstr "メモリー内のキャッシュレコードが有効な期間"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:88
+ msgid "List of user attributes the NSS responder is allowed to publish"
+-msgstr ""
++msgstr "NSS レスポンダーがパブリッシュを許可されたユーザー属性の一覧"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:91
+ msgid "How long to allow cached logins between online logins (days)"
+@@ -221,7 +216,7 @@ msgstr "認証中にユーザーに表示されるメッセージの種類"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:95
+ msgid "Filter PAM responses sent to the pam_sss"
+-msgstr ""
++msgstr "pam_sss へ送信された PAM のレスポンスをフィルタリングします"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:96
+ msgid "How many seconds to keep identity information cached for PAM requests"
+@@ -233,625 +228,630 @@ msgstr "警告が表示されるパスワード失効前の日数"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:98
+ msgid "List of trusted uids or user's name"
+-msgstr ""
++msgstr "信頼できる UID またはユーザー名の一覧"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:99
+ msgid "List of domains accessible even for untrusted users."
+-msgstr ""
++msgstr "信頼できないユーザーでさえアクセス可能なドメインの一覧。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:100
+ msgid "Message printed when user account is expired."
+-msgstr ""
++msgstr "ユーザーアカウントの有効期限が切れると、メッセージが印刷されます。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:101
+ msgid "Message printed when user account is locked."
+-msgstr ""
++msgstr "ユーザーアカウントがロックされると、メッセージが印刷されます。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:102
+ msgid "Allow certificate based/Smartcard authentication."
+-msgstr ""
++msgstr "証明書ベースまたはスマートカードによる認証を許可します。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:103
+ msgid "Path to certificate database with PKCS#11 modules."
+-msgstr ""
++msgstr "PKCS#11 モジュールでの証明書データベースへのパス。"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:104
+ msgid "How many seconds will pam_sss wait for p11_child to finish"
+-msgstr ""
++msgstr "p11_child が完了するまでに pam_sss が待つ秒数"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:105
+ msgid "Which PAM services are permitted to contact application domains"
+-msgstr ""
++msgstr "アプリケーションドメインへの接続を許可される PAM サービスはどれか"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:106
+ msgid "Allowed services for using smartcards"
+-msgstr ""
++msgstr "スマートカードの使用が許可されたサービス"
++
++#: src/config/SSSDConfig/__init__.py.in:107
++msgid "Additional timeout to wait for a card if requested"
++msgstr "要求された場合に、カードが待つ追加のタイムアウト"
++
++#: src/config/SSSDConfig/__init__.py.in:108
++msgid ""
++"PKCS#11 URI to restrict the selection of devices for Smartcard "
++"authentication"
++msgstr "スマートカード認証向けのデバイスの選択を PKCS#11 URI が制限"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:109
++#: src/config/SSSDConfig/__init__.py.in:111
+ msgid "Whether to evaluate the time-based attributes in sudo rules"
+ msgstr "sudo ルールにおいて時間による属性を評価するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:110
++#: src/config/SSSDConfig/__init__.py.in:112
+ msgid "If true, SSSD will switch back to lower-wins ordering logic"
+-msgstr ""
++msgstr "正しい場合、SSSD は小さい番号が優先される順位付けのロジックへ戻ります"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:111
++#: src/config/SSSDConfig/__init__.py.in:113
+ msgid ""
+ "Maximum number of rules that can be refreshed at once. If this is exceeded, "
+ "full refresh is performed."
+-msgstr ""
++msgstr "一度にリフレッシュ可能なルールの最大数。最大数を超えると、フルリフレッシュが実行されます。"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:117
++#: src/config/SSSDConfig/__init__.py.in:119
+ msgid "Whether to hash host names and addresses in the known_hosts file"
+ msgstr "known_hosts ファイルにおいてホスト名とアドレスをハッシュ化するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:118
++#: src/config/SSSDConfig/__init__.py.in:120
+ msgid ""
+ "How many seconds to keep a host in the known_hosts file after its host keys "
+ "were requested"
+ msgstr "ホスト鍵が要求された後 known_hosts ファイルにホストを保持する秒数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:119
++#: src/config/SSSDConfig/__init__.py.in:121
+ msgid "Path to storage of trusted CA certificates"
+-msgstr ""
++msgstr "信頼された CA 証明書のストレージへのパス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:122
++#: src/config/SSSDConfig/__init__.py.in:124
+ msgid "List of UIDs or user names allowed to access the PAC responder"
+ msgstr "PAC レスポンダーへのアクセスが許可された UID またはユーザー名の一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:123
++#: src/config/SSSDConfig/__init__.py.in:125
+ msgid "How long the PAC data is considered valid"
+-msgstr ""
++msgstr "PAC データが有効とされる期間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:126
++#: src/config/SSSDConfig/__init__.py.in:128
+ msgid "List of UIDs or user names allowed to access the InfoPipe responder"
+-msgstr ""
++msgstr "InfoPipe レスポンダーへのアクセスが許可された UID またはユーザー名の一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:127
++#: src/config/SSSDConfig/__init__.py.in:129
+ msgid "List of user attributes the InfoPipe is allowed to publish"
+-msgstr ""
++msgstr "InfoPipe がパブリッシュを許可されたユーザー属性の一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:130
++#: src/config/SSSDConfig/__init__.py.in:132
+ msgid "The provider where the secrets will be stored in"
+-msgstr ""
++msgstr "シークレットが保存されるプロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:131
++#: src/config/SSSDConfig/__init__.py.in:133
+ msgid "The maximum allowed number of nested containers"
+-msgstr ""
++msgstr "ネストされたコンテナーの最大許可数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:132
++#: src/config/SSSDConfig/__init__.py.in:134
+ msgid "The maximum number of secrets that can be stored"
+-msgstr ""
++msgstr "保存可能なシークレットの最大数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:133
++#: src/config/SSSDConfig/__init__.py.in:135
+ msgid "The maximum number of secrets that can be stored per UID"
+-msgstr ""
++msgstr "UID ごとに保存可能なシークレットの最大数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:134
++#: src/config/SSSDConfig/__init__.py.in:136
+ msgid "The maximum payload size of a secret in kilobytes"
+-msgstr ""
++msgstr "キロバイトでのシークレットの最大ペイロードサイズ"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:136
++#: src/config/SSSDConfig/__init__.py.in:138
+ msgid "The URL Custodia server is listening on"
+-msgstr ""
++msgstr "URL Custodia サーバーはリッスンしています"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:137
++#: src/config/SSSDConfig/__init__.py.in:139
+ msgid "The method to use when authenticating to a Custodia server"
+-msgstr ""
++msgstr "Custodia サーバーへの認証時に使用する方法"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:138
++#: src/config/SSSDConfig/__init__.py.in:140
+ msgid ""
+ "The name of the headers that will be added into a HTTP request with the "
+ "value defined in auth_header_value"
+-msgstr ""
++msgstr "auth_header_value で値が定義され、HTTP リクエストに追加されるヘッダーの名前"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:139
++#: src/config/SSSDConfig/__init__.py.in:141
+ msgid "The value sssd-secrets would use for auth_header_name"
+-msgstr ""
++msgstr "sssd-secrets の値は、auth_header_name で使用します"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:140
++#: src/config/SSSDConfig/__init__.py.in:142
+ msgid ""
+ "The list of the headers to forward to the Custodia server together with the "
+ "request"
+-msgstr ""
++msgstr "要求と共に Custodia サーバーへ転送するヘッダーの一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:141
++#: src/config/SSSDConfig/__init__.py.in:143
+ msgid ""
+-"The username to use when authenticating to a Custodia server using basic_auth"
+-msgstr ""
++"The username to use when authenticating to a Custodia server using "
++"basic_auth"
++msgstr "basic_auth を使った Custodia サーバーへの認証時に使用するユーザー名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:142
++#: src/config/SSSDConfig/__init__.py.in:144
+ msgid ""
+-"The password to use when authenticating to a Custodia server using basic_auth"
+-msgstr ""
++"The password to use when authenticating to a Custodia server using "
++"basic_auth"
++msgstr "basic_auth を使った Custodia サーバーへの認証時に使用するパスワード"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:143
+-msgid "If true peer's certificate is verified if proxy_url uses https protocol"
+-msgstr ""
++#: src/config/SSSDConfig/__init__.py.in:145
++msgid ""
++"If true peer's certificate is verified if proxy_url uses https protocol"
++msgstr "proxy_url が https protocol を使用する場合に、正しいピアの証明書が検証されるかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:144
++#: src/config/SSSDConfig/__init__.py.in:146
+ msgid ""
+ "If false peer's certificate may contain different hostname than proxy_url "
+ "when https protocol is used"
+-msgstr ""
++msgstr "https プロトコルが使用される場合に、間違ったピアの証明書が proxy_url 以外の異なるホスト名を含むかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:145
++#: src/config/SSSDConfig/__init__.py.in:147
+ msgid "Path to directory where certificate authority certificates are stored"
+-msgstr ""
++msgstr "CA 証明書が保存されているディレクトリーへのパス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:146
++#: src/config/SSSDConfig/__init__.py.in:148
+ msgid "Path to file containing server's CA certificate"
+-msgstr ""
++msgstr "サーバーの CA 証明書を含むファイルへのパス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:147
++#: src/config/SSSDConfig/__init__.py.in:149
+ msgid "Path to file containing client's certificate"
+-msgstr ""
++msgstr "クライアントの証明書を含むファイルへのパス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:148
++#: src/config/SSSDConfig/__init__.py.in:150
+ msgid "Path to file containing client's private key"
+-msgstr ""
++msgstr "クライアントのプライベートキーを含むファイルへのパス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:151
++#: src/config/SSSDConfig/__init__.py.in:153
+ msgid "Identity provider"
+ msgstr "アイデンティティプロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:152
++#: src/config/SSSDConfig/__init__.py.in:154
+ msgid "Authentication provider"
+ msgstr "認証プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:153
++#: src/config/SSSDConfig/__init__.py.in:155
+ msgid "Access control provider"
+ msgstr "アクセス制御プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:154
++#: src/config/SSSDConfig/__init__.py.in:156
+ msgid "Password change provider"
+ msgstr "パスワード変更プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:155
++#: src/config/SSSDConfig/__init__.py.in:157
+ msgid "SUDO provider"
+ msgstr "SUDO プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:156
++#: src/config/SSSDConfig/__init__.py.in:158
+ msgid "Autofs provider"
+ msgstr "Autofs プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:157
++#: src/config/SSSDConfig/__init__.py.in:159
+ msgid "Host identity provider"
+ msgstr "ホスト識別プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:158
++#: src/config/SSSDConfig/__init__.py.in:160
+ msgid "SELinux provider"
+-msgstr ""
++msgstr "SELinux プロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:159
++#: src/config/SSSDConfig/__init__.py.in:161
+ msgid "Session management provider"
+-msgstr ""
++msgstr "セッションマネージャーのプロバイダー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:162
++#: src/config/SSSDConfig/__init__.py.in:164
+ msgid "Whether the domain is usable by the OS or by applications"
+-msgstr ""
++msgstr "OS またはアプリケーションがドメインを使用できるかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:163
++#: src/config/SSSDConfig/__init__.py.in:165
+ msgid "Minimum user ID"
+ msgstr "最小ユーザー ID"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:164
++#: src/config/SSSDConfig/__init__.py.in:166
+ msgid "Maximum user ID"
+ msgstr "最大ユーザー ID"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:165
++#: src/config/SSSDConfig/__init__.py.in:167
+ msgid "Enable enumerating all users/groups"
+ msgstr "すべてのユーザー・グループの列挙を有効にする"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:166
++#: src/config/SSSDConfig/__init__.py.in:168
+ msgid "Cache credentials for offline login"
+ msgstr "オフラインログインのためにクレディンシャルをキャッシュする"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:167
+-msgid "Store password hashes"
+-msgstr ""
+-
+-#: src/config/SSSDConfig/__init__.py.in:168
++#: src/config/SSSDConfig/__init__.py.in:169
+ msgid "Display users/groups in fully-qualified form"
+ msgstr "ユーザー・グループを完全修飾形式で表示する"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:169
++#: src/config/SSSDConfig/__init__.py.in:170
+ msgid "Don't include group members in group lookups"
+ msgstr "グループ検索にグループメンバーを含めない"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:170
+-#: src/config/SSSDConfig/__init__.py.in:177
++#: src/config/SSSDConfig/__init__.py.in:171
+ #: src/config/SSSDConfig/__init__.py.in:178
+ #: src/config/SSSDConfig/__init__.py.in:179
+ #: src/config/SSSDConfig/__init__.py.in:180
+ #: src/config/SSSDConfig/__init__.py.in:181
+ #: src/config/SSSDConfig/__init__.py.in:182
++#: src/config/SSSDConfig/__init__.py.in:183
+ msgid "Entry cache timeout length (seconds)"
+ msgstr "エントリーキャッシュのタイムアウト長(秒)"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:171
++#: src/config/SSSDConfig/__init__.py.in:172
+ msgid ""
+ "Restrict or prefer a specific address family when performing DNS lookups"
+ msgstr "DNS 検索を実行するときに特定のアドレスファミリーを制限または優先します"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:172
++#: src/config/SSSDConfig/__init__.py.in:173
+ msgid "How long to keep cached entries after last successful login (days)"
+ msgstr "最終ログイン成功時からキャッシュエントリーを保持する日数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:173
++#: src/config/SSSDConfig/__init__.py.in:174
+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"
+ msgstr "サーバーを名前解決するときに DNS から応答を待つ時間(秒)"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:174
++#: src/config/SSSDConfig/__init__.py.in:175
+ msgid "The domain part of service discovery DNS query"
+ msgstr "サービス検索 DNS クエリーのドメイン部分"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:175
++#: src/config/SSSDConfig/__init__.py.in:176
+ msgid "Override GID value from the identity provider with this value"
+ msgstr "識別プロバイダーからの GID 値をこの値で上書きする"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:176
++#: src/config/SSSDConfig/__init__.py.in:177
+ msgid "Treat usernames as case sensitive"
+ msgstr "ユーザー名が大文字小文字を区別するよう取り扱う"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:183
++#: src/config/SSSDConfig/__init__.py.in:184
+ msgid "How often should expired entries be refreshed in background"
+ msgstr "期限切れのエントリーがバックグラウンドで更新される頻度"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:184
++#: src/config/SSSDConfig/__init__.py.in:185
+ msgid "Whether to automatically update the client's DNS entry"
+ msgstr "自動的にクライアントの DNS エントリーを更新するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:185
+-#: src/config/SSSDConfig/__init__.py.in:207
++#: src/config/SSSDConfig/__init__.py.in:186
++#: src/config/SSSDConfig/__init__.py.in:208
+ msgid "The TTL to apply to the client's DNS entry after updating it"
+ msgstr "クライアントの DNS 項目を更新後、適用する TTL"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:186
+-#: src/config/SSSDConfig/__init__.py.in:208
++#: src/config/SSSDConfig/__init__.py.in:187
++#: src/config/SSSDConfig/__init__.py.in:209
+ msgid "The interface whose IP should be used for dynamic DNS updates"
+ msgstr "動的 DNS 更新のために使用される IP のインターフェース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:187
++#: src/config/SSSDConfig/__init__.py.in:188
+ msgid "How often to periodically update the client's DNS entry"
+ msgstr "どのくらい定期的にクライアントの DNS エントリーを更新するか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:188
++#: src/config/SSSDConfig/__init__.py.in:189
+ msgid "Whether the provider should explicitly update the PTR record as well"
+-msgstr ""
+-"プロバイダーが同じように PTR レコードを明示的に更新する必要があるかどうか"
++msgstr "プロバイダーが同じように PTR レコードを明示的に更新する必要があるかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:189
++#: src/config/SSSDConfig/__init__.py.in:190
+ msgid "Whether the nsupdate utility should default to using TCP"
+ msgstr "nsupdate ユーティリティが標準で TCP を使用するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:190
++#: src/config/SSSDConfig/__init__.py.in:191
+ msgid "What kind of authentication should be used to perform the DNS update"
+ msgstr "DNS 更新を実行するために使用すべき認証の種類"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:191
++#: src/config/SSSDConfig/__init__.py.in:192
+ msgid "Override the DNS server used to perform the DNS update"
+-msgstr ""
++msgstr "DNS の更新を実行する際に使用する DNS サーバーを上書き"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:192
++#: src/config/SSSDConfig/__init__.py.in:193
+ msgid "Control enumeration of trusted domains"
+-msgstr ""
++msgstr "信頼されたドメインの列挙を制御"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:193
++#: src/config/SSSDConfig/__init__.py.in:194
+ msgid "How often should subdomains list be refreshed"
+-msgstr ""
++msgstr "サブドメインの一覧のリフレッシュ回数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:194
++#: src/config/SSSDConfig/__init__.py.in:195
+ msgid "List of options that should be inherited into a subdomain"
+-msgstr ""
++msgstr "サブドメインに継承すべきオプションの一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:195
++#: src/config/SSSDConfig/__init__.py.in:196
+ msgid "Default subdomain homedir value"
+-msgstr ""
++msgstr "デフォルトのサブドメインホームディレクトリーの値"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:196
++#: src/config/SSSDConfig/__init__.py.in:197
+ msgid "How long can cached credentials be used for cached authentication"
+-msgstr ""
++msgstr "証明書キャッシュを認証キャッシュに使用できる期間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:199
++#: src/config/SSSDConfig/__init__.py.in:200
+ msgid "Whether to automatically create private groups for users"
+-msgstr ""
++msgstr "ユーザーにプライベートグループを自動的に作成するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:202
++#: src/config/SSSDConfig/__init__.py.in:203
+ msgid "IPA domain"
+ msgstr "IPA ドメイン"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:203
++#: src/config/SSSDConfig/__init__.py.in:204
+ msgid "IPA server address"
+ msgstr "IPA サーバーのアドレス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:204
++#: src/config/SSSDConfig/__init__.py.in:205
+ msgid "Address of backup IPA server"
+ msgstr "バックアップ IPA サーバーのアドレス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:205
++#: src/config/SSSDConfig/__init__.py.in:206
+ msgid "IPA client hostname"
+ msgstr "IPA クライアントのホスト名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:206
++#: src/config/SSSDConfig/__init__.py.in:207
+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"
+ msgstr "FreeIPA にあるクライアントの DNS エントリーを自動的に更新するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:209
++#: src/config/SSSDConfig/__init__.py.in:210
+ msgid "Search base for HBAC related objects"
+ msgstr "HBAC 関連オブジェクトの検索ベース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:210
++#: src/config/SSSDConfig/__init__.py.in:211
+ msgid ""
+ "The amount of time between lookups of the HBAC rules against the IPA server"
+ msgstr "IPA サーバーに対する HBAC ルールを検索している間の合計時間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:211
++#: src/config/SSSDConfig/__init__.py.in:212
+ msgid ""
+ "The amount of time in seconds between lookups of the SELinux maps against "
+ "the IPA server"
+ msgstr "IPA サーバーに対する SELinux マップの検索の間の秒単位の合計時間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:212
++#: src/config/SSSDConfig/__init__.py.in:213
+ msgid "If set to false, host argument given by PAM will be ignored"
+ msgstr "もし偽に設定されていると、 PAM により渡されたホスト引数は無視されます"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:213
++#: src/config/SSSDConfig/__init__.py.in:214
+ msgid "The automounter location this IPA client is using"
+ msgstr "この IPA クライアントが使用している automounter の場所"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:214
++#: src/config/SSSDConfig/__init__.py.in:215
+ msgid "Search base for object containing info about IPA domain"
+ msgstr "IPA ドメインに関する情報を含むオブジェクトに対する検索ベース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:215
++#: src/config/SSSDConfig/__init__.py.in:216
+ msgid "Search base for objects containing info about ID ranges"
+ msgstr "ID 範囲に関する情報を含むオブジェクトに対する検索ベース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:216
+-#: src/config/SSSDConfig/__init__.py.in:234
++#: src/config/SSSDConfig/__init__.py.in:217
++#: src/config/SSSDConfig/__init__.py.in:235
+ msgid "Enable DNS sites - location based service discovery"
+ msgstr "DNS サイトの有効化 - 位置にサービス探索"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:217
++#: src/config/SSSDConfig/__init__.py.in:218
+ msgid "Search base for view containers"
+-msgstr ""
++msgstr "ビューコンテナーの検索ベース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:218
++#: src/config/SSSDConfig/__init__.py.in:219
+ msgid "Objectclass for view containers"
+-msgstr ""
++msgstr "ビューコンテナーのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:219
++#: src/config/SSSDConfig/__init__.py.in:220
+ msgid "Attribute with the name of the view"
+-msgstr ""
++msgstr "ビューの名前の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:220
++#: src/config/SSSDConfig/__init__.py.in:221
+ msgid "Objectclass for override objects"
+-msgstr ""
++msgstr "上書きされたオブジェクトのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:221
++#: src/config/SSSDConfig/__init__.py.in:222
+ msgid "Attribute with the reference to the original object"
+-msgstr ""
++msgstr "オリジナルオブジェクトを参照する属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:222
++#: src/config/SSSDConfig/__init__.py.in:223
+ msgid "Objectclass for user override objects"
+-msgstr ""
++msgstr "ユーザーが上書きするオブジェクトのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:223
++#: src/config/SSSDConfig/__init__.py.in:224
+ msgid "Objectclass for group override objects"
+-msgstr ""
++msgstr "グループが上書きするオブジェクトのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:224
++#: src/config/SSSDConfig/__init__.py.in:225
+ msgid "Search base for Desktop Profile related objects"
+-msgstr ""
++msgstr "デスクトッププロファイルに関連するオブジェクトの検索ベース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:225
++#: src/config/SSSDConfig/__init__.py.in:226
+ msgid ""
+ "The amount of time in seconds between lookups of the Desktop Profile rules "
+ "against the IPA server"
+-msgstr ""
++msgstr "IPA サーバーに対するデスクトッププロファイルルールを検索している間の秒単位の合計時間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:226
++#: src/config/SSSDConfig/__init__.py.in:227
+ msgid ""
+ "The amount of time in minutes between lookups of Desktop Profiles rules "
+ "against the IPA server when the last request did not find any rule"
+-msgstr ""
++msgstr "最後の要求がルールを何も見つけなかった場合の IPA サーバーに対するデスクトッププロファイルル ールを検索している間の分単位の合計時間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:229
++#: src/config/SSSDConfig/__init__.py.in:230
+ msgid "Active Directory domain"
+ msgstr "Active Directory ドメイン"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:230
++#: src/config/SSSDConfig/__init__.py.in:231
+ msgid "Enabled Active Directory domains"
+-msgstr ""
++msgstr "有効化された Active Directory ドメイン"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:231
++#: src/config/SSSDConfig/__init__.py.in:232
+ msgid "Active Directory server address"
+ msgstr "Active Directory サーバーアドレス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:232
++#: src/config/SSSDConfig/__init__.py.in:233
+ msgid "Active Directory backup server address"
+ msgstr "Active Directory バックアップサーバーのアドレス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:233
++#: src/config/SSSDConfig/__init__.py.in:234
+ msgid "Active Directory client hostname"
+ msgstr "Active Directory クライアントホスト名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:235
+-#: src/config/SSSDConfig/__init__.py.in:422
++#: src/config/SSSDConfig/__init__.py.in:236
++#: src/config/SSSDConfig/__init__.py.in:420
+ msgid "LDAP filter to determine access privileges"
+ msgstr "アクセス権限を決めるための LDAP フィルター"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:236
++#: src/config/SSSDConfig/__init__.py.in:237
+ msgid "Whether to use the Global Catalog for lookups"
+-msgstr ""
++msgstr "検索にグローバルカタログを使用するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:237
++#: src/config/SSSDConfig/__init__.py.in:238
+ msgid "Operation mode for GPO-based access control"
+-msgstr ""
++msgstr "グローバルカタログベースのアクセス制御に対するオペレーションモード"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:238
++#: src/config/SSSDConfig/__init__.py.in:239
+ msgid ""
+ "The amount of time between lookups of the GPO policy files against the AD "
+ "server"
+-msgstr ""
++msgstr "AD サーバーに対する GPO ポリシーファイルを検索している間の合計時間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:239
++#: src/config/SSSDConfig/__init__.py.in:240
+ msgid ""
+ "PAM service names that map to the GPO (Deny)InteractiveLogonRight policy "
+ "settings"
+-msgstr ""
++msgstr "GPO (Deny)InteractiveLogonRight のポリシー設定にマッピングした PAM サービス名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:240
++#: src/config/SSSDConfig/__init__.py.in:241
+ msgid ""
+ "PAM service names that map to the GPO (Deny)RemoteInteractiveLogonRight "
+ "policy settings"
+-msgstr ""
+-
+-#: src/config/SSSDConfig/__init__.py.in:241
+-msgid ""
+-"PAM service names that map to the GPO (Deny)NetworkLogonRight policy settings"
+-msgstr ""
++msgstr "GPO (Deny)RemoteInteractiveLogonRight のポリシー設定にマッピングした PAM サービス名"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:242
+ msgid ""
+-"PAM service names that map to the GPO (Deny)BatchLogonRight policy settings"
+-msgstr ""
++"PAM service names that map to the GPO (Deny)NetworkLogonRight policy "
++"settings"
++msgstr "GPO (Deny)NetworkLogonRight のポリシー設定にマッピングした PAM サービス名"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:243
+ msgid ""
+-"PAM service names that map to the GPO (Deny)ServiceLogonRight policy settings"
+-msgstr ""
++"PAM service names that map to the GPO (Deny)BatchLogonRight policy settings"
++msgstr "GPO (Deny)BatchLogonRight のポリシー設定にマッピングした PAM サービス名"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:244
+-msgid "PAM service names for which GPO-based access is always granted"
+-msgstr ""
++msgid ""
++"PAM service names that map to the GPO (Deny)ServiceLogonRight policy "
++"settings"
++msgstr "(Deny)ServiceLogonRight のポリシー設定にマッピングした PAM サービス名"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:245
+-msgid "PAM service names for which GPO-based access is always denied"
+-msgstr ""
++msgid "PAM service names for which GPO-based access is always granted"
++msgstr "GPO ベースのアクセスが常に許可される PAM サービス名"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:246
++msgid "PAM service names for which GPO-based access is always denied"
++msgstr "GPO ベースのアクセスが常に拒否される PAM サービス名"
++
++#: src/config/SSSDConfig/__init__.py.in:247
+ msgid ""
+ "Default logon right (or permit/deny) to use for unmapped PAM service names"
+-msgstr ""
++msgstr "マッピングされていない PAM サービス名に使用するデフォルトのログオン権利 (または許可/拒否)"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:247
++#: src/config/SSSDConfig/__init__.py.in:248
+ msgid "a particular site to be used by the client"
+-msgstr ""
++msgstr "クライアントが使用する特定のサイト"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:248
++#: src/config/SSSDConfig/__init__.py.in:249
+ msgid ""
+ "Maximum age in days before the machine account password should be renewed"
+-msgstr ""
++msgstr "マシンアカウントのパスワードの更新が必要となるまでの最大日数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:249
++#: src/config/SSSDConfig/__init__.py.in:250
+ msgid "Option for tuning the machine account renewal task"
+-msgstr ""
++msgstr "マシンアカウントの更新タスクをチューニングするオプション"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:252
+ #: src/config/SSSDConfig/__init__.py.in:253
++#: src/config/SSSDConfig/__init__.py.in:254
+ msgid "Kerberos server address"
+ msgstr "Kerberos サーバーのアドレス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:254
++#: src/config/SSSDConfig/__init__.py.in:255
+ msgid "Kerberos backup server address"
+ msgstr "Kerberos バックアップサーバーのアドレス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:255
++#: src/config/SSSDConfig/__init__.py.in:256
+ msgid "Kerberos realm"
+ msgstr "Kerberos レルム"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:256
++#: src/config/SSSDConfig/__init__.py.in:257
+ msgid "Authentication timeout"
+ msgstr "認証のタイムアウト"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:257
++#: src/config/SSSDConfig/__init__.py.in:258
+ msgid "Whether to create kdcinfo files"
+ msgstr "kdcinfo ファイルを作成するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:258
++#: src/config/SSSDConfig/__init__.py.in:259
+ msgid "Where to drop krb5 config snippets"
+-msgstr ""
++msgstr "krb5 設定スニペットを削除する場所"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:261
++#: src/config/SSSDConfig/__init__.py.in:262
+ msgid "Directory to store credential caches"
+ msgstr "クレディンシャルのキャッシュを保存するディレクトリー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:262
++#: src/config/SSSDConfig/__init__.py.in:263
+ msgid "Location of the user's credential cache"
+ msgstr "ユーザーのクレディンシャルキャッシュの位置"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:263
++#: src/config/SSSDConfig/__init__.py.in:264
+ msgid "Location of the keytab to validate credentials"
+ msgstr "クレディンシャルを検証するキーテーブルの場所"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:264
++#: src/config/SSSDConfig/__init__.py.in:265
+ msgid "Enable credential validation"
+ msgstr "クレディンシャルの検証を有効にする"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:265
++#: src/config/SSSDConfig/__init__.py.in:266
+ msgid "Store password if offline for later online authentication"
+ msgstr "後からオンライン認証するためにオフラインの場合にパスワードを保存します"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:266
++#: src/config/SSSDConfig/__init__.py.in:267
+ msgid "Renewable lifetime of the TGT"
+ msgstr "更新可能な TGT の有効期間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:267
++#: src/config/SSSDConfig/__init__.py.in:268
+ msgid "Lifetime of the TGT"
+ msgstr "TGT の有効期間"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:268
++#: src/config/SSSDConfig/__init__.py.in:269
+ msgid "Time between two checks for renewal"
+ msgstr "更新を確認する間隔"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:269
++#: src/config/SSSDConfig/__init__.py.in:270
+ msgid "Enables FAST"
+ msgstr "FAST を有効にする"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:270
++#: src/config/SSSDConfig/__init__.py.in:271
+ msgid "Selects the principal to use for FAST"
+ msgstr "FAST に使用するプリンシパルを選択する"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:271
++#: src/config/SSSDConfig/__init__.py.in:272
+ msgid "Enables principal canonicalization"
+ msgstr "プリンシパル正規化を有効にする"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:272
++#: src/config/SSSDConfig/__init__.py.in:273
+ msgid "Enables enterprise principals"
+ msgstr "エンタープライズ・プリンシパルの有効化"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:273
++#: src/config/SSSDConfig/__init__.py.in:274
+ msgid "A mapping from user names to Kerberos principal names"
+-msgstr ""
++msgstr "ユーザー名から Kerberos プリンシパル名までのマッピング"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:276
+ #: src/config/SSSDConfig/__init__.py.in:277
++#: src/config/SSSDConfig/__init__.py.in:278
+ msgid "Server where the change password service is running if not on the KDC"
+ msgstr "KDC になければ、パスワード変更サービスが実行されているサーバー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:280
++#: src/config/SSSDConfig/__init__.py.in:281
+ msgid "ldap_uri, The URI of the LDAP server"
+ msgstr "ldap_uri, LDAP サーバーの URI"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:281
++#: src/config/SSSDConfig/__init__.py.in:282
+ msgid "ldap_backup_uri, The URI of the LDAP server"
+ msgstr "ldap_backup_uri, LDAP サーバーの URI"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:282
++#: src/config/SSSDConfig/__init__.py.in:283
+ msgid "The default base DN"
+ msgstr "デフォルトのベース DN"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:283
++#: src/config/SSSDConfig/__init__.py.in:284
+ msgid "The Schema Type in use on the LDAP server, rfc2307"
+ msgstr "LDAP サーバーにおいて使用中のスキーマ形式, rfc2307"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:284
+-#, fuzzy
+-msgid "Mode used to change user password"
+-msgstr "パスワードの期限が切れました。いますぐパスワードを変更してください。"
+-
+ #: src/config/SSSDConfig/__init__.py.in:285
+ msgid "The default bind DN"
+ msgstr "デフォルトのバインド DN"
+@@ -956,9 +956,7 @@ msgstr "完全な参照解決を引き起こすために欠けている必要が
+ msgid ""
+ "Whether the LDAP library should perform a reverse lookup to canonicalize the "
+ "host name during a SASL bind"
+-msgstr ""
+-"LDAP ライブラリーが SASL バインド中にホスト名を正規化するために逆引きを実行す"
+-"るかどうか"
++msgstr "LDAP ライブラリーが SASL バインド中にホスト名を正規化するために逆引きを実行するかどうか"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:312
+ msgid "entryUSN attribute"
+@@ -969,7 +967,8 @@ msgid "lastUSN attribute"
+ msgstr "lastUSN 属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:315
+-msgid "How long to retain a connection to the LDAP server before disconnecting"
++msgid ""
++"How long to retain a connection to the LDAP server before disconnecting"
+ msgstr "LDAP サーバーを切断する前に接続を保持する時間"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:317
+@@ -1046,7 +1045,7 @@ msgstr "シェルの属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:338
+ msgid "UUID attribute"
+-msgstr ""
++msgstr "UUID 属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:339
+ #: src/config/SSSDConfig/__init__.py.in:381
+@@ -1111,7 +1110,7 @@ msgstr "認可されたサーバーホストを一覧化する属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:355
+ msgid "Attribute listing authorized server rhosts"
+-msgstr ""
++msgstr "認可されたサーバー rhosts を一覧化する属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:356
+ msgid "krbLastPwdChange attribute"
+@@ -1155,19 +1154,19 @@ msgstr "SSH 公開鍵の属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:366
+ msgid "attribute listing allowed authentication types for a user"
+-msgstr ""
++msgstr "ユーザー用に許可された認証タイプを一覧化する属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:367
+ msgid "attribute containing the X509 certificate of the user"
+-msgstr ""
++msgstr "ユーザーの X509 証明書を含む属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:368
+ msgid "attribute containing the email address of the user"
+-msgstr ""
++msgstr "ユーザーの電子メールアドレスを含む属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:370
+ msgid "A list of extra attributes to download along with the user entry"
+-msgstr ""
++msgstr "ユーザーエントリーと共にダウンロードする追加的な属性の一覧"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:372
+ msgid "Base DN for group lookups"
+@@ -1195,7 +1194,7 @@ msgstr "グループメンバー属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:380
+ msgid "Group UUID attribute"
+-msgstr ""
++msgstr "グループ UUID 属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:382
+ msgid "Modification time attribute for groups"
+@@ -1203,15 +1202,15 @@ msgstr "グループの変更日時の属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:383
+ msgid "Type of the group and other flags"
+-msgstr ""
++msgstr "グループおよび他のフラグのタイプ"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:384
+ msgid "The LDAP group external member attribute"
+-msgstr ""
++msgstr "LDAP グループの外部メンバーの属性"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:386
+ msgid "Maximum nesting level SSSD will follow"
+-msgstr ""
++msgstr "SSSD が従う最大ネストレベル"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:388
+ msgid "Base DN for netgroup lookups"
+@@ -1283,419 +1282,407 @@ msgstr "ID マッピングに対するデフォルトドメインの SID"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:408
+ msgid "Number of secondary slices"
+-msgstr ""
++msgstr "セカンダリースライスの数"
+ 
+ #: src/config/SSSDConfig/__init__.py.in:410
+-#, fuzzy
+-msgid "Use LDAP_MATCHING_RULE_IN_CHAIN for group lookups"
+-msgstr "グループ検索のベース DN"
+-
+-#: src/config/SSSDConfig/__init__.py.in:411
+-#, fuzzy
+-msgid "Use LDAP_MATCHING_RULE_IN_CHAIN for initgroup lookups"
+-msgstr "ネットグループ検索のベース DN"
+-
+-#: src/config/SSSDConfig/__init__.py.in:412
+ msgid "Whether to use Token-Groups"
+-msgstr ""
++msgstr "Token-Group を使うかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:413
++#: src/config/SSSDConfig/__init__.py.in:411
+ msgid "Set lower boundary for allowed IDs from the LDAP server"
+ msgstr "LDAP サーバーから許可される ID の下限の設定"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:414
++#: src/config/SSSDConfig/__init__.py.in:412
+ msgid "Set upper boundary for allowed IDs from the LDAP server"
+ msgstr "LDAP サーバーから許可される ID の上限の設定"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:415
++#: src/config/SSSDConfig/__init__.py.in:413
+ msgid "DN for ppolicy queries"
+-msgstr ""
++msgstr "ppolicy クエリーの DN"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:416
++#: src/config/SSSDConfig/__init__.py.in:414
+ msgid "How many maximum entries to fetch during a wildcard request"
+-msgstr ""
++msgstr "ワイルドカードの要求の間に取得する最大エントリーの数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:419
++#: src/config/SSSDConfig/__init__.py.in:417
+ msgid "Policy to evaluate the password expiration"
+ msgstr "パスワード失効の評価のポリシー"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:423
++#: src/config/SSSDConfig/__init__.py.in:421
+ msgid "Which attributes shall be used to evaluate if an account is expired"
+ msgstr "どの属性がアカウントが失効しているかを評価するために使用されるか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:424
++#: src/config/SSSDConfig/__init__.py.in:422
+ msgid "Which rules should be used to evaluate access control"
+ msgstr "どのルールがアクセス制御を評価するために使用されるか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:427
++#: src/config/SSSDConfig/__init__.py.in:425
+ msgid "URI of an LDAP server where password changes are allowed"
+ msgstr "パスワードの変更が許可される LDAP サーバーの URI"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:428
++#: src/config/SSSDConfig/__init__.py.in:426
+ msgid "URI of a backup LDAP server where password changes are allowed"
+ msgstr "パスワードの変更が許可されるバックアップ LDAP サーバーの URI"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:429
++#: src/config/SSSDConfig/__init__.py.in:427
+ msgid "DNS service name for LDAP password change server"
+ msgstr "LDAP パスワードの変更サーバーの DNS サービス名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:430
++#: src/config/SSSDConfig/__init__.py.in:428
+ msgid ""
+ "Whether to update the ldap_user_shadow_last_change attribute after a "
+ "password change"
+ msgstr "パスワード変更後 ldap_user_shadow_last_change 属性を更新するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:433
++#: src/config/SSSDConfig/__init__.py.in:431
+ msgid "Base DN for sudo rules lookups"
+ msgstr "sudo ルール検索のベース DN"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:434
++#: src/config/SSSDConfig/__init__.py.in:432
+ msgid "Automatic full refresh period"
+ msgstr "自動的な完全更新間隔"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:435
++#: src/config/SSSDConfig/__init__.py.in:433
+ msgid "Automatic smart refresh period"
+ msgstr "自動的なスマート更新間隔"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:436
++#: src/config/SSSDConfig/__init__.py.in:434
+ msgid "Whether to filter rules by hostname, IP addresses and network"
+-msgstr ""
+-"ホスト名、IP アドレスおよびネットワークによるフィルタールールを使用するかどう"
+-"か"
++msgstr "ホスト名、IP アドレスおよびネットワークによるフィルタールールを使用するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:437
++#: src/config/SSSDConfig/__init__.py.in:435
+ msgid ""
+ "Hostnames and/or fully qualified domain names of this machine to filter sudo "
+ "rules"
+-msgstr ""
+-"sudo ルールをフィルターするこのマシンのホスト名および/または完全修飾ドメイン"
+-"名"
++msgstr "sudo ルールをフィルターするこのマシンのホスト名および/または完全修飾ドメイン名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:438
++#: src/config/SSSDConfig/__init__.py.in:436
+ msgid "IPv4 or IPv6 addresses or network of this machine to filter sudo rules"
+-msgstr ""
+-"sudo ルールをフィルターするこのマシンの IPv4 または IPv6 アドレスまたはネット"
+-"ワーク"
++msgstr "sudo ルールをフィルターするこのマシンの IPv4 または IPv6 アドレスまたはネットワーク"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:439
++#: src/config/SSSDConfig/__init__.py.in:437
+ msgid "Whether to include rules that contains netgroup in host attribute"
+ msgstr "ホスト属性にネットワークグループを含むルールを含めるかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:440
++#: src/config/SSSDConfig/__init__.py.in:438
+ msgid ""
+ "Whether to include rules that contains regular expression in host attribute"
+ msgstr "ホスト属性に正規表現を含むルールを含めるかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:441
++#: src/config/SSSDConfig/__init__.py.in:439
+ msgid "Object class for sudo rules"
+ msgstr "sudo ルールのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:442
++#: src/config/SSSDConfig/__init__.py.in:440
+ msgid "Sudo rule name"
+ msgstr "sudo ルール名"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:443
++#: src/config/SSSDConfig/__init__.py.in:441
+ msgid "Sudo rule command attribute"
+ msgstr "sudo ルールのコマンドの属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:444
++#: src/config/SSSDConfig/__init__.py.in:442
+ msgid "Sudo rule host attribute"
+ msgstr "sudo ルールのホストの属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:445
++#: src/config/SSSDConfig/__init__.py.in:443
+ msgid "Sudo rule user attribute"
+ msgstr "sudo ルールのユーザーの属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:446
++#: src/config/SSSDConfig/__init__.py.in:444
+ msgid "Sudo rule option attribute"
+ msgstr "sudo ルールのオプションの属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:447
++#: src/config/SSSDConfig/__init__.py.in:445
+ msgid "Sudo rule runas attribute"
+-msgstr ""
++msgstr "sudo ルールの runas の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:448
++#: src/config/SSSDConfig/__init__.py.in:446
+ msgid "Sudo rule runasuser attribute"
+ msgstr "sudo ルールの runasuser の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:449
++#: src/config/SSSDConfig/__init__.py.in:447
+ msgid "Sudo rule runasgroup attribute"
+ msgstr "sudo ルールの runasgroup の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:450
++#: src/config/SSSDConfig/__init__.py.in:448
+ msgid "Sudo rule notbefore attribute"
+ msgstr "sudo ルールの notbefore の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:451
++#: src/config/SSSDConfig/__init__.py.in:449
+ msgid "Sudo rule notafter attribute"
+ msgstr "sudo ルールの notafter の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:452
++#: src/config/SSSDConfig/__init__.py.in:450
+ msgid "Sudo rule order attribute"
+ msgstr "sudo ルールの order の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:455
++#: src/config/SSSDConfig/__init__.py.in:453
+ msgid "Object class for automounter maps"
+ msgstr "automounter マップのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:456
++#: src/config/SSSDConfig/__init__.py.in:454
+ msgid "Automounter map name attribute"
+ msgstr "オートマウントのマップ名の属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:457
++#: src/config/SSSDConfig/__init__.py.in:455
+ msgid "Object class for automounter map entries"
+ msgstr "automounter マップエントリーのオブジェクトクラス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:458
++#: src/config/SSSDConfig/__init__.py.in:456
+ msgid "Automounter map entry key attribute"
+ msgstr "automounter マップエントリーのキー属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:459
++#: src/config/SSSDConfig/__init__.py.in:457
+ msgid "Automounter map entry value attribute"
+ msgstr "automounter マップエントリーの値属性"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:460
++#: src/config/SSSDConfig/__init__.py.in:458
+ msgid "Base DN for automounter map lookups"
+ msgstr "automonter のマップ検索のベース DN"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:463
++#: src/config/SSSDConfig/__init__.py.in:461
+ msgid "Comma separated list of allowed users"
+ msgstr "許可ユーザーのカンマ区切り一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:464
++#: src/config/SSSDConfig/__init__.py.in:462
+ msgid "Comma separated list of prohibited users"
+ msgstr "禁止ユーザーのカンマ区切り一覧"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:467
++#: src/config/SSSDConfig/__init__.py.in:465
+ msgid "Default shell, /bin/bash"
+ msgstr "デフォルトのシェル, /bin/bash"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:468
++#: src/config/SSSDConfig/__init__.py.in:466
+ msgid "Base for home directories"
+ msgstr "ホームディレクトリーのベース"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:471
++#: src/config/SSSDConfig/__init__.py.in:469
+ msgid "The number of preforked proxy children."
+-msgstr ""
++msgstr "事前にフォークされた子プロキシの数"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:474
++#: src/config/SSSDConfig/__init__.py.in:472
+ msgid "The name of the NSS library to use"
+ msgstr "使用する NSS ライブラリーの名前"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:475
++#: src/config/SSSDConfig/__init__.py.in:473
+ msgid "Whether to look up canonical group name from cache if possible"
+ msgstr "可能ならばキャッシュから正規化されたグループ名を検索するかどうか"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:478
++#: src/config/SSSDConfig/__init__.py.in:476
+ msgid "PAM stack to use"
+ msgstr "使用する PAM スタック"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:481
++#: src/config/SSSDConfig/__init__.py.in:479
+ msgid "Path of passwd file sources."
+-msgstr ""
++msgstr "passwd ファイルソースへのパス"
+ 
+-#: src/config/SSSDConfig/__init__.py.in:482
++#: src/config/SSSDConfig/__init__.py.in:480
+ msgid "Path of group file sources."
+-msgstr ""
++msgstr "グループファイルソースへのパス"
+ 
+-#: src/monitor/monitor.c:2452
++#: src/monitor/monitor.c:2347
+ msgid "Become a daemon (default)"
+ msgstr "デーモンとして実行(デフォルト)"
+ 
+-#: src/monitor/monitor.c:2454
++#: src/monitor/monitor.c:2349
+ msgid "Run interactive (not a daemon)"
+ msgstr "対話的に実行(デーモンではない)"
+ 
+-#: src/monitor/monitor.c:2457
++#: src/monitor/monitor.c:2352
+ msgid "Disable netlink interface"
+-msgstr ""
++msgstr "netlink インターフェースを無効にする"
+ 
+-#: src/monitor/monitor.c:2459 src/tools/sssctl/sssctl_logs.c:311
++#: src/monitor/monitor.c:2354 src/tools/sssctl/sssctl_logs.c:311
+ msgid "Specify a non-default config file"
+ msgstr "非標準の設定ファイルの指定"
+ 
+-#: src/monitor/monitor.c:2461
++#: src/monitor/monitor.c:2356
+ msgid "Refresh the configuration database, then exit"
+-msgstr ""
++msgstr "設定データベースをリフレッシュし、その後終了します"
+ 
+-#: src/monitor/monitor.c:2464
++#: src/monitor/monitor.c:2359
++msgid "Similar to --genconf, but only refreshes the given section"
++msgstr "--genconf と似ていますが、任意のセクションのみをリフレッシュします"
++
++#: src/monitor/monitor.c:2362
+ msgid "Print version number and exit"
+ msgstr "バージョン番号を表示して終了する"
+ 
+-#: src/monitor/monitor.c:2630
++#: src/monitor/monitor.c:2538
+ msgid "SSSD is already running\n"
+-msgstr ""
++msgstr "SSSD はすでに実行中です\n"
+ 
+-#: src/providers/krb5/krb5_child.c:3216 src/providers/ldap/ldap_child.c:605
++#: src/providers/krb5/krb5_child.c:3219 src/providers/ldap/ldap_child.c:605
+ msgid "Debug level"
+ msgstr "デバッグレベル"
+ 
+-#: src/providers/krb5/krb5_child.c:3218 src/providers/ldap/ldap_child.c:607
++#: src/providers/krb5/krb5_child.c:3221 src/providers/ldap/ldap_child.c:607
+ msgid "Add debug timestamps"
+ msgstr "デバッグのタイムスタンプを追加する"
+ 
+-#: src/providers/krb5/krb5_child.c:3220 src/providers/ldap/ldap_child.c:609
++#: src/providers/krb5/krb5_child.c:3223 src/providers/ldap/ldap_child.c:609
+ msgid "Show timestamps with microseconds"
+ msgstr "タイムスタンプをミリ秒単位で表示する"
+ 
+-#: src/providers/krb5/krb5_child.c:3222 src/providers/ldap/ldap_child.c:611
++#: src/providers/krb5/krb5_child.c:3225 src/providers/ldap/ldap_child.c:611
+ msgid "An open file descriptor for the debug logs"
+ msgstr "デバッグログのオープンファイルディスクリプター"
+ 
+-#: src/providers/krb5/krb5_child.c:3225 src/providers/ldap/ldap_child.c:613
++#: src/providers/krb5/krb5_child.c:3228 src/providers/ldap/ldap_child.c:613
+ msgid "Send the debug output to stderr directly."
+-msgstr ""
++msgstr "デバッグ出力を stderr に直接送信します。"
+ 
+-#: src/providers/krb5/krb5_child.c:3228
++#: src/providers/krb5/krb5_child.c:3231
+ msgid "The user to create FAST ccache as"
+-msgstr ""
++msgstr "次のように FAST ccache を作成するユーザー"
+ 
+-#: src/providers/krb5/krb5_child.c:3230
++#: src/providers/krb5/krb5_child.c:3233
+ msgid "The group to create FAST ccache as"
+-msgstr ""
++msgstr "次のように FAST ccache を作成するグループ"
+ 
+-#: src/providers/krb5/krb5_child.c:3232
++#: src/providers/krb5/krb5_child.c:3235
+ msgid "Kerberos realm to use"
+-msgstr ""
++msgstr "使用する Kerberos レルム"
+ 
+-#: src/providers/krb5/krb5_child.c:3234
++#: src/providers/krb5/krb5_child.c:3237
+ msgid "Requested lifetime of the ticket"
+-msgstr ""
++msgstr "チケットの要求された有効期間"
+ 
+-#: src/providers/krb5/krb5_child.c:3236
++#: src/providers/krb5/krb5_child.c:3239
+ msgid "Requested renewable lifetime of the ticket"
+-msgstr ""
++msgstr "チケットの要求された更新可能な有効期間"
+ 
+-#: src/providers/krb5/krb5_child.c:3238
++#: src/providers/krb5/krb5_child.c:3241
+ msgid "FAST options ('never', 'try', 'demand')"
+-msgstr ""
++msgstr "FAST のオプション ('never'、'try'、'demand')"
+ 
+-#: src/providers/krb5/krb5_child.c:3241
++#: src/providers/krb5/krb5_child.c:3244
+ msgid "Specifies the server principal to use for FAST"
+-msgstr ""
++msgstr "FAST で使用するサーバープリンシパルを指定します"
+ 
+-#: src/providers/krb5/krb5_child.c:3243
++#: src/providers/krb5/krb5_child.c:3246
+ msgid "Requests canonicalization of the principal name"
+-msgstr ""
++msgstr "プリンシパル名の正規化を要求します"
+ 
+-#: src/providers/krb5/krb5_child.c:3245
++#: src/providers/krb5/krb5_child.c:3248
+ msgid "Use custom version of krb5_get_init_creds_password"
+-msgstr ""
++msgstr "krb5_get_init_creds_password のカスタムバージョンを使用します"
+ 
+-#: src/providers/data_provider_be.c:556
++#: src/providers/data_provider_be.c:630
+ msgid "Domain of the information provider (mandatory)"
+ msgstr "情報プロバイダーのドメイン (必須)"
+ 
+-#: src/sss_client/common.c:1066
++#: src/sss_client/common.c:1067
+ msgid "Privileged socket has wrong ownership or permissions."
+ msgstr "特権ソケットの所有者またはパーミッションが誤っています。"
+ 
+-#: src/sss_client/common.c:1069
++#: src/sss_client/common.c:1070
+ msgid "Public socket has wrong ownership or permissions."
+ msgstr "公開ソケットの所有者またはパーミッションが誤っています。"
+ 
+-#: src/sss_client/common.c:1072
++#: src/sss_client/common.c:1073
+ msgid "Unexpected format of the server credential message."
+ msgstr "サーバーのクレディンシャルメッセージの予期しない形式です。"
+ 
+-#: src/sss_client/common.c:1075
++#: src/sss_client/common.c:1076
+ msgid "SSSD is not run by root."
+ msgstr "SSSD は root により実行されません。"
+ 
+-#: src/sss_client/common.c:1080
++#: src/sss_client/common.c:1081
+ msgid "An error occurred, but no description can be found."
+ msgstr "エラーが発生しましたが、説明がありませんでした。"
+ 
+-#: src/sss_client/common.c:1086
++#: src/sss_client/common.c:1087
+ msgid "Unexpected error while looking for an error description"
+ msgstr "エラーの説明を検索中に予期しないエラーが発生しました"
+ 
+-#: src/sss_client/pam_sss.c:76
++#: src/sss_client/pam_sss.c:67
+ msgid "Permission denied. "
+-msgstr ""
++msgstr "パーミッションが拒否されました。"
+ 
+-#: src/sss_client/pam_sss.c:77 src/sss_client/pam_sss.c:782
+-#: src/sss_client/pam_sss.c:793
++#: src/sss_client/pam_sss.c:68 src/sss_client/pam_sss.c:774
++#: src/sss_client/pam_sss.c:785
+ msgid "Server message: "
+ msgstr "サーバーのメッセージ: "
+ 
+-#: src/sss_client/pam_sss.c:300
++#: src/sss_client/pam_sss.c:292
+ msgid "Passwords do not match"
+ msgstr "パスワードが一致しません"
+ 
+-#: src/sss_client/pam_sss.c:488
++#: src/sss_client/pam_sss.c:480
+ msgid "Password reset by root is not supported."
+ msgstr "root によるパスワードのリセットはサポートされません。"
+ 
+-#: src/sss_client/pam_sss.c:529
++#: src/sss_client/pam_sss.c:521
+ msgid "Authenticated with cached credentials"
+ msgstr "キャッシュされているクレディンシャルを用いて認証されました"
+ 
+-#: src/sss_client/pam_sss.c:530
++#: src/sss_client/pam_sss.c:522
+ msgid ", your cached password will expire at: "
+ msgstr "、キャッシュされたパスワードが失効します: "
+ 
+-#: src/sss_client/pam_sss.c:560
++#: src/sss_client/pam_sss.c:552
+ #, c-format
+ msgid "Your password has expired. You have %1$d grace login(s) remaining."
+ msgstr "パスワードの期限が切れています。あと %1$d 回ログインできます。"
+ 
+-#: src/sss_client/pam_sss.c:606
++#: src/sss_client/pam_sss.c:598
+ #, c-format
+ msgid "Your password will expire in %1$d %2$s."
+ msgstr "あなたのパスワードは %1$d %2$s に期限切れになります。"
+ 
+-#: src/sss_client/pam_sss.c:655
++#: src/sss_client/pam_sss.c:647
+ msgid "Authentication is denied until: "
+ msgstr "次まで認証が拒否されます: "
+ 
+-#: src/sss_client/pam_sss.c:676
++#: src/sss_client/pam_sss.c:668
+ msgid "System is offline, password change not possible"
+ msgstr "システムがオフラインです、パスワード変更ができません"
+ 
+-#: src/sss_client/pam_sss.c:691
++#: src/sss_client/pam_sss.c:683
+ msgid ""
+ "After changing the OTP password, you need to log out and back in order to "
+ "acquire a ticket"
+-msgstr ""
++msgstr "OTP パスワードの変更後、チケットを取得するためにログアウト後に再びログインする必要があります"
+ 
+-#: src/sss_client/pam_sss.c:779 src/sss_client/pam_sss.c:792
++#: src/sss_client/pam_sss.c:771 src/sss_client/pam_sss.c:784
+ msgid "Password change failed. "
+ msgstr "パスワードの変更に失敗しました。 "
+ 
+-#: src/sss_client/pam_sss.c:1926
++#: src/sss_client/pam_sss.c:1921
+ msgid "New Password: "
+ msgstr "新しいパスワード: "
+ 
+-#: src/sss_client/pam_sss.c:1927
++#: src/sss_client/pam_sss.c:1922
+ msgid "Reenter new Password: "
+ msgstr "新しいパスワードの再入力: "
+ 
+-#: src/sss_client/pam_sss.c:2039 src/sss_client/pam_sss.c:2042
++#: src/sss_client/pam_sss.c:2038 src/sss_client/pam_sss.c:2041
+ msgid "First Factor: "
+-msgstr ""
++msgstr "1 番目の要素: "
+ 
+-#: src/sss_client/pam_sss.c:2040 src/sss_client/pam_sss.c:2202
++#: src/sss_client/pam_sss.c:2039 src/sss_client/pam_sss.c:2201
+ msgid "Second Factor (optional): "
+-msgstr ""
++msgstr "2 番目の要素 (オプション): "
+ 
+-#: src/sss_client/pam_sss.c:2043 src/sss_client/pam_sss.c:2205
++#: src/sss_client/pam_sss.c:2042 src/sss_client/pam_sss.c:2204
+ msgid "Second Factor: "
+-msgstr ""
++msgstr "2 番目の要素:  "
+ 
+-#: src/sss_client/pam_sss.c:2058
++#: src/sss_client/pam_sss.c:2057
+ msgid "Password: "
+ msgstr "パスワード: "
+ 
+-#: src/sss_client/pam_sss.c:2201 src/sss_client/pam_sss.c:2204
++#: src/sss_client/pam_sss.c:2200 src/sss_client/pam_sss.c:2203
+ msgid "First Factor (Current Password): "
+-msgstr ""
++msgstr "1 番目の要素 (現在のパスワード): "
+ 
+-#: src/sss_client/pam_sss.c:2208
++#: src/sss_client/pam_sss.c:2207
+ msgid "Current Password: "
+ msgstr "現在のパスワード: "
+ 
+-#: src/sss_client/pam_sss.c:2536
++#: src/sss_client/pam_sss.c:2562
+ msgid "Password expired. Change your password now."
+ msgstr "パスワードの期限が切れました。いますぐパスワードを変更してください。"
+ 
+@@ -1739,7 +1726,7 @@ msgstr "ホストへの接続に使用するポート"
+ 
+ #: src/sss_client/ssh/sss_ssh_knownhostsproxy.c:210
+ msgid "Print the host ssh public keys"
+-msgstr ""
++msgstr "ホスト SSH 公開鍵を印刷"
+ 
+ #: src/sss_client/ssh/sss_ssh_knownhostsproxy.c:252
+ msgid "Invalid port\n"
+@@ -1751,7 +1738,7 @@ msgstr "ホストが指定されていません\n"
+ 
+ #: src/sss_client/ssh/sss_ssh_knownhostsproxy.c:263
+ msgid "The path to the proxy command must be absolute\n"
+-msgstr "プロキシーコマンドへのパスは絶対パスにする必要があります\n"
++msgstr "プロキシコマンドへのパスは絶対パスにする必要があります\n"
+ 
+ #: src/tools/sss_useradd.c:49 src/tools/sss_usermod.c:48
+ msgid "The UID of the user"
+@@ -1803,8 +1790,7 @@ msgstr "追加するユーザーを指定してください\n"
+ #: src/tools/sss_groupshow.c:714 src/tools/sss_userdel.c:198
+ #: src/tools/sss_usermod.c:162
+ msgid "Error initializing the tools - no local domain\n"
+-msgstr ""
+-"ツールを初期化中にエラーが発生しました - ローカルドメインがありません\n"
++msgstr "ツールを初期化中にエラーが発生しました - ローカルドメインがありません\n"
+ 
+ #: src/tools/sss_useradd.c:123 src/tools/sss_groupadd.c:88
+ #: src/tools/sss_groupdel.c:82 src/tools/sss_groupmod.c:115
+@@ -1854,9 +1840,7 @@ msgstr "ユーザーに関する情報を取得できません\n"
+ 
+ #: src/tools/sss_useradd.c:236
+ msgid "User's home directory already exists, not copying data from skeldir\n"
+-msgstr ""
+-"ユーザーのホームディレクトリーがすでに存在します、スケルトンディレクトリーか"
+-"らデータをコピーしません\n"
++msgstr "ユーザーのホームディレクトリーがすでに存在します、スケルトンディレクトリーからデータをコピーしません\n"
+ 
+ #: src/tools/sss_useradd.c:239
+ #, c-format
+@@ -1919,16 +1903,13 @@ msgstr "グループ %1$s はドメインに対して定義された ID の範
+ #: src/tools/sss_usermod.c:289 src/tools/sss_usermod.c:296
+ #, c-format
+ msgid "NSS request failed (%1$d). Entry might remain in memory cache.\n"
+-msgstr ""
+-"NSS リクエストに失敗しました (%1$d)。項目はメモリーキャッシュに残されます。\n"
++msgstr "NSS リクエストに失敗しました (%1$d)。項目はメモリーキャッシュに残されます。\n"
+ 
+ #: src/tools/sss_groupdel.c:132
+ msgid ""
+-"No such group in local domain. Removing groups only allowed in local "
+-"domain.\n"
+-msgstr ""
+-"そのようなグループはローカルドメインにありません。グループの削除はローカルド"
+-"メインにおいてのみ許可されます。\n"
++"No such group in local domain. Removing groups only allowed in local domain."
++"\n"
++msgstr "そのようなグループはローカルドメインにありません。グループの削除はローカルドメインにおいてのみ許可されます。\n"
+ 
+ #: src/tools/sss_groupdel.c:137
+ msgid "Internal error. Could not remove group.\n"
+@@ -1954,9 +1935,7 @@ msgstr "変更するグループを指定してください\n"
+ msgid ""
+ "Cannot find group in local domain, modifying groups is allowed only in local "
+ "domain\n"
+-msgstr ""
+-"ローカルドメインにグループが見つかりませんでした。グループの変更はローカルド"
+-"メインにおいてのみ許可されます\n"
++msgstr "ローカルドメインにグループが見つかりませんでした。グループの変更はローカルドメインにおいてのみ許可されます\n"
+ 
+ #: src/tools/sss_groupmod.c:153 src/tools/sss_groupmod.c:182
+ msgid "Member groups must be in the same domain as parent group\n"
+@@ -1968,20 +1947,15 @@ msgstr "メンバーグループが親グループと同じドメインにある
+ msgid ""
+ "Cannot find group %1$s in local domain, only groups in local domain are "
+ "allowed\n"
+-msgstr ""
+-"ローカルドメインにグループ %1$s が見つかりません。ローカルドメインにあるグ"
+-"ループのみが許可されます\n"
++msgstr "ローカルドメインにグループ %1$s が見つかりません。ローカルドメインにあるグループのみが許可されます\n"
+ 
+ #: src/tools/sss_groupmod.c:257
+ msgid "Could not modify group - check if member group names are correct\n"
+-msgstr ""
+-"グループを変更できませんでした - メンバーグループ名が正しいかを確認してくださ"
+-"い\n"
++msgstr "グループを変更できませんでした - メンバーグループ名が正しいかを確認してください\n"
+ 
+ #: src/tools/sss_groupmod.c:261
+ msgid "Could not modify group - check if groupname is correct\n"
+-msgstr ""
+-"グループを変更できませんでした - グループ名が正しいかを確認してください\n"
++msgstr "グループを変更できませんでした - グループ名が正しいかを確認してください\n"
+ 
+ #: src/tools/sss_groupmod.c:265
+ msgid "Transaction error. Could not modify group.\n"
+@@ -2008,20 +1982,16 @@ msgstr "%1$s メンバーユーザー: "
+ 
+ #: src/tools/sss_groupshow.c:627
+ #, c-format
+-msgid ""
+-"\n"
++msgid "\n"
+ "%1$sIs a member of: "
+-msgstr ""
+-"\n"
++msgstr "\n"
+ "%1$s は次のメンバー: "
+ 
+ #: src/tools/sss_groupshow.c:634
+ #, c-format
+-msgid ""
+-"\n"
++msgid "\n"
+ "%1$sMember groups: "
+-msgstr ""
+-"\n"
++msgstr "\n"
+ "%1$s メンバーグループ: "
+ 
+ #: src/tools/sss_groupshow.c:670
+@@ -2034,11 +2004,9 @@ msgstr "表示するグループを指定してください\n"
+ 
+ #: src/tools/sss_groupshow.c:744
+ msgid ""
+-"No such group in local domain. Printing groups only allowed in local "
+-"domain.\n"
+-msgstr ""
+-"そのようなグループはローカルドメインにありません。グループの表示はローカルド"
+-"メインにおいてのみ許可されます。\n"
++"No such group in local domain. Printing groups only allowed in local domain."
++"\n"
++msgstr "そのようなグループはローカルドメインにありません。グループの表示はローカルドメインにおいてのみ許可されます。\n"
+ 
+ #: src/tools/sss_groupshow.c:749
+ msgid "Internal error. Could not print group.\n"
+@@ -2076,13 +2044,11 @@ msgstr "SELinux ログインコンテキストをリセットできません\n"
+ #: src/tools/sss_userdel.c:271
+ #, c-format
+ msgid "WARNING: The user (uid %1$lu) was still logged in when deleted.\n"
+-msgstr ""
+-"警告: ユーザー (uid %1$lu) が削除されたときにまだログインしていました。\n"
++msgstr "警告: ユーザー (uid %1$lu) が削除されたときにまだログインしていました。\n"
+ 
+ #: src/tools/sss_userdel.c:276
+ msgid "Cannot determine if the user was logged in on this platform"
+-msgstr ""
+-"ユーザーがこのプラットフォームにログインしていたかを確認できませんでした"
++msgstr "ユーザーがこのプラットフォームにログインしていたかを確認できませんでした"
+ 
+ #: src/tools/sss_userdel.c:281
+ msgid "Error while checking if the user was logged in\n"
+@@ -2095,8 +2061,7 @@ msgstr "削除後コマンドの実行に失敗しました: %1$s\n"
+ 
+ #: src/tools/sss_userdel.c:308
+ msgid "Not removing home dir - not owned by user\n"
+-msgstr ""
+-"ホームディレクトリーを削除していません - ユーザーにより所有されていません\n"
++msgstr "ホームディレクトリーを削除していません - ユーザーにより所有されていません\n"
+ 
+ #: src/tools/sss_userdel.c:310
+ #, c-format
+@@ -2106,9 +2071,7 @@ msgstr "ホームディレクトリーを削除できません: %1$s\n"
+ #: src/tools/sss_userdel.c:324
+ msgid ""
+ "No such user in local domain. Removing users only allowed in local domain.\n"
+-msgstr ""
+-"そのようなユーザーはローカルドメインにいません。ユーザーの削除はローカルドメ"
+-"インにおいてのみ許可されます。\n"
++msgstr "そのようなユーザーはローカルドメインにいません。ユーザーの削除はローカルドメインにおいてのみ許可されます。\n"
+ 
+ #: src/tools/sss_userdel.c:329
+ msgid "Internal error. Could not remove user.\n"
+@@ -2136,22 +2099,23 @@ msgstr "アカウントをロック解除する"
+ 
+ #: src/tools/sss_usermod.c:57
+ msgid "Add an attribute/value pair. The format is attrname=value."
+-msgstr ""
++msgstr "属性/値のペアを追加します。フォーマットは attrname=value です。"
+ 
+ #: src/tools/sss_usermod.c:58
+ msgid "Delete an attribute/value pair. The format is attrname=value."
+-msgstr ""
++msgstr "属性/値のペアを削除します。フォーマットは attrname=value です。"
+ 
+ #: src/tools/sss_usermod.c:59
+ msgid ""
+ "Set an attribute to a name/value pair. The format is attrname=value. For "
+ "multi-valued attributes, the command replaces the values already present"
+ msgstr ""
++"名前/値のペアに属性を指定します。形式は attrname=value です。複数の値を持つ属性の場合、コマンドがすでに存在する値に置き換えられます。"
+ 
+ #: src/tools/sss_usermod.c:117 src/tools/sss_usermod.c:126
+ #: src/tools/sss_usermod.c:135
+ msgid "Specify the attribute name/value pair(s)\n"
+-msgstr ""
++msgstr "属性の名前/値のペアを指定します"
+ 
+ #: src/tools/sss_usermod.c:152
+ msgid "Specify user to modify\n"
+@@ -2161,19 +2125,15 @@ msgstr "変更するユーザーを指定してください\n"
+ msgid ""
+ "Cannot find user in local domain, modifying users is allowed only in local "
+ "domain\n"
+-msgstr ""
+-"ローカルドメインにユーザーを見つけられません。ユーザーの変更はローカルドメイ"
+-"ンにおいてのみ許可されます。\n"
++msgstr "ローカルドメインにユーザーを見つけられません。ユーザーの変更はローカルドメインにおいてのみ許可されます。\n"
+ 
+ #: src/tools/sss_usermod.c:322
+ msgid "Could not modify user - check if group names are correct\n"
+-msgstr ""
+-"ユーザーを変更できませんでした - グループ名が正しいかを確認してください\n"
++msgstr "ユーザーを変更できませんでした - グループ名が正しいかを確認してください\n"
+ 
+ #: src/tools/sss_usermod.c:326
+ msgid "Could not modify user - user already member of groups?\n"
+-msgstr ""
+-"ユーザーを変更できませんでした - ユーザーはすでにグループのメンバーですか?\n"
++msgstr "ユーザーを変更できませんでした - ユーザーはすでにグループのメンバーですか?\n"
+ 
+ #: src/tools/sss_usermod.c:330
+ msgid "Transaction error. Could not modify user.\n"
+@@ -2186,16 +2146,16 @@ msgstr "指定された検索に一致するキャッシュオブジェクトが
+ #: src/tools/sss_cache.c:519
+ #, c-format
+ msgid "Couldn't invalidate %1$s\n"
+-msgstr ""
++msgstr "%1$s を無効化できませんでした"
+ 
+ #: src/tools/sss_cache.c:526
+ #, c-format
+ msgid "Couldn't invalidate %1$s %2$s\n"
+-msgstr ""
++msgstr "%1$s %2$s を無効化できませんでした"
+ 
+ #: src/tools/sss_cache.c:689
+ msgid "Invalidate all cached entries"
+-msgstr ""
++msgstr "すべてのキャッシュエントリーを無効化します"
+ 
+ #: src/tools/sss_cache.c:691
+ msgid "Invalidate particular user"
+@@ -2239,19 +2199,19 @@ msgstr "すべての autofs マップの無効化"
+ 
+ #: src/tools/sss_cache.c:714
+ msgid "Invalidate particular SSH host"
+-msgstr ""
++msgstr "特定の SSH ホストを無効化します"
+ 
+ #: src/tools/sss_cache.c:716
+ msgid "Invalidate all SSH hosts"
+-msgstr ""
++msgstr "すべての SSH ホストを無効化します"
+ 
+ #: src/tools/sss_cache.c:720
+ msgid "Invalidate particular sudo rule"
+-msgstr ""
++msgstr "特定の sudo ルールを無効化します"
+ 
+ #: src/tools/sss_cache.c:722
+ msgid "Invalidate all cached sudo rules"
+-msgstr ""
++msgstr "すべてのキャッシュ sudo ルールを無効化します"
+ 
+ #: src/tools/sss_cache.c:725
+ msgid "Only invalidate entries from a particular domain"
+@@ -2261,7 +2221,7 @@ msgstr "特定のドメインのみからエントリーを無効にする"
+ msgid ""
+ "Unexpected argument(s) provided, options that invalidate a single object "
+ "only accept a single provided argument.\n"
+-msgstr ""
++msgstr "予期しない引数が提供される場合、1 つのオブジェクトを無効化するオプションは、提供された引数を 1 つだけ受け取ります。\n"
+ 
+ #: src/tools/sss_cache.c:789
+ msgid "Please select at least one object to invalidate\n"
+@@ -2273,8 +2233,8 @@ msgid ""
+ "Could not open domain %1$s. If the domain is a subdomain (trusted domain), "
+ "use fully qualified name instead of --domain/-d parameter.\n"
+ msgstr ""
+-"ドメイン %1$s を開けませんでした。ドメインがサブドメイン (信頼済みドメイン) "
+-"であれば、--domain/-d パラメーターの代わりに完全修飾名を使用してください。\n"
++"ドメイン %1$s を開けませんでした。ドメインがサブドメイン (信頼済みドメイン) であれば、--domain/-d "
++"パラメーターの代わりに完全修飾名を使用してください。\n"
+ 
+ #: src/tools/sss_cache.c:877
+ msgid "Could not open available domains\n"
+@@ -2283,8 +2243,7 @@ msgstr "利用可能なドメインを開けませんでした\n"
+ #: src/tools/tools_util.c:202
+ #, c-format
+ msgid "Name '%1$s' does not seem to be FQDN ('%2$s = TRUE' is set)\n"
+-msgstr ""
+-"名前 '%1$s' が FQDN であるように見えません ('%2$s = TRUE' が設定されます)\n"
++msgstr "名前 '%1$s' が FQDN であるように見えません ('%2$s = TRUE' が設定されます)\n"
+ 
+ #: src/tools/tools_util.c:309
+ msgid "Out of memory\n"
+@@ -2297,279 +2256,285 @@ msgstr "%1$s は root として実行する必要があります\n"
+ 
+ #: src/tools/sssctl/sssctl.c:35
+ msgid "yes"
+-msgstr ""
++msgstr "はい"
+ 
+ #: src/tools/sssctl/sssctl.c:37
+ msgid "no"
+-msgstr ""
++msgstr "いいえ"
+ 
+ #: src/tools/sssctl/sssctl.c:39
+ msgid "error"
+-msgstr ""
++msgstr "エラー"
+ 
+ #: src/tools/sssctl/sssctl.c:42
+ msgid "Invalid result."
+-msgstr ""
++msgstr "無効な結果。"
+ 
+ #: src/tools/sssctl/sssctl.c:78
+ #, c-format
+ msgid "Unable to read user input\n"
+-msgstr ""
++msgstr "ユーザーインプットの読み込みができませんでした\n"
+ 
+ #: src/tools/sssctl/sssctl.c:91
+ #, c-format
+ msgid "Invalid input, please provide either '%s' or '%s'.\n"
+-msgstr ""
++msgstr "無効なインプットです。'%s' または '%s' のいずれかを提供してください。\n"
+ 
+ #: src/tools/sssctl/sssctl.c:109 src/tools/sssctl/sssctl.c:114
+ #, c-format
+ msgid "Error while executing external command\n"
+-msgstr ""
++msgstr "外部のコマンドを実行中にエラーが発生しました\n"
+ 
+ #: src/tools/sssctl/sssctl.c:156
+ msgid "SSSD needs to be running. Start SSSD now?"
+-msgstr ""
++msgstr "SSSD を実行する必要があります。SSSD をすぐに実行しますか?"
+ 
+ #: src/tools/sssctl/sssctl.c:195
+ msgid "SSSD must not be running. Stop SSSD now?"
+-msgstr ""
++msgstr "SSSD を実行してはいけません。SSSD を今、停止しますか?"
+ 
+ #: src/tools/sssctl/sssctl.c:231
+ msgid "SSSD needs to be restarted. Restart SSSD now?"
+-msgstr ""
++msgstr "SSSD は再起動が必要です。SSSD を今、再起動しますか?"
+ 
+ #: src/tools/sssctl/sssctl_cache.c:31
+ #, c-format
+ msgid " %s is not present in cache.\n"
+-msgstr ""
++msgstr " %s はキャッシュにありません\n"
+ 
+ #: src/tools/sssctl/sssctl_cache.c:33
+ msgid "Name"
+-msgstr ""
++msgstr "名前"
+ 
+ #: src/tools/sssctl/sssctl_cache.c:34
+ msgid "Cache entry creation date"
+-msgstr ""
++msgstr "キャッシュエントリーの作成日"
+ 
+ #: src/tools/sssctl/sssctl_cache.c:35
+ msgid "Cache entry last update time"
+-msgstr ""
++msgstr "キャッシュエントリーが最後に更新された時間"
+ 
+ #: src/tools/sssctl/sssctl_cache.c:36
+ msgid "Cache entry expiration time"
+-msgstr ""
++msgstr "キャッシュエントリーの期限切れ時間"
+ 
+ #: src/tools/sssctl/sssctl_cache.c:37
+ msgid "Cached in InfoPipe"
+-msgstr ""
++msgstr "InfoPipe にキャッシュ"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:512
++#: src/tools/sssctl/sssctl_cache.c:522
+ #, c-format
+ msgid "Error: Unable to get object [%d]: %s\n"
+-msgstr ""
++msgstr "エラー: オブジェクト [%d] を取得できません: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:528
++#: src/tools/sssctl/sssctl_cache.c:538
+ #, c-format
+ msgid "%s: Unable to read value [%d]: %s\n"
+-msgstr ""
++msgstr "%s: 値 [%d] の読み込みができません: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:556
++#: src/tools/sssctl/sssctl_cache.c:566
+ msgid "Specify name."
+-msgstr ""
++msgstr "名前を指定します。"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:566
++#: src/tools/sssctl/sssctl_cache.c:576
+ #, c-format
+ msgid "Unable to parse name %s.\n"
+-msgstr ""
++msgstr "名前 %s を構文解析できません。\n"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:592 src/tools/sssctl/sssctl_cache.c:639
++#: src/tools/sssctl/sssctl_cache.c:602 src/tools/sssctl/sssctl_cache.c:649
+ msgid "Search by SID"
+-msgstr ""
++msgstr "SID で検索"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:593
++#: src/tools/sssctl/sssctl_cache.c:603
+ msgid "Search by user ID"
+-msgstr ""
++msgstr "ユーザーID で検索"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:602
++#: src/tools/sssctl/sssctl_cache.c:612
+ msgid "Initgroups expiration time"
+-msgstr ""
++msgstr "Initgroups の期限切れ時間"
+ 
+-#: src/tools/sssctl/sssctl_cache.c:640
++#: src/tools/sssctl/sssctl_cache.c:650
+ msgid "Search by group ID"
+-msgstr ""
++msgstr "グループ ID で検索"
+ 
+ #: src/tools/sssctl/sssctl_config.c:67
+ #, c-format
+ msgid ""
+ "File %1$s does not exist. SSSD will use default configuration with files "
+ "provider.\n"
+-msgstr ""
++msgstr "ファイル %1$s は存在しません。SSSD は、ファイルプロバイダーでデフォルトの設定を使用します。\n"
+ 
+ #: src/tools/sssctl/sssctl_config.c:81
+ #, c-format
+ msgid ""
+ "File ownership and permissions check failed. Expected root:root and 0600.\n"
+-msgstr ""
++msgstr "ファイルの所有権とパーミッションの確認に失敗しました。予期される root:root および 0600。\n"
+ 
+ #: src/tools/sssctl/sssctl_config.c:104
+ #, c-format
+ msgid "Issues identified by validators: %zu\n"
+-msgstr ""
++msgstr "バリデーターで特定された問題: %zu\n"
+ 
+ #: src/tools/sssctl/sssctl_config.c:114
+ #, c-format
+ msgid "Messages generated during configuration merging: %zu\n"
+-msgstr ""
++msgstr "設定のマージ中に生成されたメッセージ: %zu\n"
+ 
+ #: src/tools/sssctl/sssctl_config.c:127
+ #, c-format
+ msgid "Used configuration snippet files: %u\n"
+-msgstr ""
++msgstr "設定スニペットファイルを使用: %u\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:89
+ #, c-format
+ msgid "Unable to create backup directory [%d]: %s"
+-msgstr ""
++msgstr "バックアップディレクトリー [%d] の作成に失敗: %s"
+ 
+ #: src/tools/sssctl/sssctl_data.c:95
+ msgid "SSSD backup of local data already exists, override?"
+-msgstr ""
++msgstr "ローカルデータの SSSD バックアップはすでに存在しますが、上書きしますか?"
+ 
+ #: src/tools/sssctl/sssctl_data.c:111
+ #, c-format
+ msgid "Unable to export user overrides\n"
+-msgstr ""
++msgstr "ユーザーの上書きをエクスポートできません\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:118
+ #, c-format
+ msgid "Unable to export group overrides\n"
+-msgstr ""
++msgstr "グループの上書きをエクスポートできません\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:134 src/tools/sssctl/sssctl_data.c:217
+ msgid "Override existing backup"
+-msgstr ""
++msgstr "既存のバックアップを上書き"
+ 
+ #: src/tools/sssctl/sssctl_data.c:164
+ #, c-format
+ msgid "Unable to import user overrides\n"
+-msgstr ""
++msgstr "ユーザーの上書きをインポートできません\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:173
+ #, c-format
+ msgid "Unable to import group overrides\n"
+-msgstr ""
++msgstr "グループの上書きをインポートできません\n"
+ 
+-#: src/tools/sssctl/sssctl_data.c:194 src/tools/sssctl/sssctl_domains.c:74
+-#: src/tools/sssctl/sssctl_domains.c:339
++#: src/tools/sssctl/sssctl_data.c:194 src/tools/sssctl/sssctl_domains.c:82
++#: src/tools/sssctl/sssctl_domains.c:315
+ msgid "Start SSSD if it is not running"
+-msgstr ""
++msgstr "実行中でない場合、SSSD を開始します"
+ 
+ #: src/tools/sssctl/sssctl_data.c:195
+ msgid "Restart SSSD after data import"
+-msgstr ""
++msgstr "データのインポートの後、SSSD を再起動します"
+ 
+ #: src/tools/sssctl/sssctl_data.c:218
+ msgid "Create clean cache files and import local data"
+-msgstr ""
++msgstr "クリーンなキャッシュファイルを作成し、ローカルデータをインポートします"
+ 
+ #: src/tools/sssctl/sssctl_data.c:219
+ msgid "Stop SSSD before removing the cache"
+-msgstr ""
++msgstr "キャッシュを削除する前に SSSD を停止します"
+ 
+ #: src/tools/sssctl/sssctl_data.c:220
+ msgid "Start SSSD when the cache is removed"
+-msgstr ""
++msgstr "キャッシュの削除後に SSSD を開始します"
+ 
+ #: src/tools/sssctl/sssctl_data.c:235
+ #, c-format
+ msgid "Creating backup of local data...\n"
+-msgstr ""
++msgstr "ローカルデータのバックアップを作成中...\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:238
+ #, c-format
+ msgid "Unable to create backup of local data, can not remove the cache.\n"
+-msgstr ""
++msgstr "ローカルデータのバックアップの作成ができません。キャッシュを削除できません。\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:243
+ #, c-format
+ msgid "Removing cache files...\n"
+-msgstr ""
++msgstr "キャッシュファイルの削除中...\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:246
+ #, c-format
+ msgid "Unable to remove cache files\n"
+-msgstr ""
++msgstr "キャッシュファイルを削除できません\n"
+ 
+ #: src/tools/sssctl/sssctl_data.c:251
+ #, c-format
+ msgid "Restoring local data...\n"
+-msgstr ""
++msgstr "ローカルデータの復元中...\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:75
++#: src/tools/sssctl/sssctl_domains.c:83
+ msgid "Show domain list including primary or trusted domain type"
+-msgstr ""
++msgstr "プライマリーまたは信頼されたドメインタイプを含むドメインリストを表示します"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:156
++#: src/tools/sssctl/sssctl_domains.c:105 src/tools/sssctl/sssctl_domains.c:354
++#: src/tools/sssctl/sssctl_user_checks.c:95
++#, c-format
++msgid "Unable to connect to system bus!\n"
++msgstr "システムバスに接続できません!\n"
++
++#: src/tools/sssctl/sssctl_domains.c:167
+ #, c-format
+ msgid "Online status: %s\n"
+-msgstr ""
++msgstr "オンライン状態: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:156
++#: src/tools/sssctl/sssctl_domains.c:167
+ msgid "Online"
+-msgstr ""
++msgstr "オンライン"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:156
++#: src/tools/sssctl/sssctl_domains.c:167
+ msgid "Offline"
+-msgstr ""
++msgstr "オフライン"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:214
++#: src/tools/sssctl/sssctl_domains.c:212
+ #, c-format
+ msgid "Active servers:\n"
+-msgstr ""
++msgstr "アクティブサーバー:\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:231
++#: src/tools/sssctl/sssctl_domains.c:223
+ msgid "not connected"
+-msgstr ""
++msgstr "接続していません"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:278
++#: src/tools/sssctl/sssctl_domains.c:260
+ #, c-format
+ msgid "Discovered %s servers:\n"
+-msgstr ""
++msgstr "%s サーバーを発見:\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:296
++#: src/tools/sssctl/sssctl_domains.c:272
+ msgid "None so far.\n"
+-msgstr ""
++msgstr "今のところありません。\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:336
++#: src/tools/sssctl/sssctl_domains.c:312
+ msgid "Show online status"
+-msgstr ""
++msgstr "オンライン状態を表示"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:337
++#: src/tools/sssctl/sssctl_domains.c:313
+ msgid "Show information about active server"
+-msgstr ""
++msgstr "アクティブサーバーに関する情報の表示"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:338
++#: src/tools/sssctl/sssctl_domains.c:314
+ msgid "Show list of discovered servers"
+-msgstr ""
++msgstr "発見されたサーバーに関する一覧を表示"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:344
++#: src/tools/sssctl/sssctl_domains.c:320
+ msgid "Specify domain name."
+-msgstr ""
++msgstr "ドメイン名を指定します。"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:360
++#: src/tools/sssctl/sssctl_domains.c:342
+ #, c-format
+ msgid "Out of memory!\n"
+-msgstr ""
++msgstr "メモリの空き容量がありません。\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:377 src/tools/sssctl/sssctl_domains.c:387
++#: src/tools/sssctl/sssctl_domains.c:362 src/tools/sssctl/sssctl_domains.c:372
+ #, c-format
+ msgid "Unable to get online status\n"
+-msgstr ""
++msgstr "オンライン状態を取得できません\n"
+ 
+-#: src/tools/sssctl/sssctl_domains.c:397
++#: src/tools/sssctl/sssctl_domains.c:382
+ #, c-format
+ msgid "Unable to get server list\n"
+-msgstr ""
++msgstr "サーバー一覧を取得できません\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:47
+ msgid "\n"
+@@ -2577,282 +2542,261 @@ msgstr "\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:237
+ msgid "Delete log files instead of truncating"
+-msgstr ""
++msgstr "切り捨てる代わりにログファイルを削除します"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:248
+ #, c-format
+ msgid "Deleting log files...\n"
+-msgstr ""
++msgstr "ログファイルを削除中...\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:251
+ #, c-format
+ msgid "Unable to remove log files\n"
+-msgstr ""
++msgstr "ログファイルを削除できません\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:257
+ #, c-format
+ msgid "Truncating log files...\n"
+-msgstr ""
++msgstr "ログファイルを切り捨てます...\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:260
+ #, c-format
+ msgid "Unable to truncate log files\n"
+-msgstr ""
++msgstr "ログファイルの切り捨てができません\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:286
+ #, c-format
+ msgid "Out of memory!"
+-msgstr ""
++msgstr "メモリの空き容量がありません。"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:289
+ #, c-format
+ msgid "Archiving log files into %s...\n"
+-msgstr ""
++msgstr "ログファイルを %s へアーカイブ...\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:292
+ #, c-format
+ msgid "Unable to archive log files\n"
+-msgstr ""
++msgstr "ログファイルのアーカイブができません\n"
+ 
+ #: src/tools/sssctl/sssctl_logs.c:317
+ msgid "Specify debug level you want to set"
+-msgstr ""
+-
+-#: src/tools/sssctl/sssctl_sifp.c:28
+-msgid ""
+-"Check that SSSD is running and the InfoPipe responder is enabled. Make sure "
+-"'ifp' is listed in the 'services' option in sssd.conf.\n"
+-msgstr ""
+-
+-#: src/tools/sssctl/sssctl_user_checks.c:91
+-#, c-format
+-msgid "Unable to connect to the InfoPipe"
+-msgstr ""
+-
+-#: src/tools/sssctl/sssctl_user_checks.c:97
+-#, c-format
+-msgid "Unable to get user object"
+-msgstr ""
++msgstr "設定したいデバッグレベルを指定します"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:101
++#: src/tools/sssctl/sssctl_user_checks.c:117
+ #, c-format
+ msgid "SSSD InfoPipe user lookup result:\n"
+-msgstr ""
+-
+-#: src/tools/sssctl/sssctl_user_checks.c:113
+-#, c-format
+-msgid "Unable to get user name attr"
+-msgstr ""
++msgstr "SSSD InfoPipe ユーザー検索の結果:\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:146
++#: src/tools/sssctl/sssctl_user_checks.c:167
+ #, c-format
+ msgid "dlopen failed with [%s].\n"
+-msgstr ""
++msgstr "dlopen は [%s] で失敗しました。\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:153
++#: src/tools/sssctl/sssctl_user_checks.c:174
+ #, c-format
+ msgid "dlsym failed with [%s].\n"
+-msgstr ""
++msgstr "dlsym は [%s] で失敗しました。\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:161
++#: src/tools/sssctl/sssctl_user_checks.c:182
+ #, c-format
+ msgid "malloc failed.\n"
+-msgstr ""
++msgstr "malloc は失敗しました。\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:168
++#: src/tools/sssctl/sssctl_user_checks.c:189
+ #, c-format
+ msgid "sss_getpwnam_r failed with [%d].\n"
+-msgstr ""
++msgstr "sss_getpwnam_r が [%d] で失敗しました。\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:173
++#: src/tools/sssctl/sssctl_user_checks.c:194
+ #, c-format
+ msgid "SSSD nss user lookup result:\n"
+-msgstr ""
++msgstr "SSSD nss ユーザー検索の結果:\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:174
++#: src/tools/sssctl/sssctl_user_checks.c:195
+ #, c-format
+ msgid " - user name: %s\n"
+-msgstr ""
++msgstr " - user name: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:175
++#: src/tools/sssctl/sssctl_user_checks.c:196
+ #, c-format
+ msgid " - user id: %d\n"
+-msgstr ""
++msgstr " - user id: %d\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:176
++#: src/tools/sssctl/sssctl_user_checks.c:197
+ #, c-format
+ msgid " - group id: %d\n"
+-msgstr ""
++msgstr " - group id: %d\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:177
++#: src/tools/sssctl/sssctl_user_checks.c:198
+ #, c-format
+ msgid " - gecos: %s\n"
+-msgstr ""
++msgstr " - gecos: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:178
++#: src/tools/sssctl/sssctl_user_checks.c:199
+ #, c-format
+ msgid " - home directory: %s\n"
+-msgstr ""
++msgstr " - home directory: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:179
++#: src/tools/sssctl/sssctl_user_checks.c:200
+ #, c-format
+-msgid ""
+-" - shell: %s\n"
++msgid " - shell: %s\n"
++"\n"
++msgstr " - shell: %s\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:211
++#: src/tools/sssctl/sssctl_user_checks.c:232
+ msgid "PAM action [auth|acct|setc|chau|open|clos], default: "
+-msgstr ""
++msgstr "PAM アクション [auth|acct|setc|chau|open|clos]、デフォルト: "
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:214
++#: src/tools/sssctl/sssctl_user_checks.c:235
+ msgid "PAM service, default: "
+-msgstr ""
++msgstr "PAM サービス、デフォルト: "
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:219
++#: src/tools/sssctl/sssctl_user_checks.c:240
+ msgid "Specify user name."
+-msgstr ""
++msgstr "ユーザー名を指定します。"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:226
++#: src/tools/sssctl/sssctl_user_checks.c:247
+ #, c-format
+-msgid ""
+-"user: %s\n"
++msgid "user: %s\n"
+ "action: %s\n"
+ "service: %s\n"
+ "\n"
+-msgstr ""
++msgstr "ユーザー: %s\n"
++"アクション: %s\n"
++"サービス: %s\n"
++"\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:232
++#: src/tools/sssctl/sssctl_user_checks.c:253
+ #, c-format
+ msgid "User name lookup with [%s] failed.\n"
+-msgstr ""
++msgstr "[%s] でのユーザー名の検索に失敗しました。\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:237
++#: src/tools/sssctl/sssctl_user_checks.c:258
+ #, c-format
+ msgid "InfoPipe User lookup with [%s] failed.\n"
+-msgstr ""
++msgstr "[%s] での InfoPipe ユーザーの検索に失敗しました。\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:244
++#: src/tools/sssctl/sssctl_user_checks.c:265
+ #, c-format
+ msgid "pam_start failed: %s\n"
+-msgstr ""
++msgstr "pam_start に失敗しました: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:249
++#: src/tools/sssctl/sssctl_user_checks.c:270
+ #, c-format
+-msgid ""
+-"testing pam_authenticate\n"
++msgid "testing pam_authenticate\n"
++"\n"
++msgstr "pam_authenticate のテスト中\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:253
++#: src/tools/sssctl/sssctl_user_checks.c:274
+ #, c-format
+ msgid "pam_get_item failed: %s\n"
+-msgstr ""
++msgstr "pam_get_item に失敗しました: %s\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:257
++#: src/tools/sssctl/sssctl_user_checks.c:278
+ #, c-format
+-msgid ""
+-"pam_authenticate for user [%s]: %s\n"
++msgid "pam_authenticate for user [%s]: %s\n"
++"\n"
++msgstr "ユーザー [%s] 向けの pam_authenticate: %s\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:260
++#: src/tools/sssctl/sssctl_user_checks.c:281
+ #, c-format
+-msgid ""
+-"testing pam_chauthtok\n"
++msgid "testing pam_chauthtok\n"
++"\n"
++msgstr "pam_chauthtok のテスト中\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:262
++#: src/tools/sssctl/sssctl_user_checks.c:283
+ #, c-format
+-msgid ""
+-"pam_chauthtok: %s\n"
++msgid "pam_chauthtok: %s\n"
++"\n"
++msgstr "pam_chauthtok: %s\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:264
++#: src/tools/sssctl/sssctl_user_checks.c:285
+ #, c-format
+-msgid ""
+-"testing pam_acct_mgmt\n"
++msgid "testing pam_acct_mgmt\n"
+ "\n"
+-msgstr ""
++msgstr "pam_acct_mgmt のテスト中\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:266
++#: src/tools/sssctl/sssctl_user_checks.c:287
+ #, c-format
+-msgid ""
+-"pam_acct_mgmt: %s\n"
++msgid "pam_acct_mgmt: %s\n"
++"\n"
++msgstr "pam_acct_mgmt: %s\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:268
++#: src/tools/sssctl/sssctl_user_checks.c:289
+ #, c-format
+-msgid ""
+-"testing pam_setcred\n"
++msgid "testing pam_setcred\n"
++"\n"
++msgstr "pam_setcred のテスト中\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:270
++#: src/tools/sssctl/sssctl_user_checks.c:291
+ #, c-format
+-msgid ""
+-"pam_setcred: [%s]\n"
++msgid "pam_setcred: [%s]\n"
++"\n"
++msgstr "pam_setcred: [%s]\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:272
++#: src/tools/sssctl/sssctl_user_checks.c:293
+ #, c-format
+-msgid ""
+-"testing pam_open_session\n"
++msgid "testing pam_open_session\n"
+ "\n"
+-msgstr ""
++msgstr "pam_open_session のテスト中\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:274
++#: src/tools/sssctl/sssctl_user_checks.c:295
+ #, c-format
+-msgid ""
+-"pam_open_session: %s\n"
++msgid "pam_open_session: %s\n"
++"\n"
++msgstr "pam_open_session: %s\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:276
++#: src/tools/sssctl/sssctl_user_checks.c:297
+ #, c-format
+-msgid ""
+-"testing pam_close_session\n"
++msgid "testing pam_close_session\n"
+ "\n"
+-msgstr ""
++msgstr "pam_close_session のテスト中\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:278
++#: src/tools/sssctl/sssctl_user_checks.c:299
+ #, c-format
+-msgid ""
+-"pam_close_session: %s\n"
++msgid "pam_close_session: %s\n"
++"\n"
++msgstr "pam_close_session: %s\n"
+ "\n"
+-msgstr ""
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:281
++#: src/tools/sssctl/sssctl_user_checks.c:302
+ #, c-format
+ msgid "unknown action\n"
+-msgstr ""
++msgstr "不明なアクション\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:284
++#: src/tools/sssctl/sssctl_user_checks.c:305
+ #, c-format
+ msgid "PAM Environment:\n"
+-msgstr ""
++msgstr "PAM 環境:\n"
+ 
+-#: src/tools/sssctl/sssctl_user_checks.c:292
++#: src/tools/sssctl/sssctl_user_checks.c:313
+ #, c-format
+ msgid " - no env -\n"
+-msgstr ""
++msgstr " - no env -\n"
+ 
+-#: src/util/util.h:75
++#: src/util/util.h:73
+ msgid "The user ID to run the server as"
+-msgstr ""
++msgstr "次のようにサーバーを実行するユーザー ID"
+ 
+-#: src/util/util.h:77
++#: src/util/util.h:75
+ msgid "The group ID to run the server as"
+-msgstr ""
++msgstr "次のようにサーバーを実行するグループ ID"
+ 
+-#: src/util/util.h:85
++#: src/util/util.h:83
+ msgid "Informs that the responder has been socket-activated"
+-msgstr ""
++msgstr "レスポンダーがソケットでアクティベートされたと知らせます"
+ 
+-#: src/util/util.h:87
++#: src/util/util.h:85
+ msgid "Informs that the responder has been dbus-activated"
+-msgstr ""
++msgstr "レスポンダーが dbus でアクティベートされたと知らせます"
++
+-- 
+2.19.1
+
diff --git a/SOURCES/0033-Translation-Add-missing-newlines-in-the-ja-po-file.patch b/SOURCES/0033-Translation-Add-missing-newlines-in-the-ja-po-file.patch
new file mode 100644
index 0000000..970ab6a
--- /dev/null
+++ b/SOURCES/0033-Translation-Add-missing-newlines-in-the-ja-po-file.patch
@@ -0,0 +1,40 @@
+From 32d171f48920eaa98b84c73f69636e6388c28133 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Thu, 6 Jun 2019 03:47:17 +0200
+Subject: [PATCH 33/33] Translation: Add missing newlines in the ja po file
+
+---
+ po/ja.po | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/po/ja.po b/po/ja.po
+index 396b693c2..f6ed9834b 100644
+--- a/po/ja.po
++++ b/po/ja.po
+@@ -2115,7 +2115,7 @@ msgstr ""
+ #: src/tools/sss_usermod.c:117 src/tools/sss_usermod.c:126
+ #: src/tools/sss_usermod.c:135
+ msgid "Specify the attribute name/value pair(s)\n"
+-msgstr "属性の名前/値のペアを指定します"
++msgstr "属性の名前/値のペアを指定します\n"
+ 
+ #: src/tools/sss_usermod.c:152
+ msgid "Specify user to modify\n"
+@@ -2146,12 +2146,12 @@ msgstr "指定された検索に一致するキャッシュオブジェクトが
+ #: src/tools/sss_cache.c:519
+ #, c-format
+ msgid "Couldn't invalidate %1$s\n"
+-msgstr "%1$s を無効化できませんでした"
++msgstr "%1$s を無効化できませんでした\n"
+ 
+ #: src/tools/sss_cache.c:526
+ #, c-format
+ msgid "Couldn't invalidate %1$s %2$s\n"
+-msgstr "%1$s %2$s を無効化できませんでした"
++msgstr "%1$s %2$s を無効化できませんでした\n"
+ 
+ #: src/tools/sss_cache.c:689
+ msgid "Invalidate all cached entries"
+-- 
+2.19.1
+
diff --git a/SOURCES/0034-TESTS-Add-a-unit-test-for-UPNs-stored-by-sss_ncache_.patch b/SOURCES/0034-TESTS-Add-a-unit-test-for-UPNs-stored-by-sss_ncache_.patch
new file mode 100644
index 0000000..54e2e7a
--- /dev/null
+++ b/SOURCES/0034-TESTS-Add-a-unit-test-for-UPNs-stored-by-sss_ncache_.patch
@@ -0,0 +1,207 @@
+From 05b37ac18ed8da00ce560ed52244c6ad7abfa6a9 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 13 Mar 2019 17:41:29 +0100
+Subject: [PATCH 34/35] TESTS: Add a unit test for UPNs stored by
+ sss_ncache_prepopulate
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 48c1e3ac34ec5b2d7cf27d7393d049c880bca319)
+---
+ src/tests/cmocka/test_negcache.c | 111 +++++++++++++++++++++++++------
+ 1 file changed, 92 insertions(+), 19 deletions(-)
+
+diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
+index a0210928b..9bddddd8d 100644
+--- a/src/tests/cmocka/test_negcache.c
++++ b/src/tests/cmocka/test_negcache.c
+@@ -39,6 +39,7 @@
+ #include "lib/idmap/sss_idmap.h"
+ #include "util/util.h"
+ #include "util/util_sss_idmap.h"
++#include "db/sysdb_private.h"
+ #include "responder/common/responder.h"
+ #include "responder/common/negcache.h"
+ 
+@@ -52,6 +53,7 @@
+ #define TEST_CONF_DB "test_nss_conf.ldb"
+ #define TEST_DOM_NAME "nss_test"
+ #define TEST_ID_PROVIDER "ldap"
++#define TEST_SUBDOM_NAME "test.subdomain"
+ 
+ /* register_cli_protocol_version is required in test since it links with
+  * responder_common.c module
+@@ -582,6 +584,29 @@ static int check_gid_in_ncache(struct sss_nc_ctx *ctx,
+     return ret;
+ }
+ 
++static int add_confdb_params(struct sss_test_conf_param params[],
++                             struct confdb_ctx *cdb, const char *section)
++{
++    const char *val[2];
++    int ret;
++
++    val[1] = NULL;
++
++    for (int i = 0; params[i].key; i++) {
++        val[0] = params[i].value;
++        ret = confdb_add_param(cdb, true, section, params[i].key, val);
++        assert_int_equal(ret, EOK);
++    }
++
++    return EOK;
++}
++
++static int add_nss_params(struct sss_test_conf_param nss_params[],
++                          struct confdb_ctx *cdb)
++{
++    return add_confdb_params(nss_params, cdb, CONFDB_NSS_CONF_ENTRY);
++}
++
+ static void test_sss_ncache_prepopulate(void **state)
+ {
+     int ret;
+@@ -589,9 +614,14 @@ static void test_sss_ncache_prepopulate(void **state)
+     struct tevent_context *ev;
+     struct sss_nc_ctx *ncache;
+     struct sss_test_ctx *tc;
+-    struct sss_domain_info *dom;
++    const char *const testdom[4] = { TEST_SUBDOM_NAME, "TEST.SUB", "test", "S-3" };
++    struct sss_domain_info *subdomain;
+ 
+-    struct sss_test_conf_param params[] = {
++    struct sss_test_conf_param nss_params[] = {
++        { "filter_users", "testuser_nss@UPN.REALM, testuser_nss_short" },
++        { NULL, NULL },
++    };
++    struct sss_test_conf_param dom_params[] = {
+         { "filter_users", "testuser1, testuser2@"TEST_DOM_NAME", testuser3@somedomain" },
+         { "filter_groups", "testgroup1, testgroup2@"TEST_DOM_NAME", testgroup3@somedomain" },
+         { NULL, NULL },
+@@ -602,22 +632,35 @@ static void test_sss_ncache_prepopulate(void **state)
+     ev = tevent_context_init(ts);
+     assert_non_null(ev);
+ 
+-    dom = talloc_zero(ts, struct sss_domain_info);
+-    assert_non_null(dom);
+-    dom->name = discard_const_p(char, TEST_DOM_NAME);
+-
+     ts->nctx = mock_nctx(ts);
+     assert_non_null(ts->nctx);
+ 
+     tc = create_dom_test_ctx(ts, TESTS_PATH, TEST_CONF_DB,
+-                             TEST_DOM_NAME, TEST_ID_PROVIDER, params);
++                             TEST_DOM_NAME, TEST_ID_PROVIDER, dom_params);
+     assert_non_null(tc);
+ 
++    ret = add_nss_params(nss_params, tc->confdb);
++    assert_int_equal(ret, EOK);
++
++    subdomain = new_subdomain(tc, tc->dom,
++                              testdom[0], testdom[1], testdom[2], testdom[3],
++                              false, false, NULL, NULL, 0,
++                              tc->confdb);
++    assert_non_null(subdomain);
++
++    ret = sysdb_subdomain_store(tc->sysdb,
++                                testdom[0], testdom[1], testdom[2], testdom[3],
++                                false, false, NULL, 0, NULL);
++    assert_int_equal(ret, EOK);
++
++    ret = sysdb_update_subdomains(tc->dom, tc->confdb);
++    assert_int_equal(ret, EOK);
++
+     ncache = ts->ctx;
+-    ts->rctx = mock_rctx(ts, ev, dom, ts->nctx);
++    ts->rctx = mock_rctx(ts, ev, tc->dom, ts->nctx);
+     assert_non_null(ts->rctx);
+ 
+-    ret = sss_names_init(ts, tc->confdb, TEST_DOM_NAME, &dom->names);
++    ret = sss_names_init(ts, tc->confdb, TEST_DOM_NAME, &tc->dom->names);
+     assert_int_equal(ret, EOK);
+ 
+     ret = sss_ncache_prepopulate(ncache, tc->confdb, ts->rctx);
+@@ -625,34 +668,37 @@ static void test_sss_ncache_prepopulate(void **state)
+ 
+     sleep(SHORTSPAN);
+ 
+-    ret = check_user_in_ncache(ncache, dom, "testuser1");
++    ret = check_user_in_ncache(ncache, tc->dom, "testuser1");
+     assert_int_equal(ret, EEXIST);
+ 
+-    ret = check_group_in_ncache(ncache, dom, "testgroup1");
++    ret = check_group_in_ncache(ncache, tc->dom, "testgroup1");
+     assert_int_equal(ret, EEXIST);
+ 
+-    ret = check_user_in_ncache(ncache, dom, "testuser2");
++    ret = check_user_in_ncache(ncache, tc->dom, "testuser2");
+     assert_int_equal(ret, EEXIST);
+ 
+-    ret = check_group_in_ncache(ncache, dom, "testgroup2");
++    ret = check_group_in_ncache(ncache, tc->dom, "testgroup2");
+     assert_int_equal(ret, EEXIST);
+ 
+-    ret = check_user_in_ncache(ncache, dom, "testuser3");
++    ret = check_user_in_ncache(ncache, tc->dom, "testuser3");
+     assert_int_equal(ret, ENOENT);
+ 
+-    ret = check_group_in_ncache(ncache, dom, "testgroup3");
++    ret = check_group_in_ncache(ncache, tc->dom, "testgroup3");
+     assert_int_equal(ret, ENOENT);
+ 
+-    ret = check_user_in_ncache(ncache, dom, "testuser3@somedomain");
++    ret = check_user_in_ncache(ncache, tc->dom, "testuser3@somedomain");
+     assert_int_equal(ret, ENOENT);
+ 
+-    ret = check_group_in_ncache(ncache, dom, "testgroup3@somedomain");
++    ret = sss_ncache_check_upn(ncache, tc->dom, "testuser3@somedomain");
++    assert_int_equal(ret, EEXIST);
++
++    ret = check_group_in_ncache(ncache, tc->dom, "testgroup3@somedomain");
+     assert_int_equal(ret, ENOENT);
+ 
+-    ret = check_user_in_ncache(ncache, dom, "root");
++    ret = check_user_in_ncache(ncache, tc->dom, "root");
+     assert_int_equal(ret, EEXIST);
+ 
+-    ret = check_group_in_ncache(ncache, dom, "root");
++    ret = check_group_in_ncache(ncache, tc->dom, "root");
+     assert_int_equal(ret, EEXIST);
+ 
+     ret = check_uid_in_ncache(ncache, 0);
+@@ -660,6 +706,33 @@ static void test_sss_ncache_prepopulate(void **state)
+ 
+     ret = check_gid_in_ncache(ncache, 0);
+     assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom, "testuser_nss@UPN.REALM");
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom->subdomains, "testuser_nss@UPN.REALM");
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom, "testuser_nss_short@" TEST_DOM_NAME);
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom->subdomains, "testuser_nss_short@" TEST_SUBDOM_NAME);
++    assert_int_equal(ret, EEXIST);
++
++    ret = check_user_in_ncache(ncache, tc->dom, "testuser_nss_short");
++    assert_int_equal(ret, EEXIST);
++
++    ret = check_user_in_ncache(ncache, tc->dom->subdomains, "testuser_nss_short");
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom, "testuser1@" TEST_DOM_NAME);
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom, "testuser2@" TEST_DOM_NAME);
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom, "testuser3@somedomain");
++    assert_int_equal(ret, EEXIST);
+ }
+ 
+ static void test_sss_ncache_default_domain_suffix(void **state)
+-- 
+2.20.1
+
diff --git a/SOURCES/0035-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch b/SOURCES/0035-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch
new file mode 100644
index 0000000..fefd20d
--- /dev/null
+++ b/SOURCES/0035-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch
@@ -0,0 +1,127 @@
+From 934341e1ef7cf2a763b604dd1fd347aa5aae7f60 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 24 Jun 2019 14:01:02 +0200
+Subject: [PATCH 35/35] negcache: add fq-usernames of know domains to all UPN
+ neg-caches
+
+The previous patch for this issue did not handle user with
+fully-qualified names from known domains correctly. Here the user was
+only added to the negative cache of the known domain but not to the
+negative UPN caches for all domains. This patch fixes this.
+
+Related to https://pagure.io/SSSD/sssd/issue/3978
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit e7e212b49bbd357129aab410cbbd5c7b1b0965a2)
+---
+ src/responder/common/negcache.c  | 54 ++++++++++++++++----------------
+ src/tests/cmocka/test_negcache.c | 17 +++++++++-
+ 2 files changed, 43 insertions(+), 28 deletions(-)
+
+diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
+index d6f72d816..d9bf1417e 100644
+--- a/src/responder/common/negcache.c
++++ b/src/responder/common/negcache.c
+@@ -1070,37 +1070,37 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
+             continue;
+         }
+         if (domainname) {
+-            dom = responder_get_domain(rctx, domainname);
+-            if (!dom) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Unknown domain name [%s], assuming [%s] is UPN\n",
+-                      domainname, filter_list[i]);
+-                for (dom = domain_list;
+-                     dom != NULL;
+-                     dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) {
+-                    ret = sss_ncache_set_upn(ncache, true, dom, filter_list[i]);
+-                    if (ret != EOK) {
+-                        DEBUG(SSSDBG_OP_FAILURE,
+-                              "sss_ncache_set_upn failed (%d [%s]), ignored\n",
+-                              ret, sss_strerror(ret));
+-                    }
++            DEBUG(SSSDBG_TRACE_ALL,
++                  "Adding [%s] to UPN negative cache of all domains.\n",
++                  filter_list[i]);
++            for (dom = domain_list;
++                 dom != NULL;
++                 dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) {
++                ret = sss_ncache_set_upn(ncache, true, dom, filter_list[i]);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE,
++                          "sss_ncache_set_upn failed (%d [%s]), ignored\n",
++                          ret, sss_strerror(ret));
+                 }
+-                continue;
+             }
+ 
+-            fqname = sss_create_internal_fqname(tmpctx, name, dom->name);
+-            if (fqname == NULL) {
+-                continue;
+-            }
++            /* Add name to domain specific cache for known domain names */
++            dom = responder_get_domain(rctx, domainname);
++            if (dom != NULL) {
++                fqname = sss_create_internal_fqname(tmpctx, name, dom->name);
++                if (fqname == NULL) {
++                    continue;
++                }
+ 
+-            ret = sss_ncache_set_user(ncache, true, dom, fqname);
+-            talloc_zfree(fqname);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "Failed to store permanent user filter for [%s]"
+-                          " (%d [%s])\n", filter_list[i],
+-                          ret, strerror(ret));
+-                continue;
++                ret = sss_ncache_set_user(ncache, true, dom, fqname);
++                talloc_zfree(fqname);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "Failed to store permanent user filter for [%s]"
++                              " (%d [%s])\n", filter_list[i],
++                              ret, strerror(ret));
++                    continue;
++                }
+             }
+         } else {
+             for (dom = domain_list;
+diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
+index 9bddddd8d..0a7e563e0 100644
+--- a/src/tests/cmocka/test_negcache.c
++++ b/src/tests/cmocka/test_negcache.c
+@@ -618,7 +618,7 @@ static void test_sss_ncache_prepopulate(void **state)
+     struct sss_domain_info *subdomain;
+ 
+     struct sss_test_conf_param nss_params[] = {
+-        { "filter_users", "testuser_nss@UPN.REALM, testuser_nss_short" },
++        { "filter_users", "testuser_nss@UPN.REALM, testuser_nss_short, all_dom_upn@"TEST_DOM_NAME },
+         { NULL, NULL },
+     };
+     struct sss_test_conf_param dom_params[] = {
+@@ -733,6 +733,21 @@ static void test_sss_ncache_prepopulate(void **state)
+ 
+     ret = sss_ncache_check_upn(ncache, tc->dom, "testuser3@somedomain");
+     assert_int_equal(ret, EEXIST);
++
++    /* Fully qualified names with a known domain part should be added to all
++     * negative UPN caches and to the negative cache of the know domain. */
++    ret = sss_ncache_check_upn(ncache, tc->dom, "all_dom_upn@"TEST_DOM_NAME);
++    assert_int_equal(ret, EEXIST);
++
++    ret = sss_ncache_check_upn(ncache, tc->dom->subdomains,
++                               "all_dom_upn@"TEST_DOM_NAME);
++    assert_int_equal(ret, EEXIST);
++
++    ret = check_user_in_ncache(ncache, tc->dom, "all_dom_upn");
++    assert_int_equal(ret, EEXIST);
++
++    ret = check_user_in_ncache(ncache, tc->dom->subdomains, "all_dom_upn");
++    assert_int_equal(ret, ENOENT);
+ }
+ 
+ static void test_sss_ncache_default_domain_suffix(void **state)
+-- 
+2.20.1
+
diff --git a/SOURCES/0036-CACHE-SSSD-doesn-t-clear-cache-entries.patch b/SOURCES/0036-CACHE-SSSD-doesn-t-clear-cache-entries.patch
new file mode 100644
index 0000000..8ecab4d
--- /dev/null
+++ b/SOURCES/0036-CACHE-SSSD-doesn-t-clear-cache-entries.patch
@@ -0,0 +1,81 @@
+From fb3f1af38edff257d603da165e0d64d12d92644e Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Sun, 16 Dec 2018 08:46:24 +0100
+Subject: [PATCH] CACHE: SSSD doesn't clear cache entries
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Once object is in cache it is refreshed when it is expired and
+requested by the system. Object ID is not checked before refresh,
+but config parameter ldap_(min|max)_id could be changed by admin.
+We should check object ID and not refresh objects outside min/max
+ID interval.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3905
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit d2adfcf54c3a37aeda675aec3ba3d174061fac1a)
+---
+ .../common/cache_req/cache_req_search.c       | 29 +++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c
+index 7423feb63..873214503 100644
+--- a/src/responder/common/cache_req/cache_req_search.c
++++ b/src/responder/common/cache_req/cache_req_search.c
+@@ -25,6 +25,7 @@
+ #include "util/util.h"
+ #include "responder/common/cache_req/cache_req_private.h"
+ #include "responder/common/cache_req/cache_req_plugin.h"
++#include "db/sysdb.h"
+ 
+ static errno_t cache_req_search_ncache(struct cache_req *cr)
+ {
+@@ -169,6 +170,30 @@ done:
+     return ret;
+ }
+ 
++static int
++cache_req_should_be_in_cache(struct cache_req *cr,
++                             struct ldb_result *result)
++{
++    id_t id = 0;
++
++    if (result == NULL || result->count != 1) {
++        /* can't decide so keep it */
++        return EOK;
++    }
++
++    id = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_UIDNUM, 0);
++    if (id && OUT_OF_ID_RANGE(id, cr->domain->id_min, cr->domain->id_max)) {
++        return ERR_ID_OUTSIDE_RANGE;
++    }
++
++    id = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_GIDNUM, 0);
++    if (id && OUT_OF_ID_RANGE(id, cr->domain->id_min, cr->domain->id_max)) {
++        return ERR_ID_OUTSIDE_RANGE;
++    }
++
++    return EOK;
++}
++
+ static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx,
+                                       struct cache_req *cr,
+                                       struct ldb_result **_result)
+@@ -191,6 +216,10 @@ static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx,
+         ret = ENOENT;
+     }
+ 
++    if (ret == EOK) {
++        ret = cache_req_should_be_in_cache(cr, result);
++    }
++
+     switch (ret) {
+     case EOK:
+         if (cr->plugin->only_one_result && result->count > 1) {
+-- 
+2.20.1
+
diff --git a/SOURCES/0037-IPA-Allow-paging-when-fetching-external-groups.patch b/SOURCES/0037-IPA-Allow-paging-when-fetching-external-groups.patch
new file mode 100644
index 0000000..8ab7283
--- /dev/null
+++ b/SOURCES/0037-IPA-Allow-paging-when-fetching-external-groups.patch
@@ -0,0 +1,34 @@
+From 0ca64be4d6d3080e0c344f5ad61545339f64a2aa Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 5 Jul 2019 10:09:15 +0200
+Subject: [PATCH] IPA: Allow paging when fetching external groups
+
+For some reason (I guess a mistake during refactoring..) the LDAP search
+request that fetches the external groups does not enable the paging
+control. This means that the number of external groups that SSSD can
+fetch is limited to 2000.
+
+Resolves: https://pagure.io/SSSD/sssd/issue/4058
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit c2e24df4320d46577aca8d1268f0336af443d541)
+---
+ src/providers/ipa/ipa_subdomains_ext_groups.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
+index 63ff7c7d7..75963bef1 100644
+--- a/src/providers/ipa/ipa_subdomains_ext_groups.c
++++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
+@@ -541,7 +541,7 @@ static void ipa_get_ad_memberships_connect_done(struct tevent_req *subreq)
+     subreq = sdap_search_bases_send(state, state->ev, state->sdap_id_ctx->opts,
+                             sdap_id_op_handle(state->sdap_op),
+                             state->sdap_id_ctx->opts->sdom->group_search_bases,
+-                            NULL, false,
++                            NULL, true,
+                             dp_opt_get_int(state->sdap_id_ctx->opts->basic,
+                                             SDAP_ENUM_SEARCH_TIMEOUT),
+                             IPA_EXT_GROUPS_FILTER,
+-- 
+2.20.1
+
diff --git a/SOURCES/0038-ad-remove-subdomain-that-has-been-disabled-through-a.patch b/SOURCES/0038-ad-remove-subdomain-that-has-been-disabled-through-a.patch
new file mode 100644
index 0000000..680b082
--- /dev/null
+++ b/SOURCES/0038-ad-remove-subdomain-that-has-been-disabled-through-a.patch
@@ -0,0 +1,47 @@
+From c9c2b60128b7faa29615123de79ed206491396a9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 30 May 2019 10:48:07 +0200
+Subject: [PATCH 38/44] ad: remove subdomain that has been disabled through
+ ad_enabled_domains from sysdb
+
+If previously enabled subdomain was disabled by removing it from ad_enabled_domains
+option in sssd.conf, its cached content (including the domain object itself)
+was kept in sysdb. Therefore eventhough the domain was effectively disabled in
+backed its cached data was still available in responders.
+
+Subdomains that are disabled on server side are correctly removed from sysdb in
+`ad_subdomains_refresh()` so this issue is related only to the configuration
+option.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4009
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 815957cd10a82aca6742b0bd56c7e7f199596cd4)
+---
+ src/providers/ad/ad_subdomains.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index b4e09fb7e..a3906e994 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -825,6 +825,15 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+ 
+         if (is_domain_enabled(sd_name, enabled_domains_list) == false) {
+             DEBUG(SSSDBG_TRACE_FUNC, "Disabling subdomain %s\n", sd_name);
++
++            /* The subdomain is now disabled in configuraiton file, we
++             * need to delete its cached content so it is not returned
++             * by responders. The subdomain shares sysdb with its parent
++             * domain so it is OK to use domain->sysdb. */
++            ret = sysdb_subdomain_delete(domain->sysdb, sd_name);
++            if (ret != EOK) {
++                goto fail;
++            }
+             continue;
+         } else {
+             DEBUG(SSSDBG_TRACE_FUNC, "Enabling subdomain %s\n", sd_name);
+-- 
+2.20.1
+
diff --git a/SOURCES/0039-sysdb-add-sysdb_domain_set_enabled.patch b/SOURCES/0039-sysdb-add-sysdb_domain_set_enabled.patch
new file mode 100644
index 0000000..a72281d
--- /dev/null
+++ b/SOURCES/0039-sysdb-add-sysdb_domain_set_enabled.patch
@@ -0,0 +1,116 @@
+From 0e16ec74c380b35fc201ded15434184d88413dc7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 30 May 2019 12:14:58 +0200
+Subject: [PATCH 39/44] sysdb: add sysdb_domain_set_enabled()
+
+This will be used in subsequent patches to disable subdomains.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4009
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 7a03e99890806257df1ed8a126673d6a032fee6a)
+---
+ src/db/sysdb.c            |  7 ++++++-
+ src/db/sysdb.h            |  6 ++++++
+ src/db/sysdb_subdomains.c | 31 +++++++++++++++++++++++++++++++
+ 3 files changed, 43 insertions(+), 1 deletion(-)
+
+diff --git a/src/db/sysdb.c b/src/db/sysdb.c
+index 06d7f2796..279bd5839 100644
+--- a/src/db/sysdb.c
++++ b/src/db/sysdb.c
+@@ -1135,7 +1135,7 @@ errno_t sysdb_set_bool(struct sysdb_ctx *sysdb,
+     errno_t ret;
+     int lret;
+ 
+-    if (dn == NULL || cn_value == NULL || attr_name == NULL) {
++    if (dn == NULL || attr_name == NULL) {
+         return EINVAL;
+     }
+ 
+@@ -1159,6 +1159,11 @@ errno_t sysdb_set_bool(struct sysdb_ctx *sysdb,
+     msg->dn = dn;
+ 
+     if (res->count == 0) {
++        if (cn_value == NULL) {
++            ret = ENOENT;
++            goto done;
++        }
++
+         lret = ldb_msg_add_string(msg, "cn", cn_value);
+         if (lret != LDB_SUCCESS) {
+             ret = sysdb_error_to_errno(lret);
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 01e7554bb..574f4b120 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -155,6 +155,7 @@
+ #define SYSDB_SUBDOMAIN_TRUST_DIRECTION "trustDirection"
+ #define SYSDB_UPN_SUFFIXES "upnSuffixes"
+ #define SYSDB_SITE "site"
++#define SYSDB_ENABLED "enabled"
+ 
+ #define SYSDB_BASE_ID "baseID"
+ #define SYSDB_ID_RANGE_SIZE "idRangeSize"
+@@ -523,6 +524,11 @@ errno_t
+ sysdb_set_site(struct sss_domain_info *dom,
+                const char *site);
+ 
++errno_t
++sysdb_domain_set_enabled(struct sysdb_ctx *sysdb,
++                         const char *name,
++                         bool enabled);
++
+ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+                               const char *name, const char *realm,
+                               const char *flat_name, const char *domain_id,
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index 34d052fdd..d467dfce5 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -1200,6 +1200,18 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+         }
+     }
+ 
++    ret = ldb_msg_add_empty(msg, SYSDB_ENABLED, LDB_FLAG_MOD_REPLACE, NULL);
++    if (ret != LDB_SUCCESS) {
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
++    ret = ldb_msg_add_string(msg, SYSDB_ENABLED, "TRUE");
++    if (ret != LDB_SUCCESS) {
++        ret = sysdb_error_to_errno(ret);
++        goto done;
++    }
++
+     ret = ldb_modify(sysdb->ldb, msg);
+     if (ret != LDB_SUCCESS) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to "
+@@ -1420,3 +1432,22 @@ done:
+     talloc_free(tmp_ctx);
+     return ret;
+ }
++
++errno_t
++sysdb_domain_set_enabled(struct sysdb_ctx *sysdb,
++                         const char *name,
++                         bool enabled)
++{
++    struct ldb_dn *dn;
++    errno_t ret;
++
++    dn = ldb_dn_new_fmt(NULL, sysdb->ldb, SYSDB_DOM_BASE, name);
++    if (dn == NULL) {
++        return ENOMEM;
++    }
++
++    ret = sysdb_set_bool(sysdb, dn, NULL, SYSDB_ENABLED, enabled);
++    talloc_free(dn);
++
++    return ret;
++}
+-- 
+2.20.1
+
diff --git a/SOURCES/0040-ad-set-enabled-false-attribute-for-subdomains-that-n.patch b/SOURCES/0040-ad-set-enabled-false-attribute-for-subdomains-that-n.patch
new file mode 100644
index 0000000..c1176cb
--- /dev/null
+++ b/SOURCES/0040-ad-set-enabled-false-attribute-for-subdomains-that-n.patch
@@ -0,0 +1,53 @@
+From 800d24dccbf655b2c65521727256c4e6c4a540d5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 30 May 2019 12:51:47 +0200
+Subject: [PATCH 40/44] ad: set enabled=false attribute for subdomains that no
+ longer exists
+
+Only forest root domain needs to be disabled because it has to be available
+for other tasks. All other non-root domains are removed from cache completely
+so it does not make sense for them.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4009
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 6882bc5f5c8805abff3511d55c0ed60cad84faab)
+---
+ src/providers/ad/ad_subdomains.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index a3906e994..57438fdd5 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -696,6 +696,13 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
+             if (sss_domain_is_forest_root(dom)) {
+                 DEBUG(SSSDBG_TRACE_ALL,
+                       "Skipping removal of forest root sdap data.\n");
++
++                ret = sysdb_domain_set_enabled(dom->sysdb, dom->name, false);
++                if (ret != EOK && ret != ENOENT) {
++                    DEBUG(SSSDBG_OP_FAILURE, "Unable to disable domain %s "
++                          "[%d]: %s\n", dom->name, ret, sss_strerror(ret));
++                    goto done;
++                }
+                 continue;
+             }
+ 
+@@ -864,6 +871,12 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+         } else {
+             DEBUG(SSSDBG_TRACE_FUNC, "Disabling forest root domain %s\n",
+                                      root_name);
++            ret = sysdb_domain_set_enabled(domain->sysdb, root_name, false);
++            if (ret != EOK && ret != ENOENT) {
++                DEBUG(SSSDBG_OP_FAILURE, "Unable to disable domain %s "
++                      "[%d]: %s\n", root_name, ret, sss_strerror(ret));
++                goto fail;
++            }
+         }
+     }
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0041-sysdb-read-and-interpret-domain-s-enabled-attribute.patch b/SOURCES/0041-sysdb-read-and-interpret-domain-s-enabled-attribute.patch
new file mode 100644
index 0000000..50e9000
--- /dev/null
+++ b/SOURCES/0041-sysdb-read-and-interpret-domain-s-enabled-attribute.patch
@@ -0,0 +1,229 @@
+From b2cd4a74e231611f7862a8bb39a655c5194a035a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 30 May 2019 12:52:33 +0200
+Subject: [PATCH 41/44] sysdb: read and interpret domain's enabled attribute
+
+Disable domain if its sysdb object has enabled=false.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4009
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit d278704d85fea74c229b67e6a63b650b0d776c88)
+---
+ src/db/sysdb_private.h                      |  3 ++-
+ src/db/sysdb_subdomains.c                   | 29 ++++++++++++++++++---
+ src/tests/cmocka/test_fqnames.c             |  2 +-
+ src/tests/cmocka/test_negcache.c            |  2 +-
+ src/tests/cmocka/test_nss_srv.c             |  2 +-
+ src/tests/cmocka/test_responder_cache_req.c |  2 +-
+ src/tests/sysdb-tests.c                     |  8 +++---
+ 7 files changed, 35 insertions(+), 13 deletions(-)
+
+diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
+index 58544d826..f3d34dd6f 100644
+--- a/src/db/sysdb_private.h
++++ b/src/db/sysdb_private.h
+@@ -206,7 +206,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
+                                       const char *forest,
+                                       const char **upn_suffixes,
+                                       uint32_t trust_direction,
+-                                      struct confdb_ctx *confdb);
++                                      struct confdb_ctx *confdb,
++                                      bool enabled);
+ 
+ /* Helper functions to deal with the timestamp cache should not be used
+  * outside the sysdb itself. The timestamp cache should be completely
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index d467dfce5..cf09b424e 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -39,7 +39,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
+                                       const char *forest,
+                                       const char **upn_suffixes,
+                                       uint32_t trust_direction,
+-                                      struct confdb_ctx *confdb)
++                                      struct confdb_ctx *confdb,
++                                      bool enabled)
+ {
+     struct sss_domain_info *dom;
+     bool inherit_option;
+@@ -127,7 +128,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
+     dom->enumerate = enumerate;
+     dom->fqnames = true;
+     dom->mpg_mode = mpg_mode;
+-    dom->state = DOM_ACTIVE;
++    dom->state = enabled ? DOM_ACTIVE : DOM_DISABLED;
+ 
+     /* use fully qualified names as output in order to avoid causing
+      * conflicts with users who have the same name and either the
+@@ -313,6 +314,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
+                            SYSDB_SUBDOMAIN_FOREST,
+                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
+                            SYSDB_UPN_SUFFIXES,
++                           SYSDB_ENABLED,
+                            NULL};
+     struct sss_domain_info *dom;
+     struct ldb_dn *basedn;
+@@ -322,6 +324,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
+     const char *id;
+     const char *forest;
+     const char *str_mpg_mode;
++    bool enabled;
+     enum sss_domain_mpg_mode mpg_mode;
+     bool enumerate;
+     uint32_t trust_direction;
+@@ -406,10 +409,14 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
+                                              SYSDB_SUBDOMAIN_TRUST_DIRECTION,
+                                              0);
+ 
++        enabled = ldb_msg_find_attr_as_bool(res->msgs[i], SYSDB_ENABLED, true);
++
+         for (dom = domain->subdomains; dom;
+                 dom = get_next_domain(dom, SSS_GND_INCLUDE_DISABLED)) {
+             if (strcasecmp(dom->name, name) == 0) {
+-                sss_domain_set_state(dom, DOM_ACTIVE);
++                if (enabled) {
++                    sss_domain_set_state(dom, DOM_ACTIVE);
++                }
+ 
+                 /* in theory these may change, but it should never happen */
+                 if (strcasecmp(dom->realm, realm) != 0) {
+@@ -522,7 +529,8 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
+         if (dom == NULL) {
+             dom = new_subdomain(domain, domain, name, realm,
+                                 flat, id, mpg_mode, enumerate, forest,
+-                                upn_suffixes, trust_direction, confdb);
++                                upn_suffixes, trust_direction, confdb,
++                                enabled);
+             if (dom == NULL) {
+                 ret = ENOMEM;
+                 goto done;
+@@ -548,12 +556,15 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
+     struct ldb_message_element *tmp_el;
+     struct ldb_dn *basedn;
+     struct ldb_result *res;
++    enum sss_domain_state state;
++    bool enabled;
+     const char *attrs[] = {"cn",
+                            SYSDB_SUBDOMAIN_REALM,
+                            SYSDB_SUBDOMAIN_FLAT,
+                            SYSDB_SUBDOMAIN_ID,
+                            SYSDB_SUBDOMAIN_FOREST,
+                            SYSDB_UPN_SUFFIXES,
++                           SYSDB_ENABLED,
+                            NULL};
+     char *view_name = NULL;
+ 
+@@ -650,6 +661,16 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
+         talloc_zfree(domain->upn_suffixes);
+     }
+ 
++    state = sss_domain_get_state(domain);
++    enabled = ldb_msg_find_attr_as_bool(res->msgs[0], SYSDB_ENABLED, true);
++    if (!enabled) {
++        sss_domain_set_state(domain, DOM_DISABLED);
++    } else if (state == DOM_DISABLED) {
++        /* We do not want to enable INACTIVE or INCONSISTENT domain. This
++         * is managed by data provider. */
++        sss_domain_set_state(domain, DOM_ACTIVE);
++    }
++
+     ret = sysdb_get_view_name(tmp_ctx, domain->sysdb, &view_name);
+     if (ret != EOK && ret != ENOENT) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
+diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c
+index 09f7db0d1..770c0d7bf 100644
+--- a/src/tests/cmocka/test_fqnames.c
++++ b/src/tests/cmocka/test_fqnames.c
+@@ -310,7 +310,7 @@ static int parse_name_test_setup(void **state)
+      */
+     test_ctx->subdom = new_subdomain(dom, dom, SUBDOMNAME, NULL, SUBFLATNAME,
+                                      NULL, MPG_DISABLED, false,
+-                                     NULL, NULL, 0, NULL);
++                                     NULL, NULL, 0, NULL, true);
+     assert_non_null(test_ctx->subdom);
+ 
+     check_leaks_push(test_ctx);
+diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
+index 0a7e563e0..0876cfdaf 100644
+--- a/src/tests/cmocka/test_negcache.c
++++ b/src/tests/cmocka/test_negcache.c
+@@ -645,7 +645,7 @@ static void test_sss_ncache_prepopulate(void **state)
+     subdomain = new_subdomain(tc, tc->dom,
+                               testdom[0], testdom[1], testdom[2], testdom[3],
+                               false, false, NULL, NULL, 0,
+-                              tc->confdb);
++                              tc->confdb, true);
+     assert_non_null(subdomain);
+ 
+     ret = sysdb_subdomain_store(tc->sysdb,
+diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
+index 0ae177571..95c080caf 100644
+--- a/src/tests/cmocka/test_nss_srv.c
++++ b/src/tests/cmocka/test_nss_srv.c
+@@ -3475,7 +3475,7 @@ static int nss_subdom_test_setup_common(void **state, bool nonfqnames)
+     subdomain = new_subdomain(nss_test_ctx, nss_test_ctx->tctx->dom,
+                               testdom[0], testdom[1], testdom[2], testdom[3],
+                               false, false, NULL, NULL, 0,
+-                              nss_test_ctx->tctx->confdb);
++                              nss_test_ctx->tctx->confdb, true);
+     assert_non_null(subdomain);
+ 
+     ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb,
+diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
+index 47d9aab54..9f3b49cd9 100644
+--- a/src/tests/cmocka/test_responder_cache_req.c
++++ b/src/tests/cmocka/test_responder_cache_req.c
+@@ -687,7 +687,7 @@ static int test_subdomain_setup(void **state)
+     test_ctx->subdomain = new_subdomain(test_ctx, test_ctx->tctx->dom,
+                               testdom[0], testdom[1], testdom[2], testdom[3],
+                               MPG_DISABLED, false, NULL, NULL, 0,
+-                              test_ctx->tctx->confdb);
++                              test_ctx->tctx->confdb, true);
+     assert_non_null(test_ctx->subdomain);
+ 
+     ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index ed98fe6ce..832d60466 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -1541,7 +1541,7 @@ START_TEST (test_sysdb_get_user_attr_subdomain)
+     /* Create subdomain */
+     subdomain = new_subdomain(test_ctx, test_ctx->domain,
+                               "test.sub", "TEST.SUB", "test", "S-3",
+-                              MPG_DISABLED, false, NULL, NULL, 0, NULL);
++                              MPG_DISABLED, false, NULL, NULL, 0, NULL, true);
+     fail_if(subdomain == NULL, "Failed to create new subdomain.");
+ 
+     ret = sss_names_init_from_args(test_ctx,
+@@ -6143,7 +6143,7 @@ START_TEST(test_sysdb_subdomain_store_user)
+ 
+     subdomain = new_subdomain(test_ctx, test_ctx->domain,
+                               testdom[0], testdom[1], testdom[2], testdom[3],
+-                              MPG_DISABLED, false, NULL, NULL, 0, NULL);
++                              MPG_DISABLED, false, NULL, NULL, 0, NULL, true);
+     fail_unless(subdomain != NULL, "Failed to create new subdomain.");
+     ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+@@ -6222,7 +6222,7 @@ START_TEST(test_sysdb_subdomain_user_ops)
+ 
+     subdomain = new_subdomain(test_ctx, test_ctx->domain,
+                               testdom[0], testdom[1], testdom[2], testdom[3],
+-                              MPG_DISABLED, false, NULL, NULL, 0, NULL);
++                              MPG_DISABLED, false, NULL, NULL, 0, NULL, true);
+     fail_unless(subdomain != NULL, "Failed to create new subdomain.");
+     ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+@@ -6295,7 +6295,7 @@ START_TEST(test_sysdb_subdomain_group_ops)
+ 
+     subdomain = new_subdomain(test_ctx, test_ctx->domain,
+                               testdom[0], testdom[1], testdom[2], testdom[3],
+-                              MPG_DISABLED, false, NULL, NULL, 0, NULL);
++                              MPG_DISABLED, false, NULL, NULL, 0, NULL, true);
+     fail_unless(subdomain != NULL, "Failed to create new subdomain.");
+     ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                 testdom[0], testdom[1], testdom[2], testdom[3],
+-- 
+2.20.1
+
diff --git a/SOURCES/0042-sysdb-add-sysdb_list_subdomains.patch b/SOURCES/0042-sysdb-add-sysdb_list_subdomains.patch
new file mode 100644
index 0000000..fea5b49
--- /dev/null
+++ b/SOURCES/0042-sysdb-add-sysdb_list_subdomains.patch
@@ -0,0 +1,104 @@
+From 3c6c9d4d939bb2f1f629421e347285bea9a59341 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 11 Jun 2019 12:17:55 +0200
+Subject: [PATCH 42/44] sysdb: add sysdb_list_subdomains()
+
+To list all cached subdomains names.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4009
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit c7e6530d642f746982c5306cf3455608d1980d1f)
+---
+ src/db/sysdb.h            |  5 ++++
+ src/db/sysdb_subdomains.c | 60 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 65 insertions(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 574f4b120..56468a169 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -529,6 +529,11 @@ sysdb_domain_set_enabled(struct sysdb_ctx *sysdb,
+                          const char *name,
+                          bool enabled);
+ 
++errno_t
++sysdb_list_subdomains(TALLOC_CTX *mem_ctx,
++                      struct sysdb_ctx *sysdb,
++                      const char ***_names);
++
+ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
+                               const char *name, const char *realm,
+                               const char *flat_name, const char *domain_id,
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index cf09b424e..af838b44c 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -1472,3 +1472,63 @@ sysdb_domain_set_enabled(struct sysdb_ctx *sysdb,
+ 
+     return ret;
+ }
++
++errno_t
++sysdb_list_subdomains(TALLOC_CTX *mem_ctx,
++                      struct sysdb_ctx *sysdb,
++                      const char ***_names)
++{
++    TALLOC_CTX *tmp_ctx;
++    struct ldb_dn *base_dn;
++    const char *attrs[] = {"cn", NULL};
++    struct ldb_message **msgs;
++    const char *name;
++    size_t count;
++    const char **names;
++    errno_t ret;
++    size_t i;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    base_dn = sysdb_base_dn(sysdb, tmp_ctx);
++    if (base_dn == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++
++    ret = sysdb_search_entry(tmp_ctx, sysdb, base_dn, LDB_SCOPE_ONELEVEL,
++                             "("SYSDB_OBJECTCLASS"="SYSDB_SUBDOMAIN_CLASS")",
++                             attrs, &count, &msgs);
++    if (ret != EOK && ret != ENOENT) {
++        goto done;
++    }
++
++    names = talloc_zero_array(tmp_ctx, const char *, count + 1);
++    if (names == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    for (i = 0; i < count; i++) {
++        name = ldb_msg_find_attr_as_string(msgs[i], "cn", NULL);
++        if (name == NULL) {
++            ret = EINVAL;
++            goto done;
++        }
++
++        names[i] = talloc_steal(names, name);
++    }
++
++    *_names = talloc_steal(mem_ctx, names);
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
+-- 
+2.20.1
+
diff --git a/SOURCES/0043-ad-remove-all-subdomains-if-only-master-domain-is-en.patch b/SOURCES/0043-ad-remove-all-subdomains-if-only-master-domain-is-en.patch
new file mode 100644
index 0000000..2ef0ad9
--- /dev/null
+++ b/SOURCES/0043-ad-remove-all-subdomains-if-only-master-domain-is-en.patch
@@ -0,0 +1,62 @@
+From 5605fa5f8adf79fa60286f5427aa2f989e663de0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 11 Jun 2019 12:18:34 +0200
+Subject: [PATCH 43/44] ad: remove all subdomains if only master domain is
+ enabled
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4009
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit d0bdaabbc95bc9ee3253e1376d849e6a8bd6c6f0)
+---
+ src/providers/ad/ad_subdomains.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 57438fdd5..0f6d781ae 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -1804,9 +1804,11 @@ static void ad_subdomains_refresh_gc_check_done(struct tevent_req *subreq)
+ {
+     struct ad_subdomains_refresh_state *state;
+     struct tevent_req *req;
++    const char **subdoms;
+     const char *ad_domain;
+     bool is_gc_usable;
+     errno_t ret;
++    int i;
+ 
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+@@ -1832,6 +1834,27 @@ static void ad_subdomains_refresh_gc_check_done(struct tevent_req *subreq)
+                            state->be_ctx->domain->name) == 0) {
+                 DEBUG(SSSDBG_TRACE_FUNC,
+                       "No other enabled domain than master.\n");
++
++                ret = sysdb_list_subdomains(state, state->be_ctx->domain->sysdb,
++                                            &subdoms);
++                if (ret != EOK) {
++                    DEBUG(SSSDBG_OP_FAILURE, "Unable to list subdomains "
++                          "[%d]: %s\n", ret, sss_strerror(ret));
++                    tevent_req_error(req, ret);
++                    return;
++                }
++
++                for (i = 0; subdoms[i] != NULL; i++) {
++                    ret = sysdb_subdomain_delete(state->be_ctx->domain->sysdb,
++                                                 subdoms[i]);
++                    if (ret != EOK) {
++                        DEBUG(SSSDBG_OP_FAILURE, "Unable to remove subdomain "
++                              "[%d]: %s\n", ret, sss_strerror(ret));
++                        tevent_req_error(req, ret);
++                        return;
++                    }
++                }
++
+                 tevent_req_done(req);
+                 return;
+             }
+-- 
+2.20.1
+
diff --git a/SOURCES/0044-ad-make-ad_enabled_domains-case-insensitive.patch b/SOURCES/0044-ad-make-ad_enabled_domains-case-insensitive.patch
new file mode 100644
index 0000000..937926a
--- /dev/null
+++ b/SOURCES/0044-ad-make-ad_enabled_domains-case-insensitive.patch
@@ -0,0 +1,30 @@
+From 0b6f144084ec3ed96eb2c60bed7bea5d6c15f15c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 12 Aug 2019 09:40:28 +0200
+Subject: [PATCH 44/44] ad: make ad_enabled_domains case insensitive
+
+The rest of the code that works with ad_enabled_domains options
+is case insensitive so we rather should be consistent.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit b3c3542188e50770b431942c0b603e6f2733cb33)
+---
+ src/providers/ad/ad_subdomains.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 0f6d781ae..e3e3d3ece 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -190,7 +190,7 @@ static errno_t ad_get_enabled_domains(TALLOC_CTX *mem_ctx,
+ 
+     is_ad_in_domains = false;
+     for (int i = 0; i < count; i++) {
+-        is_ad_in_domains += strcmp(ad_domain, domains[i]) == 0 ? true : false;
++        is_ad_in_domains += strcasecmp(ad_domain, domains[i]) == 0 ? true : false;
+     }
+ 
+     if (is_ad_in_domains == false) {
+-- 
+2.20.1
+
diff --git a/SOURCES/0045-SYSDB-Add-sysdb_search_with_ts_attr.patch b/SOURCES/0045-SYSDB-Add-sysdb_search_with_ts_attr.patch
new file mode 100644
index 0000000..cfd84d9
--- /dev/null
+++ b/SOURCES/0045-SYSDB-Add-sysdb_search_with_ts_attr.patch
@@ -0,0 +1,595 @@
+From e935d41ec6c187c61e0a6f8c353276fbf69780a5 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 28 May 2019 14:56:05 +0200
+Subject: [PATCH 45/64] SYSDB: Add sysdb_search_with_ts_attr
+
+Adds a new public sysdb call sysdb_search_with_ts_attr() that allows to
+search on the timestamp cache attributes, but merge back persistent
+cache attributes. The converse also works, when searching the persistent
+cache the timestamp attributes or even entries matches only in the
+timestamp cache are merged.
+
+What does not work is AND-ed complex filter that contains both
+attributes from the timestamp cache and the persistent cache because
+the searches use the same filter, which doesn't match. We would need to
+decompose the filter ourselves.
+
+Because matching and merging the results can be time-consuming, two
+flags are provided:
+    SYSDB_SEARCH_WITH_TS_ONLY_TS_FILTER that only searches the timestamp
+    cache, but merges back the corresponding entries from the persistent
+    cache
+    SYSDB_SEARCH_WITH_TS_ONLY_SYSDB_FILTER that only searches the
+    persistent cache but merges back the attributes from the timestamp
+    cache
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit db99504a5295ae1f9bc5166133c8f21e4510c676)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/db/sysdb.h                         |  12 ++
+ src/db/sysdb_ops.c                     |  16 +-
+ src/db/sysdb_private.h                 |  10 ++
+ src/db/sysdb_search.c                  | 231 +++++++++++++++++++++++--
+ src/tests/cmocka/test_sysdb_ts_cache.c | 198 +++++++++++++++++++++
+ 5 files changed, 446 insertions(+), 21 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 56468a169..15df1a726 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1190,6 +1190,18 @@ int sysdb_search_users(TALLOC_CTX *mem_ctx,
+                        size_t *msgs_count,
+                        struct ldb_message ***msgs);
+ 
++#define SYSDB_SEARCH_WITH_TS_ONLY_TS_FILTER     0x0001
++#define SYSDB_SEARCH_WITH_TS_ONLY_SYSDB_FILTER  0x0002
++
++errno_t sysdb_search_with_ts_attr(TALLOC_CTX *mem_ctx,
++                                  struct sss_domain_info *domain,
++                                  struct ldb_dn *base_dn,
++                                  enum ldb_scope scope,
++                                  int optflags,
++                                  const char *filter,
++                                  const char *attrs[],
++                                  struct ldb_result **_result);
++
+ int sysdb_search_users_by_timestamp(TALLOC_CTX *mem_ctx,
+                                     struct sss_domain_info *domain,
+                                     const char *sub_filter,
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index d05950732..340062f6f 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -261,14 +261,14 @@ done:
+ 
+ /* =Search-Entry========================================================== */
+ 
+-static int sysdb_cache_search_entry(TALLOC_CTX *mem_ctx,
+-                                    struct ldb_context *ldb,
+-                                    struct ldb_dn *base_dn,
+-                                    enum ldb_scope scope,
+-                                    const char *filter,
+-                                    const char **attrs,
+-                                    size_t *_msgs_count,
+-                                    struct ldb_message ***_msgs)
++int sysdb_cache_search_entry(TALLOC_CTX *mem_ctx,
++                             struct ldb_context *ldb,
++                             struct ldb_dn *base_dn,
++                             enum ldb_scope scope,
++                             const char *filter,
++                             const char **attrs,
++                             size_t *_msgs_count,
++                             struct ldb_message ***_msgs)
+ {
+     TALLOC_CTX *tmp_ctx;
+     struct ldb_result *res;
+diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
+index f3d34dd6f..7063d4594 100644
+--- a/src/db/sysdb_private.h
++++ b/src/db/sysdb_private.h
+@@ -253,6 +253,16 @@ errno_t sysdb_merge_msg_list_ts_attrs(struct sysdb_ctx *ctx,
+ struct ldb_result *sss_merge_ldb_results(struct ldb_result *res,
+                                          struct ldb_result *subres);
+ 
++/* Search Entry in an ldb cache */
++int sysdb_cache_search_entry(TALLOC_CTX *mem_ctx,
++                             struct ldb_context *ldb,
++                             struct ldb_dn *base_dn,
++                             enum ldb_scope scope,
++                             const char *filter,
++                             const char **attrs,
++                             size_t *_msgs_count,
++                             struct ldb_message ***_msgs);
++
+ /* Search Entry in the timestamp cache */
+ int sysdb_search_ts_entry(TALLOC_CTX *mem_ctx,
+                           struct sysdb_ctx *sysdb,
+diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
+index f0918bf9a..a71c43112 100644
+--- a/src/db/sysdb_search.c
++++ b/src/db/sysdb_search.c
+@@ -68,6 +68,29 @@ static errno_t merge_ts_attr(struct ldb_message *ts_msg,
+     return EOK;
+ }
+ 
++static errno_t merge_all_ts_attrs(struct ldb_message *ts_msg,
++                                  struct ldb_message *sysdb_msg,
++                                  const char *want_attrs[])
++{
++    int ret;
++
++    /* Deliberately start from 2 in order to not merge
++     * objectclass/objectcategory and avoid breaking MPGs where the OC might
++     * be made up
++     */
++    for (size_t c = 2; sysdb_ts_cache_attrs[c]; c++) {
++        ret = merge_ts_attr(ts_msg, sysdb_msg,
++                            sysdb_ts_cache_attrs[c], want_attrs);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Cannot merge ts attr %s\n", sysdb_ts_cache_attrs[c]);
++            return ret;
++        }
++    }
++
++    return EOK;
++}
++
+ static errno_t merge_msg_ts_attrs(struct sysdb_ctx *sysdb,
+                                   struct ldb_message *sysdb_msg,
+                                   const char *attrs[])
+@@ -114,21 +137,46 @@ static errno_t merge_msg_ts_attrs(struct sysdb_ctx *sysdb,
+         return EIO;
+     }
+ 
+-    /* Deliberately start from 2 in order to not merge
+-     * objectclass/objectcategory and avoid breaking MPGs where the OC might
+-     * be made up
+-     */
+-    for (size_t c = 2; sysdb_ts_cache_attrs[c]; c++) {
+-        ret = merge_ts_attr(ts_msgs[0], sysdb_msg,
+-                            sysdb_ts_cache_attrs[c], attrs);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Cannot merge ts attr %s\n", sysdb_ts_cache_attrs[c]);
+-            goto done;
+-        }
++    ret = merge_all_ts_attrs(ts_msgs[0], sysdb_msg, attrs);
++done:
++    talloc_zfree(tmp_ctx);
++    return ret;
++}
++
++static errno_t merge_msg_sysdb_attrs(TALLOC_CTX *mem_ctx,
++                                     struct sysdb_ctx *sysdb,
++                                     struct ldb_message *ts_msg,
++                                     struct ldb_message **_sysdb_msg,
++                                     const char *attrs[])
++{
++    errno_t ret;
++    TALLOC_CTX *tmp_ctx;
++    size_t msgs_count;
++    struct ldb_message **sysdb_msgs;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
+     }
+ 
+-    ret = EOK;
++    ret = sysdb_cache_search_entry(tmp_ctx, sysdb->ldb, ts_msg->dn, LDB_SCOPE_BASE,
++                                   NULL, attrs, &msgs_count, &sysdb_msgs);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    if (msgs_count != 1) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Expected 1 result for base search, got %zu\n", msgs_count);
++        goto done;
++    }
++
++    ret = merge_all_ts_attrs(ts_msg, sysdb_msgs[0], attrs);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    *_sysdb_msg = talloc_steal(mem_ctx, sysdb_msgs[0]);
+ done:
+     talloc_zfree(tmp_ctx);
+     return ret;
+@@ -166,6 +214,50 @@ errno_t sysdb_merge_res_ts_attrs(struct sysdb_ctx *ctx,
+     return EOK;
+ }
+ 
++static errno_t merge_res_sysdb_attrs(TALLOC_CTX *mem_ctx,
++                                     struct sysdb_ctx *ctx,
++                                     struct ldb_result *ts_res,
++                                     struct ldb_result **_ts_cache_res,
++                                     const char *attrs[])
++{
++    errno_t ret;
++    struct ldb_result *ts_cache_res = NULL;
++
++    if (ts_res == NULL || ctx->ldb_ts == NULL) {
++        return EOK;
++    }
++
++    ts_cache_res = talloc_zero(mem_ctx, struct ldb_result);
++    if (ts_cache_res == NULL) {
++        return ENOMEM;
++    }
++    ts_cache_res->count = ts_res->count;
++    ts_cache_res->msgs = talloc_zero_array(ts_cache_res,
++                                           struct ldb_message *,
++                                           ts_res->count);
++    if (ts_cache_res->msgs == NULL) {
++        talloc_free(ts_cache_res);
++        return ENOMEM;
++    }
++
++    for (size_t c = 0; c < ts_res->count; c++) {
++        ret = merge_msg_sysdb_attrs(ts_cache_res->msgs,
++                                    ctx,
++                                    ts_res->msgs[c],
++                                    &ts_cache_res->msgs[c], attrs);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Cannot merge sysdb cache values for %s\n",
++                  ldb_dn_get_linearized(ts_res->msgs[c]->dn));
++            /* non-fatal, we just get only the non-timestamp attrs */
++            continue;
++        }
++    }
++
++    *_ts_cache_res = ts_cache_res;
++    return EOK;
++}
++
+ errno_t sysdb_merge_msg_list_ts_attrs(struct sysdb_ctx *ctx,
+                                       size_t msgs_count,
+                                       struct ldb_message **msgs,
+@@ -543,6 +635,119 @@ done:
+     return ret;
+ }
+ 
++errno_t sysdb_search_with_ts_attr(TALLOC_CTX *mem_ctx,
++                                  struct sss_domain_info *domain,
++                                  struct ldb_dn *base_dn,
++                                  enum ldb_scope scope,
++                                  int optflags,
++                                  const char *filter,
++                                  const char *attrs[],
++                                  struct ldb_result **_res)
++{
++    TALLOC_CTX *tmp_ctx = NULL;
++    struct ldb_result *res;
++    errno_t ret;
++    struct ldb_message **ts_msgs = NULL;
++    struct ldb_result *ts_cache_res = NULL;
++    size_t ts_count;
++
++    if (filter == NULL) {
++        return EINVAL;
++    }
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    res = talloc_zero(tmp_ctx, struct ldb_result);
++    if (res == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    if (optflags & SYSDB_SEARCH_WITH_TS_ONLY_SYSDB_FILTER) {
++        /* We only care about searching the persistent db */
++        ts_cache_res = talloc_zero(tmp_ctx, struct ldb_result);
++        if (ts_cache_res == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++        ts_cache_res->count = 0;
++        ts_cache_res->msgs = NULL;
++    } else {
++        /* Because the timestamp database does not contain all the
++         * attributes, we need to search the persistent db for each
++         * of the entries found and merge the results
++         */
++        struct ldb_result ts_res;
++
++        /* We assume that some of the attributes are more up-to-date in
++         * timestamps db and we're supposed to search by them, so let's
++         * first search the timestamp db
++         */
++        ret = sysdb_search_ts_entry(tmp_ctx, domain->sysdb, base_dn,
++                                    scope, filter, attrs,
++                                    &ts_count, &ts_msgs);
++        if (ret == ENOENT) {
++            ts_count = 0;
++        } else if (ret != EOK) {
++            goto done;
++        }
++
++        memset(&ts_res, 0, sizeof(struct ldb_result));
++        ts_res.count = ts_count;
++        ts_res.msgs = ts_msgs;
++
++        /* Overlay the results from the main cache with the ts attrs */
++        ret = merge_res_sysdb_attrs(tmp_ctx,
++                                    domain->sysdb,
++                                    &ts_res,
++                                    &ts_cache_res,
++                                    attrs);
++        if (ret != EOK) {
++            goto done;
++        }
++    }
++
++    if (optflags & SYSDB_SEARCH_WITH_TS_ONLY_TS_FILTER) {
++        /* The filter only contains timestamp attrs, no need to search the
++         * persistent db
++         */
++        if (ts_cache_res) {
++            res->count = ts_cache_res->count;
++            res->msgs = talloc_steal(res, ts_cache_res->msgs);
++        }
++    } else {
++        /* Because some of the attributes being searched might exist in the persistent
++         * database only, we also search the persistent db
++         */
++        size_t count;
++
++        ret = sysdb_search_entry(res, domain->sysdb, base_dn, scope,
++                                 filter, attrs, &count, &res->msgs);
++        if (ret == ENOENT) {
++            res->count = 0;
++        } else if (ret != EOK) {
++            goto done;
++        }
++        res->count = count; /* Just to cleanly assign size_t to unsigned */
++
++        res = sss_merge_ldb_results(res, ts_cache_res);
++        if (res == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++    }
++
++    *_res = talloc_steal(mem_ctx, res);
++    ret = EOK;
++
++done:
++    talloc_zfree(tmp_ctx);
++    return ret;
++}
++
+ static errno_t sysdb_enum_dn_filter(TALLOC_CTX *mem_ctx,
+                                     struct ldb_result *ts_res,
+                                     const char *name_filter,
+diff --git a/src/tests/cmocka/test_sysdb_ts_cache.c b/src/tests/cmocka/test_sysdb_ts_cache.c
+index fdf9935da..d2296d1b8 100644
+--- a/src/tests/cmocka/test_sysdb_ts_cache.c
++++ b/src/tests/cmocka/test_sysdb_ts_cache.c
+@@ -1411,6 +1411,201 @@ static void test_sysdb_zero_now(void **state)
+     assert_true(cache_expire_ts > TEST_CACHE_TIMEOUT);
+ }
+ 
++static void test_sysdb_search_with_ts(void **state)
++{
++    int ret;
++    struct sysdb_ts_test_ctx *test_ctx = talloc_get_type_abort(*state,
++                                                     struct sysdb_ts_test_ctx);
++    struct ldb_result *res = NULL;
++    struct ldb_dn *base_dn;
++    const char *attrs[] = { SYSDB_NAME,
++                            SYSDB_OBJECTCATEGORY,
++                            SYSDB_GIDNUM,
++                            SYSDB_CACHE_EXPIRE,
++                            NULL };
++    struct sysdb_attrs *group_attrs = NULL;
++    char *filter;
++    uint64_t cache_expire_sysdb;
++    uint64_t cache_expire_ts;
++    size_t count;
++    struct ldb_message **msgs;
++
++    base_dn = sysdb_base_dn(test_ctx->tctx->dom->sysdb, test_ctx);
++    assert_non_null(base_dn);
++
++    /* Nothing must be stored in either cache at the beginning of the test */
++    ret = sysdb_search_with_ts_attr(test_ctx,
++                                    test_ctx->tctx->dom,
++                                    base_dn,
++                                    LDB_SCOPE_SUBTREE,
++                                    0,
++                                    SYSDB_NAME"=*",
++                                    attrs,
++                                    &res);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(res->count, 0);
++    talloc_free(res);
++
++    group_attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(group_attrs);
++
++    ret = sysdb_store_group(test_ctx->tctx->dom,
++                            TEST_GROUP_NAME,
++                            TEST_GROUP_GID,
++                            group_attrs,
++                            TEST_CACHE_TIMEOUT,
++                            TEST_NOW_1);
++    assert_int_equal(ret, EOK);
++    talloc_zfree(group_attrs);
++
++    group_attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(group_attrs);
++
++    ret = sysdb_store_group(test_ctx->tctx->dom,
++                            TEST_GROUP_NAME_2,
++                            TEST_GROUP_GID_2,
++                            group_attrs,
++                            TEST_CACHE_TIMEOUT,
++                            TEST_NOW_2);
++    assert_int_equal(ret, EOK);
++    talloc_zfree(group_attrs);
++
++    /* Bump the timestamps in the cache so that the ts cache
++     * and sysdb differ
++     */
++
++    group_attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(group_attrs);
++
++    ret = sysdb_store_group(test_ctx->tctx->dom,
++                            TEST_GROUP_NAME,
++                            TEST_GROUP_GID,
++                            group_attrs,
++                            TEST_CACHE_TIMEOUT,
++                            TEST_NOW_3);
++    assert_int_equal(ret, EOK);
++
++    talloc_zfree(group_attrs);
++
++
++    group_attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1);
++    assert_non_null(group_attrs);
++
++    ret = sysdb_store_group(test_ctx->tctx->dom,
++                            TEST_GROUP_NAME_2,
++                            TEST_GROUP_GID_2,
++                            group_attrs,
++                            TEST_CACHE_TIMEOUT,
++                            TEST_NOW_4);
++    assert_int_equal(ret, EOK);
++
++    talloc_zfree(group_attrs);
++
++    get_gr_timestamp_attrs(test_ctx, TEST_GROUP_NAME,
++                           &cache_expire_sysdb, &cache_expire_ts);
++    assert_int_equal(cache_expire_sysdb, TEST_CACHE_TIMEOUT + TEST_NOW_1);
++    assert_int_equal(cache_expire_ts, TEST_CACHE_TIMEOUT + TEST_NOW_3);
++
++    get_gr_timestamp_attrs(test_ctx, TEST_GROUP_NAME_2,
++                           &cache_expire_sysdb, &cache_expire_ts);
++    assert_int_equal(cache_expire_sysdb, TEST_CACHE_TIMEOUT + TEST_NOW_2);
++    assert_int_equal(cache_expire_ts, TEST_CACHE_TIMEOUT + TEST_NOW_4);
++
++    /* Search for groups that don't expire until TEST_NOW_4 */
++    filter = talloc_asprintf(test_ctx, SYSDB_CACHE_EXPIRE">=%d", TEST_NOW_4);
++    assert_non_null(filter);
++
++    /* This search should yield only one group (so, it needs to search the ts
++     * cache to hit the TEST_NOW_4), but should return attributes merged from
++     * both caches
++     */
++    ret = sysdb_search_with_ts_attr(test_ctx,
++                                    test_ctx->tctx->dom,
++                                    base_dn,
++                                    LDB_SCOPE_SUBTREE,
++                                    0,
++                                    filter,
++                                    attrs,
++                                    &res);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(res->count, 1);
++    assert_int_equal(TEST_GROUP_GID_2, ldb_msg_find_attr_as_uint64(res->msgs[0],
++                                                                   SYSDB_GIDNUM, 0));
++    talloc_free(res);
++
++    /*
++     * In contrast, sysdb_search_entry merges the timestamp attributes, but does
++     * not search the timestamp cache
++     */
++    ret = sysdb_search_entry(test_ctx,
++                             test_ctx->tctx->dom->sysdb,
++                             base_dn,
++                             LDB_SCOPE_SUBTREE,
++                             filter,
++                             attrs,
++                             &count,
++                             &msgs);
++    assert_int_equal(ret, ENOENT);
++
++    /* Should get the same result when searching by ts attrs only */
++    ret = sysdb_search_with_ts_attr(test_ctx,
++                                    test_ctx->tctx->dom,
++                                    base_dn,
++                                    LDB_SCOPE_SUBTREE,
++                                    SYSDB_SEARCH_WITH_TS_ONLY_TS_FILTER,
++                                    filter,
++                                    attrs,
++                                    &res);
++    talloc_zfree(filter);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(res->count, 1);
++    assert_int_equal(TEST_GROUP_GID_2, ldb_msg_find_attr_as_uint64(res->msgs[0],
++                                                                   SYSDB_GIDNUM, 0));
++    talloc_free(res);
++
++    /* We can also search in sysdb only as well, we should get back ts attrs */
++    filter = talloc_asprintf(test_ctx, SYSDB_GIDNUM"=%d", TEST_GROUP_GID);
++    assert_non_null(filter);
++
++    ret = sysdb_search_with_ts_attr(test_ctx,
++                                    test_ctx->tctx->dom,
++                                    base_dn,
++                                    LDB_SCOPE_SUBTREE,
++                                    SYSDB_SEARCH_WITH_TS_ONLY_SYSDB_FILTER,
++                                    filter,
++                                    attrs,
++                                    &res);
++    talloc_zfree(filter);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(res->count, 1);
++    assert_int_equal(TEST_GROUP_GID, ldb_msg_find_attr_as_uint64(res->msgs[0],
++                                                                 SYSDB_GIDNUM, 0));
++    assert_int_equal(TEST_CACHE_TIMEOUT + TEST_NOW_3,
++                     ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_CACHE_EXPIRE, 0));
++    talloc_free(res);
++
++    /* We can also search in both using an OR-filter. Note that an AND-filter is not possible
++     * unless we deconstruct the filter..
++     */
++    filter = talloc_asprintf(test_ctx, "(|("SYSDB_GIDNUM"=%d)"
++                                         "("SYSDB_CACHE_EXPIRE">=%d))",
++                                         TEST_GROUP_GID, TEST_NOW_4);
++    assert_non_null(filter);
++
++    ret = sysdb_search_with_ts_attr(test_ctx,
++                                    test_ctx->tctx->dom,
++                                    base_dn,
++                                    LDB_SCOPE_SUBTREE,
++                                    0,
++                                    filter,
++                                    attrs,
++                                    &res);
++    talloc_zfree(filter);
++    assert_int_equal(ret, EOK);
++    assert_int_equal(res->count, 2);
++    talloc_free(res);
++}
++
+ int main(int argc, const char *argv[])
+ {
+     int rv;
+@@ -1462,6 +1657,9 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(test_sysdb_zero_now,
+                                         test_sysdb_ts_setup,
+                                         test_sysdb_ts_teardown),
++        cmocka_unit_test_setup_teardown(test_sysdb_search_with_ts,
++                                        test_sysdb_ts_setup,
++                                        test_sysdb_ts_teardown),
+     };
+ 
+     /* Set debug level to invalid value so we can decide if -d 0 was used. */
+-- 
+2.20.1
+
diff --git a/SOURCES/0046-BE-search-with-sysdb_search_with_ts_attr.patch b/SOURCES/0046-BE-search-with-sysdb_search_with_ts_attr.patch
new file mode 100644
index 0000000..78e583d
--- /dev/null
+++ b/SOURCES/0046-BE-search-with-sysdb_search_with_ts_attr.patch
@@ -0,0 +1,72 @@
+From 77b4d7a26d92f9aa114d6e8d1073539afeb17fd8 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 28 May 2019 14:56:15 +0200
+Subject: [PATCH 46/64] BE: search with sysdb_search_with_ts_attr
+
+Previously, the background refresh code had used sysdb_search_entry()
+which does not run the search on the timestamp cache. Instead, this
+patch changes to using sysdb_search_with_ts_attr with the
+SYSDB_SEARCH_WITH_TS_ONLY_TS_FILTER optimization because currently only
+the dataExpireTimestamp attribute is included in the filter.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit f27955297603dd7bcbab2569394853d5d9ca90ea)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c | 19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index e8cf5da75..c6bb66b68 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -40,9 +40,8 @@ static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
+     const char *attrs[] = {attr, NULL};
+     const char *filter = NULL;
+     char **values = NULL;
+-    struct ldb_message **msgs = NULL;
+     struct sysdb_attrs **records = NULL;
+-    size_t count;
++    struct ldb_result *res;
+     time_t now = time(NULL);
+     errno_t ret;
+ 
+@@ -58,23 +57,23 @@ static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, base_dn,
+-                             LDB_SCOPE_SUBTREE, filter, attrs,
+-                             &count, &msgs);
+-    if (ret == ENOENT) {
+-        count = 0;
+-    } else if (ret != EOK) {
++    ret = sysdb_search_with_ts_attr(tmp_ctx, domain, base_dn,
++                                    LDB_SCOPE_SUBTREE,
++                                    SYSDB_SEARCH_WITH_TS_ONLY_TS_FILTER,
++                                    filter, attrs,
++                                    &res);
++    if (ret != EOK) {
+         goto done;
+     }
+ 
+-    ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &records);
++    ret = sysdb_msg2attrs(tmp_ctx, res->count, res->msgs, &records);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Could not convert ldb message to sysdb_attrs\n");
+         goto done;
+     }
+ 
+-    ret = sysdb_attrs_to_list(tmp_ctx, records, count, attr, &values);
++    ret = sysdb_attrs_to_list(tmp_ctx, records, res->count, attr, &values);
+     if (ret != EOK) {
+         goto done;
+     }
+-- 
+2.20.1
+
diff --git a/SOURCES/0047-BE-Enable-refresh-for-multiple-domains.patch b/SOURCES/0047-BE-Enable-refresh-for-multiple-domains.patch
new file mode 100644
index 0000000..d23105a
--- /dev/null
+++ b/SOURCES/0047-BE-Enable-refresh-for-multiple-domains.patch
@@ -0,0 +1,37 @@
+From 896cc774f959b1b6ee1f0c409fa837ad64ee52d4 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 24 Apr 2019 21:09:53 +0200
+Subject: [PATCH 47/64] BE: Enable refresh for multiple domains
+
+Descend into subdomains on back end refresh and make sure to start from
+users again.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 1a08b53defa7f921a9b0f9e839ca90f91b5f86d2)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index c6bb66b68..02e478c95 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -255,7 +255,9 @@ static errno_t be_refresh_step(struct tevent_req *req)
+ 
+         /* if not found than continue with next domain */
+         if (state->index == BE_REFRESH_TYPE_SENTINEL) {
+-            state->domain = get_next_domain(state->domain, 0);
++            state->domain = get_next_domain(state->domain,
++                                            SSS_GND_DESCEND);
++            state->index = 0;
+             continue;
+         }
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0048-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch b/SOURCES/0048-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch
new file mode 100644
index 0000000..79ea4b8
--- /dev/null
+++ b/SOURCES/0048-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch
@@ -0,0 +1,114 @@
+From 739910de98cfc6c1c8764855703a6a8315bb09c6 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 May 2019 22:32:13 +0200
+Subject: [PATCH 48/64] BE: Make be_refresh_ctx_init set up the periodical
+ task, too
+
+This is mostly a preparatory patch that rolls in setting up the ptask
+into be_refresh_ctx_init. Since in later patches we will call
+be_refresh_ctx_init from several different places, this will prevent
+code duplication.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit bb0bd61ac54dca429b6562e808755152d4c90ce7)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c       | 21 +++++++++++++++++++--
+ src/providers/be_refresh.h       |  2 +-
+ src/providers/data_provider_be.c | 14 --------------
+ 3 files changed, 20 insertions(+), 17 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 02e478c95..c7b048a95 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -134,11 +134,13 @@ struct be_refresh_ctx {
+     struct be_refresh_cb callbacks[BE_REFRESH_TYPE_SENTINEL];
+ };
+ 
+-struct be_refresh_ctx *be_refresh_ctx_init(TALLOC_CTX *mem_ctx)
++struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx)
+ {
+     struct be_refresh_ctx *ctx = NULL;
++    uint32_t refresh_interval;
++    errno_t ret;
+ 
+-    ctx = talloc_zero(mem_ctx, struct be_refresh_ctx);
++    ctx = talloc_zero(be_ctx, struct be_refresh_ctx);
+     if (ctx == NULL) {
+         return NULL;
+     }
+@@ -147,6 +149,21 @@ struct be_refresh_ctx *be_refresh_ctx_init(TALLOC_CTX *mem_ctx)
+     ctx->callbacks[BE_REFRESH_TYPE_GROUPS].name = "groups";
+     ctx->callbacks[BE_REFRESH_TYPE_NETGROUPS].name = "netgroups";
+ 
++    refresh_interval = be_ctx->domain->refresh_expired_interval;
++    if (refresh_interval > 0) {
++        ret = be_ptask_create(be_ctx, be_ctx, refresh_interval, 30, 5, 0,
++                              refresh_interval, BE_PTASK_OFFLINE_SKIP, 0,
++                              be_refresh_send, be_refresh_recv,
++                              be_ctx->refresh_ctx, "Refresh Records", NULL);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_FATAL_FAILURE,
++                  "Unable to initialize refresh periodic task [%d]: %s\n",
++                  ret, sss_strerror(ret));
++            talloc_free(ctx);
++            return NULL;
++        }
++    }
++
+     return ctx;
+ }
+ 
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index 927fa4a33..664f01816 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -52,7 +52,7 @@ enum be_refresh_type {
+ 
+ struct be_refresh_ctx;
+ 
+-struct be_refresh_ctx *be_refresh_ctx_init(TALLOC_CTX *mem_ctx);
++struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx);
+ 
+ errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+                           enum be_refresh_type type,
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 17513111c..8dbddbb5f 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -431,7 +431,6 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+                         struct confdb_ctx *cdb)
+ {
+-    uint32_t refresh_interval;
+     struct tevent_signal *tes;
+     struct be_ctx *be_ctx;
+     char *str = NULL;
+@@ -531,19 +530,6 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    refresh_interval = be_ctx->domain->refresh_expired_interval;
+-    if (refresh_interval > 0) {
+-        ret = be_ptask_create(be_ctx, be_ctx, refresh_interval, 30, 5, 0,
+-                              refresh_interval, BE_PTASK_OFFLINE_SKIP, 0,
+-                              be_refresh_send, be_refresh_recv,
+-                              be_ctx->refresh_ctx, "Refresh Records", NULL);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Unable to initialize refresh periodic task\n");
+-            goto done;
+-        }
+-    }
+-
+     ret = dp_init(be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup data provider "
+-- 
+2.20.1
+
diff --git a/SOURCES/0049-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch b/SOURCES/0049-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch
new file mode 100644
index 0000000..d11eeb2
--- /dev/null
+++ b/SOURCES/0049-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch
@@ -0,0 +1,146 @@
+From 106d93c6e03bfdf1bfc4f2691562b4855a1d4763 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 May 2019 22:42:47 +0200
+Subject: [PATCH 49/64] BE/LDAP: Call be_refresh_ctx_init() in the provider
+ libraries, not in back end
+
+Since later patches will pass different parameters to
+be_refresh_ctx_init(), let's call the init function in the provider
+libraries not directly in the back end.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 9d49c90ceb7388333c8682f4cbd6842ec236b9de)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_init.c        |  2 +-
+ src/providers/data_provider_be.c  |  8 --------
+ src/providers/ipa/ipa_init.c      |  2 +-
+ src/providers/ldap/ldap_common.h  |  2 +-
+ src/providers/ldap/ldap_init.c    |  2 +-
+ src/providers/ldap/sdap_refresh.c | 17 +++++++++++++----
+ 6 files changed, 17 insertions(+), 16 deletions(-)
+
+diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
+index 302bcae7d..42c2f150a 100644
+--- a/src/providers/ad/ad_init.c
++++ b/src/providers/ad/ad_init.c
+@@ -408,7 +408,7 @@ static errno_t ad_init_misc(struct be_ctx *be_ctx,
+         return ret;
+     }
+ 
+-    ret = sdap_refresh_init(be_ctx->refresh_ctx, sdap_id_ctx);
++    ret = sdap_refresh_init(be_ctx, sdap_id_ctx);
+     if (ret != EOK && ret != EEXIST) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
+               "will not work [%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 8dbddbb5f..d13654b8b 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -522,14 +522,6 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    /* Initialize be_refresh periodic task. */
+-    be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx);
+-    if (be_ctx->refresh_ctx == NULL) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+     ret = dp_init(be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup data provider "
+diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
+index 6818e2171..b3060e228 100644
+--- a/src/providers/ipa/ipa_init.c
++++ b/src/providers/ipa/ipa_init.c
+@@ -594,7 +594,7 @@ static errno_t ipa_init_misc(struct be_ctx *be_ctx,
+         }
+     }
+ 
+-    ret = sdap_refresh_init(be_ctx->refresh_ctx, sdap_id_ctx);
++    ret = sdap_refresh_init(be_ctx, sdap_id_ctx);
+     if (ret != EOK && ret != EEXIST) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
+               "will not work [%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index 04548a388..f30b67eb3 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -362,7 +362,7 @@ struct sdap_id_ctx *
+ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+                 struct sdap_service *sdap_service);
+ 
+-errno_t sdap_refresh_init(struct be_refresh_ctx *refresh_ctx,
++errno_t sdap_refresh_init(struct be_ctx *be_ctx,
+                           struct sdap_id_ctx *id_ctx);
+ 
+ errno_t sdap_init_certmap(TALLOC_CTX *mem_ctx, struct sdap_id_ctx *id_ctx);
+diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
+index 352f0b656..489e1c225 100644
+--- a/src/providers/ldap/ldap_init.c
++++ b/src/providers/ldap/ldap_init.c
+@@ -432,7 +432,7 @@ static errno_t ldap_init_misc(struct be_ctx *be_ctx,
+     }
+ 
+     /* Setup periodical refresh of expired records */
+-    ret = sdap_refresh_init(be_ctx->refresh_ctx, id_ctx);
++    ret = sdap_refresh_init(be_ctx, id_ctx);
+     if (ret != EOK && ret != EEXIST) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh will not work "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index 6d6c43e20..457df8be2 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -255,12 +255,19 @@ static errno_t sdap_refresh_netgroups_recv(struct tevent_req *req)
+     return sdap_refresh_recv(req);
+ }
+ 
+-errno_t sdap_refresh_init(struct be_refresh_ctx *refresh_ctx,
++errno_t sdap_refresh_init(struct be_ctx *be_ctx,
+                           struct sdap_id_ctx *id_ctx)
+ {
+     errno_t ret;
+ 
+-    ret = be_refresh_add_cb(refresh_ctx, BE_REFRESH_TYPE_USERS,
++    be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx);
++    if (be_ctx->refresh_ctx == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
++        return ENOMEM;
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
+                             sdap_refresh_users_send,
+                             sdap_refresh_users_recv,
+                             id_ctx);
+@@ -269,7 +276,8 @@ errno_t sdap_refresh_init(struct be_refresh_ctx *refresh_ctx,
+               "will not work [%d]: %s\n", ret, strerror(ret));
+     }
+ 
+-    ret = be_refresh_add_cb(refresh_ctx, BE_REFRESH_TYPE_GROUPS,
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
+                             sdap_refresh_groups_send,
+                             sdap_refresh_groups_recv,
+                             id_ctx);
+@@ -278,7 +286,8 @@ errno_t sdap_refresh_init(struct be_refresh_ctx *refresh_ctx,
+               "will not work [%d]: %s\n", ret, strerror(ret));
+     }
+ 
+-    ret = be_refresh_add_cb(refresh_ctx, BE_REFRESH_TYPE_NETGROUPS,
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
+                             sdap_refresh_netgroups_send,
+                             sdap_refresh_netgroups_recv,
+                             id_ctx);
+-- 
+2.20.1
+
diff --git a/SOURCES/0050-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch b/SOURCES/0050-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch
new file mode 100644
index 0000000..60dc44a
--- /dev/null
+++ b/SOURCES/0050-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch
@@ -0,0 +1,111 @@
+From f035dee4d63ebe96a8435778e4c8ce413e8c025b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 May 2019 12:09:24 +0200
+Subject: [PATCH 50/64] BE: Pass in attribute to look up with instead of
+ hardcoding SYSDB_NAME
+
+In later patches, we will implement refreshes for AD or IPA which might
+refresh objects that do not have a name yet, but always do have a different
+attribute, like a SID or a uniqueID. In this case, it's better to use that
+different attribute instead of name.
+
+This patch allows the caller to tell the refresh module which attribute
+to use.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit d1eb0a70de3c98ca9dc03a0b79287f4ce6ee4855)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c        | 12 ++++++++----
+ src/providers/be_refresh.h        |  3 ++-
+ src/providers/ldap/sdap_refresh.c |  2 +-
+ 3 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index c7b048a95..66cc4cf98 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -89,6 +89,7 @@ done:
+ 
+ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
+                                      enum be_refresh_type type,
++                                     const char *attr_name,
+                                      struct sss_domain_info *domain,
+                                      time_t period,
+                                      char ***_values)
+@@ -116,7 +117,7 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
+     }
+ 
+     ret = be_refresh_get_values_ex(mem_ctx, domain, period,
+-                                   base_dn, SYSDB_NAME, _values);
++                                   base_dn, attr_name, _values);
+ 
+     talloc_free(base_dn);
+     return ret;
+@@ -131,10 +132,12 @@ struct be_refresh_cb {
+ };
+ 
+ struct be_refresh_ctx {
++    const char *attr_name;
+     struct be_refresh_cb callbacks[BE_REFRESH_TYPE_SENTINEL];
+ };
+ 
+-struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx)
++struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx,
++                                           const char *attr_name)
+ {
+     struct be_refresh_ctx *ctx = NULL;
+     uint32_t refresh_interval;
+@@ -145,6 +148,7 @@ struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx)
+         return NULL;
+     }
+ 
++    ctx->attr_name = attr_name;
+     ctx->callbacks[BE_REFRESH_TYPE_USERS].name = "users";
+     ctx->callbacks[BE_REFRESH_TYPE_GROUPS].name = "groups";
+     ctx->callbacks[BE_REFRESH_TYPE_NETGROUPS].name = "netgroups";
+@@ -284,8 +288,8 @@ static errno_t be_refresh_step(struct tevent_req *req)
+             goto done;
+         }
+ 
+-        ret = be_refresh_get_values(state, state->index, state->domain,
+-                                    state->period, &values);
++        ret = be_refresh_get_values(state, state->index, state->ctx->attr_name,
++                                    state->domain, state->period, &values);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain DN list [%d]: %s\n",
+                                         ret, sss_strerror(ret));
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index 664f01816..8c7b1d0ba 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -52,7 +52,8 @@ enum be_refresh_type {
+ 
+ struct be_refresh_ctx;
+ 
+-struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx);
++struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx,
++                                           const char *attr_name);
+ 
+ errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+                           enum be_refresh_type type,
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index 457df8be2..ed04da36a 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -260,7 +260,7 @@ errno_t sdap_refresh_init(struct be_ctx *be_ctx,
+ {
+     errno_t ret;
+ 
+-    be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx);
++    be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx, SYSDB_NAME);
+     if (be_ctx->refresh_ctx == NULL) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
+         return ENOMEM;
+-- 
+2.20.1
+
diff --git a/SOURCES/0051-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch b/SOURCES/0051-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch
new file mode 100644
index 0000000..079b737
--- /dev/null
+++ b/SOURCES/0051-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch
@@ -0,0 +1,102 @@
+From d5808eab7a3ab48318d26ae633c8650bab761c84 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 May 2019 12:07:34 +0200
+Subject: [PATCH 51/64] BE: Change be_refresh_ctx_init to return errno and set
+ be_ctx->refresh_ctx
+
+It is a bit odd that a caller to a be_ function would set a property of
+be_ctx. IMO it is cleaner if the function has a side-effect and sets the
+property internally and rather returns errno.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 41305ef5a0ef2f4796e322190ffcc12331151643)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c        | 13 +++++++------
+ src/providers/be_refresh.h        |  4 ++--
+ src/providers/ldap/sdap_refresh.c |  4 ++--
+ 3 files changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 66cc4cf98..8a6e1ba58 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -136,8 +136,8 @@ struct be_refresh_ctx {
+     struct be_refresh_cb callbacks[BE_REFRESH_TYPE_SENTINEL];
+ };
+ 
+-struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx,
+-                                           const char *attr_name)
++errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
++                            const char *attr_name)
+ {
+     struct be_refresh_ctx *ctx = NULL;
+     uint32_t refresh_interval;
+@@ -145,7 +145,7 @@ struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx,
+ 
+     ctx = talloc_zero(be_ctx, struct be_refresh_ctx);
+     if (ctx == NULL) {
+-        return NULL;
++        return ENOMEM;
+     }
+ 
+     ctx->attr_name = attr_name;
+@@ -158,17 +158,18 @@ struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx,
+         ret = be_ptask_create(be_ctx, be_ctx, refresh_interval, 30, 5, 0,
+                               refresh_interval, BE_PTASK_OFFLINE_SKIP, 0,
+                               be_refresh_send, be_refresh_recv,
+-                              be_ctx->refresh_ctx, "Refresh Records", NULL);
++                              ctx, "Refresh Records", NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+                   "Unable to initialize refresh periodic task [%d]: %s\n",
+                   ret, sss_strerror(ret));
+             talloc_free(ctx);
+-            return NULL;
++            return ret;
+         }
+     }
+ 
+-    return ctx;
++    be_ctx->refresh_ctx = ctx;
++    return EOK;
+ }
+ 
+ errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index 8c7b1d0ba..980ac7d06 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -52,8 +52,8 @@ enum be_refresh_type {
+ 
+ struct be_refresh_ctx;
+ 
+-struct be_refresh_ctx *be_refresh_ctx_init(struct be_ctx *be_ctx,
+-                                           const char *attr_name);
++errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
++                            const char *attr_name);
+ 
+ errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+                           enum be_refresh_type type,
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index ed04da36a..baa7fa59f 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -260,8 +260,8 @@ errno_t sdap_refresh_init(struct be_ctx *be_ctx,
+ {
+     errno_t ret;
+ 
+-    be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx, SYSDB_NAME);
+-    if (be_ctx->refresh_ctx == NULL) {
++    ret = be_refresh_ctx_init(be_ctx, SYSDB_NAME);
++    if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
+         return ENOMEM;
+     }
+-- 
+2.20.1
+
diff --git a/SOURCES/0052-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch b/SOURCES/0052-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch
new file mode 100644
index 0000000..3258df8
--- /dev/null
+++ b/SOURCES/0052-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch
@@ -0,0 +1,134 @@
+From 080b154402ad076a562e0ea6d6e8c5d2fbcef5f5 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 8 May 2019 14:38:44 +0200
+Subject: [PATCH 52/64] BE/LDAP: Split out a helper function from sdap_refresh
+ for later reuse
+
+Every refresh request will send a similar account_req. Let's split out
+the function that creates the account_req into a reusable one.
+
+Also removes the type string as it was only used in DEBUG messages and
+there is already a function in the back end API that provides the same
+functionality.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit ac72bb4ab1a8d3d13f0d459efe5f23cf010c2790)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c        | 18 ++++++++++++++++++
+ src/providers/be_refresh.h        |  4 ++++
+ src/providers/ldap/sdap_refresh.c | 29 +++++------------------------
+ 3 files changed, 27 insertions(+), 24 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 8a6e1ba58..c49229e71 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -362,3 +362,21 @@ errno_t be_refresh_recv(struct tevent_req *req)
+ 
+     return EOK;
+ }
++
++struct dp_id_data *be_refresh_acct_req(TALLOC_CTX *mem_ctx,
++                                       uint32_t entry_type,
++                                       struct sss_domain_info *domain)
++{
++    struct dp_id_data *account_req;
++
++    account_req = talloc_zero(mem_ctx, struct dp_id_data);
++    if (account_req == NULL) {
++        return NULL;
++    }
++
++    account_req->entry_type = entry_type;
++    account_req->filter_type = BE_FILTER_NAME;
++    account_req->extra_value = NULL;
++    account_req->domain = domain->name;
++    return account_req;
++}
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index 980ac7d06..b7ba5d4c2 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -69,4 +69,8 @@ struct tevent_req *be_refresh_send(TALLOC_CTX *mem_ctx,
+ 
+ errno_t be_refresh_recv(struct tevent_req *req);
+ 
++struct dp_id_data *be_refresh_acct_req(TALLOC_CTX *mem_ctx,
++                                       uint32_t entry_type,
++                                       struct sss_domain_info *domain);
++
+ #endif /* _DP_REFRESH_H_ */
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index baa7fa59f..af39d8686 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -30,7 +30,6 @@ struct sdap_refresh_state {
+     struct dp_id_data *account_req;
+     struct sdap_id_ctx *id_ctx;
+     struct sdap_domain *sdom;
+-    const char *type;
+     char **names;
+     size_t index;
+ };
+@@ -74,32 +73,12 @@ static struct tevent_req *sdap_refresh_send(TALLOC_CTX *mem_ctx,
+         goto immediately;
+     }
+ 
+-    switch (entry_type) {
+-    case BE_REQ_USER:
+-        state->type = "user";
+-        break;
+-    case BE_REQ_GROUP:
+-        state->type = "group";
+-        break;
+-    case BE_REQ_NETGROUP:
+-        state->type = "netgroup";
+-        break;
+-    default:
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid entry type [%d]!\n", entry_type);
+-    }
+-
+-    state->account_req = talloc_zero(state, struct dp_id_data);
++    state->account_req = be_refresh_acct_req(state, entry_type, domain);
+     if (state->account_req == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+     }
+ 
+-    state->account_req->entry_type = entry_type;
+-    state->account_req->filter_type = BE_FILTER_NAME;
+-    state->account_req->extra_value = NULL;
+-    state->account_req->domain = domain->name;
+-    /* filter will be filled later */
+-
+     ret = sdap_refresh_step(req);
+     if (ret == EOK) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Nothing to refresh\n");
+@@ -143,7 +122,8 @@ static errno_t sdap_refresh_step(struct tevent_req *req)
+     }
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "Issuing refresh of %s %s\n",
+-          state->type, state->account_req->filter_value);
++          be_req2str(state->account_req->entry_type),
++          state->account_req->filter_value);
+ 
+     subreq = sdap_handle_acct_req_send(state, state->be_ctx,
+                                        state->account_req, state->id_ctx,
+@@ -178,7 +158,8 @@ static void sdap_refresh_done(struct tevent_req *subreq)
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to refresh %s [dp_error: %d, "
+-              "sdap_ret: %d, errno: %d]: %s\n", state->type,
++              "sdap_ret: %d, errno: %d]: %s\n",
++               be_req2str(state->account_req->entry_type),
+               dp_error, sdap_ret, ret, err_msg);
+         goto done;
+     }
+-- 
+2.20.1
+
diff --git a/SOURCES/0053-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch b/SOURCES/0053-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch
new file mode 100644
index 0000000..7bb8449
--- /dev/null
+++ b/SOURCES/0053-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch
@@ -0,0 +1,73 @@
+From 219028cb3f2059e6d1c0cb28f491fb30909d967c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 May 2019 12:07:59 +0200
+Subject: [PATCH 53/64] BE: Pass in filter_type when creating the refresh
+ account request
+
+For refreshing AD users and groups, we'll want to create a request by
+SID, for all other requests we'll want to create a request by name. This
+patch allows parametrizing the request creation by the caller.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 2cb294e6d5782aa725a2e9d7892a9e0c62e0b3a9)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c        | 3 ++-
+ src/providers/be_refresh.h        | 1 +
+ src/providers/ldap/sdap_refresh.c | 3 ++-
+ 3 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index c49229e71..c4ff71e1f 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -365,6 +365,7 @@ errno_t be_refresh_recv(struct tevent_req *req)
+ 
+ struct dp_id_data *be_refresh_acct_req(TALLOC_CTX *mem_ctx,
+                                        uint32_t entry_type,
++                                       uint32_t filter_type,
+                                        struct sss_domain_info *domain)
+ {
+     struct dp_id_data *account_req;
+@@ -375,7 +376,7 @@ struct dp_id_data *be_refresh_acct_req(TALLOC_CTX *mem_ctx,
+     }
+ 
+     account_req->entry_type = entry_type;
+-    account_req->filter_type = BE_FILTER_NAME;
++    account_req->filter_type = filter_type;
+     account_req->extra_value = NULL;
+     account_req->domain = domain->name;
+     return account_req;
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index b7ba5d4c2..c7b4872df 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -71,6 +71,7 @@ errno_t be_refresh_recv(struct tevent_req *req);
+ 
+ struct dp_id_data *be_refresh_acct_req(TALLOC_CTX *mem_ctx,
+                                        uint32_t entry_type,
++                                       uint32_t filter_type,
+                                        struct sss_domain_info *domain);
+ 
+ #endif /* _DP_REFRESH_H_ */
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index af39d8686..2206d6670 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -73,7 +73,8 @@ static struct tevent_req *sdap_refresh_send(TALLOC_CTX *mem_ctx,
+         goto immediately;
+     }
+ 
+-    state->account_req = be_refresh_acct_req(state, entry_type, domain);
++    state->account_req = be_refresh_acct_req(state, entry_type,
++                                             BE_FILTER_NAME, domain);
+     if (state->account_req == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+-- 
+2.20.1
+
diff --git a/SOURCES/0054-BE-Send-refresh-requests-in-batches.patch b/SOURCES/0054-BE-Send-refresh-requests-in-batches.patch
new file mode 100644
index 0000000..bf44794
--- /dev/null
+++ b/SOURCES/0054-BE-Send-refresh-requests-in-batches.patch
@@ -0,0 +1,300 @@
+From 84268efb9de2befd87b5e251bf2c99eb583923b6 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 8 May 2019 23:16:07 +0200
+Subject: [PATCH 54/64] BE: Send refresh requests in batches
+
+As we extend the background refresh into larger domains, the amount of
+data that SSSD refreshes on the background might be larger. And
+refreshing all expired entries in a single request might block sssd_be
+for a long time, either triggering the watchdog or starving other
+legitimate requests.
+
+Therefore the background refresh will be done in batches of 200 entries.
+The first batch of every type (up to 200 users, up to 200 groups, ...)
+will be scheduled imediatelly and subsequent batches with a 0.5 second
+delay.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 7443498cc074c323e3b307f47ed49d59a5001f64)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c            | 131 ++++++++++++++++++++++----
+ src/tests/cmocka/test_expire_common.c |   6 +-
+ src/tests/sss_idmap-tests.c           |   8 +-
+ src/util/util.h                       |   8 ++
+ 4 files changed, 128 insertions(+), 25 deletions(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index c4ff71e1f..5d86509bb 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -204,8 +204,21 @@ struct be_refresh_state {
+     struct sss_domain_info *domain;
+     enum be_refresh_type index;
+     time_t period;
++
++    char **refresh_values;
++    size_t refresh_val_size;
++    size_t refresh_index;
++
++    size_t batch_size;
++    char **refresh_batch;
+ };
+ 
++static errno_t be_refresh_batch_step(struct tevent_req *req,
++                                     uint32_t msec_delay);
++static void be_refresh_batch_step_wakeup(struct tevent_context *ev,
++                                         struct tevent_timer *tt,
++                                         struct timeval tv,
++                                         void *pvt);
+ static errno_t be_refresh_step(struct tevent_req *req);
+ static void be_refresh_done(struct tevent_req *subreq);
+ 
+@@ -236,6 +249,13 @@ struct tevent_req *be_refresh_send(TALLOC_CTX *mem_ctx,
+         goto immediately;
+     }
+ 
++    state->batch_size = 200;
++    state->refresh_batch = talloc_zero_array(state, char *, state->batch_size+1);
++    if (state->refresh_batch == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++
+     ret = be_refresh_step(req);
+     if (ret == EOK) {
+         goto immediately;
+@@ -261,8 +281,6 @@ immediately:
+ static errno_t be_refresh_step(struct tevent_req *req)
+ {
+     struct be_refresh_state *state = NULL;
+-    struct tevent_req *subreq = NULL;
+-    char **values = NULL;
+     errno_t ret;
+ 
+     state = tevent_req_data(req, struct be_refresh_state);
+@@ -289,42 +307,103 @@ static errno_t be_refresh_step(struct tevent_req *req)
+             goto done;
+         }
+ 
++        talloc_zfree(state->refresh_values);
+         ret = be_refresh_get_values(state, state->index, state->ctx->attr_name,
+-                                    state->domain, state->period, &values);
++                                    state->domain, state->period,
++                                    &state->refresh_values);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain DN list [%d]: %s\n",
+                                         ret, sss_strerror(ret));
+             goto done;
+         }
+ 
+-        DEBUG(SSSDBG_TRACE_FUNC, "Refreshing %s in domain %s\n",
+-              state->cb->name, state->domain->name);
++        for (state->refresh_val_size = 0;
++             state->refresh_values[state->refresh_val_size] != NULL;
++             state->refresh_val_size++);
++
++        DEBUG(SSSDBG_TRACE_FUNC, "Refreshing %zu %s in domain %s\n",
++              state->refresh_val_size, state->cb->name, state->domain->name);
+ 
+-        subreq = state->cb->send_fn(state, state->ev, state->be_ctx,
+-                                    state->domain, values, state->cb->pvt);
+-        if (subreq == NULL) {
+-            ret = ENOMEM;
++        ret = be_refresh_batch_step(req, 0);
++        if (ret == EOK) {
++            state->index++;
++            continue;
++        } else if (ret != EAGAIN) {
+             goto done;
+         }
+-
+-        /* make the list disappear with subreq */
+-        talloc_steal(subreq, values);
+-
+-        tevent_req_set_callback(subreq, be_refresh_done, req);
++        /* EAGAIN only, refreshing something.. */
+ 
+         state->index++;
+-        ret = EAGAIN;
+         goto done;
+     }
+ 
+     ret = EOK;
+ 
+ done:
+-    if (ret != EOK && ret != EAGAIN) {
+-        talloc_free(values);
++    return ret;
++}
++
++static errno_t be_refresh_batch_step(struct tevent_req *req,
++                                     uint32_t msec_delay)
++{
++    struct be_refresh_state *state = tevent_req_data(req, struct be_refresh_state);
++    struct timeval tv;
++    struct tevent_timer *timeout = NULL;
++
++    size_t remaining;
++    size_t batch_size;
++
++    memset(state->refresh_batch, 0, sizeof(char *) * state->batch_size);
++
++    if (state->refresh_index >= state->refresh_val_size) {
++        DEBUG(SSSDBG_FUNC_DATA, "The batch is done\n");
++        state->refresh_index = 0;
++        return EOK;
+     }
+ 
+-    return ret;
++    remaining = state->refresh_val_size - state->refresh_index;
++    batch_size = MIN(remaining, state->batch_size);
++    DEBUG(SSSDBG_FUNC_DATA,
++          "This batch will refresh %zu entries (so far %zu/%zu)\n",
++          batch_size, state->refresh_index, state->refresh_val_size);
++
++    for (size_t i = 0; i < batch_size; i++) {
++        state->refresh_batch[i] = state->refresh_values[state->refresh_index];
++        state->refresh_index++;
++    }
++
++    tv = tevent_timeval_current_ofs(0, msec_delay * 1000);
++    timeout = tevent_add_timer(state->be_ctx->ev, req, tv,
++                               be_refresh_batch_step_wakeup, req);
++    if (timeout == NULL) {
++        return ENOMEM;
++    }
++
++    return EAGAIN;
++}
++
++static void be_refresh_batch_step_wakeup(struct tevent_context *ev,
++                                         struct tevent_timer *tt,
++                                         struct timeval tv,
++                                         void *pvt)
++{
++    struct tevent_req *req;
++    struct tevent_req *subreq = NULL;
++    struct be_refresh_state *state = NULL;
++
++    req = talloc_get_type(pvt, struct tevent_req);
++    state = tevent_req_data(req, struct be_refresh_state);
++
++    DEBUG(SSSDBG_TRACE_INTERNAL, "Issuing refresh\n");
++    subreq = state->cb->send_fn(state, state->ev, state->be_ctx,
++                                state->domain,
++                                state->refresh_batch,
++                                state->cb->pvt);
++    if (subreq == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    tevent_req_set_callback(subreq, be_refresh_done, req);
+ }
+ 
+ static void be_refresh_done(struct tevent_req *subreq)
+@@ -342,8 +421,24 @@ static void be_refresh_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
++    ret = be_refresh_batch_step(req, 500);
++    if (ret == EAGAIN) {
++        DEBUG(SSSDBG_TRACE_INTERNAL,
++              "Another batch in this step in progress\n");
++        return;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "be_refresh_batch_step failed [%d]: %s\n",
++              ret, sss_strerror(ret));
++        goto done;
++    }
++
++    DEBUG(SSSDBG_TRACE_INTERNAL, "All batches in this step refreshed\n");
++
++    /* Proceed to the next step */
+     ret = be_refresh_step(req);
+     if (ret == EAGAIN) {
++        DEBUG(SSSDBG_TRACE_INTERNAL, "Another step in progress\n");
+         return;
+     }
+ 
+diff --git a/src/tests/cmocka/test_expire_common.c b/src/tests/cmocka/test_expire_common.c
+index 5d3ea02f3..4f6168190 100644
+--- a/src/tests/cmocka/test_expire_common.c
++++ b/src/tests/cmocka/test_expire_common.c
+@@ -32,7 +32,7 @@
+ #include "tests/common_check.h"
+ #include "tests/cmocka/test_expire_common.h"
+ 
+-#define MAX 100
++#define MAX_VAL 100
+ 
+ static char *now_str(TALLOC_CTX *mem_ctx, const char* format, int s)
+ {
+@@ -41,10 +41,10 @@ static char *now_str(TALLOC_CTX *mem_ctx, const char* format, int s)
+     size_t len;
+     char *timestr;
+ 
+-    timestr = talloc_array(mem_ctx, char, MAX);
++    timestr = talloc_array(mem_ctx, char, MAX_VAL);
+ 
+     tm = gmtime(&t);
+-    len = strftime(timestr, MAX, format, tm);
++    len = strftime(timestr, MAX_VAL, format, tm);
+     if (len == 0) {
+         return NULL;
+     }
+diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c
+index 885913645..ef6843403 100644
+--- a/src/tests/sss_idmap-tests.c
++++ b/src/tests/sss_idmap-tests.c
+@@ -140,8 +140,8 @@ void idmap_add_domain_with_sec_slices_setup_cb_fail(void)
+ }
+ 
+ 
+-#define MAX 1000
+-char data[MAX];
++#define DATA_MAX 1000
++char data[DATA_MAX];
+ 
+ enum idmap_error_code cb2(const char *dom_name,
+                           const char *dom_sid,
+@@ -154,10 +154,10 @@ enum idmap_error_code cb2(const char *dom_name,
+     char *p = (char*)pvt;
+     size_t len;
+ 
+-    len = snprintf(p, MAX, "%s, %s %s, %"PRIu32", %"PRIu32", %" PRIu32,
++    len = snprintf(p, DATA_MAX, "%s, %s %s, %"PRIu32", %"PRIu32", %" PRIu32,
+                    dom_name, dom_sid, range_id, min_id, max_id, first_rid);
+ 
+-    if (len >= MAX) {
++    if (len >= DATA_MAX) {
+         return IDMAP_OUT_OF_MEMORY;
+     }
+     return IDMAP_SUCCESS;
+diff --git a/src/util/util.h b/src/util/util.h
+index 3003583b7..fce7e42c3 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -68,6 +68,14 @@
+ 
+ #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+ 
++#ifndef MIN
++#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
++#endif
++
++#ifndef MAX
++#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
++#endif
++
+ #define SSSD_MAIN_OPTS SSSD_DEBUG_OPTS
+ 
+ #define SSSD_SERVER_OPTS(uid, gid) \
+-- 
+2.20.1
+
diff --git a/SOURCES/0055-BE-Extend-be_ptask_create-with-control-when-to-sched.patch b/SOURCES/0055-BE-Extend-be_ptask_create-with-control-when-to-sched.patch
new file mode 100644
index 0000000..3ce5ee4
--- /dev/null
+++ b/SOURCES/0055-BE-Extend-be_ptask_create-with-control-when-to-sched.patch
@@ -0,0 +1,465 @@
+From 70d477efb1a43b3e1750b4aca868dadc2ed435d5 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 18 Jun 2019 20:49:00 +0200
+Subject: [PATCH 55/64] BE: Extend be_ptask_create() with control when to
+ schedule next run after success
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+be_ptask_create() used to always schedule the next periodical run
+"period" seconds after the previous run started. This is great for tasks
+that are short-lived like DNS updates because we know they will be
+executed really with the configured period.
+
+But the background refresh task can potentially take a very long time in
+which case the next run could have been scheduled almost immediately and
+as a result sssd_be would always be quite busy. It is better to have the
+option to schedule the next task period seconds after the last run has
+finished. This can lead to some inconsistency, but we can warn the
+admin about that.
+
+This patch so far does not change any of the existing calls to
+be_ptask_create(), just adds BE_PTASK_SCHEDULE_FROM_LAST as an
+additional parameter.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 0fbc317ac7f1fe13cd41364c67db7d7a19d7d546)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_machine_pw_renewal.c |  4 +-
+ src/providers/ad/ad_subdomains.c         |  4 +-
+ src/providers/be_ptask.c                 | 10 ++--
+ src/providers/be_ptask.h                 | 24 ++++++++-
+ src/providers/be_ptask_private.h         |  1 +
+ src/providers/be_refresh.c               |  4 +-
+ src/providers/ipa/ipa_subdomains.c       |  4 +-
+ src/providers/ldap/ldap_id_enum.c        |  1 +
+ src/providers/ldap/sdap_sudo_shared.c    |  8 ++-
+ src/tests/cmocka/test_be_ptask.c         | 62 ++++++++++++++++--------
+ 10 files changed, 89 insertions(+), 33 deletions(-)
+
+diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c
+index 5b6ba26b7..47941dfbf 100644
+--- a/src/providers/ad/ad_machine_pw_renewal.c
++++ b/src/providers/ad/ad_machine_pw_renewal.c
+@@ -382,7 +382,9 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
+     }
+ 
+     ret = be_ptask_create(be_ctx, be_ctx, period, initial_delay, 0, 0, 60,
+-                          BE_PTASK_OFFLINE_DISABLE, 0,
++                          BE_PTASK_OFFLINE_DISABLE,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          0,
+                           ad_machine_account_password_renewal_send,
+                           ad_machine_account_password_renewal_recv,
+                           renewal_data,
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index e3e3d3ece..45a8fe0fc 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -2111,7 +2111,9 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+ 
+     period = be_ctx->domain->subdomain_refresh_interval;
+     ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period,
+-                          BE_PTASK_OFFLINE_DISABLE, 0,
++                          BE_PTASK_OFFLINE_DISABLE,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          0,
+                           ad_subdomains_ptask_send, ad_subdomains_ptask_recv, sd_ctx,
+                           "Subdomains Refresh", NULL);
+     if (ret != EOK) {
+diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c
+index c43351755..32d9a03ce 100644
+--- a/src/providers/be_ptask.c
++++ b/src/providers/be_ptask.c
+@@ -30,11 +30,6 @@
+ 
+ #define backoff_allowed(ptask) (ptask->max_backoff != 0)
+ 
+-enum be_ptask_schedule {
+-    BE_PTASK_SCHEDULE_FROM_NOW,
+-    BE_PTASK_SCHEDULE_FROM_LAST
+-};
+-
+ enum be_ptask_delay {
+     BE_PTASK_FIRST_DELAY,
+     BE_PTASK_ENABLED_DELAY,
+@@ -182,7 +177,7 @@ static void be_ptask_done(struct tevent_req *req)
+         DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: finished successfully\n",
+                                   task->name);
+ 
+-        be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_LAST);
++        be_ptask_schedule(task, BE_PTASK_PERIOD, task->success_schedule_type);
+         break;
+     default:
+         DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed with [%d]: %s\n",
+@@ -268,6 +263,7 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         time_t random_offset,
+                         time_t timeout,
+                         enum be_ptask_offline offline,
++                        enum be_ptask_schedule success_schedule_type,
+                         time_t max_backoff,
+                         be_ptask_send_t send_fn,
+                         be_ptask_recv_t recv_fn,
+@@ -300,6 +296,7 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+     task->max_backoff = max_backoff;
+     task->timeout = timeout;
+     task->offline = offline;
++    task->success_schedule_type = success_schedule_type;
+     task->send_fn = send_fn;
+     task->recv_fn = recv_fn;
+     task->pvt = pvt;
+@@ -470,6 +467,7 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+ 
+     ret = be_ptask_create(mem_ctx, be_ctx, period, first_delay,
+                           enabled_delay, random_offset, timeout, offline,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           max_backoff, be_ptask_sync_send, be_ptask_sync_recv,
+                           ctx, name, _task);
+     if (ret != EOK) {
+diff --git a/src/providers/be_ptask.h b/src/providers/be_ptask.h
+index 3b9755361..c23278e88 100644
+--- a/src/providers/be_ptask.h
++++ b/src/providers/be_ptask.h
+@@ -46,6 +46,19 @@ enum be_ptask_offline {
+     BE_PTASK_OFFLINE_EXECUTE
+ };
+ 
++/**
++ * Defines the starting point for scheduling a task
++ */
++enum be_ptask_schedule {
++    /* Schedule starting from now, typically this is used when scheduling
++     * relative to the finish time
++     */
++    BE_PTASK_SCHEDULE_FROM_NOW,
++    /* Schedule relative to the start time of the task
++     */
++    BE_PTASK_SCHEDULE_FROM_LAST
++};
++
+ typedef struct tevent_req *
+ (*be_ptask_send_t)(TALLOC_CTX *mem_ctx,
+                    struct tevent_context *ev,
+@@ -75,6 +88,14 @@ typedef errno_t
+  * The first execution is scheduled first_delay seconds after the task is
+  * created.
+  *
++ * Subsequent runs will be scheduled depending on the value of the
++ * success_schedule_type parameter:
++ *  - BE_PTASK_SCHEDULE_FROM_NOW: period seconds from the finish time
++ *  - BE_PTASK_SCHEDULE_FROM_LAST: period seconds from the last start time
++ *
++ * If the test fails, another run is always scheduled period seconds
++ * from the finish time.
++ *
+  * If request does not complete in timeout seconds, it will be
+  * cancelled and rescheduled to 'now + period'.
+  *
+@@ -83,7 +104,7 @@ typedef errno_t
+  *
+  * The random_offset is maximum number of seconds added to the
+  * expected delay. Set to 0 if no randomization is needed.
+-
++ *
+  * If max_backoff is not 0 then the period is doubled
+  * every time the task is scheduled. The maximum value of
+  * period is max_backoff. The value of period will be reset to
+@@ -100,6 +121,7 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         time_t random_offset,
+                         time_t timeout,
+                         enum be_ptask_offline offline,
++                        enum be_ptask_schedule success_schedule_type,
+                         time_t max_backoff,
+                         be_ptask_send_t send_fn,
+                         be_ptask_recv_t recv_fn,
+diff --git a/src/providers/be_ptask_private.h b/src/providers/be_ptask_private.h
+index 4144a3938..e89105f95 100644
+--- a/src/providers/be_ptask_private.h
++++ b/src/providers/be_ptask_private.h
+@@ -32,6 +32,7 @@ struct be_ptask {
+     time_t timeout;
+     time_t max_backoff;
+     enum be_ptask_offline offline;
++    enum be_ptask_schedule success_schedule_type;
+     be_ptask_send_t send_fn;
+     be_ptask_recv_t recv_fn;
+     void *pvt;
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 5d86509bb..50b023c3d 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -156,7 +156,9 @@ errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+     refresh_interval = be_ctx->domain->refresh_expired_interval;
+     if (refresh_interval > 0) {
+         ret = be_ptask_create(be_ctx, be_ctx, refresh_interval, 30, 5, 0,
+-                              refresh_interval, BE_PTASK_OFFLINE_SKIP, 0,
++                              refresh_interval, BE_PTASK_OFFLINE_SKIP,
++                              BE_PTASK_SCHEDULE_FROM_LAST,
++                              0,
+                               be_refresh_send, be_refresh_recv,
+                               ctx, "Refresh Records", NULL);
+         if (ret != EOK) {
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 94365aaca..3a17c851d 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -3134,7 +3134,9 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
+ 
+     period = be_ctx->domain->subdomain_refresh_interval;
+     ret = be_ptask_create(sd_ctx, be_ctx, period, ptask_first_delay, 0, 0, period,
+-                          BE_PTASK_OFFLINE_DISABLE, 0,
++                          BE_PTASK_OFFLINE_DISABLE,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          0,
+                           ipa_subdomains_ptask_send, ipa_subdomains_ptask_recv, sd_ctx,
+                           "Subdomains Refresh", NULL);
+     if (ret != EOK) {
+diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
+index 8832eb558..062185c55 100644
+--- a/src/providers/ldap/ldap_id_enum.c
++++ b/src/providers/ldap/ldap_id_enum.c
+@@ -99,6 +99,7 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
+                           0,                        /* random offset */
+                           period,                   /* timeout */
+                           BE_PTASK_OFFLINE_SKIP,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,                        /* max_backoff */
+                           send_fn, recv_fn,
+                           ectx, "enumeration", &sdom->enum_task);
+diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c
+index 66b788702..982fdbf7f 100644
+--- a/src/providers/ldap/sdap_sudo_shared.c
++++ b/src/providers/ldap/sdap_sudo_shared.c
+@@ -90,7 +90,9 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx,
+      * when offline. */
+     if (full > 0) {
+         ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full,
+-                              BE_PTASK_OFFLINE_DISABLE, 0,
++                              BE_PTASK_OFFLINE_DISABLE,
++                              BE_PTASK_SCHEDULE_FROM_LAST,
++                              0,
+                               full_send_fn, full_recv_fn, pvt,
+                               "SUDO Full Refresh", NULL);
+         if (ret != EOK) {
+@@ -107,7 +109,9 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx,
+      * when offline. */
+     if (smart > 0) {
+         ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0,
+-                              smart, BE_PTASK_OFFLINE_DISABLE, 0,
++                              smart, BE_PTASK_OFFLINE_DISABLE,
++                              BE_PTASK_SCHEDULE_FROM_LAST,
++                              0,
+                               smart_send_fn, smart_recv_fn, pvt,
+                               "SUDO Smart Refresh", NULL);
+         if (ret != EOK) {
+diff --git a/src/tests/cmocka/test_be_ptask.c b/src/tests/cmocka/test_be_ptask.c
+index ca80b5442..45c41ed58 100644
+--- a/src/tests/cmocka/test_be_ptask.c
++++ b/src/tests/cmocka/test_be_ptask.c
+@@ -306,7 +306,8 @@ void test_be_ptask_create_einval_be(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, NULL, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, NULL, "Test ptask", &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+@@ -319,7 +320,8 @@ void test_be_ptask_create_einval_period(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, 0, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, NULL, "Test ptask", &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+@@ -332,7 +334,8 @@ void test_be_ptask_create_einval_send(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, NULL,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, NULL,
+                           test_be_ptask_recv, NULL, "Test ptask", &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+@@ -345,7 +348,8 @@ void test_be_ptask_create_einval_recv(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           NULL, NULL, "Test ptask", &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+@@ -358,7 +362,8 @@ void test_be_ptask_create_einval_name(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, NULL, NULL, &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+@@ -373,7 +378,8 @@ void test_be_ptask_create_no_delay(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -400,7 +406,8 @@ void test_be_ptask_create_first_delay(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, DELAY, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -425,7 +432,8 @@ void test_be_ptask_disable(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -449,7 +457,8 @@ void test_be_ptask_enable(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -481,7 +490,8 @@ void test_be_ptask_enable_delay(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, DELAY, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -520,7 +530,8 @@ void test_be_ptask_offline_skip(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -553,7 +564,9 @@ void test_be_ptask_offline_disable(void **state)
+     will_return(be_add_offline_cb, test_ctx);
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_DISABLE, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_DISABLE,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -583,7 +596,9 @@ void test_be_ptask_offline_execute(void **state)
+     mark_offline(test_ctx);
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_EXECUTE, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_EXECUTE,
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -610,7 +625,8 @@ void test_be_ptask_reschedule_ok(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -641,7 +657,8 @@ void test_be_ptask_reschedule_null(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_null_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_null_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask",
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+@@ -668,7 +685,8 @@ void test_be_ptask_reschedule_error(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_error_recv, test_ctx, "Test ptask",
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+@@ -695,7 +713,8 @@ void test_be_ptask_reschedule_timeout(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 1,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_timeout_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_timeout_send,
+                           test_be_ptask_error_recv, test_ctx, "Test ptask",
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+@@ -732,7 +751,8 @@ void test_be_ptask_reschedule_backoff(void **state)
+ 
+     now_first = get_current_time();
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, PERIOD*2, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          PERIOD*2, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -786,7 +806,8 @@ void test_be_ptask_get_period(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -806,7 +827,8 @@ void test_be_ptask_get_timeout(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, TIMEOUT,
+-                          BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+-- 
+2.20.1
+
diff --git a/SOURCES/0056-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch b/SOURCES/0056-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch
new file mode 100644
index 0000000..197a06a
--- /dev/null
+++ b/SOURCES/0056-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch
@@ -0,0 +1,37 @@
+From 873c9417fefc0ce7ce02f4fe4fd3b858b9b1781b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 19 Jun 2019 22:03:16 +0200
+Subject: [PATCH 56/64] BE: Schedule the refresh interval from the finish time
+ of the last run
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+Changes scheduling the periodical task so that the next run is started
+relative to the previous run finish time, not start time to protect
+against cases where the refresh would take too long and run practically
+all the time.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 576f3691a2d22322b08fb55fe74899d2ea4975d6)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/be_refresh.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 50b023c3d..a9d4295ec 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -157,7 +157,7 @@ errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+     if (refresh_interval > 0) {
+         ret = be_ptask_create(be_ctx, be_ctx, refresh_interval, 30, 5, 0,
+                               refresh_interval, BE_PTASK_OFFLINE_SKIP,
+-                              BE_PTASK_SCHEDULE_FROM_LAST,
++                              BE_PTASK_SCHEDULE_FROM_NOW,
+                               0,
+                               be_refresh_send, be_refresh_recv,
+                               ctx, "Refresh Records", NULL);
+-- 
+2.20.1
+
diff --git a/SOURCES/0057-AD-Implement-background-refresh-for-AD-domains.patch b/SOURCES/0057-AD-Implement-background-refresh-for-AD-domains.patch
new file mode 100644
index 0000000..a9fbceb
--- /dev/null
+++ b/SOURCES/0057-AD-Implement-background-refresh-for-AD-domains.patch
@@ -0,0 +1,592 @@
+From 6777831bc1b0d1218d635d2913326883f509f3e8 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 24 Apr 2019 20:52:11 +0200
+Subject: [PATCH 57/64] AD: Implement background refresh for AD domains
+
+Split out the actual useful functionality from the AD account handler
+into a tevent request. This tevent request is then subsequently used by
+a new ad_refresh module.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit b72adfcc332b13489931483201bcc4c7ecf9ecb6)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ Makefile.am                   |   5 +-
+ src/providers/ad/ad_common.h  |   4 +
+ src/providers/ad/ad_id.c      | 140 +++++++++++++----
+ src/providers/ad/ad_id.h      |  10 ++
+ src/providers/ad/ad_init.c    |   2 +-
+ src/providers/ad/ad_refresh.c | 283 ++++++++++++++++++++++++++++++++++
+ 6 files changed, 412 insertions(+), 32 deletions(-)
+ create mode 100644 src/providers/ad/ad_refresh.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 0c24ae664..7d83b6847 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -4243,7 +4243,10 @@ libsss_ad_la_SOURCES = \
+     src/providers/ad/ad_gpo_ndr.c \
+     src/providers/ad/ad_srv.c \
+     src/providers/ad/ad_subdomains.c \
+-    src/providers/ad/ad_domain_info.c
++    src/providers/ad/ad_domain_info.c \
++    src/providers/ad/ad_refresh.c \
++    $(NULL)
++
+ 
+ if BUILD_SUDO
+ libsss_ad_la_SOURCES += \
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index 2f624df3d..44369288e 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -221,4 +221,8 @@ errno_t ad_inherit_opts_if_needed(struct dp_option *parent_opts,
+                                   struct confdb_ctx *cdb,
+                                   const char *subdom_conf_path,
+                                   int opt_id);
++
++errno_t ad_refresh_init(struct be_ctx *be_ctx,
++                        struct ad_id_ctx *id_ctx);
++
+ #endif /* AD_COMMON_H_ */
+diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
+index c3bda1662..eb6e36824 100644
+--- a/src/providers/ad/ad_id.c
++++ b/src/providers/ad/ad_id.c
+@@ -360,44 +360,36 @@ get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
+     return clist;
+ }
+ 
+-struct ad_account_info_handler_state {
+-    struct sss_domain_info *domain;
+-    struct dp_reply_std reply;
++struct ad_account_info_state {
++    const char *err_msg;
++    int dp_error;
+ };
+ 
+-static void ad_account_info_handler_done(struct tevent_req *subreq);
++static void ad_account_info_done(struct tevent_req *subreq);
+ 
+ struct tevent_req *
+-ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
+-                              struct ad_id_ctx *id_ctx,
+-                              struct dp_id_data *data,
+-                              struct dp_req_params *params)
++ad_account_info_send(TALLOC_CTX *mem_ctx,
++                     struct be_ctx *be_ctx,
++                     struct ad_id_ctx *id_ctx,
++                     struct dp_id_data *data)
+ {
+-    struct ad_account_info_handler_state *state;
+-    struct sdap_id_conn_ctx **clist;
+-    struct sdap_id_ctx *sdap_id_ctx;
+-    struct sss_domain_info *domain;
++    struct sss_domain_info *domain = NULL;
++    struct ad_account_info_state *state = NULL;
++    struct tevent_req *req = NULL;
++    struct tevent_req *subreq = NULL;
++    struct sdap_id_conn_ctx **clist = NULL;
++    struct sdap_id_ctx *sdap_id_ctx = NULL;
+     struct sdap_domain *sdom;
+-    struct tevent_req *subreq;
+-    struct tevent_req *req;
+-    struct be_ctx *be_ctx;
+     errno_t ret;
+ 
+-    sdap_id_ctx = id_ctx->sdap_id_ctx;
+-    be_ctx = params->be_ctx;
+-
+     req = tevent_req_create(mem_ctx, &state,
+-                            struct ad_account_info_handler_state);
++                            struct ad_account_info_state);
+     if (req == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+         return NULL;
+     }
+ 
+-    if (sdap_is_enum_request(data)) {
+-        DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
+-        ret = EOK;
+-        goto immediately;
+-    }
++    sdap_id_ctx = id_ctx->sdap_id_ctx;
+ 
+     domain = be_ctx->domain;
+     if (strcasecmp(data->domain, be_ctx->domain->name) != 0) {
+@@ -406,6 +398,7 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
+     }
+ 
+     if (domain == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unknown domain\n");
+         ret = EINVAL;
+         goto immediately;
+     }
+@@ -413,6 +406,7 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
+     /* Determine whether to connect to GC, LDAP or try both. */
+     clist = get_conn_list(state, id_ctx, domain, data);
+     if (clist == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create conn list\n");
+         ret = EIO;
+         goto immediately;
+     }
+@@ -423,14 +417,100 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
+         goto immediately;
+     }
+ 
+-    state->domain = sdom->dom;
+-
+     subreq = ad_handle_acct_info_send(state, data, sdap_id_ctx,
+                                       id_ctx->ad_options, sdom, clist);
+     if (subreq == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+     }
++    tevent_req_set_callback(subreq, ad_account_info_done, req);
++    return req;
++
++immediately:
++    tevent_req_error(req, ret);
++    tevent_req_post(req, be_ctx->ev);
++    return req;
++}
++
++static void ad_account_info_done(struct tevent_req *subreq)
++{
++    struct ad_account_info_state *state = NULL;
++    struct tevent_req *req = NULL;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct ad_account_info_state);
++
++    ret = ad_handle_acct_info_recv(subreq, &state->dp_error, &state->err_msg);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "ad_handle_acct_info_recv failed [%d]: %s\n",
++              ret, sss_strerror(ret));
++        /* The caller wouldn't fail either, just report the error up */
++    }
++    talloc_zfree(subreq);
++    tevent_req_done(req);
++}
++
++errno_t ad_account_info_recv(struct tevent_req *req,
++                             int *_dp_error,
++                             const char **_err_msg)
++{
++    struct ad_account_info_state *state = NULL;
++
++    state = tevent_req_data(req, struct ad_account_info_state);
++
++    if (_err_msg != NULL) {
++        *_err_msg = state->err_msg;
++    }
++
++    if (_dp_error) {
++        *_dp_error = state->dp_error;
++    }
++
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    return EOK;
++}
++
++struct ad_account_info_handler_state {
++    struct sss_domain_info *domain;
++    struct dp_reply_std reply;
++};
++
++static void ad_account_info_handler_done(struct tevent_req *subreq);
++
++struct tevent_req *
++ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
++                              struct ad_id_ctx *id_ctx,
++                              struct dp_id_data *data,
++                              struct dp_req_params *params)
++{
++    struct ad_account_info_handler_state *state;
++    struct tevent_req *subreq;
++    struct tevent_req *req;
++    errno_t ret;
++
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct ad_account_info_handler_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    if (sdap_is_enum_request(data)) {
++        DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
++        ret = EOK;
++        goto immediately;
++    }
++
++    subreq = ad_account_info_send(state, params->be_ctx, id_ctx, data);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
+ 
+     tevent_req_set_callback(subreq, ad_account_info_handler_done, req);
+ 
+@@ -451,13 +531,13 @@ static void ad_account_info_handler_done(struct tevent_req *subreq)
+     struct ad_account_info_handler_state *state;
+     struct tevent_req *req;
+     const char *err_msg;
+-    int dp_error;
++    int dp_error = DP_ERR_FATAL;
+     errno_t ret;
+ 
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct ad_account_info_handler_state);
+ 
+-    ret = ad_handle_acct_info_recv(subreq, &dp_error, &err_msg);
++    ret = ad_account_info_recv(subreq, &dp_error, &err_msg);
+     talloc_zfree(subreq);
+ 
+     /* TODO For backward compatibility we always return EOK to DP now. */
+@@ -466,8 +546,8 @@ static void ad_account_info_handler_done(struct tevent_req *subreq)
+ }
+ 
+ errno_t ad_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+-                                      struct tevent_req *req,
+-                                      struct dp_reply_std *data)
++                                     struct tevent_req *req,
++                                     struct dp_reply_std *data)
+ {
+     struct ad_account_info_handler_state *state = NULL;
+ 
+diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
+index 5154393c5..19cc54eec 100644
+--- a/src/providers/ad/ad_id.h
++++ b/src/providers/ad/ad_id.h
+@@ -33,6 +33,16 @@ errno_t ad_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+                                       struct tevent_req *req,
+                                       struct dp_reply_std *data);
+ 
++struct tevent_req *
++ad_account_info_send(TALLOC_CTX *mem_ctx,
++                     struct be_ctx *be_ctx,
++                     struct ad_id_ctx *id_ctx,
++                     struct dp_id_data *data);
++
++errno_t ad_account_info_recv(struct tevent_req *req,
++                             int *_dp_error,
++                             const char **_err_msg);
++
+ struct tevent_req *
+ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
+                          struct dp_id_data *ar,
+diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
+index 42c2f150a..f5aea8904 100644
+--- a/src/providers/ad/ad_init.c
++++ b/src/providers/ad/ad_init.c
+@@ -408,7 +408,7 @@ static errno_t ad_init_misc(struct be_ctx *be_ctx,
+         return ret;
+     }
+ 
+-    ret = sdap_refresh_init(be_ctx, sdap_id_ctx);
++    ret = ad_refresh_init(be_ctx, ad_id_ctx);
+     if (ret != EOK && ret != EEXIST) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
+               "will not work [%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ad/ad_refresh.c b/src/providers/ad/ad_refresh.c
+new file mode 100644
+index 000000000..ee541056f
+--- /dev/null
++++ b/src/providers/ad/ad_refresh.c
+@@ -0,0 +1,283 @@
++/*
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++#include <tevent.h>
++
++#include "providers/ad/ad_common.h"
++#include "providers/ad/ad_id.h"
++
++struct ad_refresh_state {
++    struct tevent_context *ev;
++    struct be_ctx *be_ctx;
++    struct dp_id_data *account_req;
++    struct ad_id_ctx *id_ctx;
++    char **names;
++    size_t index;
++};
++
++static errno_t ad_refresh_step(struct tevent_req *req);
++static void ad_refresh_done(struct tevent_req *subreq);
++
++static struct tevent_req *ad_refresh_send(TALLOC_CTX *mem_ctx,
++                                            struct tevent_context *ev,
++                                            struct be_ctx *be_ctx,
++                                            struct sss_domain_info *domain,
++                                            int entry_type,
++                                            char **names,
++                                            void *pvt)
++{
++    struct ad_refresh_state *state = NULL;
++    struct tevent_req *req = NULL;
++    errno_t ret;
++    uint32_t filter_type;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct ad_refresh_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    if (names == NULL) {
++        ret = EOK;
++        goto immediately;
++    }
++
++    state->ev = ev;
++    state->be_ctx = be_ctx;
++    state->id_ctx = talloc_get_type(pvt, struct ad_id_ctx);
++    state->names = names;
++    state->index = 0;
++
++    switch (entry_type) {
++    case BE_REQ_NETGROUP:
++        filter_type = BE_FILTER_NAME;
++        break;
++    case BE_REQ_USER:
++    case BE_REQ_GROUP:
++        filter_type = BE_FILTER_SECID;
++        break;
++    default:
++        ret = EINVAL;
++        goto immediately;
++    }
++
++    state->account_req = be_refresh_acct_req(state, entry_type,
++                                             filter_type, domain);
++    if (state->account_req == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    ret = ad_refresh_step(req);
++    if (ret == EOK) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Nothing to refresh\n");
++        goto immediately;
++    } else if (ret != EAGAIN) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "ad_refresh_step() failed "
++                                   "[%d]: %s\n", ret, sss_strerror(ret));
++        goto immediately;
++    }
++
++    return req;
++
++immediately:
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, ev);
++
++    return req;
++}
++
++static errno_t ad_refresh_step(struct tevent_req *req)
++{
++    struct ad_refresh_state *state = NULL;
++    struct tevent_req *subreq = NULL;
++    errno_t ret;
++
++    state = tevent_req_data(req, struct ad_refresh_state);
++
++    if (state->names == NULL) {
++        ret = EOK;
++        goto done;
++    }
++
++    state->account_req->filter_value = state->names[state->index];
++    if (state->account_req->filter_value == NULL) {
++        ret = EOK;
++        goto done;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Issuing refresh of %s %s\n",
++          be_req2str(state->account_req->entry_type),
++          state->account_req->filter_value);
++
++    subreq = ad_account_info_send(state, state->be_ctx, state->id_ctx,
++                                  state->account_req);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    tevent_req_set_callback(subreq, ad_refresh_done, req);
++
++    state->index++;
++    ret = EAGAIN;
++
++done:
++    return ret;
++}
++
++static void ad_refresh_done(struct tevent_req *subreq)
++{
++    struct ad_refresh_state *state = NULL;
++    struct tevent_req *req = NULL;
++    const char *err_msg = NULL;
++    errno_t dp_error;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct ad_refresh_state);
++
++    ret = ad_account_info_recv(subreq, &dp_error, &err_msg);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to refresh %s [dp_error: %d, "
++              "errno: %d]: %s\n", be_req2str(state->account_req->entry_type),
++              dp_error, ret, err_msg);
++        goto done;
++    }
++
++    ret = ad_refresh_step(req);
++    if (ret == EAGAIN) {
++        return;
++    }
++
++done:
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++static errno_t ad_refresh_recv(struct tevent_req *req)
++{
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    return EOK;
++}
++
++static struct tevent_req *
++ad_refresh_users_send(TALLOC_CTX *mem_ctx,
++                      struct tevent_context *ev,
++                      struct be_ctx *be_ctx,
++                      struct sss_domain_info *domain,
++                      char **names,
++                      void *pvt)
++{
++    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_USER, names, pvt);
++}
++
++static errno_t ad_refresh_users_recv(struct tevent_req *req)
++{
++    return ad_refresh_recv(req);
++}
++
++static struct tevent_req *
++ad_refresh_groups_send(TALLOC_CTX *mem_ctx,
++                       struct tevent_context *ev,
++                       struct be_ctx *be_ctx,
++                       struct sss_domain_info *domain,
++                       char **names,
++                       void *pvt)
++{
++    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_GROUP, names, pvt);
++}
++
++static errno_t ad_refresh_groups_recv(struct tevent_req *req)
++{
++    return ad_refresh_recv(req);
++}
++
++static struct tevent_req *
++ad_refresh_netgroups_send(TALLOC_CTX *mem_ctx,
++                          struct tevent_context *ev,
++                          struct be_ctx *be_ctx,
++                          struct sss_domain_info *domain,
++                          char **names,
++                          void *pvt)
++{
++    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_NETGROUP, names, pvt);
++}
++
++static errno_t ad_refresh_netgroups_recv(struct tevent_req *req)
++{
++    return ad_refresh_recv(req);
++}
++
++errno_t ad_refresh_init(struct be_ctx *be_ctx,
++                        struct ad_id_ctx *id_ctx)
++{
++    errno_t ret;
++
++    ret = be_refresh_ctx_init(be_ctx, SYSDB_SID_STR);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
++        return ret;
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
++                            ad_refresh_users_send,
++                            ad_refresh_users_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_GROUPS,
++                            ad_refresh_groups_send,
++                            ad_refresh_groups_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of groups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_NETGROUPS,
++                            ad_refresh_netgroups_send,
++                            ad_refresh_netgroups_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of netgroups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    return ret;
++}
+-- 
+2.20.1
+
diff --git a/SOURCES/0058-IPA-Implement-background-refresh-for-IPA-domains.patch b/SOURCES/0058-IPA-Implement-background-refresh-for-IPA-domains.patch
new file mode 100644
index 0000000..472daaa
--- /dev/null
+++ b/SOURCES/0058-IPA-Implement-background-refresh-for-IPA-domains.patch
@@ -0,0 +1,550 @@
+From 7c4055f0701c9be44f478a713c45e43e5d5914a9 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 8 May 2019 14:39:23 +0200
+Subject: [PATCH 58/64] IPA: Implement background refresh for IPA domains
+
+Split out the actual useful functionality from the IPA account lookup
+handler into a tevent request. This tevent request is then used in a new
+ipa_refresh module.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit d76756ef472da9593c691f94186d09226bb49916)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ Makefile.am                     |   1 +
+ src/providers/ipa/ipa_common.h  |   3 +
+ src/providers/ipa/ipa_id.c      | 140 +++++++++++++----
+ src/providers/ipa/ipa_id.h      |   8 +
+ src/providers/ipa/ipa_init.c    |   2 +-
+ src/providers/ipa/ipa_refresh.c | 264 ++++++++++++++++++++++++++++++++
+ 6 files changed, 386 insertions(+), 32 deletions(-)
+ create mode 100644 src/providers/ipa/ipa_refresh.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 7d83b6847..e74de422d 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -4171,6 +4171,7 @@ libsss_ipa_la_SOURCES = \
+     src/providers/ipa/ipa_srv.c \
+     src/providers/ipa/ipa_idmap.c \
+     src/providers/ipa/ipa_dn.c \
++    src/providers/ipa/ipa_refresh.c \
+     src/providers/ad/ad_opts.c \
+     src/providers/ad/ad_common.c \
+     src/providers/ad/ad_dyndns.c \
+diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
+index 31e671eb5..6bb1739ef 100644
+--- a/src/providers/ipa/ipa_common.h
++++ b/src/providers/ipa/ipa_common.h
+@@ -301,4 +301,7 @@ errno_t ipa_get_host_attrs(struct dp_option *ipa_options,
+                            struct sysdb_attrs **hosts,
+                            struct sysdb_attrs **_ipa_host);
+ 
++errno_t ipa_refresh_init(struct be_ctx *be_ctx,
++                         struct ipa_id_ctx *id_ctx);
++
+ #endif /* _IPA_COMMON_H_ */
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index e644af5ff..9abee34cb 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -1344,43 +1344,39 @@ ipa_decide_account_info_type(struct dp_id_data *data, struct be_ctx *be_ctx)
+     return IPA_ACCOUNT_INFO_OTHER;
+ }
+ 
+-struct ipa_account_info_handler_state {
++struct ipa_account_info_state {
+     enum ipa_account_info_type type;
+-    struct dp_reply_std reply;
++
++    const char *err_msg;
++    int dp_error;
+ };
+ 
+-static void ipa_account_info_handler_done(struct tevent_req *subreq);
++static void ipa_account_info_done(struct tevent_req *subreq);
+ 
+ struct tevent_req *
+-ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
+-                              struct ipa_id_ctx *id_ctx,
+-                              struct dp_id_data *data,
+-                              struct dp_req_params *params)
++ipa_account_info_send(TALLOC_CTX *mem_ctx,
++                      struct be_ctx *be_ctx,
++                      struct ipa_id_ctx *id_ctx,
++                      struct dp_id_data *data)
+ {
+-    struct ipa_account_info_handler_state *state;
++    struct ipa_account_info_state *state = NULL;
++    struct tevent_req *req = NULL;
+     struct tevent_req *subreq = NULL;
+-    struct tevent_req *req;
+     errno_t ret;
+ 
+     req = tevent_req_create(mem_ctx, &state,
+-                            struct ipa_account_info_handler_state);
++                            struct ipa_account_info_state);
+     if (req == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+         return NULL;
+     }
+ 
+-    state->type = ipa_decide_account_info_type(data, params->be_ctx);
+-
+-    if (sdap_is_enum_request(data)) {
+-        DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
+-        ret = EOK;
+-        goto immediately;
+-    }
++    state->type = ipa_decide_account_info_type(data, be_ctx);
+ 
+     switch (state->type) {
+     case IPA_ACCOUNT_INFO_SUBDOMAIN:
+         /* Subdomain lookups are handled differently on server and client. */
+-        subreq = ipa_subdomain_account_send(state, params->ev, id_ctx, data);
++        subreq = ipa_subdomain_account_send(state, be_ctx->ev, id_ctx, data);
+         break;
+     case IPA_ACCOUNT_INFO_NETGROUP:
+         if (data->filter_type != BE_FILTER_NAME) {
+@@ -1388,11 +1384,11 @@ ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
+             goto immediately;
+         }
+ 
+-        subreq = ipa_id_get_netgroup_send(state, params->ev, id_ctx,
++        subreq = ipa_id_get_netgroup_send(state, be_ctx->ev, id_ctx,
+                                           data->filter_value);
+         break;
+     case IPA_ACCOUNT_INFO_OTHER:
+-        subreq = ipa_id_get_account_info_send(state, params->ev, id_ctx, data);
++        subreq = ipa_id_get_account_info_send(state, be_ctx->ev, id_ctx, data);
+         break;
+     }
+ 
+@@ -1400,7 +1396,99 @@ ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
+         ret = ENOMEM;
+         goto immediately;
+     }
++    tevent_req_set_callback(subreq, ipa_account_info_done, req);
++    return req;
++
++immediately:
++    tevent_req_error(req, ret);
++    tevent_req_post(req, be_ctx->ev);
++    return req;
++}
++
++static void ipa_account_info_done(struct tevent_req *subreq)
++{
++    struct ipa_account_info_state *state = NULL;
++    struct tevent_req *req = NULL;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct ipa_account_info_state);
++
++    switch (state->type) {
++    case IPA_ACCOUNT_INFO_SUBDOMAIN:
++        ret = ipa_subdomain_account_recv(subreq, &state->dp_error);
++        break;
++    case IPA_ACCOUNT_INFO_NETGROUP:
++        ret = ipa_id_get_netgroup_recv(subreq, &state->dp_error);
++        break;
++    case IPA_ACCOUNT_INFO_OTHER:
++        ret = ipa_id_get_account_info_recv(subreq, &state->dp_error);
++        break;
++    default:
++        ret = EINVAL;
++        break;
++    }
++    talloc_zfree(subreq);
++
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
+ 
++errno_t ipa_account_info_recv(struct tevent_req *req,
++                              int *_dp_error)
++{
++    struct ipa_account_info_state *state = NULL;
++
++    state = tevent_req_data(req, struct ipa_account_info_state);
++
++    /* Fail the request after collecting the dp_error */
++    if (_dp_error) {
++        *_dp_error = state->dp_error;
++    }
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++    return EOK;
++}
++
++struct ipa_account_info_handler_state {
++    struct dp_reply_std reply;
++};
++
++static void ipa_account_info_handler_done(struct tevent_req *subreq);
++
++struct tevent_req *
++ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
++                              struct ipa_id_ctx *id_ctx,
++                              struct dp_id_data *data,
++                              struct dp_req_params *params)
++{
++    struct ipa_account_info_handler_state *state;
++    struct tevent_req *subreq = NULL;
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct ipa_account_info_handler_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    if (sdap_is_enum_request(data)) {
++        DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
++        ret = EOK;
++        goto immediately;
++    }
++
++    subreq = ipa_account_info_send(state, params->be_ctx, id_ctx, data);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
+     tevent_req_set_callback(subreq, ipa_account_info_handler_done, req);
+ 
+     return req;
+@@ -1425,17 +1513,7 @@ static void ipa_account_info_handler_done(struct tevent_req *subreq)
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct ipa_account_info_handler_state);
+ 
+-    switch (state->type) {
+-    case IPA_ACCOUNT_INFO_SUBDOMAIN:
+-        ret = ipa_subdomain_account_recv(subreq, &dp_error);
+-        break;
+-    case IPA_ACCOUNT_INFO_NETGROUP:
+-        ret = ipa_id_get_netgroup_recv(subreq, &dp_error);
+-        break;
+-    case IPA_ACCOUNT_INFO_OTHER:
+-        ret = ipa_id_get_account_info_recv(subreq, &dp_error);
+-        break;
+-    }
++    ret = ipa_account_info_recv(subreq, &dp_error);
+     talloc_zfree(subreq);
+ 
+     /* TODO For backward compatibility we always return EOK to DP now. */
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index 4b2549882..fe9acfeef 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -33,6 +33,14 @@
+ 
+ #define IPA_DEFAULT_VIEW_NAME "Default Trust View"
+ 
++struct tevent_req *
++ipa_account_info_send(TALLOC_CTX *mem_ctx,
++                      struct be_ctx *be_ctx,
++                      struct ipa_id_ctx *id_ctx,
++                      struct dp_id_data *data);
++errno_t ipa_account_info_recv(struct tevent_req *req,
++                              int *_dp_error);
++
+ struct tevent_req *
+ ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
+                               struct ipa_id_ctx *id_ctx,
+diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
+index b3060e228..cdfd11d7a 100644
+--- a/src/providers/ipa/ipa_init.c
++++ b/src/providers/ipa/ipa_init.c
+@@ -594,7 +594,7 @@ static errno_t ipa_init_misc(struct be_ctx *be_ctx,
+         }
+     }
+ 
+-    ret = sdap_refresh_init(be_ctx, sdap_id_ctx);
++    ret = ipa_refresh_init(be_ctx, ipa_id_ctx);
+     if (ret != EOK && ret != EEXIST) {
+         DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
+               "will not work [%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ipa/ipa_refresh.c b/src/providers/ipa/ipa_refresh.c
+new file mode 100644
+index 000000000..72051cfdd
+--- /dev/null
++++ b/src/providers/ipa/ipa_refresh.c
+@@ -0,0 +1,264 @@
++/*
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++#include <tevent.h>
++
++#include "providers/ipa/ipa_common.h"
++#include "providers/ipa/ipa_id.h"
++
++struct ipa_refresh_state {
++    struct tevent_context *ev;
++    struct be_ctx *be_ctx;
++    struct dp_id_data *account_req;
++    struct ipa_id_ctx *id_ctx;
++    char **names;
++    size_t index;
++};
++
++static errno_t ipa_refresh_step(struct tevent_req *req);
++static void ipa_refresh_done(struct tevent_req *subreq);
++
++static struct tevent_req *ipa_refresh_send(TALLOC_CTX *mem_ctx,
++                                            struct tevent_context *ev,
++                                            struct be_ctx *be_ctx,
++                                            struct sss_domain_info *domain,
++                                            int entry_type,
++                                            char **names,
++                                            void *pvt)
++{
++    struct ipa_refresh_state *state = NULL;
++    struct tevent_req *req = NULL;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct ipa_refresh_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    if (names == NULL) {
++        ret = EOK;
++        goto immediately;
++    }
++
++    state->ev = ev;
++    state->be_ctx = be_ctx;
++    state->id_ctx = talloc_get_type(pvt, struct ipa_id_ctx);
++    state->names = names;
++    state->index = 0;
++
++    state->account_req = be_refresh_acct_req(state, entry_type,
++                                             BE_FILTER_NAME, domain);
++    if (state->account_req == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    ret = ipa_refresh_step(req);
++    if (ret == EOK) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Nothing to refresh\n");
++        goto immediately;
++    } else if (ret != EAGAIN) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "ipa_refresh_step() failed "
++                                   "[%d]: %s\n", ret, sss_strerror(ret));
++        goto immediately;
++    }
++
++    return req;
++
++immediately:
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, ev);
++
++    return req;
++}
++
++static errno_t ipa_refresh_step(struct tevent_req *req)
++{
++    struct ipa_refresh_state *state = NULL;
++    struct tevent_req *subreq = NULL;
++    errno_t ret;
++
++    state = tevent_req_data(req, struct ipa_refresh_state);
++
++    if (state->names == NULL) {
++        ret = EOK;
++        goto done;
++    }
++
++    state->account_req->filter_value = state->names[state->index];
++    if (state->account_req->filter_value == NULL) {
++        ret = EOK;
++        goto done;
++    }
++
++    subreq = ipa_account_info_send(state, state->be_ctx, state->id_ctx,
++                                  state->account_req);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    tevent_req_set_callback(subreq, ipa_refresh_done, req);
++
++    state->index++;
++    ret = EAGAIN;
++
++done:
++    return ret;
++}
++
++static void ipa_refresh_done(struct tevent_req *subreq)
++{
++    struct ipa_refresh_state *state = NULL;
++    struct tevent_req *req = NULL;
++    errno_t dp_error;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct ipa_refresh_state);
++
++    ret = ipa_account_info_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to refresh %s [dp_error: %d, "
++              "errno: %d]\n", be_req2str(state->account_req->entry_type),
++              dp_error, ret);
++        goto done;
++    }
++
++    ret = ipa_refresh_step(req);
++    if (ret == EAGAIN) {
++        return;
++    }
++
++done:
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++static errno_t ipa_refresh_recv(struct tevent_req *req)
++{
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    return EOK;
++}
++
++static struct tevent_req *
++ipa_refresh_users_send(TALLOC_CTX *mem_ctx,
++                        struct tevent_context *ev,
++                        struct be_ctx *be_ctx,
++                        struct sss_domain_info *domain,
++                        char **names,
++                        void *pvt)
++{
++    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_USER, names, pvt);
++}
++
++static errno_t ipa_refresh_users_recv(struct tevent_req *req)
++{
++    return ipa_refresh_recv(req);
++}
++
++static struct tevent_req *
++ipa_refresh_groups_send(TALLOC_CTX *mem_ctx,
++                         struct tevent_context *ev,
++                         struct be_ctx *be_ctx,
++                         struct sss_domain_info *domain,
++                         char **names,
++                         void *pvt)
++{
++    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_GROUP, names, pvt);
++}
++
++static errno_t ipa_refresh_groups_recv(struct tevent_req *req)
++{
++    return ipa_refresh_recv(req);
++}
++
++static struct tevent_req *
++ipa_refresh_netgroups_send(TALLOC_CTX *mem_ctx,
++                            struct tevent_context *ev,
++                            struct be_ctx *be_ctx,
++                            struct sss_domain_info *domain,
++                            char **names,
++                            void *pvt)
++{
++    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_NETGROUP, names, pvt);
++}
++
++static errno_t ipa_refresh_netgroups_recv(struct tevent_req *req)
++{
++    return ipa_refresh_recv(req);
++}
++
++errno_t ipa_refresh_init(struct be_ctx *be_ctx,
++                         struct ipa_id_ctx *id_ctx)
++{
++    errno_t ret;
++
++    ret = be_refresh_ctx_init(be_ctx, SYSDB_NAME);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
++        return ENOMEM;
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
++                            ipa_refresh_users_send,
++                            ipa_refresh_users_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_GROUPS,
++                            ipa_refresh_groups_send,
++                            ipa_refresh_groups_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of groups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_NETGROUPS,
++                            ipa_refresh_netgroups_send,
++                            ipa_refresh_netgroups_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of netgroups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    return ret;
++}
+-- 
+2.20.1
+
diff --git a/SOURCES/0059-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch b/SOURCES/0059-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch
new file mode 100644
index 0000000..54122c7
--- /dev/null
+++ b/SOURCES/0059-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch
@@ -0,0 +1,294 @@
+From a8212a7884175fe32dccc29f3fed3688f81c76fe Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 25 Jun 2019 14:16:31 +0200
+Subject: [PATCH 59/64] BE/IPA/AD/LDAP: Add inigroups refresh support
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+In addition to refreshing users, groups and netgroups, this patch adds
+the ability to also refresh initgroups. The refresh is ran for any users
+that have the initgrExpireTimestamp attribute close to expiration.
+
+This request is ran as the first one, because the initgroups operation
+refreshes the user entry and can touch groups as well.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 1d0e75e9c5db0acf946f82705a4640063ea5aea9)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_refresh.c     | 28 +++++++++++++++++++++++
+ src/providers/be_refresh.c        | 37 +++++++++++++++++++++++--------
+ src/providers/be_refresh.h        |  1 +
+ src/providers/ipa/ipa_refresh.c   | 27 ++++++++++++++++++++++
+ src/providers/ldap/sdap_refresh.c | 17 ++++++++++++++
+ 5 files changed, 101 insertions(+), 9 deletions(-)
+
+diff --git a/src/providers/ad/ad_refresh.c b/src/providers/ad/ad_refresh.c
+index ee541056f..f0130cbaf 100644
+--- a/src/providers/ad/ad_refresh.c
++++ b/src/providers/ad/ad_refresh.c
+@@ -65,6 +65,7 @@ static struct tevent_req *ad_refresh_send(TALLOC_CTX *mem_ctx,
+     state->index = 0;
+ 
+     switch (entry_type) {
++    case BE_REQ_INITGROUPS:
+     case BE_REQ_NETGROUP:
+         filter_type = BE_FILTER_NAME;
+         break;
+@@ -187,6 +188,23 @@ static errno_t ad_refresh_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
++static struct tevent_req *
++ad_refresh_initgroups_send(TALLOC_CTX *mem_ctx,
++                           struct tevent_context *ev,
++                           struct be_ctx *be_ctx,
++                           struct sss_domain_info *domain,
++                           char **names,
++                           void *pvt)
++{
++    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_INITGROUPS, names, pvt);
++}
++
++static errno_t ad_refresh_initgroups_recv(struct tevent_req *req)
++{
++    return ad_refresh_recv(req);
++}
++
+ static struct tevent_req *
+ ad_refresh_users_send(TALLOC_CTX *mem_ctx,
+                       struct tevent_context *ev,
+@@ -249,6 +267,16 @@ errno_t ad_refresh_init(struct be_ctx *be_ctx,
+         return ret;
+     }
+ 
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_INITGROUPS,
++                            ad_refresh_initgroups_send,
++                            ad_refresh_initgroups_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
+     ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+                             BE_REFRESH_TYPE_USERS,
+                             ad_refresh_users_send,
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index a9d4295ec..6945ca9e3 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -33,11 +33,12 @@ static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
+                                         struct sss_domain_info *domain,
+                                         time_t period,
+                                         struct ldb_dn *base_dn,
+-                                        const char *attr,
++                                        const char *key_attr,
++                                        const char *value_attr,
+                                         char ***_values)
+ {
+     TALLOC_CTX *tmp_ctx = NULL;
+-    const char *attrs[] = {attr, NULL};
++    const char *attrs[] = {value_attr, NULL};
+     const char *filter = NULL;
+     char **values = NULL;
+     struct sysdb_attrs **records = NULL;
+@@ -45,13 +46,17 @@ static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
+     time_t now = time(NULL);
+     errno_t ret;
+ 
++    if (key_attr == NULL || domain == NULL || base_dn == NULL) {
++        return EINVAL;
++    }
++
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+         return ENOMEM;
+     }
+ 
+     filter = talloc_asprintf(tmp_ctx, "(&(%s<=%lld))",
+-                             SYSDB_CACHE_EXPIRE, (long long) now + period);
++                             key_attr, (long long) now + period);
+     if (filter == NULL) {
+         ret = ENOMEM;
+         goto done;
+@@ -73,7 +78,7 @@ static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    ret = sysdb_attrs_to_list(tmp_ctx, records, res->count, attr, &values);
++    ret = sysdb_attrs_to_list(tmp_ctx, records, res->count, value_attr, &values);
+     if (ret != EOK) {
+         goto done;
+     }
+@@ -96,18 +101,27 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
+ {
+     struct ldb_dn *base_dn = NULL;
+     errno_t ret;
++    const char *key_attr;
+ 
+     switch (type) {
++    case BE_REFRESH_TYPE_INITGROUPS:
++        key_attr = SYSDB_INITGR_EXPIRE;
++        base_dn = sysdb_user_base_dn(mem_ctx, domain);
++        break;
+     case BE_REFRESH_TYPE_USERS:
++        key_attr = SYSDB_CACHE_EXPIRE;
+         base_dn = sysdb_user_base_dn(mem_ctx, domain);
+         break;
+     case BE_REFRESH_TYPE_GROUPS:
++        key_attr = SYSDB_CACHE_EXPIRE;
+         base_dn = sysdb_group_base_dn(mem_ctx, domain);
+         break;
+     case BE_REFRESH_TYPE_NETGROUPS:
++        key_attr = SYSDB_CACHE_EXPIRE;
+         base_dn = sysdb_netgroup_base_dn(mem_ctx, domain);
+         break;
+-    case BE_REFRESH_TYPE_SENTINEL:
++    default:
++        DEBUG(SSSDBG_CRIT_FAILURE, "Uknown or unsupported refresh type\n");
+         return ERR_INTERNAL;
+         break;
+     }
+@@ -117,7 +131,8 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
+     }
+ 
+     ret = be_refresh_get_values_ex(mem_ctx, domain, period,
+-                                   base_dn, attr_name, _values);
++                                   base_dn, key_attr,
++                                   attr_name, _values);
+ 
+     talloc_free(base_dn);
+     return ret;
+@@ -125,6 +140,7 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
+ 
+ struct be_refresh_cb {
+     const char *name;
++    const char *attr_name;
+     bool enabled;
+     be_refresh_send_t send_fn;
+     be_refresh_recv_t recv_fn;
+@@ -132,7 +148,6 @@ struct be_refresh_cb {
+ };
+ 
+ struct be_refresh_ctx {
+-    const char *attr_name;
+     struct be_refresh_cb callbacks[BE_REFRESH_TYPE_SENTINEL];
+ };
+ 
+@@ -148,10 +163,14 @@ errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+         return ENOMEM;
+     }
+ 
+-    ctx->attr_name = attr_name;
++    ctx->callbacks[BE_REFRESH_TYPE_INITGROUPS].name = "initgroups";
++    ctx->callbacks[BE_REFRESH_TYPE_INITGROUPS].attr_name = SYSDB_NAME;
+     ctx->callbacks[BE_REFRESH_TYPE_USERS].name = "users";
++    ctx->callbacks[BE_REFRESH_TYPE_USERS].attr_name = attr_name;
+     ctx->callbacks[BE_REFRESH_TYPE_GROUPS].name = "groups";
++    ctx->callbacks[BE_REFRESH_TYPE_GROUPS].attr_name = attr_name;
+     ctx->callbacks[BE_REFRESH_TYPE_NETGROUPS].name = "netgroups";
++    ctx->callbacks[BE_REFRESH_TYPE_NETGROUPS].attr_name = SYSDB_NAME;
+ 
+     refresh_interval = be_ctx->domain->refresh_expired_interval;
+     if (refresh_interval > 0) {
+@@ -310,7 +329,7 @@ static errno_t be_refresh_step(struct tevent_req *req)
+         }
+ 
+         talloc_zfree(state->refresh_values);
+-        ret = be_refresh_get_values(state, state->index, state->ctx->attr_name,
++        ret = be_refresh_get_values(state, state->index, state->cb->attr_name,
+                                     state->domain, state->period,
+                                     &state->refresh_values);
+         if (ret != EOK) {
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index c7b4872df..4ac5b70c2 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -44,6 +44,7 @@ typedef errno_t
+ (*be_refresh_recv_t)(struct tevent_req *req);
+ 
+ enum be_refresh_type {
++    BE_REFRESH_TYPE_INITGROUPS,
+     BE_REFRESH_TYPE_USERS,
+     BE_REFRESH_TYPE_GROUPS,
+     BE_REFRESH_TYPE_NETGROUPS,
+diff --git a/src/providers/ipa/ipa_refresh.c b/src/providers/ipa/ipa_refresh.c
+index 72051cfdd..bb47b0edf 100644
+--- a/src/providers/ipa/ipa_refresh.c
++++ b/src/providers/ipa/ipa_refresh.c
+@@ -168,6 +168,23 @@ static errno_t ipa_refresh_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
++static struct tevent_req *
++ipa_refresh_initgroups_send(TALLOC_CTX *mem_ctx,
++                            struct tevent_context *ev,
++                            struct be_ctx *be_ctx,
++                            struct sss_domain_info *domain,
++                            char **names,
++                            void *pvt)
++{
++    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
++                           BE_REQ_INITGROUPS, names, pvt);
++}
++
++static errno_t ipa_refresh_initgroups_recv(struct tevent_req *req)
++{
++    return ipa_refresh_recv(req);
++}
++
+ static struct tevent_req *
+ ipa_refresh_users_send(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+@@ -230,6 +247,16 @@ errno_t ipa_refresh_init(struct be_ctx *be_ctx,
+         return ENOMEM;
+     }
+ 
++    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
++                            ipa_refresh_initgroups_send,
++                            ipa_refresh_initgroups_recv,
++                            id_ctx);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of initgroups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
+     ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+                             BE_REFRESH_TYPE_USERS,
+                             ipa_refresh_users_send,
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index 2206d6670..3ceddb61e 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -186,6 +186,23 @@ static errno_t sdap_refresh_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
++static struct tevent_req *
++sdap_refresh_initgroups_send(TALLOC_CTX *mem_ctx,
++                        struct tevent_context *ev,
++                        struct be_ctx *be_ctx,
++                        struct sss_domain_info *domain,
++                        char **names,
++                        void *pvt)
++{
++    return sdap_refresh_send(mem_ctx, ev, be_ctx, domain,
++                             BE_REQ_INITGROUPS, names, pvt);
++}
++
++static errno_t sdap_refresh_initgroups_recv(struct tevent_req *req)
++{
++    return sdap_refresh_recv(req);
++}
++
+ static struct tevent_req *
+ sdap_refresh_users_send(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+-- 
+2.20.1
+
diff --git a/SOURCES/0060-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch b/SOURCES/0060-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch
new file mode 100644
index 0000000..6eefc84
--- /dev/null
+++ b/SOURCES/0060-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch
@@ -0,0 +1,498 @@
+From 09901039f2b6a34552ce6ed82d06d4ab04f890a9 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 25 Jun 2019 15:05:59 +0200
+Subject: [PATCH 60/64] BE/IPA/AD/LDAP: Initialize the refresh callback from a
+ list to reduce logic duplication
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+This patch slightly increases the line count, but on the other hand the
+code is now more declarative and contains less logic, which should
+hopefully decrease the maintenance cost in the future.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 792235097b9b63593dc717440aab48e8671fbf12)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_refresh.c     |  66 ++++++----------
+ src/providers/be_refresh.c        | 126 +++++++++++++++++++++++-------
+ src/providers/be_refresh.h        |  17 ++--
+ src/providers/ipa/ipa_refresh.c   |  70 ++++++-----------
+ src/providers/ldap/sdap_refresh.c |  58 ++++++--------
+ 5 files changed, 179 insertions(+), 158 deletions(-)
+
+diff --git a/src/providers/ad/ad_refresh.c b/src/providers/ad/ad_refresh.c
+index f0130cbaf..ed51b305a 100644
+--- a/src/providers/ad/ad_refresh.c
++++ b/src/providers/ad/ad_refresh.c
+@@ -260,52 +260,32 @@ errno_t ad_refresh_init(struct be_ctx *be_ctx,
+                         struct ad_id_ctx *id_ctx)
+ {
+     errno_t ret;
+-
+-    ret = be_refresh_ctx_init(be_ctx, SYSDB_SID_STR);
++    struct be_refresh_cb ad_refresh_callbacks[] = {
++        { .send_fn = ad_refresh_initgroups_send,
++          .recv_fn = ad_refresh_initgroups_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = ad_refresh_users_send,
++          .recv_fn = ad_refresh_users_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = ad_refresh_groups_send,
++          .recv_fn = ad_refresh_groups_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = ad_refresh_netgroups_send,
++          .recv_fn = ad_refresh_netgroups_recv,
++          .pvt = id_ctx,
++        },
++    };
++
++    ret = be_refresh_ctx_init_with_callbacks(be_ctx,
++                                             SYSDB_SID_STR,
++                                             ad_refresh_callbacks);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize background refresh\n");
+         return ret;
+     }
+ 
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_INITGROUPS,
+-                            ad_refresh_initgroups_send,
+-                            ad_refresh_initgroups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_USERS,
+-                            ad_refresh_users_send,
+-                            ad_refresh_users_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_GROUPS,
+-                            ad_refresh_groups_send,
+-                            ad_refresh_groups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of groups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_NETGROUPS,
+-                            ad_refresh_netgroups_send,
+-                            ad_refresh_netgroups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of netgroups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+     return ret;
+ }
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 6945ca9e3..8f50e231d 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -138,21 +138,19 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
+     return ret;
+ }
+ 
+-struct be_refresh_cb {
++struct be_refresh_cb_ctx {
+     const char *name;
+     const char *attr_name;
+     bool enabled;
+-    be_refresh_send_t send_fn;
+-    be_refresh_recv_t recv_fn;
+-    void *pvt;
++    struct be_refresh_cb cb;
+ };
+ 
+ struct be_refresh_ctx {
+-    struct be_refresh_cb callbacks[BE_REFRESH_TYPE_SENTINEL];
++    struct be_refresh_cb_ctx callbacks[BE_REFRESH_TYPE_SENTINEL];
+ };
+ 
+-errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+-                            const char *attr_name)
++static errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
++                                   const char *attr_name)
+ {
+     struct be_refresh_ctx *ctx = NULL;
+     uint32_t refresh_interval;
+@@ -193,13 +191,11 @@ errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+     return EOK;
+ }
+ 
+-errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+-                          enum be_refresh_type type,
+-                          be_refresh_send_t send_fn,
+-                          be_refresh_recv_t recv_fn,
+-                          void *pvt)
++static errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
++                                 enum be_refresh_type type,
++                                 struct be_refresh_cb *cb)
+ {
+-    if (ctx == NULL || send_fn == NULL || recv_fn == NULL
++    if (ctx == NULL || cb->send_fn == NULL || cb->recv_fn == NULL
+             || type >= BE_REFRESH_TYPE_SENTINEL) {
+         return EINVAL;
+     }
+@@ -209,9 +205,78 @@ errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+     }
+ 
+     ctx->callbacks[type].enabled = true;
+-    ctx->callbacks[type].send_fn = send_fn;
+-    ctx->callbacks[type].recv_fn = recv_fn;
+-    ctx->callbacks[type].pvt = pvt;
++    ctx->callbacks[type].cb.send_fn = cb->send_fn;
++    ctx->callbacks[type].cb.recv_fn = cb->recv_fn;
++    ctx->callbacks[type].cb.pvt = cb->pvt;
++
++    return EOK;
++}
++
++static errno_t be_refresh_set_callbacks(struct be_refresh_ctx *refresh_ctx,
++                                        struct be_refresh_cb *callbacks)
++{
++    errno_t ret;
++
++    if (callbacks == NULL || refresh_ctx == NULL) {
++        return EINVAL;
++    }
++
++    ret = be_refresh_add_cb(refresh_ctx,
++                            BE_REFRESH_TYPE_INITGROUPS,
++                            &callbacks[BE_REFRESH_TYPE_INITGROUPS]);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of initgroups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(refresh_ctx,
++                            BE_REFRESH_TYPE_USERS,
++                            &callbacks[BE_REFRESH_TYPE_USERS]);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(refresh_ctx,
++                            BE_REFRESH_TYPE_GROUPS,
++                            &callbacks[BE_REFRESH_TYPE_GROUPS]);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of groups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    ret = be_refresh_add_cb(refresh_ctx,
++                            BE_REFRESH_TYPE_NETGROUPS,
++                            &callbacks[BE_REFRESH_TYPE_NETGROUPS]);
++    if (ret != EOK && ret != EEXIST) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of netgroups "
++              "will not work [%d]: %s\n", ret, strerror(ret));
++    }
++
++    return EOK;
++}
++
++errno_t be_refresh_ctx_init_with_callbacks(struct be_ctx *be_ctx,
++                                           const char *attr_name,
++                                           struct be_refresh_cb *callbacks)
++{
++    errno_t ret;
++
++    if (be_ctx == NULL || attr_name == NULL || callbacks == NULL) {
++        return EINVAL;
++    }
++
++    ret = be_refresh_ctx_init(be_ctx, attr_name);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
++        return ret;
++    }
++
++    ret = be_refresh_set_callbacks(be_ctx->refresh_ctx, callbacks);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh callbacks\n");
++        return ENOMEM;
++    }
+ 
+     return EOK;
+ }
+@@ -220,7 +285,7 @@ struct be_refresh_state {
+     struct tevent_context *ev;
+     struct be_ctx *be_ctx;
+     struct be_refresh_ctx *ctx;
+-    struct be_refresh_cb *cb;
++    struct be_refresh_cb_ctx *cb_ctx;
+ 
+     struct sss_domain_info *domain;
+     enum be_refresh_type index;
+@@ -308,10 +373,11 @@ static errno_t be_refresh_step(struct tevent_req *req)
+ 
+     while (state->domain != NULL) {
+         /* find first enabled callback */
+-        state->cb = &state->ctx->callbacks[state->index];
+-        while (state->index != BE_REFRESH_TYPE_SENTINEL && !state->cb->enabled) {
++        state->cb_ctx = &state->ctx->callbacks[state->index];
++        while (state->index != BE_REFRESH_TYPE_SENTINEL
++                && !state->cb_ctx->enabled) {
+             state->index++;
+-            state->cb = &state->ctx->callbacks[state->index];
++            state->cb_ctx = &state->ctx->callbacks[state->index];
+         }
+ 
+         /* if not found than continue with next domain */
+@@ -322,14 +388,16 @@ static errno_t be_refresh_step(struct tevent_req *req)
+             continue;
+         }
+ 
+-        if (state->cb->send_fn == NULL || state->cb->recv_fn == NULL) {
++        if (state->cb_ctx->cb.send_fn == NULL
++                || state->cb_ctx->cb.recv_fn == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Invalid parameters!\n");
+             ret = ERR_INTERNAL;
+             goto done;
+         }
+ 
+         talloc_zfree(state->refresh_values);
+-        ret = be_refresh_get_values(state, state->index, state->cb->attr_name,
++        ret = be_refresh_get_values(state, state->index,
++                                    state->cb_ctx->attr_name,
+                                     state->domain, state->period,
+                                     &state->refresh_values);
+         if (ret != EOK) {
+@@ -343,7 +411,9 @@ static errno_t be_refresh_step(struct tevent_req *req)
+              state->refresh_val_size++);
+ 
+         DEBUG(SSSDBG_TRACE_FUNC, "Refreshing %zu %s in domain %s\n",
+-              state->refresh_val_size, state->cb->name, state->domain->name);
++              state->refresh_val_size,
++              state->cb_ctx->name,
++              state->domain->name);
+ 
+         ret = be_refresh_batch_step(req, 0);
+         if (ret == EOK) {
+@@ -416,10 +486,10 @@ static void be_refresh_batch_step_wakeup(struct tevent_context *ev,
+     state = tevent_req_data(req, struct be_refresh_state);
+ 
+     DEBUG(SSSDBG_TRACE_INTERNAL, "Issuing refresh\n");
+-    subreq = state->cb->send_fn(state, state->ev, state->be_ctx,
+-                                state->domain,
+-                                state->refresh_batch,
+-                                state->cb->pvt);
++    subreq = state->cb_ctx->cb.send_fn(state, state->ev, state->be_ctx,
++                                       state->domain,
++                                       state->refresh_batch,
++                                       state->cb_ctx->cb.pvt);
+     if (subreq == NULL) {
+         tevent_req_error(req, ENOMEM);
+         return;
+@@ -436,7 +506,7 @@ static void be_refresh_done(struct tevent_req *subreq)
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct be_refresh_state);
+ 
+-    ret = state->cb->recv_fn(subreq);
++    ret = state->cb_ctx->cb.recv_fn(subreq);
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+         goto done;
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index 4ac5b70c2..42d73d938 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -51,16 +51,17 @@ enum be_refresh_type {
+     BE_REFRESH_TYPE_SENTINEL
+ };
+ 
+-struct be_refresh_ctx;
++struct be_refresh_cb {
++    be_refresh_send_t send_fn;
++    be_refresh_recv_t recv_fn;
++    void *pvt;
++};
+ 
+-errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+-                            const char *attr_name);
++struct be_refresh_ctx;
+ 
+-errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
+-                          enum be_refresh_type type,
+-                          be_refresh_send_t send_fn,
+-                          be_refresh_recv_t recv_fn,
+-                          void *pvt);
++errno_t be_refresh_ctx_init_with_callbacks(struct be_ctx *be_ctx,
++                                           const char *attr_name,
++                                           struct be_refresh_cb *callbacks);
+ 
+ struct tevent_req *be_refresh_send(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev,
+diff --git a/src/providers/ipa/ipa_refresh.c b/src/providers/ipa/ipa_refresh.c
+index bb47b0edf..7b05cf9e4 100644
+--- a/src/providers/ipa/ipa_refresh.c
++++ b/src/providers/ipa/ipa_refresh.c
+@@ -240,52 +240,32 @@ errno_t ipa_refresh_init(struct be_ctx *be_ctx,
+                          struct ipa_id_ctx *id_ctx)
+ {
+     errno_t ret;
+-
+-    ret = be_refresh_ctx_init(be_ctx, SYSDB_NAME);
++    struct be_refresh_cb ipa_refresh_callbacks[] = {
++        { .send_fn = ipa_refresh_initgroups_send,
++          .recv_fn = ipa_refresh_initgroups_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = ipa_refresh_users_send,
++          .recv_fn = ipa_refresh_users_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = ipa_refresh_groups_send,
++          .recv_fn = ipa_refresh_groups_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = ipa_refresh_netgroups_send,
++          .recv_fn = ipa_refresh_netgroups_recv,
++          .pvt = id_ctx,
++        },
++    };
++
++    ret = be_refresh_ctx_init_with_callbacks(be_ctx,
++                                             SYSDB_NAME,
++                                             ipa_refresh_callbacks);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_USERS,
+-                            ipa_refresh_initgroups_send,
+-                            ipa_refresh_initgroups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of initgroups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize background refresh\n");
++        return ret;
+     }
+ 
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_USERS,
+-                            ipa_refresh_users_send,
+-                            ipa_refresh_users_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_GROUPS,
+-                            ipa_refresh_groups_send,
+-                            ipa_refresh_groups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of groups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_NETGROUPS,
+-                            ipa_refresh_netgroups_send,
+-                            ipa_refresh_netgroups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of netgroups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    return ret;
++    return EOK;
+ }
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index 3ceddb61e..ff4d2116d 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -258,41 +258,31 @@ errno_t sdap_refresh_init(struct be_ctx *be_ctx,
+                           struct sdap_id_ctx *id_ctx)
+ {
+     errno_t ret;
+-
+-    ret = be_refresh_ctx_init(be_ctx, SYSDB_NAME);
++    struct be_refresh_cb sdap_refresh_callbacks[] = {
++        { .send_fn = sdap_refresh_initgroups_send,
++          .recv_fn = sdap_refresh_initgroups_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = sdap_refresh_users_send,
++          .recv_fn = sdap_refresh_users_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = sdap_refresh_groups_send,
++          .recv_fn = sdap_refresh_groups_recv,
++          .pvt = id_ctx,
++        },
++        { .send_fn = sdap_refresh_netgroups_send,
++          .recv_fn = sdap_refresh_netgroups_recv,
++          .pvt = id_ctx,
++        },
++    };
++
++    ret = be_refresh_ctx_init_with_callbacks(be_ctx,
++                                             SYSDB_NAME,
++                                             sdap_refresh_callbacks);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_USERS,
+-                            sdap_refresh_users_send,
+-                            sdap_refresh_users_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of users "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_USERS,
+-                            sdap_refresh_groups_send,
+-                            sdap_refresh_groups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of groups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
+-    }
+-
+-    ret = be_refresh_add_cb(be_ctx->refresh_ctx,
+-                            BE_REFRESH_TYPE_USERS,
+-                            sdap_refresh_netgroups_send,
+-                            sdap_refresh_netgroups_recv,
+-                            id_ctx);
+-    if (ret != EOK && ret != EEXIST) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh of netgroups "
+-              "will not work [%d]: %s\n", ret, strerror(ret));
++        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize background refresh\n");
++        return ret;
+     }
+ 
+     return ret;
+-- 
+2.20.1
+
diff --git a/SOURCES/0061-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch b/SOURCES/0061-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch
new file mode 100644
index 0000000..c7fea2b
--- /dev/null
+++ b/SOURCES/0061-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch
@@ -0,0 +1,303 @@
+From 441e05790e5efec4928af3d0f93c4eba72d979ae Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 25 Jun 2019 15:01:15 +0200
+Subject: [PATCH 61/64] IPA/AD/SDAP/BE: Generate refresh callbacks with a macro
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+The per-object type refresh functions are more or less boilerplate code.
+Even though macro-generated code should be used very rarely, here the
+generated code does not contain any logic at all so it makese sense to
+generate it with macros.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 60c876aefe2efc5a67929f9b3890b627cea7c549)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_refresh.c     | 71 ++-----------------------------
+ src/providers/be_refresh.h        | 20 +++++++++
+ src/providers/ipa/ipa_refresh.c   | 71 ++-----------------------------
+ src/providers/ldap/sdap_refresh.c | 71 ++-----------------------------
+ 4 files changed, 32 insertions(+), 201 deletions(-)
+
+diff --git a/src/providers/ad/ad_refresh.c b/src/providers/ad/ad_refresh.c
+index ed51b305a..0c2ebce5e 100644
+--- a/src/providers/ad/ad_refresh.c
++++ b/src/providers/ad/ad_refresh.c
+@@ -188,73 +188,10 @@ static errno_t ad_refresh_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
+-static struct tevent_req *
+-ad_refresh_initgroups_send(TALLOC_CTX *mem_ctx,
+-                           struct tevent_context *ev,
+-                           struct be_ctx *be_ctx,
+-                           struct sss_domain_info *domain,
+-                           char **names,
+-                           void *pvt)
+-{
+-    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_INITGROUPS, names, pvt);
+-}
+-
+-static errno_t ad_refresh_initgroups_recv(struct tevent_req *req)
+-{
+-    return ad_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-ad_refresh_users_send(TALLOC_CTX *mem_ctx,
+-                      struct tevent_context *ev,
+-                      struct be_ctx *be_ctx,
+-                      struct sss_domain_info *domain,
+-                      char **names,
+-                      void *pvt)
+-{
+-    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_USER, names, pvt);
+-}
+-
+-static errno_t ad_refresh_users_recv(struct tevent_req *req)
+-{
+-    return ad_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-ad_refresh_groups_send(TALLOC_CTX *mem_ctx,
+-                       struct tevent_context *ev,
+-                       struct be_ctx *be_ctx,
+-                       struct sss_domain_info *domain,
+-                       char **names,
+-                       void *pvt)
+-{
+-    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_GROUP, names, pvt);
+-}
+-
+-static errno_t ad_refresh_groups_recv(struct tevent_req *req)
+-{
+-    return ad_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-ad_refresh_netgroups_send(TALLOC_CTX *mem_ctx,
+-                          struct tevent_context *ev,
+-                          struct be_ctx *be_ctx,
+-                          struct sss_domain_info *domain,
+-                          char **names,
+-                          void *pvt)
+-{
+-    return ad_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_NETGROUP, names, pvt);
+-}
+-
+-static errno_t ad_refresh_netgroups_recv(struct tevent_req *req)
+-{
+-    return ad_refresh_recv(req);
+-}
++REFRESH_SEND_RECV_FNS(ad_refresh_initgroups, ad_refresh, BE_REQ_INITGROUPS);
++REFRESH_SEND_RECV_FNS(ad_refresh_users, ad_refresh, BE_REQ_USER);
++REFRESH_SEND_RECV_FNS(ad_refresh_groups, ad_refresh, BE_REQ_GROUP);
++REFRESH_SEND_RECV_FNS(ad_refresh_netgroups, ad_refresh, BE_REQ_NETGROUP);
+ 
+ errno_t ad_refresh_init(struct be_ctx *be_ctx,
+                         struct ad_id_ctx *id_ctx)
+diff --git a/src/providers/be_refresh.h b/src/providers/be_refresh.h
+index 42d73d938..68be40118 100644
+--- a/src/providers/be_refresh.h
++++ b/src/providers/be_refresh.h
+@@ -29,6 +29,26 @@
+ /* solve circular dependency */
+ struct be_ctx;
+ 
++#define REFRESH_SEND_RECV_FNS(outer_base, inner_base, req_type) \
++                                                                \
++static struct tevent_req *                                      \
++outer_base ##_send(TALLOC_CTX *mem_ctx,                         \
++                   struct tevent_context *ev,                   \
++                   struct be_ctx *be_ctx,                       \
++                   struct sss_domain_info *domain,              \
++                   char **names,                                \
++                   void *pvt)                                   \
++{                                                               \
++    return inner_base ##_send(mem_ctx, ev,                      \
++                              be_ctx, domain,                   \
++                              req_type, names, pvt);            \
++}                                                               \
++                                                                \
++static errno_t outer_base ##_recv(struct tevent_req *req)       \
++{                                                               \
++    return inner_base ##_recv(req);                             \
++}                                                               \
++
+ /**
+  * name_list contains SYSDB_NAME of all expired records.
+  */
+diff --git a/src/providers/ipa/ipa_refresh.c b/src/providers/ipa/ipa_refresh.c
+index 7b05cf9e4..13c38dff9 100644
+--- a/src/providers/ipa/ipa_refresh.c
++++ b/src/providers/ipa/ipa_refresh.c
+@@ -168,73 +168,10 @@ static errno_t ipa_refresh_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
+-static struct tevent_req *
+-ipa_refresh_initgroups_send(TALLOC_CTX *mem_ctx,
+-                            struct tevent_context *ev,
+-                            struct be_ctx *be_ctx,
+-                            struct sss_domain_info *domain,
+-                            char **names,
+-                            void *pvt)
+-{
+-    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_INITGROUPS, names, pvt);
+-}
+-
+-static errno_t ipa_refresh_initgroups_recv(struct tevent_req *req)
+-{
+-    return ipa_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-ipa_refresh_users_send(TALLOC_CTX *mem_ctx,
+-                        struct tevent_context *ev,
+-                        struct be_ctx *be_ctx,
+-                        struct sss_domain_info *domain,
+-                        char **names,
+-                        void *pvt)
+-{
+-    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_USER, names, pvt);
+-}
+-
+-static errno_t ipa_refresh_users_recv(struct tevent_req *req)
+-{
+-    return ipa_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-ipa_refresh_groups_send(TALLOC_CTX *mem_ctx,
+-                         struct tevent_context *ev,
+-                         struct be_ctx *be_ctx,
+-                         struct sss_domain_info *domain,
+-                         char **names,
+-                         void *pvt)
+-{
+-    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_GROUP, names, pvt);
+-}
+-
+-static errno_t ipa_refresh_groups_recv(struct tevent_req *req)
+-{
+-    return ipa_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-ipa_refresh_netgroups_send(TALLOC_CTX *mem_ctx,
+-                            struct tevent_context *ev,
+-                            struct be_ctx *be_ctx,
+-                            struct sss_domain_info *domain,
+-                            char **names,
+-                            void *pvt)
+-{
+-    return ipa_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                           BE_REQ_NETGROUP, names, pvt);
+-}
+-
+-static errno_t ipa_refresh_netgroups_recv(struct tevent_req *req)
+-{
+-    return ipa_refresh_recv(req);
+-}
++REFRESH_SEND_RECV_FNS(ipa_refresh_initgroups, ipa_refresh, BE_REQ_INITGROUPS);
++REFRESH_SEND_RECV_FNS(ipa_refresh_users, ipa_refresh, BE_REQ_USER);
++REFRESH_SEND_RECV_FNS(ipa_refresh_groups, ipa_refresh, BE_REQ_GROUP);
++REFRESH_SEND_RECV_FNS(ipa_refresh_netgroups, ipa_refresh, BE_REQ_NETGROUP);
+ 
+ errno_t ipa_refresh_init(struct be_ctx *be_ctx,
+                          struct ipa_id_ctx *id_ctx)
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index ff4d2116d..4e464b2f6 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -186,73 +186,10 @@ static errno_t sdap_refresh_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
+-static struct tevent_req *
+-sdap_refresh_initgroups_send(TALLOC_CTX *mem_ctx,
+-                        struct tevent_context *ev,
+-                        struct be_ctx *be_ctx,
+-                        struct sss_domain_info *domain,
+-                        char **names,
+-                        void *pvt)
+-{
+-    return sdap_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                             BE_REQ_INITGROUPS, names, pvt);
+-}
+-
+-static errno_t sdap_refresh_initgroups_recv(struct tevent_req *req)
+-{
+-    return sdap_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-sdap_refresh_users_send(TALLOC_CTX *mem_ctx,
+-                        struct tevent_context *ev,
+-                        struct be_ctx *be_ctx,
+-                        struct sss_domain_info *domain,
+-                        char **names,
+-                        void *pvt)
+-{
+-    return sdap_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                             BE_REQ_USER, names, pvt);
+-}
+-
+-static errno_t sdap_refresh_users_recv(struct tevent_req *req)
+-{
+-    return sdap_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-sdap_refresh_groups_send(TALLOC_CTX *mem_ctx,
+-                         struct tevent_context *ev,
+-                         struct be_ctx *be_ctx,
+-                         struct sss_domain_info *domain,
+-                         char **names,
+-                         void *pvt)
+-{
+-    return sdap_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                             BE_REQ_GROUP, names, pvt);
+-}
+-
+-static errno_t sdap_refresh_groups_recv(struct tevent_req *req)
+-{
+-    return sdap_refresh_recv(req);
+-}
+-
+-static struct tevent_req *
+-sdap_refresh_netgroups_send(TALLOC_CTX *mem_ctx,
+-                            struct tevent_context *ev,
+-                            struct be_ctx *be_ctx,
+-                            struct sss_domain_info *domain,
+-                            char **names,
+-                            void *pvt)
+-{
+-    return sdap_refresh_send(mem_ctx, ev, be_ctx, domain,
+-                             BE_REQ_NETGROUP, names, pvt);
+-}
+-
+-static errno_t sdap_refresh_netgroups_recv(struct tevent_req *req)
+-{
+-    return sdap_refresh_recv(req);
+-}
++REFRESH_SEND_RECV_FNS(sdap_refresh_initgroups, sdap_refresh, BE_REQ_INITGROUPS);
++REFRESH_SEND_RECV_FNS(sdap_refresh_users, sdap_refresh, BE_REQ_USER);
++REFRESH_SEND_RECV_FNS(sdap_refresh_groups, sdap_refresh, BE_REQ_GROUP);
++REFRESH_SEND_RECV_FNS(sdap_refresh_netgroups, sdap_refresh, BE_REQ_NETGROUP);
+ 
+ errno_t sdap_refresh_init(struct be_ctx *be_ctx,
+                           struct sdap_id_ctx *id_ctx)
+-- 
+2.20.1
+
diff --git a/SOURCES/0062-MAN-Amend-the-documentation-for-the-background-refre.patch b/SOURCES/0062-MAN-Amend-the-documentation-for-the-background-refre.patch
new file mode 100644
index 0000000..c0b6a83
--- /dev/null
+++ b/SOURCES/0062-MAN-Amend-the-documentation-for-the-background-refre.patch
@@ -0,0 +1,39 @@
+From 84f2dca9c02908eaed1a5bea2d44329e1050f9c7 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 26 Jun 2019 12:43:45 +0200
+Subject: [PATCH 62/64] MAN: Amend the documentation for the background refresh
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 039384b8851bb6a2513af83dba0df318432e0c63)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/man/sssd.conf.5.xml | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 3f05b3942..277a3c0cb 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2081,7 +2081,15 @@ pam_p11_allowed_services = +my_pam_service, -login
+                         </para>
+                         <para>
+                             The background refresh will process users,
+-                            groups and netgroups in the cache.
++                            groups and netgroups in the cache. For users
++                            who have performed the initgroups (get group
++                            membership for user, typically ran at login)
++                            operation in the past, both the user entry
++                            and the group membership are updated.
++                        </para>
++                        <para>
++                            This option is automatically inherited for all
++                            trusted domains.
+                         </para>
+                         <para>
+                             You can consider setting this value to
+-- 
+2.20.1
+
diff --git a/SOURCES/0063-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch b/SOURCES/0063-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch
new file mode 100644
index 0000000..c759d4f
--- /dev/null
+++ b/SOURCES/0063-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch
@@ -0,0 +1,219 @@
+From 3543c929ea2264ae83cc5de195a33b48da5dfd16 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 1 Jul 2019 14:15:29 +0200
+Subject: [PATCH 63/64] DP/SYSDB: Move the code to set initgrExpireTimestamp to
+ a reusable function
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+Because the initgroups request can, especially in the case of IPA provider
+with trusts, contain several sub-requests that run some provider-specific
+initgroups internally and then run post-processing AND because at the same
+time concurrent requests in the responder need to be sure that the
+initgrExpireTimestamp is only increased when the initgroups request is
+really done, we only set the initgrExpireTimestamp in the DP when the
+request finishes.
+
+This means, the background refresh task needs to also set the
+initgrExpireTimestamp attribute on its own as well. This patch so far
+splits the helper function into a reusable one so it can later be used
+by the background refresh.
+
+For examples of the bugs caused by the initgrTimestamp being set before
+the whole multi-step operation finishes, please see tickets #3744
+or #2634.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 7a08d1dea8cb9148ba1afe13f4d4567229c9b381)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/db/sysdb.h                             | 11 ++++
+ src/db/sysdb_ops.c                         | 70 ++++++++++++++++++++++
+ src/providers/data_provider/dp_target_id.c | 55 ++---------------
+ 3 files changed, 85 insertions(+), 51 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 15df1a726..dfd91f6b8 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1122,6 +1122,17 @@ errno_t sysdb_store_override(struct sss_domain_info *domain,
+                              enum sysdb_member_type type,
+                              struct sysdb_attrs *attrs, struct ldb_dn *obj_dn);
+ 
++/*
++ * Cache the time of last initgroups invocation. Typically this is not done when
++ * the provider-specific request itself finishes, because currently the request
++ * might hand over to other requests from a different provider (e.g. an AD user
++ * from a trusted domain might need to also call an IPA request to fetch the
++ * external groups). Instead, the caller of the initgroups request, typically
++ * the DP or the periodical refresh task sets the timestamp.
++ */
++errno_t sysdb_set_initgr_expire_timestamp(struct sss_domain_info *domain,
++                                          const char *name_or_upn_or_sid);
++
+ /* Password caching function.
+  * If you are in a transaction ignore sysdb and pass in the handle.
+  * If you are not in a transaction pass NULL in handle and provide sysdb,
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index 340062f6f..fa3842d8f 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -3259,6 +3259,76 @@ int sysdb_cache_password(struct sss_domain_info *domain,
+                                    SSS_AUTHTOK_TYPE_PASSWORD, 0);
+ }
+ 
++static errno_t set_initgroups_expire_attribute(struct sss_domain_info *domain,
++                                               const char *name)
++{
++    errno_t ret;
++    time_t cache_timeout;
++    struct sysdb_attrs *attrs;
++
++    attrs = sysdb_new_attrs(NULL);
++    if (attrs == NULL) {
++        return ENOMEM;
++    }
++
++    cache_timeout = domain->user_timeout
++                        ? time(NULL) + domain->user_timeout
++                        : 0;
++
++    ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, cache_timeout);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
++        goto done;
++    }
++
++    ret = sysdb_set_user_attr(domain, name, attrs, SYSDB_MOD_REP);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Failed to set initgroups expire attribute\n");
++        goto done;
++    }
++
++done:
++    talloc_zfree(attrs);
++    return ret;
++}
++
++errno_t sysdb_set_initgr_expire_timestamp(struct sss_domain_info *domain,
++                                          const char *name_or_upn_or_sid)
++{
++    const char *cname;
++    errno_t ret;
++    TALLOC_CTX *tmp_ctx;
++
++    tmp_ctx = talloc_new(NULL);
++    if (!tmp_ctx) {
++        return ENOMEM;
++    }
++
++    ret = sysdb_get_real_name(tmp_ctx, domain, name_or_upn_or_sid, &cname);
++    if (ret == ENOENT) {
++        /* No point trying to bump timestamp of an entry that does not exist..*/
++        ret = EOK;
++        goto done;
++    } else if (ret != EOK) {
++        cname = name_or_upn_or_sid;
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Failed to canonicalize name, using [%s]\n", name_or_upn_or_sid);
++    }
++
++    ret = set_initgroups_expire_attribute(domain, cname);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot set the initgroups expire attribute [%d]: %s\n",
++              ret, sss_strerror(ret));
++    }
++
++    ret = EOK;
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ /* =Custom Search================== */
+ 
+ int sysdb_search_custom(TALLOC_CTX *mem_ctx,
+diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
+index d123638eb..591ddd32d 100644
+--- a/src/providers/data_provider/dp_target_id.c
++++ b/src/providers/data_provider/dp_target_id.c
+@@ -372,69 +372,22 @@ done:
+     talloc_free(tmp_ctx);
+ }
+ 
+-static errno_t set_initgroups_expire_attribute(struct sss_domain_info *domain,
+-                                               const char *name)
+-{
+-    errno_t ret;
+-    time_t cache_timeout;
+-    struct sysdb_attrs *attrs;
+-
+-    attrs = sysdb_new_attrs(NULL);
+-    if (attrs == NULL) {
+-        return ENOMEM;
+-    }
+-
+-    cache_timeout = domain->user_timeout
+-                        ? time(NULL) + domain->user_timeout
+-                        : 0;
+-
+-    ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, cache_timeout);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
+-        goto done;
+-    }
+-
+-    ret = sysdb_set_user_attr(domain, name, attrs, SYSDB_MOD_REP);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Failed to set initgroups expire attribute\n");
+-        goto done;
+-    }
+-
+-done:
+-    talloc_zfree(attrs);
+-    return ret;
+-}
+-
+ static void dp_req_initgr_pp_set_initgr_timestamp(struct dp_initgr_ctx *ctx,
+                                                   struct dp_reply_std *reply)
+ {
+     errno_t ret;
+-    const char *cname;
+ 
+     if (reply->dp_error != DP_ERR_OK || reply->error != EOK) {
+         /* Only bump the timestamp on successful lookups */
+         return;
+     }
+ 
+-    ret = sysdb_get_real_name(ctx,
+-                              ctx->domain_info,
+-                              ctx->filter_value,
+-                              &cname);
+-    if (ret == ENOENT) {
+-        /* No point trying to bump timestamp of an entry that does not exist..*/
+-        return;
+-    } else if (ret != EOK) {
+-        cname = ctx->filter_value;
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Failed to canonicalize name, using [%s]\n", cname);
+-    }
+-
+-    ret = set_initgroups_expire_attribute(ctx->domain_info, cname);
++    ret = sysdb_set_initgr_expire_timestamp(ctx->domain_info,
++                                            ctx->filter_value);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Cannot set the initgroups expire attribute [%d]: %s\n",
+-              ret, sss_strerror(ret));
++              "Failed to set initgroups expiration for [%s]\n",
++              ctx->filter_value);
+     }
+ }
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0064-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch b/SOURCES/0064-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch
new file mode 100644
index 0000000..7062c3c
--- /dev/null
+++ b/SOURCES/0064-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch
@@ -0,0 +1,140 @@
+From e20452153abfc6bd6e941ba10d2e2cd2bc811139 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 1 Jul 2019 14:26:38 +0200
+Subject: [PATCH 64/64] IPA/AD/LDAP: Increase the initgrExpireTimestamp after
+ finishing refresh request
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+Calls sysdb_set_initgr_expire_timestamp() after each successfull refresh
+of initgroups data to make sure the initgrExpireTimestamp attribute is
+increased.
+
+If you're wondering why the timestamp is not set by the initgroups operation
+itself, see tickets #3744 or #2634 for examples of bugs caused by setting
+the initgrExpireTimestamp too soon.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit cdc44a05d11ae614eb55f219f70150d241cd850f)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/providers/ad/ad_refresh.c     | 12 ++++++++++++
+ src/providers/ipa/ipa_refresh.c   | 12 ++++++++++++
+ src/providers/ldap/sdap_refresh.c | 12 ++++++++++++
+ 3 files changed, 36 insertions(+)
+
+diff --git a/src/providers/ad/ad_refresh.c b/src/providers/ad/ad_refresh.c
+index 0c2ebce5e..7aa56f33e 100644
+--- a/src/providers/ad/ad_refresh.c
++++ b/src/providers/ad/ad_refresh.c
+@@ -26,6 +26,7 @@ struct ad_refresh_state {
+     struct be_ctx *be_ctx;
+     struct dp_id_data *account_req;
+     struct ad_id_ctx *id_ctx;
++    struct sss_domain_info *domain;
+     char **names;
+     size_t index;
+ };
+@@ -60,6 +61,7 @@ static struct tevent_req *ad_refresh_send(TALLOC_CTX *mem_ctx,
+ 
+     state->ev = ev;
+     state->be_ctx = be_ctx;
++    state->domain = domain;
+     state->id_ctx = talloc_get_type(pvt, struct ad_id_ctx);
+     state->names = names;
+     state->index = 0;
+@@ -167,6 +169,16 @@ static void ad_refresh_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
++    if (state->account_req->entry_type == BE_REQ_INITGROUPS) {
++        ret = sysdb_set_initgr_expire_timestamp(state->domain,
++                                                state->account_req->filter_value);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Failed to set initgroups expiration for [%s]\n",
++                  state->account_req->filter_value);
++        }
++    }
++
+     ret = ad_refresh_step(req);
+     if (ret == EAGAIN) {
+         return;
+diff --git a/src/providers/ipa/ipa_refresh.c b/src/providers/ipa/ipa_refresh.c
+index 13c38dff9..64f8db812 100644
+--- a/src/providers/ipa/ipa_refresh.c
++++ b/src/providers/ipa/ipa_refresh.c
+@@ -26,6 +26,7 @@ struct ipa_refresh_state {
+     struct be_ctx *be_ctx;
+     struct dp_id_data *account_req;
+     struct ipa_id_ctx *id_ctx;
++    struct sss_domain_info *domain;
+     char **names;
+     size_t index;
+ };
+@@ -59,6 +60,7 @@ static struct tevent_req *ipa_refresh_send(TALLOC_CTX *mem_ctx,
+ 
+     state->ev = ev;
+     state->be_ctx = be_ctx;
++    state->domain = domain;
+     state->id_ctx = talloc_get_type(pvt, struct ipa_id_ctx);
+     state->names = names;
+     state->index = 0;
+@@ -147,6 +149,16 @@ static void ipa_refresh_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
++    if (state->account_req->entry_type == BE_REQ_INITGROUPS) {
++        ret = sysdb_set_initgr_expire_timestamp(state->domain,
++                                                state->account_req->filter_value);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Failed to set initgroups expiration for [%s]\n",
++                  state->account_req->filter_value);
++        }
++    }
++
+     ret = ipa_refresh_step(req);
+     if (ret == EAGAIN) {
+         return;
+diff --git a/src/providers/ldap/sdap_refresh.c b/src/providers/ldap/sdap_refresh.c
+index 4e464b2f6..402db53a9 100644
+--- a/src/providers/ldap/sdap_refresh.c
++++ b/src/providers/ldap/sdap_refresh.c
+@@ -29,6 +29,7 @@ struct sdap_refresh_state {
+     struct be_ctx *be_ctx;
+     struct dp_id_data *account_req;
+     struct sdap_id_ctx *id_ctx;
++    struct sss_domain_info *domain;
+     struct sdap_domain *sdom;
+     char **names;
+     size_t index;
+@@ -63,6 +64,7 @@ static struct tevent_req *sdap_refresh_send(TALLOC_CTX *mem_ctx,
+ 
+     state->ev = ev;
+     state->be_ctx = be_ctx;
++    state->domain = domain;
+     state->id_ctx = talloc_get_type(pvt, struct sdap_id_ctx);
+     state->names = names;
+     state->index = 0;
+@@ -165,6 +167,16 @@ static void sdap_refresh_done(struct tevent_req *subreq)
+         goto done;
+     }
+ 
++    if (state->account_req->entry_type == BE_REQ_INITGROUPS) {
++        ret = sysdb_set_initgr_expire_timestamp(state->domain,
++                                                state->account_req->filter_value);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Failed to set initgroups expiration for [%s]\n",
++                  state->account_req->filter_value);
++        }
++    }
++
+     ret = sdap_refresh_step(req);
+     if (ret == EAGAIN) {
+         return;
+-- 
+2.20.1
+
diff --git a/SOURCES/0065-sss_ptr_hash-add-sss_ptr_get_value-to-make-it-useful.patch b/SOURCES/0065-sss_ptr_hash-add-sss_ptr_get_value-to-make-it-useful.patch
new file mode 100644
index 0000000..50466dc
--- /dev/null
+++ b/SOURCES/0065-sss_ptr_hash-add-sss_ptr_get_value-to-make-it-useful.patch
@@ -0,0 +1,102 @@
+From 79560617790781384dda2751701b523aed6b5cb4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Sat, 3 Feb 2018 10:58:06 +0100
+Subject: [PATCH 65/90] sss_ptr_hash: add sss_ptr_get_value to make it useful
+ in delete callbacks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/util/sss_ptr_hash.c | 31 +++++++++++++++++++++++++++++++
+ src/util/sss_ptr_hash.h | 15 +++++++++++++++
+ 2 files changed, 46 insertions(+)
+
+diff --git a/src/util/sss_ptr_hash.c b/src/util/sss_ptr_hash.c
+index 0f884c8b6..bc0db6f48 100644
+--- a/src/util/sss_ptr_hash.c
++++ b/src/util/sss_ptr_hash.c
+@@ -263,6 +263,12 @@ sss_ptr_hash_lookup_internal(hash_table_t *table,
+         return NULL;
+     }
+ 
++    /* This may happen if we are in delete callback
++     * and we try to search the hash table. */
++    if (table_value.ptr == NULL) {
++        return NULL;
++    }
++
+     if (!sss_ptr_hash_check_type(table_value.ptr, "struct sss_ptr_hash_value")) {
+         return NULL;
+     }
+@@ -288,6 +294,31 @@ void *_sss_ptr_hash_lookup(hash_table_t *table,
+     return value->ptr;
+ }
+ 
++void *_sss_ptr_get_value(hash_value_t *table_value,
++                         const char *type)
++{
++    struct sss_ptr_hash_value *value;
++
++    /* Check value type. */
++    if (table_value->type != HASH_VALUE_PTR) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid value type found: %d\n",
++              table_value->type);
++        return NULL;
++    }
++
++    if (!sss_ptr_hash_check_type(table_value->ptr, "struct sss_ptr_hash_value")) {
++        return NULL;
++    }
++
++    value = table_value->ptr;
++
++    if (!sss_ptr_hash_check_type(value->ptr, type)) {
++        return NULL;
++    }
++
++    return value->ptr;
++}
++
+ void sss_ptr_hash_delete(hash_table_t *table,
+                          const char *key,
+                          bool free_value)
+diff --git a/src/util/sss_ptr_hash.h b/src/util/sss_ptr_hash.h
+index 510b9544f..56bb19a65 100644
+--- a/src/util/sss_ptr_hash.h
++++ b/src/util/sss_ptr_hash.h
+@@ -24,6 +24,8 @@
+ #include <talloc.h>
+ #include <dhash.h>
+ 
++#include "util/util.h"
++
+ /**
+  * Create a new hash table with string key and talloc pointer value with
+  * possible delete callback.
+@@ -91,6 +93,19 @@ void *_sss_ptr_hash_lookup(hash_table_t *table,
+ #define sss_ptr_hash_lookup(table, key, type) \
+     (type *)_sss_ptr_hash_lookup(table, key, #type)
+ 
++void *_sss_ptr_get_value(hash_value_t *table_value,
++                         const char *type);
++
++/**
++ * Obtain inserted talloc pointer from table value typed to @type.
++ * The type of the value must match with @type, otherwise NULL is returned.
++ *
++ * @return talloc_ptr If the value is found as type matches.
++ * @return NULL If the value is not found or if the type is invalid.
++ */
++#define sss_ptr_get_value(table_value, type) \
++    (type *)_sss_ptr_get_value(table_value, #type)
++
+ /**
+  * Delete @key from table. If @free_value is true then also the value
+  * associated with @key is freed, otherwise it is left intact.
+-- 
+2.20.1
+
diff --git a/SOURCES/0066-sss_ptr_hash-keep-value-pointer-when-destroying-spy.patch b/SOURCES/0066-sss_ptr_hash-keep-value-pointer-when-destroying-spy.patch
new file mode 100644
index 0000000..0350bcf
--- /dev/null
+++ b/SOURCES/0066-sss_ptr_hash-keep-value-pointer-when-destroying-spy.patch
@@ -0,0 +1,34 @@
+From 00926ab450074741e2a2b5c699c440e6309e3bff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 2 Sep 2019 13:48:13 +0200
+Subject: [PATCH 66/90] sss_ptr_hash: keep value pointer when destroying spy
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Oterwise its value in delete callback is NULL.
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/util/sss_ptr_hash.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/util/sss_ptr_hash.c b/src/util/sss_ptr_hash.c
+index bc0db6f48..e8fd19ca8 100644
+--- a/src/util/sss_ptr_hash.c
++++ b/src/util/sss_ptr_hash.c
+@@ -59,10 +59,10 @@ static int
+ sss_ptr_hash_spy_destructor(struct sss_ptr_hash_spy *spy)
+ {
+     spy->value->spy = NULL;
+-    spy->value->ptr = NULL;
+ 
+     /* This results in removing entry from hash table and freeing the value. */
+     sss_ptr_hash_delete(spy->table, spy->key, false);
++
+     return 0;
+ }
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0067-autofs-fix-typo-in-test-tool.patch b/SOURCES/0067-autofs-fix-typo-in-test-tool.patch
new file mode 100644
index 0000000..97fb9b0
--- /dev/null
+++ b/SOURCES/0067-autofs-fix-typo-in-test-tool.patch
@@ -0,0 +1,29 @@
+From 49ad0b9b84c88d52694c8e9f5582dc49d0f87e2a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 5 Aug 2019 10:21:30 +0200
+Subject: [PATCH 67/90] autofs: fix typo in test tool
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/sss_client/autofs/autofs_test_client.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/sss_client/autofs/autofs_test_client.c b/src/sss_client/autofs/autofs_test_client.c
+index f4395ff7c..6bbd2a0e8 100644
+--- a/src/sss_client/autofs/autofs_test_client.c
++++ b/src/sss_client/autofs/autofs_test_client.c
+@@ -103,7 +103,7 @@ int main(int argc, const char *argv[])
+         if (ret == ENOENT) {
+             fprintf(stderr, "no such entry in map\n");
+         } else if (ret != 0) {
+-            fprintf(stderr, "getautomntent_r failed [%d]: %s\n",
++            fprintf(stderr, "getautomntbyname_r failed [%d]: %s\n",
+                     ret, strerror(ret));
+             goto end;
+         } else {
+-- 
+2.20.1
+
diff --git a/SOURCES/0068-sysdb-add-expiration-time-to-autofs-entries.patch b/SOURCES/0068-sysdb-add-expiration-time-to-autofs-entries.patch
new file mode 100644
index 0000000..36b09c3
--- /dev/null
+++ b/SOURCES/0068-sysdb-add-expiration-time-to-autofs-entries.patch
@@ -0,0 +1,155 @@
+From ccf14f490985b96bd6f5871b55c1398024e34af0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 13 Aug 2019 12:21:47 +0200
+Subject: [PATCH 68/90] sysdb: add expiration time to autofs entries
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will be later used to expire single entries during
+`get entry by name` operation.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb_autofs.c                  | 13 ++++++++++++-
+ src/db/sysdb_autofs.h                  |  4 +++-
+ src/db/sysdb_upgrade.c                 |  2 +-
+ src/providers/ldap/sdap_async_autofs.c | 11 ++++++++---
+ src/tests/sysdb-tests.c                |  4 ++--
+ 5 files changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
+index 89803a778..c92a51658 100644
+--- a/src/db/sysdb_autofs.c
++++ b/src/db/sysdb_autofs.c
+@@ -248,7 +248,9 @@ sysdb_save_autofsentry(struct sss_domain_info *domain,
+                        const char *map,
+                        const char *key,
+                        const char *value,
+-                       struct sysdb_attrs *attrs)
++                       struct sysdb_attrs *attrs,
++                       int cache_timeout,
++                       time_t now)
+ {
+     errno_t ret;
+     TALLOC_CTX *tmp_ctx;
+@@ -307,6 +309,15 @@ sysdb_save_autofsentry(struct sss_domain_info *domain,
+         goto done;
+     }
+ 
++    ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
++                                 ((cache_timeout) ?
++                                  (now + cache_timeout) : 0));
++    if (ret) {
++        DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb cache expire [%d]: %s\n",
++              ret, strerror(ret));
++        goto done;
++    }
++
+     dn = sysdb_autofsentry_dn(tmp_ctx, domain, map, key, value);
+     if (!dn) {
+         ret = ENOMEM;
+diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h
+index d1ef8412e..a3aba726c 100644
+--- a/src/db/sysdb_autofs.h
++++ b/src/db/sysdb_autofs.h
+@@ -58,7 +58,9 @@ sysdb_save_autofsentry(struct sss_domain_info *domain,
+                        const char *map,
+                        const char *key,
+                        const char *value,
+-                       struct sysdb_attrs *attrs);
++                       struct sysdb_attrs *attrs,
++                       int cache_timeout,
++                       time_t now);
+ errno_t
+ sysdb_del_autofsentry(struct sss_domain_info *domain,
+                       const char *entry_dn);
+diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
+index f6a481147..392d04b07 100644
+--- a/src/db/sysdb_upgrade.c
++++ b/src/db/sysdb_upgrade.c
+@@ -1255,7 +1255,7 @@ int sysdb_upgrade_11(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
+ 
+                 ret = sysdb_save_autofsentry(domain,
+                                              (const char *) val->data,
+-                                             key, value, NULL);
++                                             key, value, NULL, 0, 0);
+                 if (ret != EOK) {
+                     DEBUG(SSSDBG_OP_FAILURE,
+                           "Cannot save autofs entry [%s]-[%s] into map %s\n",
+diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
+index 8d1742ad1..787283872 100644
+--- a/src/providers/ldap/sdap_async_autofs.c
++++ b/src/providers/ldap/sdap_async_autofs.c
+@@ -86,7 +86,8 @@ static errno_t
+ add_autofs_entry(struct sss_domain_info *domain,
+                  const char *map,
+                  struct sdap_options *opts,
+-                 struct sysdb_attrs *entry)
++                 struct sysdb_attrs *entry,
++                 time_t now)
+ {
+     const char *key;
+     const char *value;
+@@ -103,7 +104,8 @@ add_autofs_entry(struct sss_domain_info *domain,
+         return EINVAL;
+     }
+ 
+-    return sysdb_save_autofsentry(domain, map, key, value, NULL);
++    return sysdb_save_autofsentry(domain, map, key, value, NULL,
++                                  domain->autofsmap_timeout, now);
+ }
+ 
+ static errno_t
+@@ -119,11 +121,14 @@ save_autofs_entries(struct sss_domain_info *domain,
+     int hret;
+     errno_t ret;
+     struct sysdb_attrs *entry;
++    time_t now;
+ 
+     if (!add_dn_list) {
+         return EOK;
+     }
+ 
++    now = time(NULL);
++
+     for (i=0; add_dn_list[i]; i++) {
+         key.type = HASH_KEY_STRING;
+         key.str = (char *) add_dn_list[i];
+@@ -144,7 +149,7 @@ save_autofs_entries(struct sss_domain_info *domain,
+ 
+         DEBUG(SSSDBG_TRACE_FUNC,
+               "Saving autofs entry [%s]\n", add_dn_list[i]);
+-        ret = add_autofs_entry(domain, map, opts, entry);
++        ret = add_autofs_entry(domain, map, opts, entry, now);
+         if (ret) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+                   "Cannot save entry [%s] to cache\n", add_dn_list[i]);
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index 832d60466..23f2bd383 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -6466,7 +6466,7 @@ START_TEST(test_autofs_store_entry_in_map)
+ 
+         ret = sysdb_save_autofsentry(test_ctx->domain,
+                                      autofsmapname, autofskey,
+-                                     autofsval, NULL);
++                                     autofsval, NULL, 0, 0);
+         fail_if(ret != EOK, "Could not save autofs entry %s", autofskey);
+     }
+ 
+@@ -6521,7 +6521,7 @@ START_TEST(test_autofs_key_duplicate)
+ 
+     ret = sysdb_save_autofsentry(test_ctx->domain,
+                                  autofsmapname, autofskey,
+-                                 autofsval, NULL);
++                                 autofsval, NULL, 0, 0);
+     fail_if(ret != EOK, "Could not save autofs entry %s", autofskey);
+     talloc_free(test_ctx);
+ }
+-- 
+2.20.1
+
diff --git a/SOURCES/0069-sysdb-add-sysdb_get_autofsentry.patch b/SOURCES/0069-sysdb-add-sysdb_get_autofsentry.patch
new file mode 100644
index 0000000..27ca583
--- /dev/null
+++ b/SOURCES/0069-sysdb-add-sysdb_get_autofsentry.patch
@@ -0,0 +1,123 @@
+From 57e33404e0f98d9358e8c31eb2c2f764ee380b13 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 13 Aug 2019 12:59:49 +0200
+Subject: [PATCH 69/90] sysdb: add sysdb_get_autofsentry
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb_autofs.c | 73 +++++++++++++++++++++++++++++++++++++++++++
+ src/db/sysdb_autofs.h |  8 +++++
+ 2 files changed, 81 insertions(+)
+
+diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
+index c92a51658..f5186451e 100644
+--- a/src/db/sysdb_autofs.c
++++ b/src/db/sysdb_autofs.c
+@@ -341,6 +341,79 @@ done:
+     return ret;
+ }
+ 
++errno_t
++sysdb_get_autofsentry(TALLOC_CTX *mem_ctx,
++                      struct sss_domain_info *domain,
++                      const char *map_name,
++                      const char *entry_name,
++                      struct ldb_message **_entry)
++{
++    TALLOC_CTX *tmp_ctx;
++    char *safe_entryname;
++    char *filter;
++    struct ldb_dn *mapdn;
++    size_t count;
++    struct ldb_message **msgs;
++    errno_t ret;
++    const char *attrs[] = { SYSDB_AUTOFS_ENTRY_KEY,
++                            SYSDB_AUTOFS_ENTRY_VALUE,
++                            SYSDB_CACHE_EXPIRE,
++                            NULL };
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
++        return ENOMEM;
++    }
++
++    ret = sss_filter_sanitize(tmp_ctx, entry_name, &safe_entryname);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Cannot sanitize map [%s] error [%d]: %s\n",
++               map_name, ret, strerror(ret));
++        goto done;
++    }
++
++    filter = talloc_asprintf(tmp_ctx, "(&(objectclass=%s)(%s=%s))",
++                             SYSDB_AUTOFS_ENTRY_OC, SYSDB_AUTOFS_ENTRY_KEY,
++                             safe_entryname);
++    if (filter == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    mapdn = sysdb_autofsmap_dn(tmp_ctx, domain, map_name);
++    if (!mapdn) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_SUBTREE,
++                             filter, attrs, &count, &msgs);
++    if (ret == ENOENT) {
++        goto done;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "sysdb search failed: %d\n", ret);
++        goto done;
++    }
++
++    if (count != 1) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "More than one entry %s:%s found\n",
++              map_name, entry_name);
++        ret = ERR_INTERNAL;
++        goto done;
++    }
++
++    *_entry = talloc_steal(mem_ctx, msgs[0]);
++
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
+ errno_t
+ sysdb_del_autofsentry(struct sss_domain_info *domain,
+                       const char *entry_dn)
+diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h
+index a3aba726c..0cbe6ddbf 100644
+--- a/src/db/sysdb_autofs.h
++++ b/src/db/sysdb_autofs.h
+@@ -61,6 +61,14 @@ sysdb_save_autofsentry(struct sss_domain_info *domain,
+                        struct sysdb_attrs *attrs,
+                        int cache_timeout,
+                        time_t now);
++
++errno_t
++sysdb_get_autofsentry(TALLOC_CTX *mem_ctx,
++                      struct sss_domain_info *domain,
++                      const char *map_name,
++                      const char *entry_name,
++                      struct ldb_message **_entry);
++
+ errno_t
+ sysdb_del_autofsentry(struct sss_domain_info *domain,
+                       const char *entry_dn);
+-- 
+2.20.1
+
diff --git a/SOURCES/0070-sysdb-add-enumerationExpireTimestamp.patch b/SOURCES/0070-sysdb-add-enumerationExpireTimestamp.patch
new file mode 100644
index 0000000..933eab4
--- /dev/null
+++ b/SOURCES/0070-sysdb-add-enumerationExpireTimestamp.patch
@@ -0,0 +1,31 @@
+From c366050029983969cbaf3795f05115893f7617e9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 14 Aug 2019 11:37:10 +0200
+Subject: [PATCH 70/90] sysdb: add enumerationExpireTimestamp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index dfd91f6b8..0a7e7c4f8 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -98,6 +98,7 @@
+ #define SYSDB_LAST_UPDATE "lastUpdate"
+ #define SYSDB_CACHE_EXPIRE "dataExpireTimestamp"
+ #define SYSDB_INITGR_EXPIRE "initgrExpireTimestamp"
++#define SYSDB_ENUM_EXPIRE "enumerationExpireTimestamp"
+ #define SYSDB_IFP_CACHED "ifpCached"
+ 
+ #define SYSDB_AUTHORIZED_SERVICE "authorizedService"
+-- 
+2.20.1
+
diff --git a/SOURCES/0071-sysdb-store-enumeration-expiration-time-in-autofs-ma.patch b/SOURCES/0071-sysdb-store-enumeration-expiration-time-in-autofs-ma.patch
new file mode 100644
index 0000000..9bd8c98
--- /dev/null
+++ b/SOURCES/0071-sysdb-store-enumeration-expiration-time-in-autofs-ma.patch
@@ -0,0 +1,139 @@
+From 11ffb775d725172a4247a9826cadecb872c7d0dc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 14 Aug 2019 12:29:56 +0200
+Subject: [PATCH 71/90] sysdb: store enumeration expiration time in autofs map
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We need to distinguish between 'object expired' when we need
+to obtain only the map entry and 'enumeration expired' when
+we need to enumerated the map entry.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb_autofs.c                  | 22 ++++++++++++++++++----
+ src/db/sysdb_autofs.h                  |  3 ++-
+ src/providers/ldap/sdap_async_autofs.c |  7 ++++---
+ src/tests/sysdb-tests.c                |  2 +-
+ 4 files changed, 25 insertions(+), 9 deletions(-)
+
+diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
+index f5186451e..dc1ea5586 100644
+--- a/src/db/sysdb_autofs.c
++++ b/src/db/sysdb_autofs.c
+@@ -101,8 +101,10 @@ sysdb_save_autofsmap(struct sss_domain_info *domain,
+                      const char *autofsmapname,
+                      struct sysdb_attrs *attrs,
+                      int cache_timeout,
+-                     time_t now)
++                     time_t now,
++                     bool enumerated)
+ {
++    time_t expiration = cache_timeout ? now + cache_timeout : 0;
+     errno_t ret;
+     TALLOC_CTX *tmp_ctx;
+ 
+@@ -150,15 +152,22 @@ sysdb_save_autofsmap(struct sss_domain_info *domain,
+         goto done;
+     }
+ 
+-    ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
+-                                 ((cache_timeout) ?
+-                                  (now + cache_timeout) : 0));
++    ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE, expiration);
+     if (ret) {
+         DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb cache expire [%d]: %s\n",
+               ret, strerror(ret));
+         goto done;
+     }
+ 
++    if (enumerated) {
++        ret = sysdb_attrs_add_time_t(attrs, SYSDB_ENUM_EXPIRE, expiration);
++        if (ret) {
++            DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb enum expire [%d]: %s\n",
++                  ret, strerror(ret));
++            goto done;
++        }
++    }
++
+     ret = sysdb_store_custom(domain, name, AUTOFS_MAP_SUBDIR, attrs);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_custom failed [%d]: %s\n",
+@@ -569,6 +578,11 @@ sysdb_invalidate_autofs_maps(struct sss_domain_info *domain)
+         goto done;
+     }
+ 
++    ret = sysdb_attrs_add_time_t(sys_attrs, SYSDB_ENUM_EXPIRE, 1);
++    if (ret != EOK) {
++        goto done;
++    }
++
+     ret = sysdb_transaction_start(domain->sysdb);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h
+index 0cbe6ddbf..7170334c6 100644
+--- a/src/db/sysdb_autofs.h
++++ b/src/db/sysdb_autofs.h
+@@ -41,7 +41,8 @@ sysdb_save_autofsmap(struct sss_domain_info *domain,
+                      const char *autofsmapname,
+                      struct sysdb_attrs *attrs,
+                      int cache_timeout,
+-                     time_t now);
++                     time_t now,
++                     bool enumerated);
+ 
+ errno_t
+ sysdb_get_map_byname(TALLOC_CTX *mem_ctx,
+diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
+index 787283872..453e95f7b 100644
+--- a/src/providers/ldap/sdap_async_autofs.c
++++ b/src/providers/ldap/sdap_async_autofs.c
+@@ -189,7 +189,8 @@ del_autofs_entries(struct sss_domain_info *dom,
+ static errno_t
+ save_autofs_map(struct sss_domain_info *dom,
+                 struct sdap_options *opts,
+-                struct sysdb_attrs *map)
++                struct sysdb_attrs *map,
++                bool enumerated)
+ {
+     const char *mapname;
+     errno_t ret;
+@@ -201,7 +202,7 @@ save_autofs_map(struct sss_domain_info *dom,
+     now = time(NULL);
+ 
+     ret = sysdb_save_autofsmap(dom, mapname, mapname,
+-                               NULL, dom->autofsmap_timeout, now);
++                               NULL, dom->autofsmap_timeout, now, enumerated);
+     if (ret != EOK) {
+         return ret;
+     }
+@@ -898,7 +899,7 @@ sdap_autofs_setautomntent_save(struct tevent_req *req)
+     in_transaction = true;
+ 
+     /* Save the map itself */
+-    ret = save_autofs_map(state->dom, state->opts, state->map);
++    ret = save_autofs_map(state->dom, state->opts, state->map, true);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+              "Cannot save autofs map entry [%d]: %s\n",
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index 23f2bd383..108ef8943 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -6374,7 +6374,7 @@ START_TEST(test_autofs_create_map)
+     fail_if(autofsmapname == NULL, "Out of memory\n");
+ 
+     ret = sysdb_save_autofsmap(test_ctx->domain, autofsmapname,
+-                               autofsmapname, NULL, 0, 0);
++                               autofsmapname, NULL, 0, 0, false);
+     fail_if(ret != EOK, "Could not store autofs map %s", autofsmapname);
+     talloc_free(test_ctx);
+ }
+-- 
+2.20.1
+
diff --git a/SOURCES/0072-sysdb-store-original-dn-in-autofs-map.patch b/SOURCES/0072-sysdb-store-original-dn-in-autofs-map.patch
new file mode 100644
index 0000000..294eccc
--- /dev/null
+++ b/SOURCES/0072-sysdb-store-original-dn-in-autofs-map.patch
@@ -0,0 +1,124 @@
+From efe44597a3f1181fe60771c0efbfcab54585dc42 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 14:20:26 +0200
+Subject: [PATCH 72/90] sysdb: store original dn in autofs map
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will be used later when fetching single entry.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb_autofs.c                  |  9 +++++++++
+ src/db/sysdb_autofs.h                  |  1 +
+ src/providers/ldap/sdap_async_autofs.c | 10 +++++++++-
+ src/tests/sysdb-tests.c                |  6 +++++-
+ 4 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
+index dc1ea5586..971abafa3 100644
+--- a/src/db/sysdb_autofs.c
++++ b/src/db/sysdb_autofs.c
+@@ -99,6 +99,7 @@ errno_t
+ sysdb_save_autofsmap(struct sss_domain_info *domain,
+                      const char *name,
+                      const char *autofsmapname,
++                     const char *origdn,
+                      struct sysdb_attrs *attrs,
+                      int cache_timeout,
+                      time_t now,
+@@ -138,6 +139,13 @@ sysdb_save_autofsmap(struct sss_domain_info *domain,
+         goto done;
+     }
+ 
++    ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, origdn);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Could not set origdn [%d]: %s\n",
++              ret, strerror(ret));
++        goto done;
++    }
++
+     ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Could not set name attribute [%d]: %s\n",
+@@ -202,6 +210,7 @@ sysdb_get_map_byname(TALLOC_CTX *mem_ctx,
+     size_t count;
+     struct ldb_message **msgs;
+     const char *attrs[] = { SYSDB_OBJECTCLASS,
++                            SYSDB_ORIG_DN,
+                             SYSDB_CACHE_EXPIRE,
+                             SYSDB_LAST_UPDATE,
+                             SYSDB_AUTOFS_MAP_NAME,
+diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h
+index 7170334c6..79ecbd94e 100644
+--- a/src/db/sysdb_autofs.h
++++ b/src/db/sysdb_autofs.h
+@@ -39,6 +39,7 @@ errno_t
+ sysdb_save_autofsmap(struct sss_domain_info *domain,
+                      const char *name,
+                      const char *autofsmapname,
++                     const char *origdn,
+                      struct sysdb_attrs *attrs,
+                      int cache_timeout,
+                      time_t now,
+diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
+index 453e95f7b..7548d4a67 100644
+--- a/src/providers/ldap/sdap_async_autofs.c
++++ b/src/providers/ldap/sdap_async_autofs.c
+@@ -193,15 +193,23 @@ save_autofs_map(struct sss_domain_info *dom,
+                 bool enumerated)
+ {
+     const char *mapname;
++    const char *origdn;
+     errno_t ret;
+     time_t now;
+ 
+     mapname = get_autofs_map_name(map, opts);
+     if (!mapname) return EINVAL;
+ 
++    ret = sysdb_attrs_get_string(map, SYSDB_ORIG_DN, &origdn);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get original dn [%d]: %s\n",
++              ret, sss_strerror(ret));
++        return ret;
++    }
++
+     now = time(NULL);
+ 
+-    ret = sysdb_save_autofsmap(dom, mapname, mapname,
++    ret = sysdb_save_autofsmap(dom, mapname, mapname, origdn,
+                                NULL, dom->autofsmap_timeout, now, enumerated);
+     if (ret != EOK) {
+         return ret;
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index 108ef8943..22460d9db 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -6365,6 +6365,7 @@ START_TEST(test_autofs_create_map)
+ {
+     struct sysdb_test_ctx *test_ctx;
+     const char *autofsmapname;
++    const char *origdn;
+     errno_t ret;
+ 
+     ret = setup_sysdb_tests(&test_ctx);
+@@ -6373,8 +6374,11 @@ START_TEST(test_autofs_create_map)
+     autofsmapname = talloc_asprintf(test_ctx, "testmap%d", _i);
+     fail_if(autofsmapname == NULL, "Out of memory\n");
+ 
++    origdn = talloc_asprintf(test_ctx, "cn=testmap%d,dc=test", _i);
++    fail_if(origdn == NULL, "Out of memory\n");
++
+     ret = sysdb_save_autofsmap(test_ctx->domain, autofsmapname,
+-                               autofsmapname, NULL, 0, 0, false);
++                               autofsmapname, origdn, NULL, 0, 0, false);
+     fail_if(ret != EOK, "Could not store autofs map %s", autofsmapname);
+     talloc_free(test_ctx);
+ }
+-- 
+2.20.1
+
diff --git a/SOURCES/0073-sysdb-add-sysdb_del_autofsentry_by_key.patch b/SOURCES/0073-sysdb-add-sysdb_del_autofsentry_by_key.patch
new file mode 100644
index 0000000..894ff88
--- /dev/null
+++ b/SOURCES/0073-sysdb-add-sysdb_del_autofsentry_by_key.patch
@@ -0,0 +1,69 @@
+From 49b5baf0e6ef978d971427160677c2c95e89c418 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 13:50:17 +0200
+Subject: [PATCH 73/90] sysdb: add sysdb_del_autofsentry_by_key
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb_autofs.c | 22 ++++++++++++++++++++++
+ src/db/sysdb_autofs.h |  5 +++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
+index 971abafa3..11841d50d 100644
+--- a/src/db/sysdb_autofs.c
++++ b/src/db/sysdb_autofs.c
+@@ -449,6 +449,28 @@ sysdb_del_autofsentry(struct sss_domain_info *domain,
+     return ret;
+ }
+ 
++errno_t
++sysdb_del_autofsentry_by_key(struct sss_domain_info *domain,
++                             const char *map_name,
++                             const char *entry_key)
++{
++    struct ldb_message *entry;
++    errno_t ret;
++
++    ret = sysdb_get_autofsentry(NULL, domain, map_name, entry_key, &entry);
++    if (ret == ENOENT) {
++        return EOK;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Unable to get autofs entry [%d]: %s\n",
++              ret, sss_strerror(ret));
++        return ret;
++    }
++
++    ret = sysdb_delete_entry(domain->sysdb, entry->dn, true);
++    talloc_free(entry);
++    return ret;
++}
++
+ errno_t
+ sysdb_autofs_entries_by_map(TALLOC_CTX *mem_ctx,
+                             struct sss_domain_info *domain,
+diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h
+index 79ecbd94e..3775e2a17 100644
+--- a/src/db/sysdb_autofs.h
++++ b/src/db/sysdb_autofs.h
+@@ -75,6 +75,11 @@ errno_t
+ sysdb_del_autofsentry(struct sss_domain_info *domain,
+                       const char *entry_dn);
+ 
++errno_t
++sysdb_del_autofsentry_by_key(struct sss_domain_info *domain,
++                             const char *map_name,
++                             const char *entry_key);
++
+ errno_t
+ sysdb_autofs_entries_by_map(TALLOC_CTX *mem_ctx,
+                             struct sss_domain_info *domain,
+-- 
+2.20.1
+
diff --git a/SOURCES/0074-autofs-move-data-provider-functions-to-responder-com.patch b/SOURCES/0074-autofs-move-data-provider-functions-to-responder-com.patch
new file mode 100644
index 0000000..db1a92f
--- /dev/null
+++ b/SOURCES/0074-autofs-move-data-provider-functions-to-responder-com.patch
@@ -0,0 +1,125 @@
+From 4665606235605b1d5d1ec7462257aaa86aa3d7b1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 28 Aug 2019 11:47:07 +0200
+Subject: [PATCH 74/90] autofs: move data provider functions to responder
+ common code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So it can be later used from cache_req.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ Makefile.am                                   |  2 +-
+ src/responder/common/responder.h              | 19 +++++++++++
+ .../responder_dp_autofs.c}                    |  0
+ src/tests/cmocka/common_mock_resp_dp.c        | 34 +++++++++++++++++++
+ 4 files changed, 54 insertions(+), 1 deletion(-)
+ rename src/responder/{autofs/autofssrv_dp.c => common/responder_dp_autofs.c} (100%)
+
+diff --git a/Makefile.am b/Makefile.am
+index e74de422d..c109afe56 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -576,6 +576,7 @@ SSSD_RESPONDER_OBJ = \
+     src/responder/common/responder_common.c \
+     src/responder/common/responder_dp.c \
+     src/responder/common/responder_dp_ssh.c \
++    src/responder/common/responder_dp_autofs.c \
+     src/responder/common/responder_packet.c \
+     src/responder/common/responder_get_domains.c \
+     src/responder/common/responder_utils.c \
+@@ -1434,7 +1435,6 @@ if BUILD_AUTOFS
+ sssd_autofs_SOURCES = \
+     src/responder/autofs/autofssrv.c \
+     src/responder/autofs/autofssrv_cmd.c \
+-    src/responder/autofs/autofssrv_dp.c \
+     $(SSSD_RESPONDER_OBJ)
+ sssd_autofs_LDADD = \
+     $(LIBADD_DL) \
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index 987a5d17d..17b04c3de 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -363,6 +363,25 @@ sss_dp_get_ssh_host_recv(TALLOC_CTX *mem_ctx,
+                          dbus_uint32_t *dp_ret,
+                          char **err_msg);
+ 
++enum sss_dp_autofs_type {
++    SSS_DP_AUTOFS
++};
++
++struct tevent_req *
++sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
++                       struct resp_ctx *rctx,
++                       struct sss_domain_info *dom,
++                       bool fast_reply,
++                       enum sss_dp_autofs_type type,
++                       const char *name);
++
++errno_t
++sss_dp_get_autofs_recv(TALLOC_CTX *mem_ctx,
++                       struct tevent_req *req,
++                       dbus_uint16_t *dp_err,
++                       dbus_uint32_t *dp_ret,
++                       char **err_msg);
++
+ bool sss_utf8_check(const uint8_t *s, size_t n);
+ 
+ void responder_set_fd_limit(rlim_t fd_limit);
+diff --git a/src/responder/autofs/autofssrv_dp.c b/src/responder/common/responder_dp_autofs.c
+similarity index 100%
+rename from src/responder/autofs/autofssrv_dp.c
+rename to src/responder/common/responder_dp_autofs.c
+diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c
+index a85257515..93e507100 100644
+--- a/src/tests/cmocka/common_mock_resp_dp.c
++++ b/src/tests/cmocka/common_mock_resp_dp.c
+@@ -95,6 +95,40 @@ sss_dp_get_ssh_host_recv(TALLOC_CTX *mem_ctx,
+     return test_request_recv(req);
+ }
+ 
++struct tevent_req *
++sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
++                       struct resp_ctx *rctx,
++                       struct sss_domain_info *dom,
++                       bool fast_reply,
++                       enum sss_dp_autofs_type type,
++                       const char *mapname,
++                       const char *entryname)
++{
++    return test_req_succeed_send(mem_ctx, rctx->ev);
++}
++
++
++errno_t
++sss_dp_get_autofs_recv(TALLOC_CTX *mem_ctx,
++                       struct tevent_req *req,
++                       dbus_uint16_t *dp_err,
++                       dbus_uint32_t *dp_ret,
++                       char **err_msg)
++{
++    acct_cb_t cb;
++
++    *dp_err = sss_mock_type(dbus_uint16_t);
++    *dp_ret = sss_mock_type(dbus_uint32_t);
++    *err_msg = sss_mock_ptr_type(char *);
++
++    cb = sss_mock_ptr_type(acct_cb_t);
++    if (cb) {
++        (cb)(sss_mock_ptr_type(void *));
++    }
++
++    return test_request_recv(req);
++}
++
+ errno_t
+ sss_dp_req_recv(TALLOC_CTX *mem_ctx,
+                 struct tevent_req *req,
+-- 
+2.20.1
+
diff --git a/SOURCES/0075-cache_req-add-autofs-map-entries-plugin.patch b/SOURCES/0075-cache_req-add-autofs-map-entries-plugin.patch
new file mode 100644
index 0000000..a8a1121
--- /dev/null
+++ b/SOURCES/0075-cache_req-add-autofs-map-entries-plugin.patch
@@ -0,0 +1,278 @@
+From 01b7dc92180cf80080f657b80f72cec20eafa0e7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 13 Aug 2019 13:31:21 +0200
+Subject: [PATCH 75/90] cache_req: add autofs map entries plugin
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ Makefile.am                                   |   1 +
+ src/responder/common/cache_req/cache_req.c    |   2 +
+ src/responder/common/cache_req/cache_req.h    |  14 ++
+ .../common/cache_req/cache_req_data.c         |   1 +
+ .../common/cache_req/cache_req_plugin.h       |   1 +
+ .../plugins/cache_req_autofs_map_entries.c    | 156 ++++++++++++++++++
+ src/tests/cwrap/Makefile.am                   |   1 +
+ 7 files changed, 176 insertions(+)
+ create mode 100644 src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+
+diff --git a/Makefile.am b/Makefile.am
+index c109afe56..879f38311 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -559,6 +559,7 @@ SSSD_CACHE_REQ_OBJ = \
+ 	src/responder/common/cache_req/plugins/cache_req_svc_by_port.c \
+ 	src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c \
+ 	src/responder/common/cache_req/plugins/cache_req_host_by_name.c \
++	src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c \
+ 	$(NULL)
+ 
+ SSSD_RESPONDER_IFACE_OBJ = \
+diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
+index 28b563392..2ce9deca0 100644
+--- a/src/responder/common/cache_req/cache_req.c
++++ b/src/responder/common/cache_req/cache_req.c
+@@ -60,6 +60,8 @@ cache_req_get_plugin(enum cache_req_type type)
+         &cache_req_netgroup_by_name,
+ 
+         &cache_req_host_by_name,
++
++        &cache_req_autofs_map_entries,
+     };
+ 
+     if (type >= CACHE_REQ_SENTINEL) {
+diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
+index 84dd22c25..0c214a483 100644
+--- a/src/responder/common/cache_req/cache_req.h
++++ b/src/responder/common/cache_req/cache_req.h
+@@ -54,6 +54,8 @@ enum cache_req_type {
+ 
+     CACHE_REQ_HOST_BY_NAME,
+ 
++    CACHE_REQ_AUTOFS_MAP_ENTRIES,
++
+     CACHE_REQ_SENTINEL
+ };
+ 
+@@ -430,4 +432,16 @@ cache_req_host_by_name_send(TALLOC_CTX *mem_ctx,
+ #define cache_req_host_by_name_recv(mem_ctx, req, _result) \
+     cache_req_single_domain_recv(mem_ctx, req, _result)
+ 
++struct tevent_req *
++cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx,
++                                  struct tevent_context *ev,
++                                  struct resp_ctx *rctx,
++                                  struct sss_nc_ctx *ncache,
++                                  int cache_refresh_percent,
++                                  const char *domain,
++                                  const char *name);
++
++#define cache_req_autofs_map_entries_recv(mem_ctx, req, _result) \
++    cache_req_single_domain_recv(mem_ctx, req, _result)
++
+ #endif /* _CACHE_REQ_H_ */
+diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c
+index 77959f9fe..20d73ebfd 100644
+--- a/src/responder/common/cache_req/cache_req_data.c
++++ b/src/responder/common/cache_req/cache_req_data.c
+@@ -93,6 +93,7 @@ cache_req_data_create(TALLOC_CTX *mem_ctx,
+     case CACHE_REQ_INITGROUPS_BY_UPN:
+     case CACHE_REQ_NETGROUP_BY_NAME:
+     case CACHE_REQ_OBJECT_BY_NAME:
++    case CACHE_REQ_AUTOFS_MAP_ENTRIES:
+         if (input->name.input == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+             ret = ERR_INTERNAL;
+diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h
+index d547c9bf3..1071cd889 100644
+--- a/src/responder/common/cache_req/cache_req_plugin.h
++++ b/src/responder/common/cache_req/cache_req_plugin.h
+@@ -314,5 +314,6 @@ extern const struct cache_req_plugin cache_req_svc_by_name;
+ extern const struct cache_req_plugin cache_req_svc_by_port;
+ extern const struct cache_req_plugin cache_req_netgroup_by_name;
+ extern const struct cache_req_plugin cache_req_host_by_name;
++extern const struct cache_req_plugin cache_req_autofs_map_entries;
+ 
+ #endif /* _CACHE_REQ_PLUGIN_H_ */
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+new file mode 100644
+index 000000000..73d2b3cf2
+--- /dev/null
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+@@ -0,0 +1,156 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++#include <ldb.h>
++
++#include "db/sysdb.h"
++#include "db/sysdb_autofs.h"
++#include "util/util.h"
++#include "providers/data_provider.h"
++#include "responder/common/cache_req/cache_req_plugin.h"
++
++static const char *
++cache_req_autofs_map_entries_create_debug_name(TALLOC_CTX *mem_ctx,
++                                               struct cache_req_data *data,
++                                               struct sss_domain_info *domain)
++{
++    return talloc_strdup(mem_ctx, data->name.name);
++}
++
++static errno_t
++cache_req_autofs_map_entries_lookup(TALLOC_CTX *mem_ctx,
++                                    struct cache_req *cr,
++                                    struct cache_req_data *data,
++                                    struct sss_domain_info *domain,
++                                    struct ldb_result **_result)
++{
++    TALLOC_CTX *tmp_ctx;
++    struct ldb_message *map;
++    struct ldb_message **mounts;
++    struct ldb_message **msgs;
++    struct ldb_result *result;
++    size_t count;
++    size_t i;
++    errno_t ret;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    ret = sysdb_get_map_byname(tmp_ctx, domain, data->name.name, &map);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    ret = sysdb_autofs_entries_by_map(tmp_ctx, domain, data->name.name,
++                                      &count, &mounts);
++    if (ret != EOK && ret != ENOENT) {
++        goto done;
++    }
++
++    msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, count + 1);
++    if (msgs == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    msgs[0] = talloc_steal(msgs, map);
++    for (i = 0; i < count; i++) {
++        msgs[i + 1] = talloc_steal(msgs, mounts[i]);
++    }
++
++    result = cache_req_create_ldb_result_from_msg_list(tmp_ctx, msgs, count + 1);
++    if (result == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    *_result = talloc_steal(mem_ctx, result);
++    ret = EOK;
++
++done:
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
++static struct tevent_req *
++cache_req_autofs_map_entries_dp_send(TALLOC_CTX *mem_ctx,
++                                     struct cache_req *cr,
++                                     struct cache_req_data *data,
++                                     struct sss_domain_info *domain,
++                                     struct ldb_result *result)
++{
++    return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
++                                  SSS_DP_AUTOFS, data->name.name);
++}
++
++const struct cache_req_plugin cache_req_autofs_map_entries = {
++    .name = "Get autofs entries",
++    .attr_expiration = SYSDB_ENUM_EXPIRE,
++    .parse_name = true,
++    .ignore_default_domain = true,
++    .bypass_cache = false,
++    .only_one_result = false,
++    .search_all_domains = false,
++    .require_enumeration = false,
++    .allow_missing_fqn = true,
++    .allow_switch_to_upn = false,
++    .upn_equivalent = CACHE_REQ_SENTINEL,
++    .get_next_domain_flags = 0,
++
++    .is_well_known_fn = NULL,
++    .prepare_domain_data_fn = NULL,
++    .create_debug_name_fn = cache_req_autofs_map_entries_create_debug_name,
++    .global_ncache_add_fn = NULL,
++    .ncache_check_fn = NULL,
++    .ncache_add_fn = NULL,
++    .ncache_filter_fn = NULL,
++    .lookup_fn = cache_req_autofs_map_entries_lookup,
++    .dp_send_fn = cache_req_autofs_map_entries_dp_send,
++    .dp_recv_fn = cache_req_common_dp_recv,
++    .dp_get_domain_check_fn = NULL,
++    .dp_get_domain_send_fn = NULL,
++    .dp_get_domain_recv_fn = NULL,
++};
++
++struct tevent_req *
++cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx,
++                                  struct tevent_context *ev,
++                                  struct resp_ctx *rctx,
++                                  struct sss_nc_ctx *ncache,
++                                  int cache_refresh_percent,
++                                  const char *domain,
++                                  const char *name)
++{
++    struct cache_req_data *data;
++
++    data = cache_req_data_name(mem_ctx, CACHE_REQ_AUTOFS_MAP_ENTRIES, name);
++    if (data == NULL) {
++        return NULL;
++    }
++
++    return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
++                                         cache_refresh_percent,
++                                         CACHE_REQ_POSIX_DOM, domain,
++                                         data);
++}
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 1edefc678..dfaf3f770 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -64,6 +64,7 @@ SSSD_CACHE_REQ_OBJ = \
+     ../../../src/responder/common/cache_req/plugins/cache_req_svc_by_port.c \
+     ../../../src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c \
+     ../../../src/responder/common/cache_req/plugins/cache_req_host_by_name.c \
++    ../../../src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c \
+     $(NULL)
+ 
+ SSSD_RESPONDER_IFACE_OBJ = \
+-- 
+2.20.1
+
diff --git a/SOURCES/0076-cache_req-add-autofs-map-by-name-plugin.patch b/SOURCES/0076-cache_req-add-autofs-map-by-name-plugin.patch
new file mode 100644
index 0000000..6dce4ab
--- /dev/null
+++ b/SOURCES/0076-cache_req-add-autofs-map-by-name-plugin.patch
@@ -0,0 +1,247 @@
+From e683556dc6671a6047de8bb970d32360d5aa59dc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 6 Aug 2019 12:08:59 +0200
+Subject: [PATCH 76/90] cache_req: add autofs map by name plugin
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We will use the current data provider call that downloads all map entries
+but we will replace it later when new call is available.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ Makefile.am                                   |   1 +
+ src/responder/common/cache_req/cache_req.c    |   1 +
+ src/responder/common/cache_req/cache_req.h    |  13 ++
+ .../common/cache_req/cache_req_data.c         |   1 +
+ .../common/cache_req/cache_req_plugin.h       |   1 +
+ .../plugins/cache_req_autofs_map_by_name.c    | 124 ++++++++++++++++++
+ src/tests/cwrap/Makefile.am                   |   1 +
+ 7 files changed, 142 insertions(+)
+ create mode 100644 src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 879f38311..461a9355f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -560,6 +560,7 @@ SSSD_CACHE_REQ_OBJ = \
+ 	src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c \
+ 	src/responder/common/cache_req/plugins/cache_req_host_by_name.c \
+ 	src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c \
++	src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c \
+ 	$(NULL)
+ 
+ SSSD_RESPONDER_IFACE_OBJ = \
+diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
+index 2ce9deca0..75f396a23 100644
+--- a/src/responder/common/cache_req/cache_req.c
++++ b/src/responder/common/cache_req/cache_req.c
+@@ -62,6 +62,7 @@ cache_req_get_plugin(enum cache_req_type type)
+         &cache_req_host_by_name,
+ 
+         &cache_req_autofs_map_entries,
++        &cache_req_autofs_map_by_name
+     };
+ 
+     if (type >= CACHE_REQ_SENTINEL) {
+diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
+index 0c214a483..66a13445c 100644
+--- a/src/responder/common/cache_req/cache_req.h
++++ b/src/responder/common/cache_req/cache_req.h
+@@ -55,6 +55,7 @@ enum cache_req_type {
+     CACHE_REQ_HOST_BY_NAME,
+ 
+     CACHE_REQ_AUTOFS_MAP_ENTRIES,
++    CACHE_REQ_AUTOFS_MAP_BY_NAME,
+ 
+     CACHE_REQ_SENTINEL
+ };
+@@ -444,4 +445,16 @@ cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx,
+ #define cache_req_autofs_map_entries_recv(mem_ctx, req, _result) \
+     cache_req_single_domain_recv(mem_ctx, req, _result)
+ 
++struct tevent_req *
++cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx,
++                                  struct tevent_context *ev,
++                                  struct resp_ctx *rctx,
++                                  struct sss_nc_ctx *ncache,
++                                  int cache_refresh_percent,
++                                  const char *domain,
++                                  const char *name);
++
++#define cache_req_autofs_map_by_name_recv(mem_ctx, req, _result) \
++    cache_req_single_domain_recv(mem_ctx, req, _result)
++
+ #endif /* _CACHE_REQ_H_ */
+diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c
+index 20d73ebfd..ad6176641 100644
+--- a/src/responder/common/cache_req/cache_req_data.c
++++ b/src/responder/common/cache_req/cache_req_data.c
+@@ -94,6 +94,7 @@ cache_req_data_create(TALLOC_CTX *mem_ctx,
+     case CACHE_REQ_NETGROUP_BY_NAME:
+     case CACHE_REQ_OBJECT_BY_NAME:
+     case CACHE_REQ_AUTOFS_MAP_ENTRIES:
++    case CACHE_REQ_AUTOFS_MAP_BY_NAME:
+         if (input->name.input == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+             ret = ERR_INTERNAL;
+diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h
+index 1071cd889..c040bf380 100644
+--- a/src/responder/common/cache_req/cache_req_plugin.h
++++ b/src/responder/common/cache_req/cache_req_plugin.h
+@@ -315,5 +315,6 @@ extern const struct cache_req_plugin cache_req_svc_by_port;
+ extern const struct cache_req_plugin cache_req_netgroup_by_name;
+ extern const struct cache_req_plugin cache_req_host_by_name;
+ extern const struct cache_req_plugin cache_req_autofs_map_entries;
++extern const struct cache_req_plugin cache_req_autofs_map_by_name;
+ 
+ #endif /* _CACHE_REQ_PLUGIN_H_ */
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+new file mode 100644
+index 000000000..2f69c762c
+--- /dev/null
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+@@ -0,0 +1,124 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++#include <ldb.h>
++
++#include "db/sysdb.h"
++#include "db/sysdb_autofs.h"
++#include "util/util.h"
++#include "providers/data_provider.h"
++#include "responder/common/cache_req/cache_req_plugin.h"
++
++static const char *
++cache_req_autofs_map_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
++                                               struct cache_req_data *data,
++                                               struct sss_domain_info *domain)
++{
++    return talloc_strdup(mem_ctx, data->name.name);
++}
++
++static errno_t
++cache_req_autofs_map_by_name_lookup(TALLOC_CTX *mem_ctx,
++                                    struct cache_req *cr,
++                                    struct cache_req_data *data,
++                                    struct sss_domain_info *domain,
++                                    struct ldb_result **_result)
++{
++    struct ldb_message *map;
++    struct ldb_result *result;
++    errno_t ret;
++
++    ret = sysdb_get_map_byname(mem_ctx, domain, data->name.name, &map);
++    if (ret != EOK) {
++        return ret;
++    }
++
++    result = cache_req_create_ldb_result_from_msg(mem_ctx, map);
++    if (result == NULL) {
++        talloc_free(map);
++        return ENOMEM;
++    }
++
++    *_result = talloc_steal(mem_ctx, result);
++    return EOK;
++}
++
++static struct tevent_req *
++cache_req_autofs_map_by_name_dp_send(TALLOC_CTX *mem_ctx,
++                                     struct cache_req *cr,
++                                     struct cache_req_data *data,
++                                     struct sss_domain_info *domain,
++                                     struct ldb_result *result)
++{
++    return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
++                                  SSS_DP_AUTOFS, data->name.name);
++}
++
++const struct cache_req_plugin cache_req_autofs_map_by_name = {
++    .name = "Get autofs map",
++    .attr_expiration = SYSDB_CACHE_EXPIRE,
++    .parse_name = true,
++    .ignore_default_domain = true,
++    .bypass_cache = false,
++    .only_one_result = false,
++    .search_all_domains = false,
++    .require_enumeration = false,
++    .allow_missing_fqn = true,
++    .allow_switch_to_upn = false,
++    .upn_equivalent = CACHE_REQ_SENTINEL,
++    .get_next_domain_flags = 0,
++
++    .is_well_known_fn = NULL,
++    .prepare_domain_data_fn = NULL,
++    .create_debug_name_fn = cache_req_autofs_map_by_name_create_debug_name,
++    .global_ncache_add_fn = NULL,
++    .ncache_check_fn = NULL,
++    .ncache_add_fn = NULL,
++    .ncache_filter_fn = NULL,
++    .lookup_fn = cache_req_autofs_map_by_name_lookup,
++    .dp_send_fn = cache_req_autofs_map_by_name_dp_send,
++    .dp_recv_fn = cache_req_common_dp_recv,
++    .dp_get_domain_check_fn = NULL,
++    .dp_get_domain_send_fn = NULL,
++    .dp_get_domain_recv_fn = NULL,
++};
++
++struct tevent_req *
++cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx,
++                                  struct tevent_context *ev,
++                                  struct resp_ctx *rctx,
++                                  struct sss_nc_ctx *ncache,
++                                  int cache_refresh_percent,
++                                  const char *domain,
++                                  const char *name)
++{
++    struct cache_req_data *data;
++
++    data = cache_req_data_name(mem_ctx, CACHE_REQ_AUTOFS_MAP_BY_NAME, name);
++    if (data == NULL) {
++        return NULL;
++    }
++
++    return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
++                                         cache_refresh_percent,
++                                         CACHE_REQ_POSIX_DOM, domain,
++                                         data);
++}
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index dfaf3f770..3fbcebf3c 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -65,6 +65,7 @@ SSSD_CACHE_REQ_OBJ = \
+     ../../../src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c \
+     ../../../src/responder/common/cache_req/plugins/cache_req_host_by_name.c \
+     ../../../src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c \
++    ../../../src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c \
+     $(NULL)
+ 
+ SSSD_RESPONDER_IFACE_OBJ = \
+-- 
+2.20.1
+
diff --git a/SOURCES/0077-cache_req-add-autofs-entry-by-name-plugin.patch b/SOURCES/0077-cache_req-add-autofs-entry-by-name-plugin.patch
new file mode 100644
index 0000000..fcbf391
--- /dev/null
+++ b/SOURCES/0077-cache_req-add-autofs-entry-by-name-plugin.patch
@@ -0,0 +1,321 @@
+From 6fe479a210adb53d419ca75512dec3a584296289 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 13 Aug 2019 13:00:23 +0200
+Subject: [PATCH 77/90] cache_req: add autofs entry by name plugin
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We will use the current data provider call that downloads all map entries
+but we will replace it later when new call is available.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ Makefile.am                                   |   1 +
+ src/responder/common/cache_req/cache_req.c    |   3 +-
+ src/responder/common/cache_req/cache_req.h    |  21 +++
+ .../common/cache_req/cache_req_data.c         |  33 +++++
+ .../common/cache_req/cache_req_plugin.h       |   1 +
+ .../common/cache_req/cache_req_private.h      |   1 +
+ .../plugins/cache_req_autofs_entry_by_name.c  | 129 ++++++++++++++++++
+ src/tests/cwrap/Makefile.am                   |   1 +
+ 8 files changed, 189 insertions(+), 1 deletion(-)
+ create mode 100644 src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 461a9355f..bc74906a7 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -561,6 +561,7 @@ SSSD_CACHE_REQ_OBJ = \
+ 	src/responder/common/cache_req/plugins/cache_req_host_by_name.c \
+ 	src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c \
+ 	src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c \
++	src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c \
+ 	$(NULL)
+ 
+ SSSD_RESPONDER_IFACE_OBJ = \
+diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
+index 75f396a23..febca2468 100644
+--- a/src/responder/common/cache_req/cache_req.c
++++ b/src/responder/common/cache_req/cache_req.c
+@@ -62,7 +62,8 @@ cache_req_get_plugin(enum cache_req_type type)
+         &cache_req_host_by_name,
+ 
+         &cache_req_autofs_map_entries,
+-        &cache_req_autofs_map_by_name
++        &cache_req_autofs_map_by_name,
++        &cache_req_autofs_entry_by_name
+     };
+ 
+     if (type >= CACHE_REQ_SENTINEL) {
+diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
+index 66a13445c..412f6221b 100644
+--- a/src/responder/common/cache_req/cache_req.h
++++ b/src/responder/common/cache_req/cache_req.h
+@@ -56,6 +56,7 @@ enum cache_req_type {
+ 
+     CACHE_REQ_AUTOFS_MAP_ENTRIES,
+     CACHE_REQ_AUTOFS_MAP_BY_NAME,
++    CACHE_REQ_AUTOFS_ENTRY_BY_NAME,
+ 
+     CACHE_REQ_SENTINEL
+ };
+@@ -126,6 +127,13 @@ cache_req_data_host(TALLOC_CTX *mem_ctx,
+                     const char *name,
+                     const char *alias,
+                     const char **attrs);
++
++struct cache_req_data *
++cache_req_data_autofs_entry(TALLOC_CTX *mem_ctx,
++                            enum cache_req_type type,
++                            const char *mapname,
++                            const char *entryname);
++
+ void
+ cache_req_data_set_bypass_cache(struct cache_req_data *data,
+                                 bool bypass_cache);
+@@ -457,4 +465,17 @@ cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx,
+ #define cache_req_autofs_map_by_name_recv(mem_ctx, req, _result) \
+     cache_req_single_domain_recv(mem_ctx, req, _result)
+ 
++struct tevent_req *
++cache_req_autofs_entry_by_name_send(TALLOC_CTX *mem_ctx,
++                                    struct tevent_context *ev,
++                                    struct resp_ctx *rctx,
++                                    struct sss_nc_ctx *ncache,
++                                    int cache_refresh_percent,
++                                    const char *domain,
++                                    const char *mapname,
++                                    const char *entryname);
++
++#define cache_req_autofs_entry_by_name_recv(mem_ctx, req, _result) \
++    cache_req_single_domain_recv(mem_ctx, req, _result)
++
+ #endif /* _CACHE_REQ_H_ */
+diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c
+index ad6176641..01eeedbc4 100644
+--- a/src/responder/common/cache_req/cache_req_data.c
++++ b/src/responder/common/cache_req/cache_req_data.c
+@@ -209,6 +209,25 @@ cache_req_data_create(TALLOC_CTX *mem_ctx,
+             goto done;
+         }
+         break;
++    case CACHE_REQ_AUTOFS_ENTRY_BY_NAME:
++        if (input->name.input == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
++            ret = ERR_INTERNAL;
++            goto done;
++        }
++
++        data->name.input = talloc_strdup(data, input->name.input);
++        if (data->name.input == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++
++        data->autofs_entry_name = talloc_strdup(data, input->autofs_entry_name);
++        if (data->autofs_entry_name == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++        break;
+     case CACHE_REQ_SENTINEL:
+         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid cache request type!\n");
+         ret = ERR_INTERNAL;
+@@ -356,6 +375,20 @@ cache_req_data_host(TALLOC_CTX *mem_ctx,
+     return cache_req_data_create(mem_ctx, type, &input);
+ }
+ 
++struct cache_req_data *
++cache_req_data_autofs_entry(TALLOC_CTX *mem_ctx,
++                            enum cache_req_type type,
++                            const char *mapname,
++                            const char *entryname)
++{
++    struct cache_req_data input = {0};
++
++    input.name.input = mapname;
++    input.autofs_entry_name = entryname;
++
++    return cache_req_data_create(mem_ctx, type, &input);
++}
++
+ void
+ cache_req_data_set_bypass_cache(struct cache_req_data *data,
+                                 bool bypass_cache)
+diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h
+index c040bf380..745a36c0e 100644
+--- a/src/responder/common/cache_req/cache_req_plugin.h
++++ b/src/responder/common/cache_req/cache_req_plugin.h
+@@ -316,5 +316,6 @@ extern const struct cache_req_plugin cache_req_netgroup_by_name;
+ extern const struct cache_req_plugin cache_req_host_by_name;
+ extern const struct cache_req_plugin cache_req_autofs_map_entries;
+ extern const struct cache_req_plugin cache_req_autofs_map_by_name;
++extern const struct cache_req_plugin cache_req_autofs_entry_by_name;
+ 
+ #endif /* _CACHE_REQ_PLUGIN_H_ */
+diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
+index a88c838d9..34bd3ce15 100644
+--- a/src/responder/common/cache_req/cache_req_private.h
++++ b/src/responder/common/cache_req/cache_req_private.h
+@@ -83,6 +83,7 @@ struct cache_req_data {
+     const char *sid;
+     const char *alias;
+     const char **attrs;
++    const char *autofs_entry_name;
+ 
+     struct {
+         struct cache_req_parsed_name *name;
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+new file mode 100644
+index 000000000..17b0b508e
+--- /dev/null
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+@@ -0,0 +1,129 @@
++/*
++    Authors:
++        Pavel Březina <pbrezina@redhat.com>
++
++    Copyright (C) 2019 Red Hat
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <talloc.h>
++#include <ldb.h>
++
++#include "db/sysdb.h"
++#include "db/sysdb_autofs.h"
++#include "util/util.h"
++#include "providers/data_provider.h"
++#include "responder/common/cache_req/cache_req_plugin.h"
++
++static const char *
++cache_req_autofs_entry_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
++                                                 struct cache_req_data *data,
++                                                 struct sss_domain_info *domain)
++{
++    return talloc_asprintf(mem_ctx, "%s:%s",
++                           data->name.name,
++                           data->autofs_entry_name);
++}
++
++static errno_t
++cache_req_autofs_entry_by_name_lookup(TALLOC_CTX *mem_ctx,
++                                      struct cache_req *cr,
++                                      struct cache_req_data *data,
++                                      struct sss_domain_info *domain,
++                                      struct ldb_result **_result)
++{
++    struct ldb_message *entry;
++    struct ldb_result *result;
++    errno_t ret;
++
++    ret = sysdb_get_autofsentry(mem_ctx, domain, data->name.name,
++                                data->autofs_entry_name, &entry);
++    if (ret != EOK) {
++        return ret;
++    }
++
++    result = cache_req_create_ldb_result_from_msg(mem_ctx, entry);
++    if (result == NULL) {
++        talloc_free(entry);
++        return ENOMEM;
++    }
++
++    *_result = talloc_steal(mem_ctx, result);
++    return EOK;
++}
++
++static struct tevent_req *
++cache_req_autofs_entry_by_name_dp_send(TALLOC_CTX *mem_ctx,
++                                       struct cache_req *cr,
++                                       struct cache_req_data *data,
++                                       struct sss_domain_info *domain,
++                                       struct ldb_result *result)
++{
++    return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
++                                  SSS_DP_AUTOFS, data->name.name);
++}
++
++const struct cache_req_plugin cache_req_autofs_entry_by_name = {
++    .name = "Get autofs entry",
++    .attr_expiration = SYSDB_CACHE_EXPIRE,
++    .parse_name = true,
++    .ignore_default_domain = true,
++    .bypass_cache = false,
++    .only_one_result = false,
++    .search_all_domains = false,
++    .require_enumeration = false,
++    .allow_missing_fqn = true,
++    .allow_switch_to_upn = false,
++    .upn_equivalent = CACHE_REQ_SENTINEL,
++    .get_next_domain_flags = 0,
++
++    .is_well_known_fn = NULL,
++    .prepare_domain_data_fn = NULL,
++    .create_debug_name_fn = cache_req_autofs_entry_by_name_create_debug_name,
++    .global_ncache_add_fn = NULL,
++    .ncache_check_fn = NULL,
++    .ncache_add_fn = NULL,
++    .ncache_filter_fn = NULL,
++    .lookup_fn = cache_req_autofs_entry_by_name_lookup,
++    .dp_send_fn = cache_req_autofs_entry_by_name_dp_send,
++    .dp_recv_fn = cache_req_common_dp_recv,
++    .dp_get_domain_check_fn = NULL,
++    .dp_get_domain_send_fn = NULL,
++    .dp_get_domain_recv_fn = NULL,
++};
++
++struct tevent_req *
++cache_req_autofs_entry_by_name_send(TALLOC_CTX *mem_ctx,
++                                    struct tevent_context *ev,
++                                    struct resp_ctx *rctx,
++                                    struct sss_nc_ctx *ncache,
++                                    int cache_refresh_percent,
++                                    const char *domain,
++                                    const char *mapname,
++                                    const char *entryname)
++{
++    struct cache_req_data *data;
++
++    data = cache_req_data_autofs_entry(mem_ctx, CACHE_REQ_AUTOFS_ENTRY_BY_NAME,
++                                       mapname, entryname);
++    if (data == NULL) {
++        return NULL;
++    }
++
++    return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
++                                         cache_refresh_percent,
++                                         CACHE_REQ_POSIX_DOM, domain,
++                                         data);
++}
+diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
+index 3fbcebf3c..aaec6c700 100644
+--- a/src/tests/cwrap/Makefile.am
++++ b/src/tests/cwrap/Makefile.am
+@@ -66,6 +66,7 @@ SSSD_CACHE_REQ_OBJ = \
+     ../../../src/responder/common/cache_req/plugins/cache_req_host_by_name.c \
+     ../../../src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c \
+     ../../../src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c \
++    ../../../src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c \
+     $(NULL)
+ 
+ SSSD_RESPONDER_IFACE_OBJ = \
+-- 
+2.20.1
+
diff --git a/SOURCES/0078-autofs-convert-code-to-cache_req.patch b/SOURCES/0078-autofs-convert-code-to-cache_req.patch
new file mode 100644
index 0000000..6446d23
--- /dev/null
+++ b/SOURCES/0078-autofs-convert-code-to-cache_req.patch
@@ -0,0 +1,2158 @@
+From b0043a95f86b240d0beb551ef4e9ff9a4be99995 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 7 Aug 2019 13:59:04 +0200
+Subject: [PATCH 78/90] autofs: convert code to cache_req
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will simplify the code a lot so it can be further extended.
+At this point the conversion is done 1:1, we will do additional
+changes in next patches.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/responder/autofs/autofs_private.h |   72 +-
+ src/responder/autofs/autofssrv.c      |    7 +-
+ src/responder/autofs/autofssrv_cmd.c  | 1651 ++++++++-----------------
+ 3 files changed, 549 insertions(+), 1181 deletions(-)
+
+diff --git a/src/responder/autofs/autofs_private.h b/src/responder/autofs/autofs_private.h
+index 6a39b17ad..3be25d4d9 100644
+--- a/src/responder/autofs/autofs_private.h
++++ b/src/responder/autofs/autofs_private.h
+@@ -21,7 +21,9 @@
+ #ifndef _AUTOFSSRV_PRIVATE_H_
+ #define _AUTOFSSRV_PRIVATE_H_
+ 
++#include "responder/common/responder.h"
+ #include "responder/common/responder_sbus.h"
++#include "responder/common/cache_req/cache_req.h"
+ 
+ #define SSS_AUTOFS_PROTO_VERSION        0x001
+ 
+@@ -33,75 +35,33 @@ struct autofs_ctx {
+     hash_table_t *maps;
+ };
+ 
+-struct autofs_state_ctx {
+-    char *automntmap_name;
+-};
+-
+ struct autofs_cmd_ctx {
+-    struct cli_ctx *cctx;
+-    char *mapname;
+-    char *key;
+-    uint32_t cursor;
++    struct autofs_ctx *autofs_ctx;
++    struct cli_ctx *cli_ctx;
++
++    const char *mapname;
++    const char *keyname;
+     uint32_t max_entries;
+-    bool check_next;
++    uint32_t cursor;
+ };
+ 
+-struct autofs_dom_ctx {
+-    struct autofs_cmd_ctx  *cmd_ctx;
+-    struct sss_domain_info *domain;
+-    bool check_provider;
+-
+-    /* cache results */
+-    struct ldb_message *map;
+-
+-    size_t entry_count;
+-    struct ldb_message **entries;
+-
+-    struct autofs_map_ctx *map_ctx;
+-};
++struct autofs_enum_ctx {
++    /* Results. First result is the map objects, next results are map entries. */
++    struct cache_req_result *result;
+ 
+-struct autofs_map_ctx {
+-    /* state of the map entry */
+-    bool ready;
++    /* True if the map was found. */
+     bool found;
+ 
+-    /* requests */
+-    struct setent_req_list *reqs;
+-
+-    hash_table_t *map_table;
+-    char *mapname;
++    /* False if the result is being created. */
++    bool ready;
+ 
+-    /* map entry */
+-    struct ldb_message *map;
+-    size_t entry_count;
+-    struct ldb_message **entries;
++    /* Requests that awaits the data. */
++    struct setent_req_list *notify_list;
+ };
+ 
+ struct sss_cmd_table *get_autofs_cmds(void);
+ int autofs_connection_setup(struct cli_ctx *cctx);
+ 
+-void autofs_map_hash_delete_cb(hash_entry_t *item,
+-                               hash_destroy_enum deltype, void *pvt);
+-
+ errno_t autofs_orphan_maps(struct autofs_ctx *actx);
+ 
+-enum sss_dp_autofs_type {
+-    SSS_DP_AUTOFS
+-};
+-
+-struct tevent_req *
+-sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
+-                       struct resp_ctx *rctx,
+-                       struct sss_domain_info *dom,
+-                       bool fast_reply,
+-                       enum sss_dp_autofs_type type,
+-                       const char *name);
+-
+-errno_t
+-sss_dp_get_autofs_recv(TALLOC_CTX *mem_ctx,
+-                       struct tevent_req *req,
+-                       dbus_uint16_t *dp_err,
+-                       dbus_uint32_t *dp_ret,
+-                       char **err_msg);
+-
+ #endif /* _AUTOFSSRV_PRIVATE_H_ */
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index 7d236f4d9..309ed76b1 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -28,6 +28,7 @@
+ #include "responder/common/responder.h"
+ #include "providers/data_provider.h"
+ #include "responder/autofs/autofs_private.h"
++#include "util/sss_ptr_hash.h"
+ 
+ static int autofs_clean_hash_table(struct sbus_request *dbus_req, void *data);
+ 
+@@ -105,7 +106,6 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
+     struct autofs_ctx *autofs_ctx;
+     struct be_conn *iter;
+     int ret;
+-    int hret;
+     int max_retries;
+ 
+     autofs_cmds = get_autofs_cmds();
+@@ -158,9 +158,8 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
+     }
+ 
+     /* Create the lookup table for setautomntent results */
+-    hret = sss_hash_create_ex(autofs_ctx, 10, &autofs_ctx->maps, 0, 0, 0, 0,
+-                              autofs_map_hash_delete_cb, NULL);
+-    if (hret != HASH_SUCCESS) {
++    autofs_ctx->maps = sss_ptr_hash_create(autofs_ctx, NULL, NULL);
++    if (autofs_ctx->maps == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Unable to initialize automount maps hash table\n");
+         ret = EIO;
+diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
+index 9ea2ab71b..670b6d50d 100644
+--- a/src/responder/autofs/autofssrv_cmd.c
++++ b/src/responder/autofs/autofssrv_cmd.c
+@@ -25,20 +25,22 @@
+ #include "util/util.h"
+ #include "responder/common/responder.h"
+ #include "responder/common/responder_packet.h"
++#include "responder/common/cache_req/cache_req.h"
+ #include "responder/autofs/autofs_private.h"
+ #include "db/sysdb.h"
+ #include "db/sysdb_autofs.h"
+ #include "confdb/confdb.h"
++#include "util/sss_ptr_hash.h"
+ 
+ static int autofs_cmd_send_error(struct autofs_cmd_ctx *cmdctx, int err)
+ {
+-    return sss_cmd_send_error(cmdctx->cctx, err);
++    return sss_cmd_send_error(cmdctx->cli_ctx, err);
+ }
+ 
+ static int
+ autofs_cmd_send_empty(struct autofs_cmd_ctx *cmdctx)
+ {
+-    return sss_cmd_send_empty(cmdctx->cctx);
++    return sss_cmd_send_empty(cmdctx->cli_ctx);
+ }
+ 
+ static int
+@@ -54,7 +56,7 @@ autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
+         if (ret) {
+             return EFAULT;
+         }
+-        sss_cmd_done(cmdctx->cctx, cmdctx);
++        sss_cmd_done(cmdctx->cli_ctx, cmdctx);
+         break;
+ 
+     case EAGAIN:
+@@ -70,7 +72,7 @@ autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
+         if (ret) {
+             return EFAULT;
+         }
+-        sss_cmd_done(cmdctx->cctx, cmdctx);
++        sss_cmd_done(cmdctx->cli_ctx, cmdctx);
+         break;
+     }
+ 
+@@ -78,1058 +80,524 @@ autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
+ }
+ 
+ static errno_t
+-autofs_setent_add_ref(TALLOC_CTX *memctx,
+-                      struct autofs_map_ctx *map_ctx,
+-                      struct tevent_req *req)
++autofs_fill_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp)
+ {
+-    return setent_add_ref(memctx, &map_ctx->reqs, req);
+-}
+-
+-static void
+-autofs_setent_notify(struct autofs_map_ctx *map_ctx, errno_t ret)
+-{
+-    setent_notify(&map_ctx->reqs, ret);
+-}
+-
+-errno_t
+-autofs_orphan_maps(struct autofs_ctx *actx)
+-{
+-    int hret;
+-    unsigned long mcount;
+-    unsigned long i;
+-    hash_key_t *maps;
++    errno_t ret;
++    const char *key;
++    size_t keylen;
++    const char *value;
++    size_t valuelen;
++    uint8_t *body;
++    size_t blen;
++    size_t len;
+ 
+-    if (!actx || !actx->maps) {
++    key = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_KEY, NULL);
++    value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
++    if (!key || !value) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Incomplete entry\n");
+         return EINVAL;
+     }
+ 
+-    hret = hash_keys(actx->maps, &mcount, &maps);
+-    if (hret != HASH_SUCCESS) {
+-        return EIO;
+-    }
+-
+-    for (i = 0; i < mcount; i++) {
+-        hret = hash_delete(actx->maps, &maps[i]);
+-        if (hret != HASH_SUCCESS) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete key from hash\n");
+-            continue;
+-        }
+-    }
+-
+-    return EOK;
+-}
++    keylen = 1 + strlen(key);
++    valuelen = 1 + strlen(value);
++    len = sizeof(uint32_t) + sizeof(uint32_t) + keylen + sizeof(uint32_t) + valuelen;
+ 
+-static errno_t
+-get_autofs_map(struct autofs_ctx *actx,
+-               char *mapname,
+-               struct autofs_map_ctx **map)
+-{
+-    hash_key_t key;
+-    hash_value_t value;
+-    int hret;
+-
+-    key.type = HASH_KEY_STRING;
+-    key.str = mapname;
+-
+-    hret = hash_lookup(actx->maps, &key, &value);
+-    if (hret == HASH_SUCCESS) {
+-        *map = talloc_get_type(value.ptr, struct autofs_map_ctx);
+-        return EOK;
+-    } else if (hret == HASH_ERROR_KEY_NOT_FOUND) {
+-        return ENOENT;
++    ret = sss_packet_grow(packet, len);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
++        return ret;
+     }
+ 
+-    DEBUG(SSSDBG_CRIT_FAILURE,
+-          "Unexpected error reading from autofs map hash [%d][%s]\n",
+-          hret, hash_error_string(hret));
+-    return EIO;
+-}
+-
+-static int autofs_map_hash_remove (TALLOC_CTX *ctx);
++    sss_packet_get_body(packet, &body, &blen);
+ 
+-void
+-autofs_map_hash_delete_cb(hash_entry_t *item,
+-                          hash_destroy_enum deltype, void *pvt)
+-{
+-    struct autofs_map_ctx *map;
++    SAFEALIGN_SET_UINT32(&body[*rp], len, rp);
++    SAFEALIGN_SET_UINT32(&body[*rp], keylen, rp);
+ 
+-    if (deltype != HASH_ENTRY_DESTROY) {
+-        return;
++    if (keylen == 1) {
++        body[*rp] = '\0';
++    } else {
++        memcpy(&body[*rp], key, keylen);
+     }
++    *rp += keylen;
+ 
+-    map = talloc_get_type(item->value.ptr, struct autofs_map_ctx);
+-    if (!map) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Invalid autofs map\n");
+-        return;
++    SAFEALIGN_SET_UINT32(&body[*rp], valuelen, rp);
++    if (valuelen == 1) {
++        body[*rp] = '\0';
++    } else {
++        memcpy(&body[*rp], value, valuelen);
+     }
++    *rp += valuelen;
+ 
+-    /* So that the destructor wouldn't attempt to remove the map from hash
+-     * table */
+-    map->map_table = NULL;
++    return EOK;
+ }
+ 
+-static errno_t
+-set_autofs_map(struct autofs_ctx *actx,
+-               struct autofs_map_ctx *map)
++errno_t
++autofs_orphan_maps(struct autofs_ctx *autofs_ctx)
+ {
+-    hash_key_t key;
+-    hash_value_t value;
+-    int hret;
+-
+-    if (map->mapname == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs map name.\n");
+-        return EINVAL;
+-    }
+-
+-    /* Add this entry to the hash table */
+-    key.type = HASH_KEY_STRING;
+-    key.str = map->mapname;
+-    value.type = HASH_VALUE_PTR;
+-    value.ptr = map;
+-    hret = hash_enter(actx->maps, &key, &value);
+-    if (hret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Unable to add hash table entry for [%s]\n", key.str);
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "Hash error [%d][%s]\n", hret, hash_error_string(hret));
+-        return EIO;
+-    }
+-    talloc_steal(actx->maps, map);
+-    talloc_set_destructor((TALLOC_CTX *) map, autofs_map_hash_remove);
++    sss_ptr_hash_delete_all(autofs_ctx->maps, true);
+ 
+     return EOK;
+ }
+ 
+-static int
+-autofs_map_hash_remove(TALLOC_CTX *ctx)
++static void
++autofs_enumctx_lifetime_timeout(struct tevent_context *ev,
++                                struct tevent_timer *te,
++                                struct timeval current_time,
++                                void *pvt)
+ {
+-    int hret;
+-    hash_key_t key;
+-    struct autofs_map_ctx *map =
+-            talloc_get_type(ctx, struct autofs_map_ctx);
+-
+-    if (map->map_table == NULL) {
+-        DEBUG(SSSDBG_TRACE_LIBS, "autofs map [%s] was already removed\n",
+-              map->mapname);
+-        return 0;
+-    }
++    struct autofs_enum_ctx *enum_ctx;
+ 
+-    key.type = HASH_KEY_STRING;
+-    key.str = map->mapname;
++    enum_ctx = talloc_get_type(pvt, struct autofs_enum_ctx);
+ 
+-    /* Remove the autofs map result object from the lookup table */
+-    hret = hash_delete(map->map_table, &key);
+-    if (hret != HASH_SUCCESS) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not remove key from table! [%d][%s]\n",
+-              hret, hash_error_string(hret));
+-        return -1;
+-    }
+-    return 0;
++    /* Free the context. It will be automatically removed from the hash table. */
++    talloc_free(enum_ctx);
+ }
+ 
+-static struct tevent_req *
+-setautomntent_send(TALLOC_CTX *mem_ctx,
+-                   const char *rawname,
+-                   struct autofs_cmd_ctx *cmdctx);
+-static errno_t setautomntent_recv(struct tevent_req *req);
+-static void sss_autofs_cmd_setautomntent_done(struct tevent_req *req);
+-
+-/* FIXME - file a ticket to have per-responder private
+- * data instead of growing the cli_ctx structure */
+-static int
+-sss_autofs_cmd_setautomntent(struct cli_ctx *client)
++static void
++autofs_set_enumctx_lifetime(struct autofs_ctx *autofs_ctx,
++                            struct autofs_enum_ctx *enum_ctx,
++                            uint32_t lifetime)
+ {
+-    struct autofs_cmd_ctx *cmdctx;
+-    struct cli_protocol *pctx;
+-    uint8_t *body;
+-    size_t blen;
+-    errno_t ret = EOK;
+-    const char *rawname;
+-    struct tevent_req *req;
+-
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_setautomntent\n");
+-
+-    cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
+-    if (!cmdctx) {
+-        return ENOMEM;
+-    }
+-    cmdctx->cctx = client;
+-
+-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
+-
+-    sss_packet_get_body(pctx->creq->in, &body, &blen);
+-
+-    /* if not terminated fail */
+-    if (body[blen -1] != '\0') {
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    /* If the body isn't valid UTF-8, fail */
+-    if (!sss_utf8_check(body, blen -1)) {
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    rawname = (const char *)body;
+-    DEBUG(SSSDBG_TRACE_FUNC,
+-          "Got request for automount map named %s\n", rawname);
++    struct timeval tv;
++    struct tevent_timer *te;
+ 
+-    req = setautomntent_send(cmdctx, rawname, cmdctx);
+-    if (!req) {
++    tv = tevent_timeval_current_ofs(lifetime, 0);
++    te = tevent_add_timer(autofs_ctx->rctx->ev, enum_ctx, tv,
++                          autofs_enumctx_lifetime_timeout, enum_ctx);
++    if (te == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Fatal error calling setautomntent_send\n");
+-        ret = EIO;
+-        goto done;
++              "Could not set up life timer for autofs maps. "
++              "Entries may become stale.\n");
+     }
+-    tevent_req_set_callback(req, sss_autofs_cmd_setautomntent_done, cmdctx);
+-
+-    ret = EOK;
+-done:
+-    return autofs_cmd_done(cmdctx, ret);
+ }
+ 
+-static void sss_autofs_cmd_setautomntent_done(struct tevent_req *req)
++static struct autofs_enum_ctx *
++autofs_create_enumeration_context(TALLOC_CTX *mem_ctx,
++                                  struct autofs_ctx *autofs_ctx,
++                                  const char *mapname)
+ {
+-    struct autofs_cmd_ctx *cmdctx =
+-        tevent_req_callback_data(req, struct autofs_cmd_ctx);
+-    struct cli_protocol *pctx;
++    struct autofs_enum_ctx *enum_ctx;
+     errno_t ret;
+-    errno_t reqret;
+-    uint8_t *body;
+-    size_t blen;
+ 
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "setautomntent done\n");
+-
+-    reqret = setautomntent_recv(req);
+-    talloc_zfree(req);
+-    if (reqret != EOK && reqret != ENOENT) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
+-        autofs_cmd_done(cmdctx, reqret);
+-        return;
++    enum_ctx = talloc_zero(mem_ctx, struct autofs_enum_ctx);
++    if (enum_ctx == NULL) {
++        return NULL;
+     }
+ 
+-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
++    enum_ctx->ready = false;
+ 
+-    /* Either we succeeded or no domains were eligible */
+-    ret = sss_packet_new(pctx->creq, 0,
+-                         sss_packet_get_cmd(pctx->creq->in),
+-                         &pctx->creq->out);
+-    if (ret == EOK) {
+-        if (reqret == ENOENT) {
+-            DEBUG(SSSDBG_TRACE_FUNC, "setautomntent did not find requested map\n");
+-            /* Notify the caller that this entry wasn't found */
+-            ret = sss_cmd_empty_packet(pctx->creq->out);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_TRACE_INTERNAL,
+-                      "sss_cmd_empty_packet() failed: %s [%d]\n",
+-                      sss_strerror(ret), ret);
+-            }
+-        } else {
+-            DEBUG(SSSDBG_TRACE_FUNC, "setautomntent found data\n");
+-            ret = sss_packet_grow(pctx->creq->out, 2*sizeof(uint32_t));
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't grow the packet\n");
+-                talloc_free(cmdctx);
+-                return;
+-            }
+-
+-            sss_packet_get_body(pctx->creq->out, &body, &blen);
+-
+-            /* Got some results */
+-            SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
+-
+-            /* Reserved padding */
+-            SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
+-        }
+-
+-        sss_cmd_done(cmdctx->cctx, NULL);
+-        return;
++    ret = sss_ptr_hash_add(autofs_ctx->maps, mapname,
++                           enum_ctx, struct autofs_enum_ctx);
++    if (ret != EOK) {
++        talloc_free(enum_ctx);
++        return NULL;
+     }
+ 
+-    DEBUG(SSSDBG_CRIT_FAILURE, "Error creating packet\n");
+-    return;
++    return enum_ctx;
+ }
+ 
+-struct setautomntent_state {
+-    struct autofs_cmd_ctx *cmdctx;
+-    struct autofs_dom_ctx *dctx;
+-
+-    char *mapname;
+-    struct autofs_map_ctx *map;
++struct autofs_setent_state {
++    struct autofs_ctx *autofs_ctx;
++    struct autofs_enum_ctx *enum_ctx;
+ };
+ 
+-struct setautomntent_lookup_ctx {
+-    struct autofs_ctx *actx;
+-    struct autofs_dom_ctx *dctx;
+-    struct resp_ctx *rctx;
+-    struct cli_ctx *cctx;
+-
+-    bool returned_to_mainloop;
+-
+-    char *mapname;
+-    struct autofs_map_ctx *map;
+-};
+-
+-static errno_t
+-lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx);
+-
+-static void
+-autofs_map_result_timeout(struct tevent_context *ev,
+-                          struct tevent_timer *te,
+-                          struct timeval current_time,
+-                          void *pvt)
+-{
+-    struct autofs_map_ctx *map =
+-            talloc_get_type(pvt, struct autofs_map_ctx);
+-
+-    /* Free the autofs map result context
+-     * The destructor for the autofs map will remove itself
+-     * from the hash table
+-     */
+-    talloc_free(map);
+-}
+-
+-static void
+-set_autofs_map_lifetime(uint32_t lifetime,
+-                        struct setautomntent_lookup_ctx *lookup_ctx,
+-                        struct autofs_map_ctx *map)
+-{
+-    struct timeval tv;
+-    struct tevent_timer *te;
+-
+-    tv = tevent_timeval_current_ofs(lifetime, 0);
+-    te = tevent_add_timer(lookup_ctx->rctx->ev,
+-                          map, tv,
+-                          autofs_map_result_timeout,
+-                          map);
+-    if (!te) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Could not set up life timer for autofs maps. "
+-               "Entries may become stale.\n");
+-    }
+-}
+-
+-static errno_t
+-setautomntent_get_autofs_map(struct autofs_ctx *actx,
+-                             char *mapname,
+-                             struct autofs_map_ctx **map);
++static void autofs_setent_done(struct tevent_req *subreq);
+ 
+ static struct tevent_req *
+-setautomntent_send(TALLOC_CTX *mem_ctx,
+-                   const char *rawname,
+-                   struct autofs_cmd_ctx *cmdctx)
++autofs_setent_send(TALLOC_CTX *mem_ctx,
++                   struct tevent_context *ev,
++                   struct autofs_ctx *autofs_ctx,
++                   const char *mapname)
+ {
+-    char *domname;
+-    errno_t ret;
++    struct autofs_setent_state *state;
++    struct tevent_req *subreq;
+     struct tevent_req *req;
+-    struct setautomntent_state *state;
+-    struct cli_ctx *client = cmdctx->cctx;
+-    struct autofs_dom_ctx *dctx;
+-    struct autofs_ctx *actx;
+-    struct autofs_state_ctx *state_ctx;
+-    struct setautomntent_lookup_ctx *lookup_ctx;
+-
+-    actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
+-    state_ctx = talloc_get_type(client->state_ctx, struct autofs_state_ctx);
+-
+-    req = tevent_req_create(mem_ctx, &state, struct setautomntent_state);
+-    if (!req) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,
+-              "Could not create tevent request for setautomntent\n");
+-        return NULL;
+-    }
+-    state->cmdctx = cmdctx;
+-
+-    dctx = talloc_zero(state, struct autofs_dom_ctx);
+-    if (!dctx) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory\n");
+-        ret = ENOMEM;
+-        goto fail;
+-    }
+-    dctx->cmd_ctx = state->cmdctx;
+-    state->dctx = dctx;
++    errno_t ret;
+ 
+-    ret = sss_parse_name_for_domains(state, client->rctx->domains,
+-                                     NULL, rawname,
+-                                     &domname, &state->mapname);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE,
+-              "Invalid name received [%s]\n", rawname);
+-        goto fail;
++    req = tevent_req_create(mem_ctx, &state, struct autofs_setent_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
++        return NULL;
+     }
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC,
+-         "Requesting info for automount map [%s] from [%s]\n",
+-         state->mapname, domname?domname:"<ALL>");
+-
+-    if (domname) {
+-        dctx->domain = responder_get_domain(client->rctx, domname);
+-        if (!dctx->domain) {
+-            ret = EINVAL;
+-            goto fail;
+-        }
++    state->autofs_ctx = autofs_ctx;
+ 
+-        state_ctx->automntmap_name = talloc_strdup(client, rawname);
+-        if (!state_ctx->automntmap_name) {
+-            ret = ENOMEM;
+-            goto fail;
+-        }
+-    } else {
+-        /* this is a multidomain search */
+-        dctx->domain = client->rctx->domains;
+-        cmdctx->check_next = true;
+-
+-        state_ctx->automntmap_name = talloc_strdup(client, state->mapname);
+-        if (!state_ctx->automntmap_name) {
+-            ret = ENOMEM;
+-            goto fail;
+-        }
+-    }
+-
+-    dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
+-    /* Is the result context already available?
+-     * Check for existing lookups for this map
+-     */
+-    ret = setautomntent_get_autofs_map(actx, state->mapname, &state->map);
+-    if (ret == EOK) {
+-        /* Another process already requested this map
+-         * Check whether it's ready for processing.
+-         */
+-        if (state->map->ready) {
+-            if (state->map->found) {
+-                DEBUG(SSSDBG_TRACE_LIBS,
+-                      "Map %s is ready to be processed\n", state->mapname);
+-                tevent_req_done(req);
+-                tevent_req_post(req, actx->rctx->ev);
+-                return req;
+-            } else {
+-                DEBUG(SSSDBG_TRACE_LIBS,
+-                      "Map %s was marked as nonexistent\n", state->mapname);
+-                tevent_req_error(req, ENOENT);
+-                tevent_req_post(req, actx->rctx->ev);
+-                return req;
+-            }
++    /* Lookup current results if available. */
++    state->enum_ctx = sss_ptr_hash_lookup(autofs_ctx->maps, mapname,
++                                          struct autofs_enum_ctx);
++    if (state->enum_ctx != NULL) {
++        if (state->enum_ctx->ready) {
++            ret = EOK;
++            goto done;
+         }
+ 
+-        /* Result object is still being constructed
+-         * Register for notification when it's ready
+-         */
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "Map %s is being looked up, registering for notification\n",
+-               state->mapname);
+-        ret = autofs_setent_add_ref(state, state->map, req);
++        /* Map is still being created. We will watch the request. */
++        ret = setent_add_ref(state, &state->enum_ctx->notify_list, req);
+         if (ret != EOK) {
+-            goto fail;
+-        }
+-        /* Will return control below */
+-    } else if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "Map %s needs to be looked up\n", state->mapname);
+-
+-        state->map = talloc_zero(actx, struct autofs_map_ctx);
+-        if (!state->map) {
+-            ret = ENOMEM;
+-            goto fail;
+-        }
+-        dctx->map_ctx = state->map;
+-
+-        state->map->mapname = talloc_strdup(state->map, state->mapname);
+-        if (!state->map->mapname) {
+-            talloc_free(state->map);
+-            ret = ENOMEM;
+-            goto fail;
++            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to watch enumeration request "
++                  "[%d]: %s\n", ret, sss_strerror(ret));
++            goto done;
+         }
+-        state->map->map_table = actx->maps;
+ 
+-        ret = autofs_setent_add_ref(state, state->map, req);
+-        if (ret != EOK) {
+-            talloc_free(state->map);
+-            goto fail;
+-        }
++        ret = EAGAIN;
++        goto done;
++    }
+ 
+-        ret = set_autofs_map(actx, state->map);
+-        if (ret != EOK) {
+-            talloc_free(state->map);
+-            goto fail;
+-        }
++    /* Map does not yet exist. Create the enumeration object and fetch data. */
++    state->enum_ctx = autofs_create_enumeration_context(state, autofs_ctx, mapname);
++    if (state->enum_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create enumeration context!\n");
++        ret = ENOMEM;
++        goto done;
++    }
+ 
+-        /* Perform lookup */
+-        lookup_ctx = talloc_zero(state->map, struct setautomntent_lookup_ctx);
+-        if (!lookup_ctx) {
+-            talloc_free(state->map);
+-            ret = ENOMEM;
+-            goto fail;
+-        }
++    subreq = cache_req_autofs_map_entries_send(mem_ctx, ev, autofs_ctx->rctx,
++                                               autofs_ctx->rctx->ncache,
++                                               0, NULL, mapname);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
++        ret = ENOMEM;
++        goto done;
++    }
+ 
+-        /* Steal the dom_ctx onto the lookup_ctx so it doesn't go out of scope if
+-        * this request is canceled while other requests are in-progress.
+-        */
+-        lookup_ctx->dctx = talloc_steal(lookup_ctx, state->dctx);
+-        lookup_ctx->actx = actx;
+-        lookup_ctx->map = state->map;
+-        lookup_ctx->rctx = client->rctx;
+-        lookup_ctx->mapname =
+-                    talloc_strdup(lookup_ctx, state->mapname);
+-        if (!lookup_ctx->mapname) {
+-            talloc_free(state->map);
+-            ret = ENOMEM;
+-            goto fail;
+-        }
++    tevent_req_set_callback(subreq, autofs_setent_done, req);
+ 
+-        ret = lookup_automntmap_step(lookup_ctx);
+-        if (ret == EAGAIN) {
+-            DEBUG(SSSDBG_TRACE_INTERNAL, "lookup_automntmap_step "
+-                  "is refreshing the cache, re-entering the mainloop\n");
+-            return req;
+-        } else if (ret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Could not get data from cache\n");
+-            talloc_free(state->map);
+-            ret = ENOMEM;
+-            goto fail;
+-        }
++    ret = EAGAIN;
+ 
++done:
++    if (ret == EOK) {
+         tevent_req_done(req);
+-        tevent_req_post(req, cmdctx->cctx->ev);
+-        return req;
+-    } else {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Unexpected error from get_autofs_map [%d]: %s\n",
+-               ret, strerror(ret));
+-        goto fail;
++        tevent_req_post(req, ev);
++    } else if (ret != EAGAIN) {
++        tevent_req_error(req, ret);
++        tevent_req_post(req, ev);
+     }
+ 
+     return req;
+-
+-fail:
+-    tevent_req_error(req, ret);
+-    tevent_req_post(req, actx->rctx->ev);
+-    return req;
+ }
+ 
+-static errno_t
+-setautomntent_get_autofs_map(struct autofs_ctx *actx,
+-                             char *mapname,
+-                             struct autofs_map_ctx **map)
++static void autofs_setent_done(struct tevent_req *subreq)
+ {
++    struct autofs_setent_state *state;
++    struct cache_req_result *result;
++    struct tevent_req *req;
+     errno_t ret;
+ 
+-    if (strcmp(mapname, "auto.master") == 0) {
+-        /* Iterate over the hash and remove all maps */
+-        ret = autofs_orphan_maps(actx);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove existing maps from hash\n");
+-        }
+-        return ENOENT;
+-    }
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct autofs_setent_state);
+ 
+-    return get_autofs_map(actx, mapname, map);
+-}
++    ret = cache_req_autofs_map_entries_recv(state, subreq, &result);
++    talloc_zfree(subreq);
+ 
+-static errno_t
+-lookup_automntmap_update_cache(struct setautomntent_lookup_ctx *lookup_ctx);
+-
+-static errno_t
+-lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx)
+-{
+-    errno_t ret;
+-    struct sss_domain_info *dom = lookup_ctx->dctx->domain;
+-    struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
+-    struct sysdb_ctx *sysdb;
+-    struct autofs_map_ctx *map;
+-
+-    /* Check each domain for this map name */
+-    while (dom) {
+-        if (dom != dctx->domain) {
+-            /* make sure we reset the check_provider flag when we check
+-             * a new domain */
+-            dctx->check_provider =
+-                    NEED_CHECK_PROVIDER(dom->provider);
+-        }
++    switch (ret) {
++    case EOK:
++        state->enum_ctx->found = true;
++        state->enum_ctx->result = talloc_steal(state->enum_ctx, result);
++        autofs_set_enumctx_lifetime(state->autofs_ctx, state->enum_ctx,
++                        state->enum_ctx->result->domain->autofsmap_timeout);
++        break;
++    case ENOENT:
++        state->enum_ctx->found = false;
++        state->enum_ctx->result = NULL;
++        autofs_set_enumctx_lifetime(state->autofs_ctx, state->enum_ctx,
++                                    state->autofs_ctx->neg_timeout);
++        break;
++    default:
++        DEBUG(SSSDBG_OP_FAILURE, "Unable to get map data [%d]: %s\n",
++              ret, sss_strerror(ret));
+ 
+-        /* make sure to update the dctx if we changed domain */
+-        dctx->domain = dom;
++        setent_notify(&state->enum_ctx->notify_list, ret);
++        talloc_zfree(state->enum_ctx);
++        tevent_req_error(req, ret);
++        return;
++    }
+ 
+-        DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s@%s]\n",
+-              lookup_ctx->mapname, dom->name);
+-        sysdb = dom->sysdb;
+-        if (sysdb == NULL) {
+-            DEBUG(SSSDBG_FATAL_FAILURE,
+-                  "Fatal: Sysdb CTX not found for this domain!\n");
+-            return EIO;
+-        }
++    state->enum_ctx->ready = true;
+ 
+-        /* Look into the cache */
+-        talloc_free(dctx->map);
+-        ret = sysdb_get_map_byname(dctx, dom, lookup_ctx->mapname,
+-                                   &dctx->map);
+-        if (ret != EOK && ret != ENOENT) {
+-            DEBUG(SSSDBG_OP_FAILURE, "Could not check cache\n");
+-            return ret;
+-        } else if (ret == ENOENT) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "No automount map [%s] in cache for domain [%s]\n",
+-                   lookup_ctx->mapname, dom->name);
+-            if (!dctx->check_provider) {
+-                if (dctx->cmd_ctx->check_next) {
+-                    DEBUG(SSSDBG_TRACE_INTERNAL, "Moving on to next domain\n");
+-                    dom = get_next_domain(dom, 0);
+-                    continue;
+-                }
+-                else break;
+-            }
+-        }
++    /* Make the enumeration context disappear with maps table. */
++    talloc_steal(state->autofs_ctx->maps, state->enum_ctx);
+ 
+-        ret = get_autofs_map(lookup_ctx->actx, lookup_ctx->mapname, &map);
+-        if (ret != EOK) {
+-            /* Something really bad happened! */
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Autofs map entry was lost!\n");
+-            return ret;
+-        }
++    setent_notify_done(&state->enum_ctx->notify_list);
++    tevent_req_done(req);
++    return;
++}
+ 
+-        if (dctx->map == NULL && !dctx->check_provider) {
+-            DEBUG(SSSDBG_MINOR_FAILURE,
+-                  "Autofs map not found, setting negative cache\n");
+-            map->ready = true;
+-            map->found = false;
+-            set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
+-            return ENOENT;
+-        }
++static errno_t
++autofs_setent_recv(struct tevent_req *req,
++                   struct autofs_enum_ctx **_enum_ctx)
++{
++    struct autofs_setent_state *state;
++    state = tevent_req_data(req, struct autofs_setent_state);
+ 
+-        if (dctx->check_provider) {
+-            ret = lookup_automntmap_update_cache(lookup_ctx);
+-            if (ret == EAGAIN) {
+-                DEBUG(SSSDBG_TRACE_INTERNAL,
+-                      "Looking up automount maps from the DP\n");
+-                return EAGAIN;
+-            } else if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE,
+-                      "Error looking up automount maps [%d]: %s\n",
+-                       ret, strerror(ret));
+-                return ret;
+-            }
+-        }
++    TEVENT_REQ_RETURN_ON_ERROR(req);
+ 
+-        /* OK, the map is in cache and valid.
+-         * Let's get all members and return it
+-         */
+-        ret = sysdb_autofs_entries_by_map(map, dom, map->mapname,
+-                                          &map->entry_count,
+-                                          &map->entries);
+-        if (ret != EOK && ret != ENOENT) {
+-            DEBUG(SSSDBG_OP_FAILURE,
+-                  "Error looking automount map entries [%d]: %s\n",
+-                  ret, strerror(ret));
+-            map->ready = true;
+-            map->found = false;
+-            set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
+-            return EIO;
+-        }
++    *_enum_ctx = state->enum_ctx;
+ 
+-        map->map = talloc_steal(map, dctx->map);
++    return EOK;
++}
+ 
+-        DEBUG(SSSDBG_TRACE_FUNC,
+-              "setautomntent done for map %s\n", lookup_ctx->mapname);
+-        map->ready = true;
+-        map->found = true;
+-        set_autofs_map_lifetime(dom->autofsmap_timeout, lookup_ctx, map);
+-        return EOK;
+-    }
++static errno_t
++autofs_read_setautomntent_input(struct cli_ctx *cli_ctx,
++                                const char **_mapname)
++{
++    struct cli_protocol *pctx;
++    uint8_t *body;
++    size_t blen;
+ 
+-    map = talloc_zero(lookup_ctx->actx, struct autofs_map_ctx);
+-    if (!map) {
+-        return ENOMEM;
+-    }
++    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+ 
+-    map->ready = true;
+-    map->found = false;
+-    map->map_table = lookup_ctx->actx->maps;
++    sss_packet_get_body(pctx->creq->in, &body, &blen);
+ 
+-    map->mapname = talloc_strdup(map, lookup_ctx->mapname);
+-    if (!map->mapname) {
+-        talloc_free(map);
+-        return ENOMEM;
++    /* if not terminated fail */
++    if (body[blen - 1] != '\0') {
++        return EINVAL;
+     }
+ 
+-    ret = set_autofs_map(lookup_ctx->actx, map);
+-    if (ret != EOK) {
+-        talloc_free(map);
+-        return ENOMEM;
++    /* If the body isn't valid UTF-8, fail */
++    if (!sss_utf8_check(body, blen - 1)) {
++        return EINVAL;
+     }
+ 
+-    set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
++    *_mapname = (const char *)body;
+ 
+-    /* If we've gotten here, then no domain contained this map */
+-    return ENOENT;
++    return EOK;
+ }
+ 
+-static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
+-                                            const char *err_msg, void *ptr);
+-static void autofs_dp_send_map_req_done(struct tevent_req *req);
+-
+ static errno_t
+-lookup_automntmap_update_cache(struct setautomntent_lookup_ctx *lookup_ctx)
++autofs_write_setautomntent_output(struct cli_ctx *cli_ctx,
++                                  struct autofs_enum_ctx *enum_ctx)
+ {
++    struct cli_protocol *pctx;
++    uint8_t *body;
++    size_t blen;
+     errno_t ret;
+-    uint64_t cache_expire = 0;
+-    struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
+-    struct tevent_req *req = NULL;
+-    struct dp_callback_ctx *cb_ctx = NULL;
+-
+-    if (dctx->map != NULL) {
+-        if (strcmp(lookup_ctx->mapname, "auto.master") != 0) {
+-            cache_expire = ldb_msg_find_attr_as_uint64(dctx->map,
+-                                                       SYSDB_CACHE_EXPIRE, 0);
+-        }
+ 
+-        /* if we have any reply let's check cache validity */
+-        ret = sss_cmd_check_cache(dctx->map, 0, cache_expire);
+-        if (ret == EOK) {
+-            DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning..\n");
+-            return EOK;
+-        } else if (ret != EAGAIN && ret != ENOENT) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache: %d\n", ret);
+-            goto error;
+-        }
+-    }
++    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+ 
+-    /* dont loop forever :-) */
+-    dctx->check_provider = false;
+-
+-    /* keep around current data in case backend is offline */
+-    /* FIXME - do this by default */
+-#if 0
+-    if (dctx->res->count) {
+-        dctx->res = talloc_steal(dctx, dctx->res);
+-    }
+-#endif
+-
+-    req = sss_dp_get_autofs_send(lookup_ctx->cctx, lookup_ctx->rctx,
+-                                 lookup_ctx->dctx->domain, true,
+-                                 SSS_DP_AUTOFS, lookup_ctx->mapname);
+-    if (!req) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Out of memory sending data provider request\n");
+-        ret = ENOMEM;
+-        goto error;
++    ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
++                         &pctx->creq->out);
++    if (ret != EOK) {
++        return ret;
+     }
+ 
+-    cb_ctx = talloc_zero(lookup_ctx->dctx, struct dp_callback_ctx);
+-    if(!cb_ctx) {
+-        talloc_zfree(req);
+-        ret = ENOMEM;
+-        goto error;
++    if (!enum_ctx->found) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Map was not found\n");
++        return sss_cmd_empty_packet(pctx->creq->out);
+     }
+-    cb_ctx->callback = lookup_automntmap_cache_updated;
+-    cb_ctx->ptr = lookup_ctx;
+-    cb_ctx->cctx = lookup_ctx->dctx->cmd_ctx->cctx;
+-    cb_ctx->mem_ctx = lookup_ctx->dctx;
+-
+-    tevent_req_set_callback(req, autofs_dp_send_map_req_done, cb_ctx);
+ 
+-    return EAGAIN;
++    DEBUG(SSSDBG_TRACE_FUNC, "Map found\n");
+ 
+-error:
+-    ret = autofs_cmd_send_error(lookup_ctx->dctx->cmd_ctx, ret);
++    ret = sss_packet_grow(pctx->creq->out, 2 * sizeof(uint32_t));
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
+-        talloc_free(lookup_ctx->cctx);
+         return ret;
+     }
+-    autofs_cmd_done(lookup_ctx->dctx->cmd_ctx, ret);
+-    return EOK;
+-}
+-
+-static void autofs_dp_send_map_req_done(struct tevent_req *req)
+-{
+-    struct dp_callback_ctx *cb_ctx =
+-            tevent_req_callback_data(req, struct dp_callback_ctx);
+-    struct setautomntent_lookup_ctx *lookup_ctx =
+-            talloc_get_type(cb_ctx->ptr, struct setautomntent_lookup_ctx);
+-
+-    errno_t ret;
+-    dbus_uint16_t err_maj;
+-    dbus_uint32_t err_min;
+-    char *err_msg;
+-
+-    ret = sss_dp_get_autofs_recv(cb_ctx->mem_ctx, req,
+-                                 &err_maj, &err_min,
+-                                 &err_msg);
+-    talloc_free(req);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
+-        talloc_free(lookup_ctx->cctx);
+-        return;
+-    }
+-
+-    cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
+-}
+-
+-static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
+-                                            const char *err_msg, void *ptr)
+-{
+-    struct setautomntent_lookup_ctx *lookup_ctx =
+-            talloc_get_type(ptr, struct setautomntent_lookup_ctx);
+-    struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
+-    errno_t ret;
+-
+-    if (err_maj) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Unable to get information from Data Provider\n"
+-              "Error: %u, %u, %s\n"
+-              "Will try to return what we have in cache\n",
+-               (unsigned int)err_maj, (unsigned int)err_min, err_msg);
+-
+-        /* Try to fall back to cache */
+-        ret = lookup_automntmap_step(lookup_ctx);
+-        if (ret == EOK) {
+-            /* We have cached results to return */
+-            autofs_setent_notify(lookup_ctx->map, ret);
+-            return;
+-        }
+ 
+-        /* Otherwise try the next domain */
+-        if (dctx->cmd_ctx->check_next
+-                && (dctx->domain = get_next_domain(dctx->domain, 0))) {
+-            dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
+-        }
+-    }
++    sss_packet_get_body(pctx->creq->out, &body, &blen);
+ 
+-    ret = lookup_automntmap_step(lookup_ctx);
+-    if (ret != EOK) {
+-        if (ret == EAGAIN) {
+-            return;
+-        }
+-    }
++    /* Got some results */
++    SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
+ 
+-    /* We have results to return */
+-    autofs_setent_notify(lookup_ctx->map, ret);
+-}
++    /* Reserved padding */
++    SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
+ 
+-static errno_t
+-setautomntent_recv(struct tevent_req *req)
+-{
+-    TEVENT_REQ_RETURN_ON_ERROR(req);
+     return EOK;
+ }
+ 
+-static errno_t
+-getautomntent_process(struct autofs_cmd_ctx *cmdctx,
+-                      struct autofs_map_ctx *map,
+-                      uint32_t cursor, uint32_t max_entries);
+ static void
+-getautomntent_implicit_done(struct tevent_req *req);
+-static errno_t
+-fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp);
+-
++sss_autofs_cmd_setautomntent_done(struct tevent_req *req);
+ 
+ static int
+-sss_autofs_cmd_getautomntent(struct cli_ctx *client)
++sss_autofs_cmd_setautomntent(struct cli_ctx *cli_ctx)
+ {
+-    struct autofs_cmd_ctx *cmdctx;
+-    struct autofs_map_ctx *map;
+-    struct autofs_ctx *actx;
+-    struct cli_protocol *pctx;
+-    uint8_t *body;
+-    size_t blen;
+-    errno_t ret;
+-    uint32_t namelen;
+-    size_t c = 0;
++    struct autofs_cmd_ctx *cmd_ctx;
++    struct autofs_ctx *autofs_ctx;
+     struct tevent_req *req;
++    errno_t ret;
+ 
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntent\n");
++    autofs_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct autofs_ctx);
+ 
+-    cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
+-    if (!cmdctx) {
++    cmd_ctx = talloc_zero(cli_ctx, struct autofs_cmd_ctx);
++    if (cmd_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create command context.\n");
+         return ENOMEM;
+     }
+-    cmdctx->cctx = client;
+ 
+-    actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
+-    if (!actx) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs context\n");
+-        return EIO;
+-    }
++    cmd_ctx->cli_ctx = cli_ctx;
++    cmd_ctx->autofs_ctx = autofs_ctx;
+ 
+-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
+-
+-    /* get autofs map name and index to query */
+-    sss_packet_get_body(pctx->creq->in, &body, &blen);
+-
+-    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
+-
+-    if (namelen == 0 || namelen > blen - c) {
+-        ret = EINVAL;
++    ret = autofs_read_setautomntent_input(cli_ctx, &cmd_ctx->mapname);
++    if (ret != EOK) {
+         goto done;
+     }
+ 
+-    cmdctx->mapname = (char *) body+c;
++    DEBUG(SSSDBG_TRACE_FUNC, "Creating enumeration context for %s\n",
++          cmd_ctx->mapname);
+ 
+-    /* if not null-terminated fail */
+-    if (cmdctx->mapname[namelen] != '\0') {
+-        ret = EINVAL;
++    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx,
++                             cmd_ctx->mapname);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
++        ret = ENOMEM;
+         goto done;
+     }
+ 
+-    /* If the name isn't valid UTF-8, fail */
+-    if (!sss_utf8_check((const uint8_t *) cmdctx->mapname, namelen -1)) {
+-        ret = EINVAL;
+-        goto done;
+-    }
++    tevent_req_set_callback(req, sss_autofs_cmd_setautomntent_done, cmd_ctx);
+ 
+-    SAFEALIGN_COPY_UINT32_CHECK(&cmdctx->cursor, body+c+namelen+1, blen, &c);
+-    SAFEALIGN_COPY_UINT32_CHECK(&cmdctx->max_entries, body+c+namelen+1, blen, &c);
++    ret = EOK;
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC,
+-          "Requested data of map %s cursor %d max entries %d\n",
+-           cmdctx->mapname, cmdctx->cursor, cmdctx->max_entries);
++done:
++    return autofs_cmd_done(cmd_ctx, ret);
++}
+ 
+-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
+-    if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
+-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
+-        if (req == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
+-            ret = EIO;
+-            goto done;
+-        }
++static void
++sss_autofs_cmd_setautomntent_done(struct tevent_req *req)
++{
++    struct autofs_enum_ctx *enum_ctx;
++    struct autofs_cmd_ctx *cmd_ctx;
++    errno_t ret;
+ 
+-        tevent_req_set_callback(req, getautomntent_implicit_done, cmdctx);
+-        ret = EOK;
+-        goto done;
+-    } else if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "An unexpected error occurred: [%d][%s]\n",
+-              ret, strerror(ret));
+-        goto done;
+-    }
++    cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
+ 
+-    if (map->ready == false) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
+-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
+-        if (req == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
+-            ret = EIO;
+-            goto done;
+-        }
++    ret = autofs_setent_recv(req, &enum_ctx);
++    talloc_zfree(req);
++    if (ret != EOK) {
++        autofs_cmd_done(cmd_ctx, ret);
++        return;
++    }
+ 
+-        tevent_req_set_callback(req, getautomntent_implicit_done, cmdctx);
+-        ret = EOK;
+-        goto done;
+-    } else if (map->found == false) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "negative cache hit\n");
+-        ret = ENOENT;
+-        goto done;
++    ret = autofs_write_setautomntent_output(cmd_ctx->cli_ctx, enum_ctx);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        autofs_cmd_done(cmd_ctx, ret);
++        return;
+     }
+ 
+-    DEBUG(SSSDBG_TRACE_INTERNAL,
+-          "returning entries for [%s]\n", map->mapname);
++    sss_cmd_done(cmd_ctx->cli_ctx, NULL);
++}
+ 
+-    ret = getautomntent_process(cmdctx, map, cmdctx->cursor, cmdctx->max_entries);
++static int
++sss_autofs_cmd_endautomntent(struct cli_ctx *client)
++{
++    struct cli_protocol *pctx;
++    errno_t ret;
+ 
+-done:
+-    return autofs_cmd_done(cmdctx, ret);
++    DEBUG(SSSDBG_TRACE_FUNC, "endautomntent called\n");
++
++    pctx = talloc_get_type(client->protocol_ctx, struct cli_protocol);
++
++    /* create response packet */
++    ret = sss_packet_new(pctx->creq, 0,
++                         sss_packet_get_cmd(pctx->creq->in),
++                         &pctx->creq->out);
++
++    if (ret != EOK) {
++        return ret;
++    }
++
++    sss_cmd_done(client, NULL);
++    return EOK;
+ }
+ 
+-static void
+-getautomntent_implicit_done(struct tevent_req *req)
++static errno_t
++autofs_read_getautomntent_input(struct cli_ctx *cli_ctx,
++                                const char **_mapname,
++                                uint32_t *_cursor,
++                                uint32_t *_max_entries)
+ {
+-    errno_t ret;
+-    struct autofs_map_ctx *map;
+-    struct autofs_cmd_ctx *cmdctx =
+-        tevent_req_callback_data(req, struct autofs_cmd_ctx);
+-    struct autofs_ctx *actx =
+-        talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct autofs_ctx);
++    struct cli_protocol *pctx;
++    const char *mapname;
++    uint32_t namelen;
++    uint8_t *body;
++    size_t blen;
++    size_t c = 0;
+ 
+-    ret = setautomntent_recv(req);
+-    talloc_zfree(req);
+-    if (ret != EOK) {
+-        if (ret != ENOENT) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
+-        } else {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "No such map\n");
+-        }
+-        goto done;
++    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
++
++    sss_packet_get_body(pctx->creq->in, &body, &blen);
++
++    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
++    if (namelen == 0 || namelen > blen - c) {
++        return EINVAL;
+     }
+ 
+-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Cannot get map after setautomntent succeeded?\n");
+-        goto done;
++    mapname = (const char *)body + c;
++
++    /* if not null-terminated fail */
++    if (mapname[namelen] != '\0') {
++        return EINVAL;
+     }
+ 
+-    if (map->ready == false) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Map not ready after setautomntent succeeded\n");
+-        goto done;
++    /* If the name isn't valid UTF-8, fail */
++    if (!sss_utf8_check((const uint8_t *)mapname, namelen - 1)) {
++        return EINVAL;
+     }
+ 
+-    ret = getautomntent_process(cmdctx, map,
+-                                cmdctx->cursor, cmdctx->max_entries);
+-done:
+-    autofs_cmd_done(cmdctx, ret);
+-    return;
++    SAFEALIGN_COPY_UINT32_CHECK(_cursor, body + c + namelen + 1, blen, &c);
++    SAFEALIGN_COPY_UINT32_CHECK(_max_entries, body + c + namelen + 1, blen, &c);
++    *_mapname = mapname;
++
++    return EOK;
+ }
+ 
+ static errno_t
+-getautomntent_process(struct autofs_cmd_ctx *cmdctx,
+-                      struct autofs_map_ctx *map,
+-                      uint32_t cursor, uint32_t max_entries)
++autofs_write_getautomntent_output(struct cli_ctx *cli_ctx,
++                                  struct autofs_enum_ctx *enum_ctx,
++                                  uint32_t cursor,
++                                  uint32_t max_entries)
+ {
+     struct cli_protocol *pctx;
+-    errno_t ret;
++    struct ldb_message **entries;
+     struct ldb_message *entry;
+-    size_t rp;
+-    uint32_t i, stop, left, nentries;
++    size_t count;
++    size_t num_entries;
+     uint8_t *body;
+     size_t blen;
++    size_t rp;
++    uint32_t i;
++    uint32_t stop;
++    uint32_t left;
++    errno_t ret;
+ 
+-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
++    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+ 
+-    /* create response packet */
+-    ret = sss_packet_new(pctx->creq, 0,
+-                         sss_packet_get_cmd(pctx->creq->in),
++    count = enum_ctx->found ? enum_ctx->result->count - 1 : 0;
++    entries = count > 0 ? enum_ctx->result->msgs + 1 : NULL;
++
++    ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
+                          &pctx->creq->out);
+     if (ret != EOK) {
+         return ret;
+     }
+ 
+-    if (!map->map || !map->entries || !map->entries[0] ||
+-        cursor >= map->entry_count) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "No entries found\n");
+-        ret = sss_cmd_empty_packet(pctx->creq->out);
+-        if (ret != EOK) {
+-            return autofs_cmd_done(cmdctx, ret);
+-        }
+-        goto done;
++    if (!enum_ctx->found || count == 0 || cursor >= count) {
++        DEBUG(SSSDBG_TRACE_FUNC, "No entries was not found\n");
++        return sss_cmd_empty_packet(pctx->creq->out);
+     }
+ 
+     /* allocate memory for number of entries in the packet */
+     ret = sss_packet_grow(pctx->creq->out, sizeof(uint32_t));
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
+-        goto done;
++        return ret;
+     }
+ 
+-    rp = sizeof(uint32_t);  /* We'll write the number of entries here */
+-
+-    left = map->entry_count - cursor;
++    rp = sizeof(uint32_t);  /* We will first write the elements. */
++    left = count - cursor;
+     stop = max_entries < left ? max_entries : left;
+ 
+-    nentries = 0;
+-    for (i=0; i < stop; i++) {
+-        entry = map->entries[cursor];
++    num_entries = 0;
++    for (i = 0; i < stop; i++) {
++        entry = entries[cursor];
+         cursor++;
+ 
+-        ret = fill_autofs_entry(entry, pctx->creq->out, &rp);
++        ret = autofs_fill_entry(entry, pctx->creq->out, &rp);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+                   "Cannot fill entry %d/%d, skipping\n", i, stop);
+             continue;
+         }
+-        nentries++;
++        num_entries++;
+     }
+ 
+     /* packet grows in fill_autofs_entry, body pointer may change,
+@@ -1137,311 +605,212 @@ getautomntent_process(struct autofs_cmd_ctx *cmdctx,
+     sss_packet_get_body(pctx->creq->out, &body, &blen);
+ 
+     rp = 0;
+-    SAFEALIGN_SET_UINT32(&body[rp], nentries, &rp);
+-
+-    ret = EOK;
+-done:
+-    sss_packet_set_error(pctx->creq->out, ret);
+-    sss_cmd_done(cmdctx->cctx, cmdctx);
++    SAFEALIGN_SET_UINT32(&body[rp], num_entries, &rp);
+ 
+     return EOK;
+ }
+ 
+-static errno_t
+-fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp)
++static void
++sss_autofs_cmd_getautomntent_done(struct tevent_req *req);
++
++static int
++sss_autofs_cmd_getautomntent(struct cli_ctx *cli_ctx)
+ {
++    struct autofs_cmd_ctx *cmd_ctx;
++    struct autofs_ctx *autofs_ctx;
++    struct tevent_req *req;
+     errno_t ret;
+-    const char *key;
+-    size_t keylen;
+-    const char *value;
+-    size_t valuelen;
+-    uint8_t *body;
+-    size_t blen;
+-    size_t len;
+ 
+-    key = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_KEY, NULL);
+-    value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
+-    if (!key || !value) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Incomplete entry\n");
+-        return EINVAL;
++    autofs_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct autofs_ctx);
++
++    cmd_ctx = talloc_zero(cli_ctx, struct autofs_cmd_ctx);
++    if (cmd_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create command context.\n");
++        return ENOMEM;
+     }
+ 
+-    keylen = 1 + strlen(key);
+-    valuelen = 1 + strlen(value);
+-    len = sizeof(uint32_t) + sizeof(uint32_t) + keylen + sizeof(uint32_t) + valuelen;
++    cmd_ctx->cli_ctx = cli_ctx;
++    cmd_ctx->autofs_ctx = autofs_ctx;
+ 
+-    ret = sss_packet_grow(packet, len);
++    ret = autofs_read_getautomntent_input(cli_ctx, &cmd_ctx->mapname,
++                                          &cmd_ctx->cursor,
++                                          &cmd_ctx->max_entries);
+     if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
+-        return ret;
++        goto done;
+     }
+ 
+-    sss_packet_get_body(packet, &body, &blen);
+-
+-    SAFEALIGN_SET_UINT32(&body[*rp], len, rp);
+-    SAFEALIGN_SET_UINT32(&body[*rp], keylen, rp);
++    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining enumeration context for %s\n",
++          cmd_ctx->mapname);
+ 
+-    if (keylen == 1) {
+-        body[*rp] = '\0';
+-    } else {
+-        memcpy(&body[*rp], key, keylen);
++    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx, cmd_ctx->mapname);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
++        ret = ENOMEM;
++        goto done;
+     }
+-    *rp += keylen;
+ 
+-    SAFEALIGN_SET_UINT32(&body[*rp], valuelen, rp);
+-    if (valuelen == 1) {
+-        body[*rp] = '\0';
+-    } else {
+-        memcpy(&body[*rp], value, valuelen);
+-    }
+-    *rp += valuelen;
++    tevent_req_set_callback(req, sss_autofs_cmd_getautomntent_done, cmd_ctx);
+ 
+-    return EOK;
++    ret = EOK;
++
++done:
++    return autofs_cmd_done(cmd_ctx, ret);
+ }
+ 
+-static errno_t
+-getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
+-                         struct autofs_map_ctx *map,
+-                         const char *key);
+ static void
+-getautomntbyname_implicit_done(struct tevent_req *req);
+-
+-static int
+-sss_autofs_cmd_getautomntbyname(struct cli_ctx *client)
++sss_autofs_cmd_getautomntent_done(struct tevent_req *req)
+ {
++    struct autofs_enum_ctx *enum_ctx;
++    struct autofs_cmd_ctx *cmd_ctx;
+     errno_t ret;
+-    struct autofs_cmd_ctx *cmdctx;
+-    struct autofs_map_ctx *map;
+-    struct autofs_ctx *actx;
+-    struct cli_protocol *pctx;
+-    uint8_t *body;
+-    size_t blen;
+-    uint32_t namelen;
+-    uint32_t keylen;
+-    size_t c = 0;
+-    struct tevent_req *req;
+ 
+-    DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntbyname\n");
++    cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
+ 
+-    cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
+-    if (!cmdctx) {
+-        return ENOMEM;
++    ret = autofs_setent_recv(req, &enum_ctx);
++    talloc_zfree(req);
++    if (ret != EOK) {
++        autofs_cmd_done(cmd_ctx, ret);
++        return;
+     }
+-    cmdctx->cctx = client;
+ 
+-    actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
+-    if (!actx) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs context\n");
+-        return EIO;
++    ret = autofs_write_getautomntent_output(cmd_ctx->cli_ctx, enum_ctx,
++                                            cmd_ctx->cursor,
++                                            cmd_ctx->max_entries);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        autofs_cmd_done(cmd_ctx, ret);
++        return;
+     }
+ 
+-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
++    sss_cmd_done(cmd_ctx->cli_ctx, NULL);
++}
+ 
+-    /* get autofs map name and index to query */
+-    sss_packet_get_body(pctx->creq->in, &body, &blen);
++static errno_t
++autofs_read_getautomntbyname_input(struct cli_ctx *cli_ctx,
++                                   const char **_mapname,
++                                   const char **_keyname)
++{
++    struct cli_protocol *pctx;
++    const char *mapname;
++    const char *keyname;
++    uint32_t namelen;
++    uint32_t keylen;
++    uint8_t *body;
++    size_t blen;
++    size_t c = 0;
+ 
+-    /* FIXME - split out a function to get string from <len><str>\0 */
+-    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
++    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
++
++    sss_packet_get_body(pctx->creq->in, &body, &blen);
+ 
++    /* Get map name. */
++    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body + c, blen, &c);
+     if (namelen == 0 || namelen > blen - c) {
+-        ret = EINVAL;
+-        goto done;
++        return EINVAL;
+     }
+ 
+-    cmdctx->mapname = (char *) body+c;
++    mapname = (const  char *) body + c;
+ 
+     /* if not null-terminated fail */
+-    if (cmdctx->mapname[namelen] != '\0') {
+-        ret = EINVAL;
+-        goto done;
++    if (mapname[namelen] != '\0') {
++        return EINVAL;
+     }
+ 
+     /* If the name isn't valid UTF-8, fail */
+-    if (!sss_utf8_check((const uint8_t *) cmdctx->mapname, namelen -1)) {
+-        ret = EINVAL;
+-        goto done;
++    if (!sss_utf8_check((const uint8_t *)mapname, namelen - 1)) {
++        return EINVAL;
+     }
+ 
+     c += namelen + 1;
+ 
+-    /* FIXME - split out a function to get string from <len><str>\0 */
+-    SAFEALIGN_COPY_UINT32_CHECK(&keylen, body+c, blen, &c);
+-
++    /* Get key name. */
++    SAFEALIGN_COPY_UINT32_CHECK(&keylen, body + c, blen, &c);
+     if (keylen == 0 || keylen > blen - c) {
+-        ret = EINVAL;
+-        goto done;
++        return EINVAL;
+     }
+ 
+-    cmdctx->key = (char *) body+c;
++    keyname = (const char *) body + c;
+ 
+     /* if not null-terminated fail */
+-    if (cmdctx->key[keylen] != '\0') {
+-        ret = EINVAL;
+-        goto done;
++    if (keyname[keylen] != '\0') {
++        return EINVAL;
+     }
+ 
+     /* If the key isn't valid UTF-8, fail */
+-    if (!sss_utf8_check((const uint8_t *) cmdctx->key, keylen -1)) {
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    DEBUG(SSSDBG_TRACE_FUNC,
+-          "Requested data of map %s key %s\n", cmdctx->mapname, cmdctx->key);
+-
+-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
+-    if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
+-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
+-        if (req == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
+-            ret = EIO;
+-            goto done;
+-        }
+-
+-        tevent_req_set_callback(req, getautomntbyname_implicit_done, cmdctx);
+-        ret = EOK;
+-        goto done;
+-    } else if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "An unexpected error occurred: [%d][%s]\n",
+-              ret, strerror(ret));
+-        goto done;
+-    }
+-
+-    if (map->ready == false) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
+-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
+-        if (req == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
+-            ret = EIO;
+-            goto done;
+-        }
+-
+-        tevent_req_set_callback(req, getautomntbyname_implicit_done, cmdctx);
+-        ret = EOK;
+-        goto done;
+-    } else if (map->found == false) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "negative cache hit\n");
+-        ret = ENOENT;
+-        goto done;
+-    }
+-
+-    DEBUG(SSSDBG_TRACE_INTERNAL,
+-          "Looking up value for [%s] in [%s]\n", cmdctx->key, map->mapname);
+-
+-    ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
+-
+-done:
+-    return autofs_cmd_done(cmdctx, ret);
+-}
+-
+-static void
+-getautomntbyname_implicit_done(struct tevent_req *req)
+-{
+-    errno_t ret;
+-    struct autofs_map_ctx *map;
+-    struct autofs_cmd_ctx *cmdctx =
+-        tevent_req_callback_data(req, struct autofs_cmd_ctx);
+-    struct autofs_ctx *actx =
+-        talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct autofs_ctx);
+-
+-    ret = setautomntent_recv(req);
+-    talloc_zfree(req);
+-    if (ret != EOK) {
+-        if (ret != ENOENT) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
+-        } else {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "No such map\n");
+-        }
+-        goto done;
+-    }
+-
+-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Cannot get map after setautomntent succeeded?\n");
+-        goto done;
++    if (!sss_utf8_check((const uint8_t *)keyname, keylen - 1)) {
++        return EINVAL;
+     }
+ 
+-    if (map->ready == false) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Map not ready after setautomntent succeeded\n");
+-        goto done;
+-    }
++    *_mapname = mapname;
++    *_keyname = keyname;
+ 
+-    ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
+-done:
+-    autofs_cmd_done(cmdctx, ret);
+-    return;
++    return EOK;
+ }
+ 
+ static errno_t
+-getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
+-                         struct autofs_map_ctx *map,
+-                         const char *key)
++autofs_write_getautomntbyname_output(struct cli_ctx *cli_ctx,
++                                     struct autofs_enum_ctx *enum_ctx,
++                                     const char *keyname)
+ {
+     struct cli_protocol *pctx;
+-    errno_t ret;
+-    size_t i;
+-    const char *k;
++    struct ldb_message **entries;
++    struct ldb_message *entry = NULL;
++    const char *entry_key;
+     const char *value;
+-    size_t valuelen;
++    size_t value_len;
+     size_t len;
++    size_t count;
+     uint8_t *body;
+-    size_t blen, rp;
++    size_t blen;
++    size_t rp;
++    size_t i;
++    errno_t ret;
+ 
+-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
++    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+ 
+-    /* create response packet */
+-    ret = sss_packet_new(pctx->creq, 0,
+-                         sss_packet_get_cmd(pctx->creq->in),
++    count = enum_ctx->found ? enum_ctx->result->count - 1 : 0;
++    entries = count > 0 ? enum_ctx->result->msgs + 1 : NULL;
++
++    ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
+                          &pctx->creq->out);
+     if (ret != EOK) {
+         return ret;
+     }
+ 
+-    if (!map->map || !map->entries || !map->entries[0]) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "No entries found\n");
+-        ret = sss_cmd_empty_packet(pctx->creq->out);
+-        if (ret != EOK) {
+-            return autofs_cmd_done(cmdctx, ret);
+-        }
+-        goto done;
+-    }
+-
+-    for (i=0; i < map->entry_count; i++) {
+-        k = ldb_msg_find_attr_as_string(map->entries[i],
+-                                        SYSDB_AUTOFS_ENTRY_KEY, NULL);
+-        if (!k) {
++    for (i = 0; i < count; i++) {
++        entry_key = ldb_msg_find_attr_as_string(entries[i],
++                                                SYSDB_AUTOFS_ENTRY_KEY,
++                                                NULL);
++        if (entry_key == NULL) {
+             DEBUG(SSSDBG_MINOR_FAILURE, "Skipping incomplete entry\n");
+             continue;
+         }
+ 
+-        if (strcmp(k, key) == 0) {
+-            DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", key);
++        if (strcmp(entry_key, keyname) == 0) {
++            DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", keyname);
++            entry = entries[i];
+             break;
+         }
+     }
+ 
+-    if (i >= map->entry_count) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "No key named [%s] found\n", key);
+-        ret = sss_cmd_empty_packet(pctx->creq->out);
+-        if (ret != EOK) {
+-            return autofs_cmd_done(cmdctx, ret);
+-        }
+-        goto done;
++    if (!enum_ctx->found || count == 0 || entry == NULL) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Key [%s] was not found\n", keyname);
++        return sss_cmd_empty_packet(pctx->creq->out);
+     }
+ 
+-    value = ldb_msg_find_attr_as_string(map->entries[i],
+-                                        SYSDB_AUTOFS_ENTRY_VALUE, NULL);
++    value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
++    if (value == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "No entry value found in [%s]\n", keyname);
++        return EINVAL;
++    }
+ 
+-    valuelen = 1 + strlen(value);
+-    len = sizeof(uint32_t) + sizeof(uint32_t) + valuelen;
++    value_len = 1 + strlen(value);
++    len = sizeof(uint32_t) + sizeof(uint32_t) + value_len;
+ 
+     ret = sss_packet_grow(pctx->creq->out, len);
+     if (ret != EOK) {
+-        goto done;
++        return ret;
+     }
+ 
+     sss_packet_get_body(pctx->creq->out, &body, &blen);
+@@ -1449,43 +818,88 @@ getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
+     rp = 0;
+     SAFEALIGN_SET_UINT32(&body[rp], len, &rp);
+ 
+-    SAFEALIGN_SET_UINT32(&body[rp], valuelen, &rp);
+-    if (valuelen == 1) {
++    SAFEALIGN_SET_UINT32(&body[rp], value_len, &rp);
++    if (value_len == 1) {
+         body[rp] = '\0';
+     } else {
+-        memcpy(&body[rp], value, valuelen);
++        memcpy(&body[rp], value, value_len);
+     }
+-    rp += valuelen;
+-
+-    ret = EOK;
+-done:
+-    sss_packet_set_error(pctx->creq->out, ret);
+-    sss_cmd_done(cmdctx->cctx, cmdctx);
+ 
+     return EOK;
+ }
+ 
++static void
++sss_autofs_cmd_getautomntbyname_done(struct tevent_req *req);
++
+ static int
+-sss_autofs_cmd_endautomntent(struct cli_ctx *client)
++sss_autofs_cmd_getautomntbyname(struct cli_ctx *cli_ctx)
+ {
+-    struct cli_protocol *pctx;
++    struct autofs_cmd_ctx *cmd_ctx;
++    struct autofs_ctx *autofs_ctx;
++    struct tevent_req *req;
+     errno_t ret;
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC, "endautomntent called\n");
++    autofs_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct autofs_ctx);
+ 
+-    pctx = talloc_get_type(client->protocol_ctx, struct cli_protocol);
++    cmd_ctx = talloc_zero(cli_ctx, struct autofs_cmd_ctx);
++    if (cmd_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create command context.\n");
++        return ENOMEM;
++    }
+ 
+-    /* create response packet */
+-    ret = sss_packet_new(pctx->creq, 0,
+-                         sss_packet_get_cmd(pctx->creq->in),
+-                         &pctx->creq->out);
++    cmd_ctx->cli_ctx = cli_ctx;
++    cmd_ctx->autofs_ctx = autofs_ctx;
+ 
++    ret = autofs_read_getautomntbyname_input(cli_ctx, &cmd_ctx->mapname,
++                                             &cmd_ctx->keyname);
+     if (ret != EOK) {
+-        return ret;
++        goto done;
+     }
+ 
+-    sss_cmd_done(client, NULL);
+-    return EOK;
++    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining enumeration context for %s\n",
++          cmd_ctx->mapname);
++
++    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx, cmd_ctx->mapname);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    tevent_req_set_callback(req, sss_autofs_cmd_getautomntbyname_done, cmd_ctx);
++
++    ret = EOK;
++
++done:
++    return autofs_cmd_done(cmd_ctx, ret);
++}
++
++static void
++sss_autofs_cmd_getautomntbyname_done(struct tevent_req *req)
++{
++    struct autofs_enum_ctx *enum_ctx;
++    struct autofs_cmd_ctx *cmd_ctx;
++    errno_t ret;
++
++    cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
++
++    ret = autofs_setent_recv(req, &enum_ctx);
++    talloc_zfree(req);
++    if (ret != EOK) {
++        autofs_cmd_done(cmd_ctx, ret);
++        return;
++    }
++
++    ret = autofs_write_getautomntbyname_output(cmd_ctx->cli_ctx, enum_ctx,
++                                               cmd_ctx->keyname);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
++              "[%d]: %s\n", ret, sss_strerror(ret));
++        autofs_cmd_done(cmd_ctx, ret);
++        return;
++    }
++
++    sss_cmd_done(cmd_ctx->cli_ctx, NULL);
+ }
+ 
+ struct cli_protocol_version *register_cli_protocol_version(void)
+@@ -1518,10 +932,5 @@ int autofs_connection_setup(struct cli_ctx *cctx)
+     ret = sss_connection_setup(cctx);
+     if (ret != EOK) return ret;
+ 
+-    cctx->state_ctx = talloc_zero(cctx, struct autofs_state_ctx);
+-    if (!cctx->state_ctx) {
+-        return ENOMEM;
+-    }
+-
+     return EOK;
+ }
+-- 
+2.20.1
+
diff --git a/SOURCES/0079-autofs-use-cache_req-to-obtain-single-entry-in-geten.patch b/SOURCES/0079-autofs-use-cache_req-to-obtain-single-entry-in-geten.patch
new file mode 100644
index 0000000..3e308a2
--- /dev/null
+++ b/SOURCES/0079-autofs-use-cache_req-to-obtain-single-entry-in-geten.patch
@@ -0,0 +1,131 @@
+From 27d2dcfb76625bffe34d2fe185d7677db3f372d6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 13 Aug 2019 13:10:03 +0200
+Subject: [PATCH 79/90] autofs: use cache_req to obtain single entry in
+ getentrybyname
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/responder/autofs/autofssrv_cmd.c | 54 ++++++++++------------------
+ 1 file changed, 19 insertions(+), 35 deletions(-)
+
+diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
+index 670b6d50d..59e64014d 100644
+--- a/src/responder/autofs/autofssrv_cmd.c
++++ b/src/responder/autofs/autofssrv_cmd.c
+@@ -750,27 +750,28 @@ autofs_read_getautomntbyname_input(struct cli_ctx *cli_ctx,
+ 
+ static errno_t
+ autofs_write_getautomntbyname_output(struct cli_ctx *cli_ctx,
+-                                     struct autofs_enum_ctx *enum_ctx,
++                                     struct cache_req_result *result,
+                                      const char *keyname)
+ {
+     struct cli_protocol *pctx;
+-    struct ldb_message **entries;
+-    struct ldb_message *entry = NULL;
+-    const char *entry_key;
++    struct ldb_message *entry;
+     const char *value;
+     size_t value_len;
+     size_t len;
+-    size_t count;
+     uint8_t *body;
+     size_t blen;
+     size_t rp;
+-    size_t i;
+     errno_t ret;
+ 
+     pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+ 
+-    count = enum_ctx->found ? enum_ctx->result->count - 1 : 0;
+-    entries = count > 0 ? enum_ctx->result->msgs + 1 : NULL;
++    if (result == NULL || result->count == 0) {
++        DEBUG(SSSDBG_TRACE_FUNC, "Key [%s] was not found\n", keyname);
++        return sss_cmd_empty_packet(pctx->creq->out);
++    }
++
++    DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", keyname);
++    entry = result->msgs[0];
+ 
+     ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
+                          &pctx->creq->out);
+@@ -778,27 +779,6 @@ autofs_write_getautomntbyname_output(struct cli_ctx *cli_ctx,
+         return ret;
+     }
+ 
+-    for (i = 0; i < count; i++) {
+-        entry_key = ldb_msg_find_attr_as_string(entries[i],
+-                                                SYSDB_AUTOFS_ENTRY_KEY,
+-                                                NULL);
+-        if (entry_key == NULL) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Skipping incomplete entry\n");
+-            continue;
+-        }
+-
+-        if (strcmp(entry_key, keyname) == 0) {
+-            DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", keyname);
+-            entry = entries[i];
+-            break;
+-        }
+-    }
+-
+-    if (!enum_ctx->found || count == 0 || entry == NULL) {
+-        DEBUG(SSSDBG_TRACE_FUNC, "Key [%s] was not found\n", keyname);
+-        return sss_cmd_empty_packet(pctx->creq->out);
+-    }
+-
+     value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
+     if (value == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "No entry value found in [%s]\n", keyname);
+@@ -856,10 +836,14 @@ sss_autofs_cmd_getautomntbyname(struct cli_ctx *cli_ctx)
+         goto done;
+     }
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining enumeration context for %s\n",
+-          cmd_ctx->mapname);
++    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining autofs entry %s:%s\n",
++          cmd_ctx->mapname, cmd_ctx->keyname);
+ 
+-    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx, cmd_ctx->mapname);
++    req = cache_req_autofs_entry_by_name_send(cli_ctx, cli_ctx->ev,
++                                              autofs_ctx->rctx,
++                                              autofs_ctx->rctx->ncache, 0, NULL,
++                                              cmd_ctx->mapname,
++                                              cmd_ctx->keyname);
+     if (req == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
+         ret = ENOMEM;
+@@ -877,20 +861,20 @@ done:
+ static void
+ sss_autofs_cmd_getautomntbyname_done(struct tevent_req *req)
+ {
+-    struct autofs_enum_ctx *enum_ctx;
++    struct cache_req_result *result;
+     struct autofs_cmd_ctx *cmd_ctx;
+     errno_t ret;
+ 
+     cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
+ 
+-    ret = autofs_setent_recv(req, &enum_ctx);
++    ret = cache_req_autofs_entry_by_name_recv(cmd_ctx, req, &result);
+     talloc_zfree(req);
+     if (ret != EOK) {
+         autofs_cmd_done(cmd_ctx, ret);
+         return;
+     }
+ 
+-    ret = autofs_write_getautomntbyname_output(cmd_ctx->cli_ctx, enum_ctx,
++    ret = autofs_write_getautomntbyname_output(cmd_ctx->cli_ctx, result,
+                                                cmd_ctx->keyname);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
+-- 
+2.20.1
+
diff --git a/SOURCES/0080-autofs-use-cache_req-to-obtain-map-in-setent.patch b/SOURCES/0080-autofs-use-cache_req-to-obtain-map-in-setent.patch
new file mode 100644
index 0000000..ecca7e3
--- /dev/null
+++ b/SOURCES/0080-autofs-use-cache_req-to-obtain-map-in-setent.patch
@@ -0,0 +1,82 @@
+From 61a7bf4d2a93f99a5c94da4367d350f8038bb935 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 14 Aug 2019 11:41:56 +0200
+Subject: [PATCH 80/90] autofs: use cache_req to obtain map in setent
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/responder/autofs/autofssrv_cmd.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
+index 59e64014d..d413f8570 100644
+--- a/src/responder/autofs/autofssrv_cmd.c
++++ b/src/responder/autofs/autofssrv_cmd.c
+@@ -365,7 +365,7 @@ autofs_read_setautomntent_input(struct cli_ctx *cli_ctx,
+ 
+ static errno_t
+ autofs_write_setautomntent_output(struct cli_ctx *cli_ctx,
+-                                  struct autofs_enum_ctx *enum_ctx)
++                                  struct cache_req_result *result)
+ {
+     struct cli_protocol *pctx;
+     uint8_t *body;
+@@ -380,7 +380,7 @@ autofs_write_setautomntent_output(struct cli_ctx *cli_ctx,
+         return ret;
+     }
+ 
+-    if (!enum_ctx->found) {
++    if (result == NULL || result->count == 0) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Map was not found\n");
+         return sss_cmd_empty_packet(pctx->creq->out);
+     }
+@@ -430,11 +430,13 @@ sss_autofs_cmd_setautomntent(struct cli_ctx *cli_ctx)
+         goto done;
+     }
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC, "Creating enumeration context for %s\n",
++    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining autofs map %s\n",
+           cmd_ctx->mapname);
+ 
+-    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx,
+-                             cmd_ctx->mapname);
++    req = cache_req_autofs_map_by_name_send(cli_ctx, cli_ctx->ev,
++                                            autofs_ctx->rctx,
++                                            autofs_ctx->rctx->ncache, 0, NULL,
++                                            cmd_ctx->mapname);
+     if (req == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
+         ret = ENOMEM;
+@@ -452,20 +454,20 @@ done:
+ static void
+ sss_autofs_cmd_setautomntent_done(struct tevent_req *req)
+ {
+-    struct autofs_enum_ctx *enum_ctx;
++    struct cache_req_result *result;
+     struct autofs_cmd_ctx *cmd_ctx;
+     errno_t ret;
+ 
+     cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
+ 
+-    ret = autofs_setent_recv(req, &enum_ctx);
++    ret = cache_req_autofs_map_by_name_recv(cmd_ctx, req, &result);
+     talloc_zfree(req);
+     if (ret != EOK) {
+         autofs_cmd_done(cmd_ctx, ret);
+         return;
+     }
+ 
+-    ret = autofs_write_setautomntent_output(cmd_ctx->cli_ctx, enum_ctx);
++    ret = autofs_write_setautomntent_output(cmd_ctx->cli_ctx, result);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+-- 
+2.20.1
+
diff --git a/SOURCES/0081-dp-replace-autofs-handler-with-enumerate-method.patch b/SOURCES/0081-dp-replace-autofs-handler-with-enumerate-method.patch
new file mode 100644
index 0000000..0525173
--- /dev/null
+++ b/SOURCES/0081-dp-replace-autofs-handler-with-enumerate-method.patch
@@ -0,0 +1,196 @@
+From ca1ee9933b9cdb474cef46bde127eaf85f1861d1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 28 Aug 2019 12:11:51 +0200
+Subject: [PATCH 81/90] dp: replace autofs handler with enumerate method
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/providers/data_provider/dp.h              |  3 +-
+ .../data_provider/dp_target_autofs.c          |  2 +-
+ src/providers/ipa/ipa_autofs.c                |  4 +-
+ src/providers/ldap/ldap_common.h              | 14 +++----
+ src/providers/ldap/sdap_autofs.c              | 38 +++++++++----------
+ 5 files changed, 31 insertions(+), 30 deletions(-)
+
+diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
+index e8b2f9c8f..8ef4a92ae 100644
+--- a/src/providers/data_provider/dp.h
++++ b/src/providers/data_provider/dp.h
+@@ -78,7 +78,6 @@ enum dp_methods {
+     DPM_ACCESS_HANDLER,
+     DPM_SELINUX_HANDLER,
+     DPM_SUDO_HANDLER,
+-    DPM_AUTOFS_HANDLER,
+     DPM_HOSTID_HANDLER,
+     DPM_DOMAINS_HANDLER,
+     DPM_SESSION_HANDLER,
+@@ -86,6 +85,8 @@ enum dp_methods {
+ 
+     DPM_REFRESH_ACCESS_RULES,
+ 
++    DPM_AUTOFS_ENUMERATE,
++
+     DP_METHOD_SENTINEL
+ };
+ 
+diff --git a/src/providers/data_provider/dp_target_autofs.c b/src/providers/data_provider/dp_target_autofs.c
+index 13b12f5dd..5f24f2975 100644
+--- a/src/providers/data_provider/dp_target_autofs.c
++++ b/src/providers/data_provider/dp_target_autofs.c
+@@ -48,7 +48,7 @@ errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+     key = mapname;
+ 
+     dp_req_with_reply(dp_cli, NULL, "AutoFS", key, sbus_req, DPT_AUTOFS,
+-                      DPM_AUTOFS_HANDLER, dp_flags, data,
++                      DPM_AUTOFS_ENUMERATE, dp_flags, data,
+                       dp_req_reply_std, struct dp_reply_std);
+ 
+     return EOK;
+diff --git a/src/providers/ipa/ipa_autofs.c b/src/providers/ipa/ipa_autofs.c
+index b2e4cbc06..50e30f39f 100644
+--- a/src/providers/ipa/ipa_autofs.c
++++ b/src/providers/ipa/ipa_autofs.c
+@@ -47,8 +47,8 @@ errno_t ipa_autofs_init(TALLOC_CTX *mem_ctx,
+         return ret;
+     }
+ 
+-    dp_set_method(dp_methods, DPM_AUTOFS_HANDLER,
+-                  sdap_autofs_handler_send, sdap_autofs_handler_recv, id_ctx->sdap_id_ctx,
++    dp_set_method(dp_methods, DPM_AUTOFS_ENUMERATE,
++                  sdap_autofs_enumerate_handler_send, sdap_autofs_enumerate_handler_recv, id_ctx,
+                   struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+ 
+     return ret;
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index f30b67eb3..85dc6949c 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -156,15 +156,15 @@ sdap_pam_chpass_handler_recv(TALLOC_CTX *mem_ctx,
+ 
+ /* autofs */
+ struct tevent_req *
+-sdap_autofs_handler_send(TALLOC_CTX *mem_ctx,
+-                         struct sdap_id_ctx *id_ctx,
+-                         struct dp_autofs_data *data,
+-                         struct dp_req_params *params);
++sdap_autofs_enumerate_handler_send(TALLOC_CTX *mem_ctx,
++                                   struct sdap_id_ctx *id_ctx,
++                                   struct dp_autofs_data *data,
++                                   struct dp_req_params *params);
+ 
+ errno_t
+-sdap_autofs_handler_recv(TALLOC_CTX *mem_ctx,
+-                         struct tevent_req *req,
+-                         struct dp_reply_std *data);
++sdap_autofs_enumerate_handler_recv(TALLOC_CTX *mem_ctx,
++                                   struct tevent_req *req,
++                                   struct dp_reply_std *data);
+ 
+ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *service_name, const char *dns_service_name,
+diff --git a/src/providers/ldap/sdap_autofs.c b/src/providers/ldap/sdap_autofs.c
+index c02c04d5c..f65028d4e 100644
+--- a/src/providers/ldap/sdap_autofs.c
++++ b/src/providers/ldap/sdap_autofs.c
+@@ -201,26 +201,26 @@ sdap_autofs_get_map_recv(struct tevent_req *req, int *dp_error_out)
+     return EOK;
+ }
+ 
+-struct sdap_autofs_handler_state {
++struct sdap_autofs_enumerate_handler_state {
+     struct dp_reply_std reply;
+ };
+ 
+-static void sdap_autofs_handler_done(struct tevent_req *subreq);
++static void sdap_autofs_enumerate_handler_done(struct tevent_req *subreq);
+ 
+ struct tevent_req *
+-sdap_autofs_handler_send(TALLOC_CTX *mem_ctx,
+-                         struct sdap_id_ctx *id_ctx,
+-                         struct dp_autofs_data *data,
+-                         struct dp_req_params *params)
++sdap_autofs_enumerate_handler_send(TALLOC_CTX *mem_ctx,
++                                   struct sdap_id_ctx *id_ctx,
++                                   struct dp_autofs_data *data,
++                                   struct dp_req_params *params)
+ {
+-    struct sdap_autofs_handler_state *state;
++    struct sdap_autofs_enumerate_handler_state *state;
+     struct tevent_req *subreq;
+     struct tevent_req *req;
+     const char *master_map;
+ 
+     errno_t ret;
+ 
+-    req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_handler_state);
++    req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_enumerate_handler_state);
+     if (req == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+         return NULL;
+@@ -250,7 +250,7 @@ sdap_autofs_handler_send(TALLOC_CTX *mem_ctx,
+         goto immediately;
+     }
+ 
+-    tevent_req_set_callback(subreq, sdap_autofs_handler_done, req);
++    tevent_req_set_callback(subreq, sdap_autofs_enumerate_handler_done, req);
+ 
+     return req;
+ 
+@@ -264,15 +264,15 @@ immediately:
+     return req;
+ }
+ 
+-static void sdap_autofs_handler_done(struct tevent_req *subreq)
++static void sdap_autofs_enumerate_handler_done(struct tevent_req *subreq)
+ {
+-    struct sdap_autofs_handler_state *state;
++    struct sdap_autofs_enumerate_handler_state *state;
+     struct tevent_req *req;
+     int dp_error;
+     errno_t ret;
+ 
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+-    state = tevent_req_data(req, struct sdap_autofs_handler_state);
++    state = tevent_req_data(req, struct sdap_autofs_enumerate_handler_state);
+ 
+     ret = sdap_autofs_get_map_recv(subreq, &dp_error);
+     talloc_zfree(subreq);
+@@ -283,13 +283,13 @@ static void sdap_autofs_handler_done(struct tevent_req *subreq)
+ }
+ 
+ errno_t
+-sdap_autofs_handler_recv(TALLOC_CTX *mem_ctx,
+-                         struct tevent_req *req,
+-                         struct dp_reply_std *data)
++sdap_autofs_enumerate_handler_recv(TALLOC_CTX *mem_ctx,
++                                   struct tevent_req *req,
++                                   struct dp_reply_std *data)
+ {
+-    struct sdap_autofs_handler_state *state = NULL;
++    struct sdap_autofs_enumerate_handler_state *state = NULL;
+ 
+-    state = tevent_req_data(req, struct sdap_autofs_handler_state);
++    state = tevent_req_data(req, struct sdap_autofs_enumerate_handler_state);
+ 
+     TEVENT_REQ_RETURN_ON_ERROR(req);
+ 
+@@ -313,8 +313,8 @@ errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx,
+         return ret;
+     }
+ 
+-    dp_set_method(dp_methods, DPM_AUTOFS_HANDLER,
+-                  sdap_autofs_handler_send, sdap_autofs_handler_recv, id_ctx,
++    dp_set_method(dp_methods, DPM_AUTOFS_ENUMERATE,
++                  sdap_autofs_enumerate_handler_send, sdap_autofs_enumerate_handler_recv, id_ctx,
+                   struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+ 
+     return EOK;
+-- 
+2.20.1
+
diff --git a/SOURCES/0082-dp-add-additional-autofs-methods.patch b/SOURCES/0082-dp-add-additional-autofs-methods.patch
new file mode 100644
index 0000000..f4124ee
--- /dev/null
+++ b/SOURCES/0082-dp-add-additional-autofs-methods.patch
@@ -0,0 +1,358 @@
+From 0b780a0d50e4ebb279b3ba36869d8e62c3c38044 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 28 Aug 2019 12:40:56 +0200
+Subject: [PATCH 82/90] dp: add additional autofs methods
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/providers/data_provider/dp.h              |  2 ++
+ src/providers/data_provider/dp_custom_data.h  |  1 +
+ src/providers/data_provider/dp_iface.h        |  4 ++-
+ src/providers/data_provider/dp_iface.xml      |  2 ++
+ .../data_provider/dp_iface_generated.c        | 36 +++++++++++++++++--
+ .../data_provider/dp_iface_generated.h        |  2 +-
+ .../data_provider/dp_target_autofs.c          | 28 +++++++++++++--
+ .../plugins/cache_req_autofs_entry_by_name.c  |  3 +-
+ .../plugins/cache_req_autofs_map_by_name.c    |  3 +-
+ .../plugins/cache_req_autofs_map_entries.c    |  3 +-
+ src/responder/common/responder.h              |  7 ++--
+ src/responder/common/responder_dp_autofs.c    | 19 ++++++----
+ 12 files changed, 91 insertions(+), 19 deletions(-)
+
+diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
+index 8ef4a92ae..df774fcf4 100644
+--- a/src/providers/data_provider/dp.h
++++ b/src/providers/data_provider/dp.h
+@@ -85,6 +85,8 @@ enum dp_methods {
+ 
+     DPM_REFRESH_ACCESS_RULES,
+ 
++    DPM_AUTOFS_GET_MAP,
++    DPM_AUTOFS_GET_ENTRY,
+     DPM_AUTOFS_ENUMERATE,
+ 
+     DP_METHOD_SENTINEL
+diff --git a/src/providers/data_provider/dp_custom_data.h b/src/providers/data_provider/dp_custom_data.h
+index 7c64bde45..b5f41786c 100644
+--- a/src/providers/data_provider/dp_custom_data.h
++++ b/src/providers/data_provider/dp_custom_data.h
+@@ -37,6 +37,7 @@ struct dp_hostid_data {
+ 
+ struct dp_autofs_data {
+     const char *mapname;
++    const char *entryname;
+ };
+ 
+ struct dp_subdomains_data {
+diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
+index 0a2f81eb5..5af1fdff0 100644
+--- a/src/providers/data_provider/dp_iface.h
++++ b/src/providers/data_provider/dp_iface.h
+@@ -52,7 +52,9 @@ errno_t dp_host_handler(struct sbus_request *sbus_req,
+ errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+                           void *dp_cli,
+                           uint32_t dp_flags,
+-                          const char *mapname);
++                          uint32_t method,
++                          const char *mapname,
++                          const char *entryname);
+ 
+ errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
+                               void *dp_cli,
+diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
+index c2431850b..545d9aaa4 100644
+--- a/src/providers/data_provider/dp_iface.xml
++++ b/src/providers/data_provider/dp_iface.xml
+@@ -50,7 +50,9 @@
+         </method>
+         <method name="autofsHandler">
+             <arg name="dp_flags" type="u" direction="in" />
++            <arg name="method" type="u" direction="in" />
+             <arg name="mapname" type="s" direction="in" />
++            <arg name="entryname" type="s" direction="in" />
+             <arg name="dp_error" type="q" direction="out" />
+             <arg name="error" type="u" direction="out" />
+             <arg name="error_message" type="s" direction="out" />
+diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
+index 4d0934445..453ca8854 100644
+--- a/src/providers/data_provider/dp_iface_generated.c
++++ b/src/providers/data_provider/dp_iface_generated.c
+@@ -12,8 +12,8 @@
+ /* invokes a handler with a 's' DBus signature */
+ static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr);
+ 
+-/* invokes a handler with a 'us' DBus signature */
+-static int invoke_us_method(struct sbus_request *dbus_req, void *function_ptr);
++/* invokes a handler with a 'uuss' DBus signature */
++static int invoke_uuss_method(struct sbus_request *dbus_req, void *function_ptr);
+ 
+ /* invokes a handler with a 'uss' DBus signature */
+ static int invoke_uss_method(struct sbus_request *dbus_req, void *function_ptr);
+@@ -21,6 +21,9 @@ static int invoke_uss_method(struct sbus_request *dbus_req, void *function_ptr);
+ /* invokes a handler with a 'uusss' DBus signature */
+ static int invoke_uusss_method(struct sbus_request *dbus_req, void *function_ptr);
+ 
++/* invokes a handler with a 'us' DBus signature */
++static int invoke_us_method(struct sbus_request *dbus_req, void *function_ptr);
++
+ /* arguments for org.freedesktop.sssd.DataProvider.Client.Register */
+ const struct sbus_arg_meta iface_dp_client_Register__in[] = {
+     { "Name", "s" },
+@@ -217,7 +220,9 @@ const struct sbus_interface_meta iface_dp_access_control_meta = {
+ /* arguments for org.freedesktop.sssd.dataprovider.autofsHandler */
+ const struct sbus_arg_meta iface_dp_autofsHandler__in[] = {
+     { "dp_flags", "u" },
++    { "method", "u" },
+     { "mapname", "s" },
++    { "entryname", "s" },
+     { NULL, }
+ };
+ 
+@@ -358,7 +363,7 @@ const struct sbus_method_meta iface_dp__methods[] = {
+         iface_dp_autofsHandler__in,
+         iface_dp_autofsHandler__out,
+         offsetof(struct iface_dp, autofsHandler),
+-        invoke_us_method,
++        invoke_uuss_method,
+     },
+     {
+         "hostHandler", /* name */
+@@ -400,6 +405,31 @@ const struct sbus_interface_meta iface_dp_meta = {
+     sbus_invoke_get_all, /* GetAll invoker */
+ };
+ 
++/* invokes a handler with a 'uuss' DBus signature */
++static int invoke_uuss_method(struct sbus_request *dbus_req, void *function_ptr)
++{
++    uint32_t arg_0;
++    uint32_t arg_1;
++    const char * arg_2;
++    const char * arg_3;
++    int (*handler)(struct sbus_request *, void *, uint32_t, uint32_t, const char *, const char *) = function_ptr;
++
++    if (!sbus_request_parse_or_finish(dbus_req,
++                               DBUS_TYPE_UINT32, &arg_0,
++                               DBUS_TYPE_UINT32, &arg_1,
++                               DBUS_TYPE_STRING, &arg_2,
++                               DBUS_TYPE_STRING, &arg_3,
++                               DBUS_TYPE_INVALID)) {
++         return EOK; /* request handled */
++    }
++
++    return (handler)(dbus_req, dbus_req->intf->handler_data,
++                     arg_0,
++                     arg_1,
++                     arg_2,
++                     arg_3);
++}
++
+ /* invokes a handler with a 's' DBus signature */
+ static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr)
+ {
+diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
+index b629ec774..7dd0f27cc 100644
+--- a/src/providers/data_provider/dp_iface_generated.h
++++ b/src/providers/data_provider/dp_iface_generated.h
+@@ -107,7 +107,7 @@ struct iface_dp {
+     struct sbus_vtable vtable; /* derive from sbus_vtable */
+     sbus_msg_handler_fn pamHandler;
+     sbus_msg_handler_fn sudoHandler;
+-    int (*autofsHandler)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, const char *arg_mapname);
++    int (*autofsHandler)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, uint32_t arg_method, const char *arg_mapname, const char *arg_entryname);
+     int (*hostHandler)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, const char *arg_name, const char *arg_alias);
+     int (*getDomains)(struct sbus_request *req, void *data, const char *arg_domain_hint);
+     int (*getAccountInfo)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, uint32_t arg_entry_type, const char *arg_filter, const char *arg_domain, const char *arg_extra);
+diff --git a/src/providers/data_provider/dp_target_autofs.c b/src/providers/data_provider/dp_target_autofs.c
+index 5f24f2975..8b5447aef 100644
+--- a/src/providers/data_provider/dp_target_autofs.c
++++ b/src/providers/data_provider/dp_target_autofs.c
+@@ -26,14 +26,19 @@
+ #include "providers/data_provider/dp_iface.h"
+ #include "providers/backend.h"
+ #include "util/util.h"
++#include "responder/common/responder.h"
+ 
+ errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+                           void *dp_cli,
+                           uint32_t dp_flags,
+-                          const char *mapname)
++                          uint32_t method,
++                          const char *mapname,
++                          const char *entryname)
+ {
+     struct dp_autofs_data *data;
+     const char *key;
++    enum dp_methods dp_method;
++
+ 
+     if (mapname == NULL) {
+         return EINVAL;
+@@ -45,10 +50,27 @@ errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+     }
+ 
+     data->mapname = mapname;
+-    key = mapname;
++    data->entryname = entryname;
++
++    key = talloc_asprintf(sbus_req, "%u:%s:%s", method, mapname, entryname);
++    if (key == NULL) {
++        return ENOMEM;
++    }
++
++    switch (method) {
++    case SSS_DP_AUTOFS_ENUMERATE:
++        dp_method = DPM_AUTOFS_ENUMERATE;
++        break;
++    case SSS_DP_AUTOFS_GET_MAP:
++        dp_method = DPM_AUTOFS_GET_MAP;
++        break;
++    case SSS_DP_AUTOFS_GET_ENTRY:
++        dp_method = DPM_AUTOFS_GET_ENTRY;
++        break;
++    }
+ 
+     dp_req_with_reply(dp_cli, NULL, "AutoFS", key, sbus_req, DPT_AUTOFS,
+-                      DPM_AUTOFS_ENUMERATE, dp_flags, data,
++                      dp_method, dp_flags, data,
+                       dp_req_reply_std, struct dp_reply_std);
+ 
+     return EOK;
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+index 17b0b508e..f4d0cb140 100644
+--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+@@ -72,7 +72,8 @@ cache_req_autofs_entry_by_name_dp_send(TALLOC_CTX *mem_ctx,
+                                        struct ldb_result *result)
+ {
+     return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
+-                                  SSS_DP_AUTOFS, data->name.name);
++                                  SSS_DP_AUTOFS_ENUMERATE,
++                                  data->name.name, NULL);
+ }
+ 
+ const struct cache_req_plugin cache_req_autofs_entry_by_name = {
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+index 2f69c762c..268711678 100644
+--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+@@ -69,7 +69,8 @@ cache_req_autofs_map_by_name_dp_send(TALLOC_CTX *mem_ctx,
+                                      struct ldb_result *result)
+ {
+     return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
+-                                  SSS_DP_AUTOFS, data->name.name);
++                                  SSS_DP_AUTOFS_ENUMERATE,
++                                  data->name.name, NULL);
+ }
+ 
+ const struct cache_req_plugin cache_req_autofs_map_by_name = {
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+index 73d2b3cf2..7a2691f2f 100644
+--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+@@ -101,7 +101,8 @@ cache_req_autofs_map_entries_dp_send(TALLOC_CTX *mem_ctx,
+                                      struct ldb_result *result)
+ {
+     return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
+-                                  SSS_DP_AUTOFS, data->name.name);
++                                  SSS_DP_AUTOFS_ENUMERATE,
++                                  data->name.name, NULL);
+ }
+ 
+ const struct cache_req_plugin cache_req_autofs_map_entries = {
+diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
+index 17b04c3de..4007bfd41 100644
+--- a/src/responder/common/responder.h
++++ b/src/responder/common/responder.h
+@@ -364,7 +364,9 @@ sss_dp_get_ssh_host_recv(TALLOC_CTX *mem_ctx,
+                          char **err_msg);
+ 
+ enum sss_dp_autofs_type {
+-    SSS_DP_AUTOFS
++    SSS_DP_AUTOFS_ENUMERATE,
++    SSS_DP_AUTOFS_GET_MAP,
++    SSS_DP_AUTOFS_GET_ENTRY
+ };
+ 
+ struct tevent_req *
+@@ -373,7 +375,8 @@ sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
+                        struct sss_domain_info *dom,
+                        bool fast_reply,
+                        enum sss_dp_autofs_type type,
+-                       const char *name);
++                       const char *mapname,
++                       const char *entryname);
+ 
+ errno_t
+ sss_dp_get_autofs_recv(TALLOC_CTX *mem_ctx,
+diff --git a/src/responder/common/responder_dp_autofs.c b/src/responder/common/responder_dp_autofs.c
+index bb8c2a428..edf31d035 100644
+--- a/src/responder/common/responder_dp_autofs.c
++++ b/src/responder/common/responder_dp_autofs.c
+@@ -34,7 +34,8 @@ struct sss_dp_get_autofs_info {
+ 
+     bool fast_reply;
+     enum sss_dp_autofs_type type;
+-    const char *name;
++    const char *mapname;
++    const char *entryname;
+ };
+ 
+ static DBusMessage *
+@@ -46,7 +47,8 @@ sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
+                        struct sss_domain_info *dom,
+                        bool fast_reply,
+                        enum sss_dp_autofs_type type,
+-                       const char *name)
++                       const char *mapname,
++                       const char *entryname)
+ {
+     struct tevent_req *req;
+     struct sss_dp_req_state *state;
+@@ -64,6 +66,8 @@ sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
+         goto error;
+     }
+ 
++    entryname = entryname == NULL ? "" : entryname;
++
+     info = talloc_zero(state, struct sss_dp_get_autofs_info);
+     if (info == NULL) {
+         ret = ENOMEM;
+@@ -71,10 +75,11 @@ sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
+     }
+     info->fast_reply = fast_reply;
+     info->type = type;
+-    info->name = name;
++    info->mapname = mapname;
++    info->entryname = entryname;
+     info->dom = dom;
+ 
+-    key = talloc_asprintf(state, "%d:%s@%s", type, name, dom->name);
++    key = talloc_asprintf(state, "%d:%s@%s:%s", type, mapname, dom->name, entryname);
+     if (!key) {
+         ret = ENOMEM;
+         goto error;
+@@ -124,11 +129,13 @@ sss_dp_get_autofs_msg(void *pvt)
+     /* create the message */
+     DEBUG(SSSDBG_TRACE_FUNC,
+           "Creating autofs request for [%s][%u][%s]\n",
+-           info->dom->name, dp_flags, info->name);
++           info->dom->name, dp_flags, info->mapname);
+ 
+     dbret = dbus_message_append_args(msg,
+                                      DBUS_TYPE_UINT32, &dp_flags,
+-                                     DBUS_TYPE_STRING, &info->name,
++                                     DBUS_TYPE_UINT32, &info->type,
++                                     DBUS_TYPE_STRING, &info->mapname,
++                                     DBUS_TYPE_STRING, &info->entryname,
+                                      DBUS_TYPE_INVALID);
+     if (!dbret) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
+-- 
+2.20.1
+
diff --git a/SOURCES/0083-ldap-add-base_dn-to-sdap_search_bases.patch b/SOURCES/0083-ldap-add-base_dn-to-sdap_search_bases.patch
new file mode 100644
index 0000000..053eab0
--- /dev/null
+++ b/SOURCES/0083-ldap-add-base_dn-to-sdap_search_bases.patch
@@ -0,0 +1,257 @@
+From fb9a42d952924b5ff084a103d43b6192c4ff0c1f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 13:51:59 +0200
+Subject: [PATCH 83/90] ldap: add base_dn to sdap_search_bases
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+To implement cases where we need to search a specific dn but we need
+to filter the result with configured filters.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/providers/ad/ad_subdomains.c              |  5 ++--
+ src/providers/ipa/ipa_subdomains.c            |  6 ++---
+ src/providers/ipa/ipa_subdomains_ext_groups.c |  2 +-
+ src/providers/ipa/ipa_sudo_async.c            |  8 +++----
+ src/providers/ldap/sdap_async_sudo.c          |  2 +-
+ src/providers/ldap/sdap_ops.c                 | 24 ++++++++++++-------
+ src/providers/ldap/sdap_ops.h                 |  6 +++--
+ 7 files changed, 31 insertions(+), 22 deletions(-)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 45a8fe0fc..f0b5d59d2 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -1110,7 +1110,7 @@ static void ad_get_slave_domain_connect_done(struct tevent_req *subreq)
+                                     sdap_id_op_handle(state->sdap_op),
+                                     state->root_sdom->search_bases,
+                                     NULL, false, 0,
+-                                    SLAVE_DOMAIN_FILTER, attrs);
++                                    SLAVE_DOMAIN_FILTER, attrs, NULL);
+     if (subreq == NULL) {
+         tevent_req_error(req, ret);
+         return;
+@@ -1304,7 +1304,8 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
+ 
+     subreq = sdap_search_bases_return_first_send(state, ev, opts, sh,
+                                                  opts->sdom->search_bases,
+-                                                 NULL, false, 0, filter, attrs);
++                                                 NULL, false, 0, filter, attrs,
++                                                 NULL);
+     if (subreq == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 3a17c851d..322420264 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -1005,7 +1005,7 @@ ipa_subdomains_ranges_send(TALLOC_CTX *mem_ctx,
+ 
+     subreq = sdap_search_bases_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh,
+                                     sd_ctx->ranges_search_bases, NULL, false,
+-                                    0, RANGE_FILTER, attrs);
++                                    0, RANGE_FILTER, attrs, NULL);
+     if (subreq == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+@@ -1251,7 +1251,7 @@ ipa_subdomains_master_send(TALLOC_CTX *mem_ctx,
+     subreq = sdap_search_bases_return_first_send(state, ev,
+                                      sd_ctx->sdap_id_ctx->opts, sh,
+                                      sd_ctx->master_search_bases, NULL, false,
+-                                     0, MASTER_DOMAIN_FILTER, attrs);
++                                     0, MASTER_DOMAIN_FILTER, attrs, NULL);
+     if (subreq == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+@@ -1397,7 +1397,7 @@ ipa_subdomains_slave_send(TALLOC_CTX *mem_ctx,
+ 
+     subreq = sdap_search_bases_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh,
+                                     sd_ctx->search_bases, NULL, false,
+-                                    0, SUBDOMAINS_FILTER, attrs);
++                                    0, SUBDOMAINS_FILTER, attrs, NULL);
+     if (subreq == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
+index 75963bef1..cd80048b3 100644
+--- a/src/providers/ipa/ipa_subdomains_ext_groups.c
++++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
+@@ -545,7 +545,7 @@ static void ipa_get_ad_memberships_connect_done(struct tevent_req *subreq)
+                             dp_opt_get_int(state->sdap_id_ctx->opts->basic,
+                                             SDAP_ENUM_SEARCH_TIMEOUT),
+                             IPA_EXT_GROUPS_FILTER,
+-                            NULL);
++                            NULL, NULL);
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
+         ret = ENOMEM;
+diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c
+index 060687c77..19bcd94c9 100644
+--- a/src/providers/ipa/ipa_sudo_async.c
++++ b/src/providers/ipa/ipa_sudo_async.c
+@@ -492,7 +492,7 @@ ipa_sudo_fetch_addtl_cmdgroups(struct tevent_req *req)
+ 
+     subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
+                                     state->sh, state->sudo_sb, map, true, 0,
+-                                    filter, NULL);
++                                    filter, NULL, NULL);
+     if (subreq == NULL) {
+         return ENOMEM;
+     }
+@@ -582,7 +582,7 @@ ipa_sudo_fetch_rules(struct tevent_req *req)
+ 
+     subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
+                                     state->sh, state->sudo_sb, map, true, 0,
+-                                    filter, NULL);
++                                    filter, NULL, NULL);
+     if (subreq == NULL) {
+         return ENOMEM;
+     }
+@@ -662,7 +662,7 @@ ipa_sudo_fetch_cmdgroups(struct tevent_req *req)
+     subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
+                                     state->sh, state->sudo_sb,
+                                     state->map_cmdgroup, true, 0,
+-                                    filter, NULL);
++                                    filter, NULL, NULL);
+     if (subreq == NULL) {
+         return ENOMEM;
+     }
+@@ -742,7 +742,7 @@ ipa_sudo_fetch_cmds(struct tevent_req *req)
+     subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
+                                     state->sh, state->sudo_sb,
+                                     state->map_cmd, true, 0,
+-                                    filter, NULL);
++                                    filter, NULL, NULL);
+     if (subreq == NULL) {
+         return ENOMEM;
+     }
+diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c
+index 5ccfad61f..c19ee87c2 100644
+--- a/src/providers/ldap/sdap_async_sudo.c
++++ b/src/providers/ldap/sdap_async_sudo.c
+@@ -75,7 +75,7 @@ sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
+ 
+     subreq = sdap_search_bases_send(state, ev, opts, sh, sb,
+                                     opts->sudorule_map, true, 0,
+-                                    ldap_filter, NULL);
++                                    ldap_filter, NULL, NULL);
+     if (subreq == NULL) {
+         ret = ENOMEM;
+         goto immediately;
+diff --git a/src/providers/ldap/sdap_ops.c b/src/providers/ldap/sdap_ops.c
+index a90857469..2125b21aa 100644
+--- a/src/providers/ldap/sdap_ops.c
++++ b/src/providers/ldap/sdap_ops.c
+@@ -37,6 +37,7 @@ struct sdap_search_bases_ex_state {
+     int timeout;
+     bool allow_paging;
+     bool return_first_reply;
++    const char *base_dn;
+ 
+     size_t base_iter;
+     struct sdap_search_base *cur_base;
+@@ -60,7 +61,8 @@ sdap_search_bases_ex_send(TALLOC_CTX *mem_ctx,
+                           bool return_first_reply,
+                           int timeout,
+                           const char *filter,
+-                          const char **attrs)
++                          const char **attrs,
++                          const char *base_dn)
+ {
+     struct tevent_req *req;
+     struct sdap_search_bases_ex_state *state;
+@@ -86,6 +88,7 @@ sdap_search_bases_ex_send(TALLOC_CTX *mem_ctx,
+     state->attrs = attrs;
+     state->allow_paging = allow_paging;
+     state->return_first_reply = return_first_reply;
++    state->base_dn = base_dn;
+ 
+     state->timeout = timeout == 0
+                      ? dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT)
+@@ -133,6 +136,7 @@ static errno_t sdap_search_bases_ex_next_base(struct tevent_req *req)
+ {
+     struct sdap_search_bases_ex_state *state;
+     struct tevent_req *subreq;
++    const char *base_dn;
+     char *filter;
+ 
+     state = tevent_req_data(req, struct sdap_search_bases_ex_state);
+@@ -148,12 +152,12 @@ static errno_t sdap_search_bases_ex_next_base(struct tevent_req *req)
+         return ENOMEM;
+     }
+ 
+-    DEBUG(SSSDBG_TRACE_FUNC, "Issuing LDAP lookup with base [%s]\n",
+-                             state->cur_base->basedn);
++    base_dn = state->base_dn != NULL ? state->base_dn : state->cur_base->basedn;
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Issuing LDAP lookup with base [%s]\n", base_dn);
+ 
+     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+-                                   state->cur_base->basedn,
+-                                   state->cur_base->scope, filter,
++                                   base_dn, state->cur_base->scope, filter,
+                                    state->attrs, state->map,
+                                    state->map_num_attrs, state->timeout,
+                                    state->allow_paging);
+@@ -253,11 +257,12 @@ sdap_search_bases_send(TALLOC_CTX *mem_ctx,
+                        bool allow_paging,
+                        int timeout,
+                        const char *filter,
+-                       const char **attrs)
++                       const char **attrs,
++                       const char *base_dn)
+ {
+     return sdap_search_bases_ex_send(mem_ctx, ev, opts, sh, bases, map,
+                                      allow_paging, false, timeout,
+-                                     filter, attrs);
++                                     filter, attrs, base_dn);
+ }
+ 
+ int sdap_search_bases_recv(struct tevent_req *req,
+@@ -278,11 +283,12 @@ sdap_search_bases_return_first_send(TALLOC_CTX *mem_ctx,
+                                     bool allow_paging,
+                                     int timeout,
+                                     const char *filter,
+-                                    const char **attrs)
++                                    const char **attrs,
++                                    const char *base_dn)
+ {
+     return sdap_search_bases_ex_send(mem_ctx, ev, opts, sh, bases, map,
+                                      allow_paging, true, timeout,
+-                                     filter, attrs);
++                                     filter, attrs, base_dn);
+ }
+ 
+ int sdap_search_bases_return_first_recv(struct tevent_req *req,
+diff --git a/src/providers/ldap/sdap_ops.h b/src/providers/ldap/sdap_ops.h
+index cc9de00d2..648a2b68c 100644
+--- a/src/providers/ldap/sdap_ops.h
++++ b/src/providers/ldap/sdap_ops.h
+@@ -34,7 +34,8 @@ struct tevent_req *sdap_search_bases_send(TALLOC_CTX *mem_ctx,
+                                           bool allow_paging,
+                                           int timeout,
+                                           const char *filter,
+-                                          const char **attrs);
++                                          const char **attrs,
++                                          const char *base_dn);
+ 
+ int sdap_search_bases_recv(struct tevent_req *req,
+                            TALLOC_CTX *mem_ctx,
+@@ -51,7 +52,8 @@ sdap_search_bases_return_first_send(TALLOC_CTX *mem_ctx,
+                                     bool allow_paging,
+                                     int timeout,
+                                     const char *filter,
+-                                    const char **attrs);
++                                    const char **attrs,
++                                    const char *base_dn);
+ 
+ int sdap_search_bases_return_first_recv(struct tevent_req *req,
+                                         TALLOC_CTX *mem_ctx,
+-- 
+2.20.1
+
diff --git a/SOURCES/0084-ldap-rename-sdap_autofs_get_map-to-sdap_autofs_enume.patch b/SOURCES/0084-ldap-rename-sdap_autofs_get_map-to-sdap_autofs_enume.patch
new file mode 100644
index 0000000..75575e6
--- /dev/null
+++ b/SOURCES/0084-ldap-rename-sdap_autofs_get_map-to-sdap_autofs_enume.patch
@@ -0,0 +1,194 @@
+From bd15a135c1b73996208557f36718410a7a6b20b2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 11:56:55 +0200
+Subject: [PATCH 84/90] ldap: rename sdap_autofs_get_map to
+ sdap_autofs_enumerate
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+get_map name will be later used to obtain only the map object.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/providers/ldap/sdap_autofs.c | 60 ++++++++++++++++----------------
+ 1 file changed, 30 insertions(+), 30 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_autofs.c b/src/providers/ldap/sdap_autofs.c
+index f65028d4e..5b9146199 100644
+--- a/src/providers/ldap/sdap_autofs.c
++++ b/src/providers/ldap/sdap_autofs.c
+@@ -34,7 +34,7 @@
+ #include "db/sysdb_autofs.h"
+ #include "util/util.h"
+ 
+-struct autofs_get_map_state {
++struct sdap_autofs_enumerate_state {
+     struct tevent_context *ev;
+     struct sdap_id_ctx *ctx;
+     struct sdap_id_op *op;
+@@ -44,23 +44,23 @@ struct autofs_get_map_state {
+ };
+ 
+ static errno_t
+-sdap_autofs_get_map_retry(struct tevent_req *req);
++sdap_autofs_enumerate_retry(struct tevent_req *req);
+ static void
+-sdap_autofs_get_map_connect_done(struct tevent_req *subreq);
++sdap_autofs_enumerate_connect_done(struct tevent_req *subreq);
+ static void
+-sdap_autofs_get_map_done(struct tevent_req *req);
++sdap_autofs_enumerate_done(struct tevent_req *req);
+ 
+ static struct tevent_req *
+-sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
+-                         struct tevent_context *ev,
+-                         struct sdap_id_ctx *ctx,
+-                         const char *map_name)
++sdap_autofs_enumerate_send(TALLOC_CTX *mem_ctx,
++                           struct tevent_context *ev,
++                           struct sdap_id_ctx *ctx,
++                           const char *map_name)
+ {
+     struct tevent_req *req;
+-    struct autofs_get_map_state *state;
++    struct sdap_autofs_enumerate_state *state;
+     int ret;
+ 
+-    req = tevent_req_create(mem_ctx, &state, struct autofs_get_map_state);
++    req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_enumerate_state);
+     if (!req) return NULL;
+ 
+     state->ev = ev;
+@@ -75,7 +75,7 @@ sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
+         goto fail;
+     }
+ 
+-    ret = sdap_autofs_get_map_retry(req);
++    ret = sdap_autofs_enumerate_retry(req);
+     if (ret != EOK) {
+         goto fail;
+     }
+@@ -89,10 +89,10 @@ fail:
+ }
+ 
+ static errno_t
+-sdap_autofs_get_map_retry(struct tevent_req *req)
++sdap_autofs_enumerate_retry(struct tevent_req *req)
+ {
+-    struct autofs_get_map_state *state =
+-                tevent_req_data(req, struct autofs_get_map_state);
++    struct sdap_autofs_enumerate_state *state =
++                tevent_req_data(req, struct sdap_autofs_enumerate_state);
+     struct tevent_req *subreq;
+     int ret = EOK;
+ 
+@@ -101,17 +101,17 @@ sdap_autofs_get_map_retry(struct tevent_req *req)
+         return ret;
+     }
+ 
+-    tevent_req_set_callback(subreq, sdap_autofs_get_map_connect_done, req);
++    tevent_req_set_callback(subreq, sdap_autofs_enumerate_connect_done, req);
+     return EOK;
+ }
+ 
+ static void
+-sdap_autofs_get_map_connect_done(struct tevent_req *subreq)
++sdap_autofs_enumerate_connect_done(struct tevent_req *subreq)
+ {
+     struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                       struct tevent_req);
+-    struct autofs_get_map_state *state =
+-                tevent_req_data(req, struct autofs_get_map_state);
++    struct sdap_autofs_enumerate_state *state =
++                tevent_req_data(req, struct sdap_autofs_enumerate_state);
+     int dp_error = DP_ERR_FATAL;
+     int ret;
+ 
+@@ -137,17 +137,17 @@ sdap_autofs_get_map_connect_done(struct tevent_req *subreq)
+         tevent_req_error(req, ENOMEM);
+         return;
+     }
+-    tevent_req_set_callback(subreq, sdap_autofs_get_map_done, req);
++    tevent_req_set_callback(subreq, sdap_autofs_enumerate_done, req);
+ 
+ }
+ 
+ static void
+-sdap_autofs_get_map_done(struct tevent_req *subreq)
++sdap_autofs_enumerate_done(struct tevent_req *subreq)
+ {
+     struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                       struct tevent_req);
+-    struct autofs_get_map_state *state =
+-        tevent_req_data(req, struct autofs_get_map_state);
++    struct sdap_autofs_enumerate_state *state =
++        tevent_req_data(req, struct sdap_autofs_enumerate_state);
+     int dp_error = DP_ERR_FATAL;
+     int ret;
+ 
+@@ -157,7 +157,7 @@ sdap_autofs_get_map_done(struct tevent_req *subreq)
+     ret = sdap_id_op_done(state->op, ret, &dp_error);
+     if (dp_error == DP_ERR_OK && ret != EOK) {
+         /* retry */
+-        ret = sdap_autofs_get_map_retry(req);
++        ret = sdap_autofs_enumerate_retry(req);
+         if (ret != EOK) {
+             tevent_req_error(req, ret);
+             return;
+@@ -187,10 +187,10 @@ sdap_autofs_get_map_done(struct tevent_req *subreq)
+ }
+ 
+ static errno_t
+-sdap_autofs_get_map_recv(struct tevent_req *req, int *dp_error_out)
++sdap_autofs_enumerate_recv(struct tevent_req *req, int *dp_error_out)
+ {
+-    struct autofs_get_map_state *state =
+-        tevent_req_data(req, struct autofs_get_map_state);
++    struct sdap_autofs_enumerate_state *state =
++        tevent_req_data(req, struct sdap_autofs_enumerate_state);
+ 
+     if (dp_error_out) {
+         *dp_error_out = state->dp_error;
+@@ -217,7 +217,6 @@ sdap_autofs_enumerate_handler_send(TALLOC_CTX *mem_ctx,
+     struct tevent_req *subreq;
+     struct tevent_req *req;
+     const char *master_map;
+-
+     errno_t ret;
+ 
+     req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_enumerate_handler_state);
+@@ -241,8 +240,8 @@ sdap_autofs_enumerate_handler_send(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
+-    subreq = sdap_autofs_get_map_send(mem_ctx, params->ev,
+-                                      id_ctx, data->mapname);
++    subreq = sdap_autofs_enumerate_send(mem_ctx, params->ev,
++                                        id_ctx, data->mapname);
+     if (subreq == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request for %s.\n",
+               data->mapname);
+@@ -262,6 +261,7 @@ immediately:
+     tevent_req_post(req, params->ev);
+ 
+     return req;
++
+ }
+ 
+ static void sdap_autofs_enumerate_handler_done(struct tevent_req *subreq)
+@@ -274,7 +274,7 @@ static void sdap_autofs_enumerate_handler_done(struct tevent_req *subreq)
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct sdap_autofs_enumerate_handler_state);
+ 
+-    ret = sdap_autofs_get_map_recv(subreq, &dp_error);
++    ret = sdap_autofs_enumerate_recv(subreq, &dp_error);
+     talloc_zfree(subreq);
+ 
+     /* TODO For backward compatibility we always return EOK to DP now. */
+-- 
+2.20.1
+
diff --git a/SOURCES/0085-ldap-implement-autofs-get-map.patch b/SOURCES/0085-ldap-implement-autofs-get-map.patch
new file mode 100644
index 0000000..29d4651
--- /dev/null
+++ b/SOURCES/0085-ldap-implement-autofs-get-map.patch
@@ -0,0 +1,475 @@
+From fcb6f55c09d1d6f6487d771ac829e02565393c56 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 12:42:05 +0200
+Subject: [PATCH 85/90] ldap: implement autofs get map
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will obtain only the map object.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/providers/ipa/ipa_autofs.c                |   4 +
+ src/providers/ldap/ldap_common.h              |  11 +
+ src/providers/ldap/sdap_async_autofs.c        | 207 ++++++++++++++++++
+ src/providers/ldap/sdap_autofs.c              | 123 +++++++++--
+ src/providers/ldap/sdap_autofs.h              |   7 +
+ .../plugins/cache_req_autofs_map_by_name.c    |   2 +-
+ 6 files changed, 340 insertions(+), 14 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_autofs.c b/src/providers/ipa/ipa_autofs.c
+index 50e30f39f..19d74071f 100644
+--- a/src/providers/ipa/ipa_autofs.c
++++ b/src/providers/ipa/ipa_autofs.c
+@@ -51,5 +51,9 @@ errno_t ipa_autofs_init(TALLOC_CTX *mem_ctx,
+                   sdap_autofs_enumerate_handler_send, sdap_autofs_enumerate_handler_recv, id_ctx,
+                   struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+ 
++    dp_set_method(dp_methods, DPM_AUTOFS_GET_MAP,
++                  sdap_autofs_get_map_handler_send, sdap_autofs_get_map_handler_recv, id_ctx,
++                  struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
++
+     return ret;
+ }
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index 85dc6949c..36623aca8 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -166,6 +166,17 @@ sdap_autofs_enumerate_handler_recv(TALLOC_CTX *mem_ctx,
+                                    struct tevent_req *req,
+                                    struct dp_reply_std *data);
+ 
++struct tevent_req *
++sdap_autofs_get_map_handler_send(TALLOC_CTX *mem_ctx,
++                                 struct sdap_id_ctx *id_ctx,
++                                 struct dp_autofs_data *data,
++                                 struct dp_req_params *params);
++
++errno_t
++sdap_autofs_get_map_handler_recv(TALLOC_CTX *mem_ctx,
++                                 struct tevent_req *req,
++                                 struct dp_reply_std *data);
++
+ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *service_name, const char *dns_service_name,
+                       const char *urls, const char *backup_urls,
+diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
+index 7548d4a67..52ceb84ac 100644
+--- a/src/providers/ldap/sdap_async_autofs.c
++++ b/src/providers/ldap/sdap_async_autofs.c
+@@ -28,6 +28,7 @@
+ #include "db/sysdb_autofs.h"
+ #include "providers/ldap/ldap_common.h"
+ #include "providers/ldap/sdap_autofs.h"
++#include "providers/ldap/sdap_ops.h"
+ 
+ enum autofs_map_op {
+     AUTOFS_MAP_OP_ADD,
+@@ -970,3 +971,209 @@ sdap_autofs_setautomntent_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
++struct sdap_autofs_get_map_state {
++    struct sdap_id_ctx *id_ctx;
++    struct sdap_options *opts;
++    struct sdap_id_op *sdap_op;
++    const char *mapname;
++    int dp_error;
++};
++
++static errno_t sdap_autofs_get_map_retry(struct tevent_req *req);
++static void sdap_autofs_get_map_connect_done(struct tevent_req *subreq);
++static void sdap_autofs_get_map_done(struct tevent_req *subreq);
++
++struct tevent_req *sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
++                                            struct sdap_id_ctx *id_ctx,
++                                            const char *mapname)
++{
++    struct tevent_req *req;
++    struct sdap_autofs_get_map_state *state;
++    int ret;
++
++    req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_get_map_state);
++    if (!req) {
++        return NULL;
++    }
++
++    state->id_ctx = id_ctx;
++    state->opts = id_ctx->opts;
++    state->mapname = mapname;
++    state->dp_error = DP_ERR_FATAL;
++
++    state->sdap_op = sdap_id_op_create(state, id_ctx->conn->conn_cache);
++    if (!state->sdap_op) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sdap_autofs_get_map_retry(req);
++    if (ret == EAGAIN) {
++        /* asynchronous processing */
++        return req;
++    }
++
++done:
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, id_ctx->be->ev);
++
++    return req;
++}
++
++static errno_t sdap_autofs_get_map_retry(struct tevent_req *req)
++{
++    struct sdap_autofs_get_map_state *state;
++    struct tevent_req *subreq;
++    int ret;
++
++    state = tevent_req_data(req, struct sdap_autofs_get_map_state);
++
++    subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: "
++                                   "%d(%s)\n", ret, strerror(ret));
++        return ret;
++    }
++
++    tevent_req_set_callback(subreq, sdap_autofs_get_map_connect_done, req);
++
++    return EAGAIN;
++}
++
++static void sdap_autofs_get_map_connect_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    struct sdap_autofs_get_map_state *state;
++    char *filter;
++    char *safe_mapname;
++    const char **attrs;
++    int dp_error;
++    int ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct sdap_autofs_get_map_state);
++
++    ret = sdap_id_op_connect_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "LDAP connection failed "
++                                   "[%d]: %s\n", ret, strerror(ret));
++        state->dp_error = dp_error;
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "LDAP connection successful\n");
++
++    ret = sss_filter_sanitize(state, state->mapname, &safe_mapname);
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
++                 state->opts->autofs_mobject_map[SDAP_AT_AUTOFS_MAP_NAME].name,
++                 safe_mapname,
++                 state->opts->autofs_mobject_map[SDAP_OC_AUTOFS_MAP].name);
++    if (filter == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build filter\n");
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    ret = build_attrs_from_map(state, state->opts->autofs_mobject_map,
++                               SDAP_OPTS_AUTOFS_MAP, NULL, &attrs, NULL);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build attributes from map\n");
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    subreq = sdap_search_bases_return_first_send(state, state->id_ctx->be->ev,
++                    state->opts, sdap_id_op_handle(state->sdap_op),
++                    state->opts->sdom->autofs_search_bases,
++                    state->opts->autofs_mobject_map, false,
++                    dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT),
++                    filter, attrs);
++    if (subreq == NULL) {
++        state->dp_error = DP_ERR_FATAL;
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++
++    tevent_req_set_callback(subreq, sdap_autofs_get_map_done, req);
++}
++
++static void sdap_autofs_get_map_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    struct sdap_autofs_get_map_state *state;
++    struct sysdb_attrs **reply;
++    size_t reply_count;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct sdap_autofs_get_map_state);
++
++    ret = sdap_search_bases_return_first_recv(subreq, state, &reply_count,
++                                              &reply);
++    talloc_zfree(subreq);
++
++    ret = sdap_id_op_done(state->sdap_op, ret, &state->dp_error);
++    if (state->dp_error == DP_ERR_OK && ret != EOK) {
++        /* retry */
++        ret = sdap_autofs_get_map_retry(req);
++        if (ret != EOK) {
++            tevent_req_error(req, ret);
++        }
++        return;
++    } else if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    if (reply_count == 0) {
++        ret = sysdb_delete_autofsmap(state->id_ctx->be->domain, state->mapname);
++        if (ret != EOK && ret != ENOENT) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                "Cannot delete autofs map %s [%d]: %s\n",
++                 state->mapname, ret, strerror(ret));
++            tevent_req_error(req, ret);
++            return;
++        }
++
++        tevent_req_done(req);
++        return;
++    }
++
++    ret = save_autofs_map(state->id_ctx->be->domain, state->opts, reply[0], false);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++             "Cannot save autofs map %s [%d]: %s\n",
++              state->mapname, ret, strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++errno_t sdap_autofs_get_map_recv(struct tevent_req *req,
++                                 int *dp_error)
++{
++    struct sdap_autofs_get_map_state *state;
++
++    state = tevent_req_data(req, struct sdap_autofs_get_map_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    *dp_error = state->dp_error;
++
++    return EOK;
++}
+diff --git a/src/providers/ldap/sdap_autofs.c b/src/providers/ldap/sdap_autofs.c
+index 5b9146199..9a5ed11e8 100644
+--- a/src/providers/ldap/sdap_autofs.c
++++ b/src/providers/ldap/sdap_autofs.c
+@@ -34,6 +34,27 @@
+ #include "db/sysdb_autofs.h"
+ #include "util/util.h"
+ 
++static void
++sdap_autofs_invalidate_maps(struct sdap_id_ctx *id_ctx,
++                            const char *mapname)
++{
++    const char *master_map;
++    errno_t ret;
++
++    master_map = dp_opt_get_string(id_ctx->opts->basic,
++                                   SDAP_AUTOFS_MAP_MASTER_NAME);
++    if (strcmp(master_map, mapname) == 0) {
++        DEBUG(SSSDBG_FUNC_DATA, "Refresh of automount master map triggered: "
++              "%s\n", mapname);
++
++        ret = sysdb_invalidate_autofs_maps(id_ctx->be->domain);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not invalidate autofs maps, "
++                  "backend might return stale entries\n");
++        }
++    }
++}
++
+ struct sdap_autofs_enumerate_state {
+     struct tevent_context *ev;
+     struct sdap_id_ctx *ctx;
+@@ -216,7 +237,6 @@ sdap_autofs_enumerate_handler_send(TALLOC_CTX *mem_ctx,
+     struct sdap_autofs_enumerate_handler_state *state;
+     struct tevent_req *subreq;
+     struct tevent_req *req;
+-    const char *master_map;
+     errno_t ret;
+ 
+     req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_enumerate_handler_state);
+@@ -227,18 +247,7 @@ sdap_autofs_enumerate_handler_send(TALLOC_CTX *mem_ctx,
+ 
+     DEBUG(SSSDBG_FUNC_DATA, "Requested refresh for: %s\n", data->mapname);
+ 
+-    master_map = dp_opt_get_string(id_ctx->opts->basic,
+-                                   SDAP_AUTOFS_MAP_MASTER_NAME);
+-    if (strcmp(master_map, data->mapname) == 0) {
+-        DEBUG(SSSDBG_FUNC_DATA, "Refresh of automount master map triggered: "
+-              "%s\n", data->mapname);
+-
+-        ret = sysdb_invalidate_autofs_maps(id_ctx->be->domain);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not invalidate autofs maps, "
+-                  "backend might return stale entries\n");
+-        }
+-    }
++    sdap_autofs_invalidate_maps(id_ctx, data->mapname);
+ 
+     subreq = sdap_autofs_enumerate_send(mem_ctx, params->ev,
+                                         id_ctx, data->mapname);
+@@ -298,6 +307,90 @@ sdap_autofs_enumerate_handler_recv(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++struct sdap_autofs_get_map_handler_state {
++    struct dp_reply_std reply;
++};
++
++static void sdap_autofs_get_map_handler_done(struct tevent_req *subreq);
++
++struct tevent_req *
++sdap_autofs_get_map_handler_send(TALLOC_CTX *mem_ctx,
++                                 struct sdap_id_ctx *id_ctx,
++                                 struct dp_autofs_data *data,
++                                 struct dp_req_params *params)
++{
++    struct sdap_autofs_get_map_handler_state *state;
++    struct tevent_req *subreq;
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct sdap_autofs_get_map_handler_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    DEBUG(SSSDBG_FUNC_DATA, "Requested refresh for: %s\n", data->mapname);
++
++    sdap_autofs_invalidate_maps(id_ctx, data->mapname);
++
++    subreq = sdap_autofs_get_map_send(mem_ctx, id_ctx, data->mapname);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request for %s.\n",
++              data->mapname);
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    tevent_req_set_callback(subreq, sdap_autofs_get_map_handler_done, req);
++
++    return req;
++
++immediately:
++    dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
++
++    /* TODO For backward compatibility we always return EOK to DP now. */
++    tevent_req_done(req);
++    tevent_req_post(req, params->ev);
++
++    return req;
++}
++
++static void sdap_autofs_get_map_handler_done(struct tevent_req *subreq)
++{
++    struct sdap_autofs_get_map_handler_state *state;
++    struct tevent_req *req;
++    int dp_error;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct sdap_autofs_get_map_handler_state);
++
++    ret = sdap_autofs_get_map_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++
++    /* TODO For backward compatibility we always return EOK to DP now. */
++    dp_reply_std_set(&state->reply, dp_error, ret, NULL);
++    tevent_req_done(req);
++}
++
++errno_t
++sdap_autofs_get_map_handler_recv(TALLOC_CTX *mem_ctx,
++                                 struct tevent_req *req,
++                                 struct dp_reply_std *data)
++{
++    struct sdap_autofs_get_map_handler_state *state = NULL;
++
++    state = tevent_req_data(req, struct sdap_autofs_get_map_handler_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    *data = state->reply;
++
++    return EOK;
++}
++
+ errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx,
+                          struct be_ctx *be_ctx,
+                          struct sdap_id_ctx *id_ctx,
+@@ -317,5 +410,9 @@ errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx,
+                   sdap_autofs_enumerate_handler_send, sdap_autofs_enumerate_handler_recv, id_ctx,
+                   struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+ 
++    dp_set_method(dp_methods, DPM_AUTOFS_GET_MAP,
++                  sdap_autofs_get_map_handler_send, sdap_autofs_get_map_handler_recv, id_ctx,
++                  struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
++
+     return EOK;
+ }
+diff --git a/src/providers/ldap/sdap_autofs.h b/src/providers/ldap/sdap_autofs.h
+index 593d8c94f..34b9ca953 100644
+--- a/src/providers/ldap/sdap_autofs.h
++++ b/src/providers/ldap/sdap_autofs.h
+@@ -43,5 +43,12 @@ sdap_autofs_setautomntent_send(TALLOC_CTX *memctx,
+ errno_t
+ sdap_autofs_setautomntent_recv(struct tevent_req *req);
+ 
++struct tevent_req *sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
++                                            struct sdap_id_ctx *id_ctx,
++                                            const char *mapname);
++
++errno_t sdap_autofs_get_map_recv(struct tevent_req *req,
++                                 int *dp_error);
++
+ #endif /* _SDAP_AUTOFS_H_ */
+ 
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+index 268711678..4c1685728 100644
+--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+@@ -69,7 +69,7 @@ cache_req_autofs_map_by_name_dp_send(TALLOC_CTX *mem_ctx,
+                                      struct ldb_result *result)
+ {
+     return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
+-                                  SSS_DP_AUTOFS_ENUMERATE,
++                                  SSS_DP_AUTOFS_GET_MAP,
+                                   data->name.name, NULL);
+ }
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0086-ldap-implement-autofs-get-entry.patch b/SOURCES/0086-ldap-implement-autofs-get-entry.patch
new file mode 100644
index 0000000..ba12606
--- /dev/null
+++ b/SOURCES/0086-ldap-implement-autofs-get-entry.patch
@@ -0,0 +1,448 @@
+From 2e452583728b2596aba65a96d25f7f8312765538 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 14:07:01 +0200
+Subject: [PATCH 86/90] ldap: implement autofs get entry
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/providers/ipa/ipa_autofs.c                |   4 +
+ src/providers/ldap/ldap_common.h              |  11 +
+ src/providers/ldap/sdap_async_autofs.c        | 235 +++++++++++++++++-
+ src/providers/ldap/sdap_autofs.c              |  88 +++++++
+ src/providers/ldap/sdap_autofs.h              |   8 +
+ .../plugins/cache_req_autofs_entry_by_name.c  |   4 +-
+ 6 files changed, 347 insertions(+), 3 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_autofs.c b/src/providers/ipa/ipa_autofs.c
+index 19d74071f..5f72d60cd 100644
+--- a/src/providers/ipa/ipa_autofs.c
++++ b/src/providers/ipa/ipa_autofs.c
+@@ -55,5 +55,9 @@ errno_t ipa_autofs_init(TALLOC_CTX *mem_ctx,
+                   sdap_autofs_get_map_handler_send, sdap_autofs_get_map_handler_recv, id_ctx,
+                   struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+ 
++    dp_set_method(dp_methods, DPM_AUTOFS_GET_ENTRY,
++                  sdap_autofs_get_entry_handler_send, sdap_autofs_get_entry_handler_recv, id_ctx,
++                  struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
++
+     return ret;
+ }
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index 36623aca8..893f29a38 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -177,6 +177,17 @@ sdap_autofs_get_map_handler_recv(TALLOC_CTX *mem_ctx,
+                                  struct tevent_req *req,
+                                  struct dp_reply_std *data);
+ 
++struct tevent_req *
++sdap_autofs_get_entry_handler_send(TALLOC_CTX *mem_ctx,
++                                 struct sdap_id_ctx *id_ctx,
++                                 struct dp_autofs_data *data,
++                                 struct dp_req_params *params);
++
++errno_t
++sdap_autofs_get_entry_handler_recv(TALLOC_CTX *mem_ctx,
++                                   struct tevent_req *req,
++                                   struct dp_reply_std *data);
++
+ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *service_name, const char *dns_service_name,
+                       const char *urls, const char *backup_urls,
+diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
+index 52ceb84ac..c31df2f59 100644
+--- a/src/providers/ldap/sdap_async_autofs.c
++++ b/src/providers/ldap/sdap_async_autofs.c
+@@ -1100,7 +1100,7 @@ static void sdap_autofs_get_map_connect_done(struct tevent_req *subreq)
+                     state->opts->sdom->autofs_search_bases,
+                     state->opts->autofs_mobject_map, false,
+                     dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT),
+-                    filter, attrs);
++                    filter, attrs, NULL);
+     if (subreq == NULL) {
+         state->dp_error = DP_ERR_FATAL;
+         tevent_req_error(req, ENOMEM);
+@@ -1177,3 +1177,236 @@ errno_t sdap_autofs_get_map_recv(struct tevent_req *req,
+ 
+     return EOK;
+ }
++
++struct sdap_autofs_get_entry_state {
++    struct sdap_id_ctx *id_ctx;
++    struct sdap_options *opts;
++    struct sdap_id_op *sdap_op;
++    const char *mapname;
++    const char *entryname;
++    int dp_error;
++};
++
++static errno_t sdap_autofs_get_entry_retry(struct tevent_req *req);
++static void sdap_autofs_get_entry_connect_done(struct tevent_req *subreq);
++static void sdap_autofs_get_entry_done(struct tevent_req *subreq);
++
++struct tevent_req *sdap_autofs_get_entry_send(TALLOC_CTX *mem_ctx,
++                                              struct sdap_id_ctx *id_ctx,
++                                              const char *mapname,
++                                              const char *entryname)
++{
++    struct tevent_req *req;
++    struct sdap_autofs_get_entry_state *state;
++    int ret;
++
++    req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_get_entry_state);
++    if (!req) {
++        return NULL;
++    }
++
++    state->id_ctx = id_ctx;
++    state->opts = id_ctx->opts;
++    state->mapname = mapname;
++    state->entryname = entryname;
++    state->dp_error = DP_ERR_FATAL;
++
++    state->sdap_op = sdap_id_op_create(state, id_ctx->conn->conn_cache);
++    if (!state->sdap_op) {
++        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sdap_autofs_get_entry_retry(req);
++    if (ret == EAGAIN) {
++        /* asynchronous processing */
++        return req;
++    }
++
++done:
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, id_ctx->be->ev);
++
++    return req;
++}
++
++static errno_t sdap_autofs_get_entry_retry(struct tevent_req *req)
++{
++    struct sdap_autofs_get_entry_state *state;
++    struct tevent_req *subreq;
++    int ret;
++
++    state = tevent_req_data(req, struct sdap_autofs_get_entry_state);
++
++    subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: "
++                                   "%d(%s)\n", ret, strerror(ret));
++        return ret;
++    }
++
++    tevent_req_set_callback(subreq, sdap_autofs_get_entry_connect_done, req);
++
++    return EAGAIN;
++}
++
++static void sdap_autofs_get_entry_connect_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    struct sdap_autofs_get_entry_state *state;
++    struct ldb_message *map;
++    char *filter;
++    char *safe_entryname;
++    const char **attrs;
++    const char *base_dn;
++    int dp_error;
++    int ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct sdap_autofs_get_entry_state);
++
++    ret = sdap_id_op_connect_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "LDAP connection failed "
++                                   "[%d]: %s\n", ret, strerror(ret));
++        state->dp_error = dp_error;
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "LDAP connection successful\n");
++
++    ret = sysdb_get_map_byname(state, state->id_ctx->be->domain,
++                               state->mapname, &map);
++    if (ret == ENOENT) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Map %s does not exist!\n", state->mapname);
++        tevent_req_error(req, ret);
++        return;
++    } else if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get map %s [%d]: %s\n",
++              state->mapname, ret, sss_strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    base_dn = ldb_msg_find_attr_as_string(map, SYSDB_ORIG_DN, NULL);
++    if (base_dn == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get originalDN\n");
++        tevent_req_error(req, ERR_INTERNAL);
++        return;
++    }
++
++    ret = sss_filter_sanitize(state, state->entryname, &safe_entryname);
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
++                 state->opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].name,
++                 safe_entryname,
++                 state->opts->autofs_entry_map[SDAP_OC_AUTOFS_ENTRY].name);
++    if (filter == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build filter\n");
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    ret = build_attrs_from_map(state, state->opts->autofs_entry_map,
++                               SDAP_OPTS_AUTOFS_ENTRY, NULL, &attrs, NULL);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build attributes from map\n");
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    subreq = sdap_search_bases_return_first_send(state, state->id_ctx->be->ev,
++                    state->opts, sdap_id_op_handle(state->sdap_op),
++                    state->opts->sdom->autofs_search_bases,
++                    state->opts->autofs_entry_map, false,
++                    dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT),
++                    filter, attrs, base_dn);
++    if (subreq == NULL) {
++        state->dp_error = DP_ERR_FATAL;
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++
++    tevent_req_set_callback(subreq, sdap_autofs_get_entry_done, req);
++}
++
++static void sdap_autofs_get_entry_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    struct sdap_autofs_get_entry_state *state;
++    struct sysdb_attrs **reply;
++    size_t reply_count;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct sdap_autofs_get_entry_state);
++
++    ret = sdap_search_bases_return_first_recv(subreq, state, &reply_count,
++                                              &reply);
++    talloc_zfree(subreq);
++
++    ret = sdap_id_op_done(state->sdap_op, ret, &state->dp_error);
++    if (state->dp_error == DP_ERR_OK && ret != EOK) {
++        /* retry */
++        ret = sdap_autofs_get_entry_retry(req);
++        if (ret != EOK) {
++            tevent_req_error(req, ret);
++        }
++        return;
++    } else if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    if (reply_count == 0) {
++        ret = sysdb_del_autofsentry_by_key(state->id_ctx->be->domain,
++                                           state->mapname, state->entryname);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot delete entry %s:%s\n",
++                  state->mapname, state->entryname);
++            tevent_req_error(req, ret);
++            return;
++        }
++
++        tevent_req_done(req);
++        return;
++    }
++
++    ret = add_autofs_entry(state->id_ctx->be->domain, state->mapname,
++                           state->opts, reply[0], time(NULL));
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++             "Cannot save autofs entry %s:%s [%d]: %s\n",
++              state->mapname, state->entryname, ret, strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++errno_t sdap_autofs_get_entry_recv(struct tevent_req *req,
++                                   int *dp_error)
++{
++    struct sdap_autofs_get_entry_state *state;
++
++    state = tevent_req_data(req, struct sdap_autofs_get_entry_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    *dp_error = state->dp_error;
++
++    return EOK;
++}
+diff --git a/src/providers/ldap/sdap_autofs.c b/src/providers/ldap/sdap_autofs.c
+index 9a5ed11e8..b1e4b5aef 100644
+--- a/src/providers/ldap/sdap_autofs.c
++++ b/src/providers/ldap/sdap_autofs.c
+@@ -391,6 +391,90 @@ sdap_autofs_get_map_handler_recv(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++struct sdap_autofs_get_entry_handler_state {
++    struct dp_reply_std reply;
++};
++
++static void sdap_autofs_get_entry_handler_done(struct tevent_req *subreq);
++
++struct tevent_req *
++sdap_autofs_get_entry_handler_send(TALLOC_CTX *mem_ctx,
++                                 struct sdap_id_ctx *id_ctx,
++                                 struct dp_autofs_data *data,
++                                 struct dp_req_params *params)
++{
++    struct sdap_autofs_get_entry_handler_state *state;
++    struct tevent_req *subreq;
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct sdap_autofs_get_entry_handler_state);
++    if (req == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
++        return NULL;
++    }
++
++    DEBUG(SSSDBG_FUNC_DATA, "Requested refresh for: %s:%s\n",
++          data->mapname, data->entryname);
++
++    subreq = sdap_autofs_get_entry_send(mem_ctx, id_ctx,
++                                        data->mapname, data->entryname);
++    if (subreq == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request for %s:%s.\n",
++              data->mapname, data->entryname);
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    tevent_req_set_callback(subreq, sdap_autofs_get_entry_handler_done, req);
++
++    return req;
++
++immediately:
++    dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
++
++    /* TODO For backward compatibility we always return EOK to DP now. */
++    tevent_req_done(req);
++    tevent_req_post(req, params->ev);
++
++    return req;
++}
++
++static void sdap_autofs_get_entry_handler_done(struct tevent_req *subreq)
++{
++    struct sdap_autofs_get_entry_handler_state *state;
++    struct tevent_req *req;
++    int dp_error;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct sdap_autofs_get_entry_handler_state);
++
++    ret = sdap_autofs_get_entry_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++
++    /* TODO For backward compatibility we always return EOK to DP now. */
++    dp_reply_std_set(&state->reply, dp_error, ret, NULL);
++    tevent_req_done(req);
++}
++
++errno_t
++sdap_autofs_get_entry_handler_recv(TALLOC_CTX *mem_ctx,
++                                   struct tevent_req *req,
++                                   struct dp_reply_std *data)
++{
++    struct sdap_autofs_get_entry_handler_state *state = NULL;
++
++    state = tevent_req_data(req, struct sdap_autofs_get_entry_handler_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    *data = state->reply;
++
++    return EOK;
++}
++
+ errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx,
+                          struct be_ctx *be_ctx,
+                          struct sdap_id_ctx *id_ctx,
+@@ -414,5 +498,9 @@ errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx,
+                   sdap_autofs_get_map_handler_send, sdap_autofs_get_map_handler_recv, id_ctx,
+                   struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+ 
++    dp_set_method(dp_methods, DPM_AUTOFS_GET_ENTRY,
++                  sdap_autofs_get_entry_handler_send, sdap_autofs_get_entry_handler_recv, id_ctx,
++                  struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
++
+     return EOK;
+ }
+diff --git a/src/providers/ldap/sdap_autofs.h b/src/providers/ldap/sdap_autofs.h
+index 34b9ca953..210393746 100644
+--- a/src/providers/ldap/sdap_autofs.h
++++ b/src/providers/ldap/sdap_autofs.h
+@@ -50,5 +50,13 @@ struct tevent_req *sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
+ errno_t sdap_autofs_get_map_recv(struct tevent_req *req,
+                                  int *dp_error);
+ 
++struct tevent_req *sdap_autofs_get_entry_send(TALLOC_CTX *mem_ctx,
++                                              struct sdap_id_ctx *id_ctx,
++                                              const char *mapname,
++                                              const char *entryname);
++
++errno_t sdap_autofs_get_entry_recv(struct tevent_req *req,
++                                   int *dp_error);
++
+ #endif /* _SDAP_AUTOFS_H_ */
+ 
+diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+index f4d0cb140..422fe90c4 100644
+--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+@@ -72,8 +72,8 @@ cache_req_autofs_entry_by_name_dp_send(TALLOC_CTX *mem_ctx,
+                                        struct ldb_result *result)
+ {
+     return sss_dp_get_autofs_send(mem_ctx, cr->rctx, domain, true,
+-                                  SSS_DP_AUTOFS_ENUMERATE,
+-                                  data->name.name, NULL);
++                                  SSS_DP_AUTOFS_GET_ENTRY,
++                                  data->name.name, data->autofs_entry_name);
+ }
+ 
+ const struct cache_req_plugin cache_req_autofs_entry_by_name = {
+-- 
+2.20.1
+
diff --git a/SOURCES/0087-autofs-allow-to-run-only-setent-without-enumeration-.patch b/SOURCES/0087-autofs-allow-to-run-only-setent-without-enumeration-.patch
new file mode 100644
index 0000000..c6c2c24
--- /dev/null
+++ b/SOURCES/0087-autofs-allow-to-run-only-setent-without-enumeration-.patch
@@ -0,0 +1,49 @@
+From 3e04a812772191e2c0e4f4be70584990a7235cbe Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 15 Aug 2019 12:52:04 +0200
+Subject: [PATCH 87/90] autofs: allow to run only setent without enumeration in
+ test tool
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So we can test that setent stores only the map object.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/sss_client/autofs/autofs_test_client.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/sss_client/autofs/autofs_test_client.c b/src/sss_client/autofs/autofs_test_client.c
+index 6bbd2a0e8..18d666895 100644
+--- a/src/sss_client/autofs/autofs_test_client.c
++++ b/src/sss_client/autofs/autofs_test_client.c
+@@ -44,9 +44,11 @@ int main(int argc, const char *argv[])
+     char *key = NULL;
+     char *value = NULL;
+     char *pc_key = NULL;
++    int pc_setent = 0;
+     struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         { "by-name",  'n', POPT_ARG_STRING, &pc_key, 0, "Request map by name", NULL },
++        { "only-setent",  's', POPT_ARG_VAL, &pc_setent, 1, "Run only setent, do not enumerate", NULL },
+         POPT_TABLEEND
+     };
+     poptContext pc = NULL;
+@@ -75,6 +77,10 @@ int main(int argc, const char *argv[])
+     }
+     printf("setautomntent done for %s\n", mapname);
+ 
++    if (pc_setent) {
++        goto end;
++    }
++
+     if (!pc_key) {
+         do {
+             ret = _sss_getautomntent_r(&key, &value, ctx);
+-- 
+2.20.1
+
diff --git a/SOURCES/0088-autofs-always-refresh-auto.master.patch b/SOURCES/0088-autofs-always-refresh-auto.master.patch
new file mode 100644
index 0000000..a3db06c
--- /dev/null
+++ b/SOURCES/0088-autofs-always-refresh-auto.master.patch
@@ -0,0 +1,218 @@
+From ac712654f07be9e9c05156c89af54eac483d75d6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 2 Sep 2019 13:05:14 +0200
+Subject: [PATCH 88/90] autofs: always refresh auto.master
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/responder/autofs/autofs_private.h | 10 ++++-
+ src/responder/autofs/autofssrv.c      | 25 ++++++++----
+ src/responder/autofs/autofssrv_cmd.c  | 56 ++++++++++++++++++++++-----
+ 3 files changed, 74 insertions(+), 17 deletions(-)
+
+diff --git a/src/responder/autofs/autofs_private.h b/src/responder/autofs/autofs_private.h
+index 3be25d4d9..175a7768f 100644
+--- a/src/responder/autofs/autofs_private.h
++++ b/src/responder/autofs/autofs_private.h
+@@ -21,6 +21,8 @@
+ #ifndef _AUTOFSSRV_PRIVATE_H_
+ #define _AUTOFSSRV_PRIVATE_H_
+ 
++#include <dhash.h>
++
+ #include "responder/common/responder.h"
+ #include "responder/common/responder_sbus.h"
+ #include "responder/common/cache_req/cache_req.h"
+@@ -55,6 +57,12 @@ struct autofs_enum_ctx {
+     /* False if the result is being created. */
+     bool ready;
+ 
++    /* Enumeration context key. */
++    const char *key;
++
++    /* Hash table that contains this enumeration context. */
++    hash_table_t *table;
++
+     /* Requests that awaits the data. */
+     struct setent_req_list *notify_list;
+ };
+@@ -62,6 +70,6 @@ struct autofs_enum_ctx {
+ struct sss_cmd_table *get_autofs_cmds(void);
+ int autofs_connection_setup(struct cli_ctx *cctx);
+ 
+-errno_t autofs_orphan_maps(struct autofs_ctx *actx);
++void autofs_orphan_maps(struct autofs_ctx *actx);
+ 
+ #endif /* _AUTOFSSRV_PRIVATE_H_ */
+diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
+index 309ed76b1..922da5fd4 100644
+--- a/src/responder/autofs/autofssrv.c
++++ b/src/responder/autofs/autofssrv.c
+@@ -85,17 +85,26 @@ static int autofs_clean_hash_table(struct sbus_request *dbus_req, void *data)
+     struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
+     struct autofs_ctx *actx =
+             talloc_get_type(rctx->pvt_ctx, struct autofs_ctx);
+-    errno_t ret;
+ 
+-    ret = autofs_orphan_maps(actx);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Could not invalidate maps\n");
+-        return ret;
+-    }
++    autofs_orphan_maps(actx);
+ 
+     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
+ }
+ 
++static void
++autofs_maps_delete_cb(hash_entry_t *item,
++                      hash_destroy_enum deltype,
++                      void *pvt)
++{
++    struct autofs_ctx *autofs_ctx;
++    struct autofs_enum_ctx *enum_ctx;
++
++    autofs_ctx = talloc_get_type(pvt, struct autofs_ctx);
++
++    enum_ctx = sss_ptr_get_value(&item->value, struct autofs_enum_ctx);
++    talloc_unlink(autofs_ctx->maps, enum_ctx);
++}
++
+ static int
+ autofs_process_init(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *ev,
+@@ -158,7 +167,9 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
+     }
+ 
+     /* Create the lookup table for setautomntent results */
+-    autofs_ctx->maps = sss_ptr_hash_create(autofs_ctx, NULL, NULL);
++    autofs_ctx->maps = sss_ptr_hash_create(autofs_ctx,
++                                           autofs_maps_delete_cb,
++                                           autofs_ctx);
+     if (autofs_ctx->maps == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Unable to initialize automount maps hash table\n");
+diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
+index d413f8570..71938399e 100644
+--- a/src/responder/autofs/autofssrv_cmd.c
++++ b/src/responder/autofs/autofssrv_cmd.c
+@@ -131,12 +131,12 @@ autofs_fill_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *
+     return EOK;
+ }
+ 
+-errno_t
++void
+ autofs_orphan_maps(struct autofs_ctx *autofs_ctx)
+ {
+-    sss_ptr_hash_delete_all(autofs_ctx->maps, true);
+-
+-    return EOK;
++    /* It will automatically decrease the refcount of enum_ctx through
++     * delete callback. */
++    sss_ptr_hash_delete_all(autofs_ctx->maps, false);
+ }
+ 
+ static void
+@@ -149,8 +149,8 @@ autofs_enumctx_lifetime_timeout(struct tevent_context *ev,
+ 
+     enum_ctx = talloc_get_type(pvt, struct autofs_enum_ctx);
+ 
+-    /* Free the context. It will be automatically removed from the hash table. */
+-    talloc_free(enum_ctx);
++    /* Remove it from the table. It will automatically decrease the refcount. */
++    sss_ptr_hash_delete(enum_ctx->table, enum_ctx->key, false);
+ }
+ 
+ static void
+@@ -185,6 +185,13 @@ autofs_create_enumeration_context(TALLOC_CTX *mem_ctx,
+     }
+ 
+     enum_ctx->ready = false;
++    enum_ctx->table = autofs_ctx->maps;
++
++    enum_ctx->key = talloc_strdup(enum_ctx, mapname);
++    if (enum_ctx->key == NULL) {
++        talloc_free(enum_ctx);
++        return NULL;
++    }
+ 
+     ret = sss_ptr_hash_add(autofs_ctx->maps, mapname,
+                            enum_ctx, struct autofs_enum_ctx);
+@@ -196,6 +203,34 @@ autofs_create_enumeration_context(TALLOC_CTX *mem_ctx,
+     return enum_ctx;
+ }
+ 
++static void
++autofs_orphan_master_map(struct autofs_ctx *autofs_ctx,
++                         const char *mapname)
++{
++    struct sss_domain_info *dom;
++    errno_t ret;
++
++    if (strcmp(mapname, "auto.master") != 0) {
++        return;
++    }
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Invalidating master map\n");
++
++    /* Remove and invalidate all maps. */
++    autofs_orphan_maps(autofs_ctx);
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Invalidating autofs maps\n");
++    for (dom = autofs_ctx->rctx->domains;
++         dom != NULL;
++         dom = get_next_domain(dom, SSS_GND_DESCEND)) {
++        ret = sysdb_invalidate_autofs_maps(dom);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Unable to invalidate maps in "
++                  "%s [%d]: %s\n", dom->name, ret, sss_strerror(ret));
++        }
++    }
++}
++
+ struct autofs_setent_state {
+     struct autofs_ctx *autofs_ctx;
+     struct autofs_enum_ctx *enum_ctx;
+@@ -323,7 +358,8 @@ static void autofs_setent_done(struct tevent_req *subreq)
+ }
+ 
+ static errno_t
+-autofs_setent_recv(struct tevent_req *req,
++autofs_setent_recv(TALLOC_CTX *mem_ctx,
++                   struct tevent_req *req,
+                    struct autofs_enum_ctx **_enum_ctx)
+ {
+     struct autofs_setent_state *state;
+@@ -331,7 +367,7 @@ autofs_setent_recv(struct tevent_req *req,
+ 
+     TEVENT_REQ_RETURN_ON_ERROR(req);
+ 
+-    *_enum_ctx = state->enum_ctx;
++    *_enum_ctx = talloc_reference(mem_ctx, state->enum_ctx);
+ 
+     return EOK;
+ }
+@@ -430,6 +466,8 @@ sss_autofs_cmd_setautomntent(struct cli_ctx *cli_ctx)
+         goto done;
+     }
+ 
++    autofs_orphan_master_map(autofs_ctx, cmd_ctx->mapname);
++
+     DEBUG(SSSDBG_TRACE_FUNC, "Obtaining autofs map %s\n",
+           cmd_ctx->mapname);
+ 
+@@ -668,7 +706,7 @@ sss_autofs_cmd_getautomntent_done(struct tevent_req *req)
+ 
+     cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
+ 
+-    ret = autofs_setent_recv(req, &enum_ctx);
++    ret = autofs_setent_recv(cmd_ctx, req, &enum_ctx);
+     talloc_zfree(req);
+     if (ret != EOK) {
+         autofs_cmd_done(cmd_ctx, ret);
+-- 
+2.20.1
+
diff --git a/SOURCES/0089-sysdb-invalidate-also-autofs-entries.patch b/SOURCES/0089-sysdb-invalidate-also-autofs-entries.patch
new file mode 100644
index 0000000..03a174d
--- /dev/null
+++ b/SOURCES/0089-sysdb-invalidate-also-autofs-entries.patch
@@ -0,0 +1,194 @@
+From 58f3d546954d7c2298a0b57865f7d5ad51f69aec Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 5 Sep 2019 11:32:11 +0200
+Subject: [PATCH 89/90] sysdb: invalidate also autofs entries
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Autofs entries got data expiration attribute so we must
+make sure it is invalidated as well.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/db/sysdb_autofs.c | 131 ++++++++++++++++++++++++++++++++++++++++++
+ src/db/sysdb_autofs.h |   4 ++
+ 2 files changed, 135 insertions(+)
+
+diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
+index 11841d50d..413b00722 100644
+--- a/src/db/sysdb_autofs.c
++++ b/src/db/sysdb_autofs.c
+@@ -530,6 +530,37 @@ done:
+     return ret;
+ }
+ 
++errno_t
++sysdb_set_autofsentry_attr(struct sss_domain_info *domain,
++                           const char *mapname,
++                           const char *key,
++                           const char *value,
++                           struct sysdb_attrs *attrs,
++                           int mod_op)
++{
++    TALLOC_CTX *tmp_ctx;
++    struct ldb_dn *dn;
++    errno_t ret;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
++        return ENOMEM;
++    }
++
++    dn = sysdb_autofsentry_dn(tmp_ctx, domain, mapname, key, value);
++    if (dn == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
++
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ errno_t
+ sysdb_set_autofsmap_attr(struct sss_domain_info *domain,
+                          const char *name,
+@@ -558,6 +589,99 @@ done:
+     return ret;
+ }
+ 
++errno_t
++sysdb_invalidate_autofs_entries(struct sss_domain_info *domain,
++                                const char *mapname)
++{
++    TALLOC_CTX *tmp_ctx;
++    bool in_transaction = false;
++    struct ldb_message **entries;
++    struct sysdb_attrs *attrs;
++    const char *value;
++    const char *key;
++    size_t count;
++    errno_t ret;
++    size_t i;
++    int sret;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
++        return ENOMEM;
++    }
++
++    ret = sysdb_autofs_entries_by_map(tmp_ctx, domain, mapname,
++                                      &count, &entries);
++    if (ret == ENOENT) {
++        ret = EOK;
++        goto done;
++    } else if (ret != EOK) {
++        goto done;
++    }
++
++    attrs = sysdb_new_attrs(tmp_ctx);
++    if (attrs == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE, 1);
++    if (ret != EOK) {
++        goto done;
++    }
++
++    ret = sysdb_transaction_start(domain->sysdb);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
++        goto done;
++    }
++    in_transaction = true;
++
++    for (i = 0; i < count; i++) {
++        key = ldb_msg_find_attr_as_string(entries[i], SYSDB_AUTOFS_ENTRY_KEY,
++                                          NULL);
++        if (key == NULL) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "An entry with no key?\n");
++            continue;
++        }
++
++        value = ldb_msg_find_attr_as_string(entries[i],
++                                            SYSDB_AUTOFS_ENTRY_VALUE,
++                                            NULL);
++        if (value == NULL) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "An entry with no value?\n");
++            continue;
++        }
++
++        ret = sysdb_set_autofsentry_attr(domain, mapname, key, value,
++                                         attrs, SYSDB_MOD_REP);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not expire entry %s\n", key);
++            continue;
++        }
++    }
++
++    ret = sysdb_transaction_commit(domain->sysdb);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Could not commit transaction\n");
++        goto done;
++    }
++    in_transaction = false;
++
++    ret = EOK;
++
++done:
++    if (in_transaction) {
++        sret = sysdb_transaction_cancel(domain->sysdb);
++        if (sret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
++        }
++    }
++
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ errno_t
+ sysdb_invalidate_autofs_maps(struct sss_domain_info *domain)
+ {
+@@ -634,6 +758,13 @@ sysdb_invalidate_autofs_maps(struct sss_domain_info *domain)
+             DEBUG(SSSDBG_MINOR_FAILURE, "Could not expire map %s\n", name);
+             continue;
+         }
++
++        ret =  sysdb_invalidate_autofs_entries(domain, name);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Could not expire map entries %s\n",
++                  name);
++            continue;
++        }
+     }
+ 
+     ret = sysdb_transaction_commit(domain->sysdb);
+diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h
+index 3775e2a17..37489f2e8 100644
+--- a/src/db/sysdb_autofs.h
++++ b/src/db/sysdb_autofs.h
+@@ -93,6 +93,10 @@ sysdb_set_autofsmap_attr(struct sss_domain_info *domain,
+                          struct sysdb_attrs *attrs,
+                          int mod_op);
+ 
++errno_t
++sysdb_invalidate_autofs_entries(struct sss_domain_info *domain,
++                                const char *mapname);
++
+ errno_t
+ sysdb_invalidate_autofs_maps(struct sss_domain_info *domain);
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0090-sss_cache-invalidate-also-autofs-entries.patch b/SOURCES/0090-sss_cache-invalidate-also-autofs-entries.patch
new file mode 100644
index 0000000..6e076a2
--- /dev/null
+++ b/SOURCES/0090-sss_cache-invalidate-also-autofs-entries.patch
@@ -0,0 +1,49 @@
+From 9131b90f08e69a4d71c6d1524e3b8929d947b7c7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Thu, 5 Sep 2019 11:32:53 +0200
+Subject: [PATCH 90/90] sss_cache: invalidate also autofs entries
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Invalidating map will also invalidate all its child entries.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2607
+
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/tools/sss_cache.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
+index 6bdcf610c..34bfa76bc 100644
+--- a/src/tools/sss_cache.c
++++ b/src/tools/sss_cache.c
+@@ -576,8 +576,23 @@ static errno_t invalidate_entry(TALLOC_CTX *ctx,
+                                                  sys_attrs, SYSDB_MOD_REP);
+                     break;
+                 case TYPE_AUTOFSMAP:
++                    /* For users, we also need to reset the enumeration
++                     * expiration time. */
++                    ret = sysdb_attrs_add_time_t(sys_attrs,
++                                                 SYSDB_ENUM_EXPIRE, 1);
++                    if (ret != EOK) {
++                        return ret;
++                    }
++
+                     ret = sysdb_set_autofsmap_attr(domain, name,
+                                                    sys_attrs, SYSDB_MOD_REP);
++                    if (ret != EOK) {
++                        DEBUG(SSSDBG_MINOR_FAILURE, "Could not invalidate "
++                              "autofs map %s\n", name);
++                        break;
++                    }
++
++                    ret = sysdb_invalidate_autofs_entries(domain, name);
+                     break;
+                 case TYPE_SSH_HOST:
+ #ifdef BUILD_SSH
+-- 
+2.20.1
+
diff --git a/SOURCES/0091-CONFDB-Files-domain-if-activated-without-.conf.patch b/SOURCES/0091-CONFDB-Files-domain-if-activated-without-.conf.patch
new file mode 100644
index 0000000..6ee7bb0
--- /dev/null
+++ b/SOURCES/0091-CONFDB-Files-domain-if-activated-without-.conf.patch
@@ -0,0 +1,35 @@
+From 5b571efa60f8ce86089772fdd43555174692d0d2 Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Thu, 5 Sep 2019 09:28:55 +0200
+Subject: [PATCH 91/92] CONFDB: Files domain if activated without .conf
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Implicit files domain gets activated when no sssd.conf present
+and sssd is started. This does not respect --disable-files-domain
+configure option
+
+Resolves:
+https://bugzilla.redhat.com/show_bug.cgi?id=1713352
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/confdb/confdb_setup.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
+index 5e3558965..e9944957d 100644
+--- a/src/confdb/confdb_setup.c
++++ b/src/confdb/confdb_setup.c
+@@ -34,7 +34,6 @@
+ "version: 2\n\n" \
+ "dn: cn=sssd,cn=config\n" \
+ "cn: sssd\n" \
+-"enable_files_domain: true\n" \
+ "services: nss\n\n"
+ #endif /* SSSD_FALLBACK_CONFIG_LDIF */
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0092-TESTS-adapt-tests-to-enabled-default-files-domain.patch b/SOURCES/0092-TESTS-adapt-tests-to-enabled-default-files-domain.patch
new file mode 100644
index 0000000..6f14e43
--- /dev/null
+++ b/SOURCES/0092-TESTS-adapt-tests-to-enabled-default-files-domain.patch
@@ -0,0 +1,65 @@
+From e48cdfb69b43964d5472bdf011af59343c719a06 Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Thu, 5 Sep 2019 09:30:04 +0200
+Subject: [PATCH 92/92] TESTS: adapt tests to enabled default files domain
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some tests expect that SSSD is compiled with --enable-files-domain
+option (test_no_sssd_conf). But having this enabled by default
+breaks some other tests.
+
+This patch adds --enable-files-domain to test build and explicitly
+disables the domain in configuration of some tests (ldap, enumeration).
+
+Resolves:
+https://bugzilla.redhat.com/show_bug.cgi?id=1713352
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ Makefile.am                        | 2 ++
+ src/tests/intg/test_enumeration.py | 1 +
+ src/tests/intg/test_ldap.py        | 1 +
+ 3 files changed, 4 insertions(+)
+
+diff --git a/Makefile.am b/Makefile.am
+index bc74906a7..45a042624 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3766,6 +3766,8 @@ intgcheck-prepare:
+ 	    --enable-intgcheck-reqs \
+ 	    --without-semanage \
+ 	    --with-session-recording-shell=/bin/false \
++	    --enable-local-provider \
++	    --enable-files-domain \
+ 	    $(INTGCHECK_CONFIGURE_FLAGS) \
+ 	    CFLAGS="-O2 -g $$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \
+ 	$(MAKE) $(AM_MAKEFLAGS) ; \
+diff --git a/src/tests/intg/test_enumeration.py b/src/tests/intg/test_enumeration.py
+index 669fd86c7..c105c6df0 100644
+--- a/src/tests/intg/test_enumeration.py
++++ b/src/tests/intg/test_enumeration.py
+@@ -113,6 +113,7 @@ def format_basic_conf(ldap_conn, schema):
+         debug_level         = 0xffff
+         domains             = LDAP
+         services            = nss, pam
++        enable_files_domain = false
+ 
+         [nss]
+         debug_level         = 0xffff
+diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py
+index 787255f92..c432068f9 100644
+--- a/src/tests/intg/test_ldap.py
++++ b/src/tests/intg/test_ldap.py
+@@ -117,6 +117,7 @@ def format_basic_conf(ldap_conn, schema):
+         debug_level         = 0xffff
+         domains             = LDAP
+         services            = nss, pam
++        enable_files_domain = false
+ 
+         [nss]
+         debug_level         = 0xffff
+-- 
+2.20.1
+
diff --git a/SOURCES/0093-utils-extend-some-find_domain_-calls-to-search-disab.patch b/SOURCES/0093-utils-extend-some-find_domain_-calls-to-search-disab.patch
new file mode 100644
index 0000000..31c7070
--- /dev/null
+++ b/SOURCES/0093-utils-extend-some-find_domain_-calls-to-search-disab.patch
@@ -0,0 +1,272 @@
+From 2ea937af47c529ca827bcdd307a47e2b96690d38 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 12 Sep 2019 14:49:30 +0200
+Subject: [PATCH 93/97] utils: extend some find_domain_* calls to search
+ disabled domain
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This extension is needed to support disabled domains since it is
+now important to know if a domain is really unknown or only disabled.
+While an unknown domain might typically lead to an error, a caller might
+just ignore requests for disabled domains or objects from disabled
+domains.
+
+Related to https://pagure.io/SSSD/sssd/issue/4078
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ipa/ipa_id.c                 |  3 +-
+ src/responder/sudo/sudosrv_get_sudorules.c |  3 +-
+ src/tests/cmocka/test_utils.c              | 90 ++++++++++++++++++++++
+ src/util/domain_info_utils.c               | 31 +++++---
+ src/util/util.h                            |  7 +-
+ 5 files changed, 122 insertions(+), 12 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index 9abee34cb..f34692aa2 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -138,7 +138,8 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req)
+ 
+     state->user_domain = find_domain_by_object_name_ex(
+                                         state->ipa_ctx->sdap_id_ctx->be->domain,
+-                                        ar->filter_value, true);
++                                        ar->filter_value, true,
++                                        SSS_GND_DESCEND);
+     /* Use provided domain as fallback because no known domain was found in the
+      * user name. */
+     if (state->user_domain == NULL) {
+diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
+index d928a5ead..c9c11bfde 100644
+--- a/src/responder/sudo/sudosrv_get_sudorules.c
++++ b/src/responder/sudo/sudosrv_get_sudorules.c
+@@ -147,7 +147,8 @@ static errno_t sudosrv_format_runas(struct resp_ctx *rctx,
+             continue;
+         }
+ 
+-        dom = find_domain_by_object_name_ex(rctx->domains, value, true);
++        dom = find_domain_by_object_name_ex(rctx->domains, value, true,
++                                            SSS_GND_DESCEND);
+         if (dom == NULL) {
+             continue;
+         }
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index 1a8699a2a..d49eb9fbc 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -400,6 +400,92 @@ void test_find_domain_by_name_disabled(void **state)
+     }
+ }
+ 
++void test_find_domain_by_name_ex_disabled(void **state)
++{
++    struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
++                                                      struct dom_list_test_ctx);
++    struct sss_domain_info *dom;
++    struct sss_domain_info *disabled_dom;
++    size_t c;
++    size_t mis;
++
++    mis = test_ctx->dom_count/2;
++    assert_true((mis >= 1 && mis < test_ctx->dom_count));
++
++    dom = test_ctx->dom_list;
++    for (c = 0; c < mis; c++) {
++        assert_non_null(dom);
++        dom = dom->next;
++    }
++    assert_non_null(dom);
++    sss_domain_set_state(dom, DOM_DISABLED);
++    disabled_dom = dom;
++
++    dom = find_domain_by_name(test_ctx->dom_list, disabled_dom->name, true);
++    assert_null(dom);
++
++    dom = find_domain_by_name_ex(test_ctx->dom_list, disabled_dom->name, true,
++                                 SSS_GND_DESCEND);
++    assert_null(dom);
++
++    dom = find_domain_by_name_ex(test_ctx->dom_list, disabled_dom->name, true,
++                                 SSS_GND_DESCEND | SSS_GND_INCLUDE_DISABLED);
++    assert_non_null(dom);
++    assert_ptr_equal(disabled_dom, dom);
++
++    dom = find_domain_by_name_ex(test_ctx->dom_list, disabled_dom->name, true,
++                                 SSS_GND_ALL_DOMAINS);
++    assert_non_null(dom);
++    assert_ptr_equal(disabled_dom, dom);
++}
++
++void test_find_domain_by_object_name_ex(void **state)
++{
++    struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
++                                                      struct dom_list_test_ctx);
++    struct sss_domain_info *dom;
++    struct sss_domain_info *disabled_dom;
++    size_t c;
++    size_t mis;
++    char *obj_name;
++
++    mis = test_ctx->dom_count/2;
++    assert_true((mis >= 1 && mis < test_ctx->dom_count));
++
++    dom = test_ctx->dom_list;
++    for (c = 0; c < mis; c++) {
++        assert_non_null(dom);
++        dom = dom->next;
++    }
++    assert_non_null(dom);
++    sss_domain_set_state(dom, DOM_DISABLED);
++    disabled_dom = dom;
++
++    obj_name = talloc_asprintf(global_talloc_context, "myname@%s",
++                               disabled_dom->name);
++    assert_non_null(obj_name);
++
++
++    dom = find_domain_by_object_name(test_ctx->dom_list, obj_name);
++    assert_null(dom);
++
++    dom = find_domain_by_object_name_ex(test_ctx->dom_list, obj_name, true,
++                                        SSS_GND_DESCEND);
++    assert_null(dom);
++
++    dom = find_domain_by_object_name_ex(test_ctx->dom_list, obj_name, true,
++                                    SSS_GND_DESCEND | SSS_GND_INCLUDE_DISABLED);
++    assert_non_null(dom);
++    assert_ptr_equal(disabled_dom, dom);
++
++    dom = find_domain_by_object_name_ex(test_ctx->dom_list, obj_name, true,
++                                        SSS_GND_ALL_DOMAINS);
++    assert_non_null(dom);
++    assert_ptr_equal(disabled_dom, dom);
++
++    talloc_free(obj_name);
++}
++
+ void test_find_domain_by_sid_null(void **state)
+ {
+     struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
+@@ -1877,6 +1963,10 @@ int main(int argc, const char *argv[])
+                                         setup_dom_list, teardown_dom_list),
+         cmocka_unit_test_setup_teardown(test_find_domain_by_name_disabled,
+                                         setup_dom_list, teardown_dom_list),
++        cmocka_unit_test_setup_teardown(test_find_domain_by_name_ex_disabled,
++                                        setup_dom_list, teardown_dom_list),
++        cmocka_unit_test_setup_teardown(test_find_domain_by_object_name_ex,
++                                        setup_dom_list, teardown_dom_list),
+ 
+         cmocka_unit_test_setup_teardown(test_sss_names_init,
+                                         confdb_test_setup,
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 4b1c9df39..c56a0611e 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -93,9 +93,10 @@ bool subdomain_enumerates(struct sss_domain_info *parent,
+     return false;
+ }
+ 
+-struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
+-                                            const char *name,
+-                                            bool match_any)
++struct sss_domain_info *find_domain_by_name_ex(struct sss_domain_info *domain,
++                                                const char *name,
++                                                bool match_any,
++                                                uint32_t gnd_flags)
+ {
+     struct sss_domain_info *dom = domain;
+ 
+@@ -103,21 +104,31 @@ struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
+         return NULL;
+     }
+ 
+-    while (dom && sss_domain_get_state(dom) == DOM_DISABLED) {
+-        dom = get_next_domain(dom, SSS_GND_DESCEND);
++    if (!(gnd_flags & SSS_GND_INCLUDE_DISABLED)) {
++        while (dom && sss_domain_get_state(dom) == DOM_DISABLED) {
++            dom = get_next_domain(dom, gnd_flags);
++        }
+     }
++
+     while (dom) {
+         if (strcasecmp(dom->name, name) == 0 ||
+             ((match_any == true) && (dom->flat_name != NULL) &&
+              (strcasecmp(dom->flat_name, name) == 0))) {
+             return dom;
+         }
+-        dom = get_next_domain(dom, SSS_GND_DESCEND);
++        dom = get_next_domain(dom, gnd_flags);
+     }
+ 
+     return NULL;
+ }
+ 
++struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
++                                            const char *name,
++                                            bool match_any)
++{
++    return find_domain_by_name_ex(domain, name, match_any, SSS_GND_DESCEND);
++}
++
+ struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
+                                               const char *sid)
+ {
+@@ -175,7 +186,8 @@ sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
+ 
+ struct sss_domain_info *
+ find_domain_by_object_name_ex(struct sss_domain_info *domain,
+-                              const char *object_name, bool strict)
++                              const char *object_name, bool strict,
++                              uint32_t gnd_flags)
+ {
+     TALLOC_CTX *tmp_ctx;
+     struct sss_domain_info *dom = NULL;
+@@ -203,7 +215,7 @@ find_domain_by_object_name_ex(struct sss_domain_info *domain,
+             dom = domain;
+         }
+     } else {
+-        dom = find_domain_by_name(domain, domainname, true);
++        dom = find_domain_by_name_ex(domain, domainname, true, gnd_flags);
+     }
+ 
+ done:
+@@ -215,7 +227,8 @@ struct sss_domain_info *
+ find_domain_by_object_name(struct sss_domain_info *domain,
+                            const char *object_name)
+ {
+-    return find_domain_by_object_name_ex(domain, object_name, false);
++    return find_domain_by_object_name_ex(domain, object_name, false,
++                                         SSS_GND_DESCEND);
+ }
+ 
+ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
+diff --git a/src/util/util.h b/src/util/util.h
+index fce7e42c3..8a754dbfd 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -542,6 +542,10 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
+ struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
+                                             const char *name,
+                                             bool match_any);
++struct sss_domain_info *find_domain_by_name_ex(struct sss_domain_info *domain,
++                                               const char *name,
++                                               bool match_any,
++                                               uint32_t gnd_flags);
+ struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
+                                            const char *sid);
+ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom);
+@@ -560,7 +564,8 @@ find_domain_by_object_name(struct sss_domain_info *domain,
+ 
+ struct sss_domain_info *
+ find_domain_by_object_name_ex(struct sss_domain_info *domain,
+-                              const char *object_name, bool strict);
++                              const char *object_name, bool strict,
++                              uint32_t gnd_flags);
+ 
+ bool subdomain_enumerates(struct sss_domain_info *parent,
+                           const char *sd_name);
+-- 
+2.20.1
+
diff --git a/SOURCES/0094-ipa-support-disabled-domains.patch b/SOURCES/0094-ipa-support-disabled-domains.patch
new file mode 100644
index 0000000..4aabefd
--- /dev/null
+++ b/SOURCES/0094-ipa-support-disabled-domains.patch
@@ -0,0 +1,208 @@
+From 698e27d8b465d1a507554532938058e053569b1b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 7 Aug 2019 18:14:15 +0200
+Subject: [PATCH 94/97] ipa: support disabled domains
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+IPA does not disable domains with the help of a flag in the domain
+objects but more general with the help of the SID blacklist. With this
+patch the blacklist is read with other data about trusted domains and if
+the domain SID of a trusted domain is found the domain is disabled. As a
+result uses and groups from this domain cannot be looked up anymore.
+
+Related to https://pagure.io/SSSD/sssd/issue/4078
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c | 149 +++++++++++++++++++++++++++--
+ 1 file changed, 139 insertions(+), 10 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 322420264..2ffc6bf7a 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -43,6 +43,7 @@
+ #define IPA_TRUSTED_DOMAIN_SID "ipaNTTrustedDomainSID"
+ #define IPA_RANGE_TYPE "ipaRangeType"
+ #define IPA_ADDITIONAL_SUFFIXES "ipaNTAdditionalSuffixes"
++#define IPA_SID_BLACKLIST_INCOMING "ipaNTSIDBlacklistIncoming"
+ 
+ #define IPA_BASE_ID "ipaBaseID"
+ #define IPA_ID_RANGE_SIZE "ipaIDRangeSize"
+@@ -745,6 +746,129 @@ static void ipa_subdom_store_step(struct sss_domain_info *parent,
+     }
+ }
+ 
++static errno_t add_dom_sids_to_list(TALLOC_CTX *mem_ctx, const char **sids,
++                                    char ***list)
++{
++    size_t c;
++    errno_t ret;
++
++    for (c = 0; sids != NULL && sids[c] != NULL; c++) {
++        if (is_domain_sid(sids[c])) {
++            ret = add_string_to_list(mem_ctx, sids[c], list);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "add_string_to_list failed.\n");
++                return ret;
++            }
++        }
++    }
++
++    return EOK;
++}
++
++static errno_t ipa_get_disabled_domain_sids(TALLOC_CTX *mem_ctx, size_t count,
++                                            struct sysdb_attrs **reply,
++                                            char ***disabled_domain_sids)
++{
++    size_t c;
++    char **dom_sid_list = NULL;
++    const char **tmp_list;
++    int ret;
++
++    for (c = 0; c < count; c++) {
++        ret = sysdb_attrs_get_string_array(reply[c], IPA_SID_BLACKLIST_INCOMING,
++                                           mem_ctx, &tmp_list);
++        if (ret != EOK) {
++            if (ret != ENOENT) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "sysdb_attrs_get_string_array failed, list of disabled "
++                      "domains might be incomplete.\n");
++            }
++            continue;
++        }
++
++        ret = add_dom_sids_to_list(mem_ctx, tmp_list, &dom_sid_list);
++        talloc_free(tmp_list);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "add_dom_sids_to_list failed.\n");
++            talloc_free(dom_sid_list);
++            return ret;
++        }
++    }
++
++    *disabled_domain_sids = dom_sid_list;
++
++    return EOK;
++}
++
++static errno_t ipa_subdomains_check_domain_state(struct sss_domain_info *dom,
++                                                 char **disabled_domain_sids)
++{
++    int ret;
++
++    if (dom->domain_id == NULL) {
++        return EINVAL;
++    }
++
++    if (disabled_domain_sids != NULL
++            && string_in_list(dom->domain_id, disabled_domain_sids, true)) {
++        DEBUG(SSSDBG_TRACE_ALL, "Domain [%s] is disabled on the server.\n",
++                                dom->name);
++        /* disable domain if not already disabled */
++        if (sss_domain_get_state(dom) != DOM_DISABLED) {
++            sss_domain_set_state(dom, DOM_DISABLED);
++            ret = sysdb_domain_set_enabled(dom->sysdb, dom->name, false);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_domain_set_enabled failed.\n");
++                return ret;
++            }
++        }
++    } else {
++        /* enabled domain if it was disabled */
++        DEBUG(SSSDBG_TRACE_ALL, "Domain [%s] is enabled on the server.\n",
++                                dom->name);
++        if (sss_domain_get_state(dom) == DOM_DISABLED) {
++            sss_domain_set_state(dom, DOM_ACTIVE);
++            ret = sysdb_domain_set_enabled(dom->sysdb, dom->name, true);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE, "sysdb_domain_set_enabled failed.\n");
++                return ret;
++            }
++        }
++    }
++
++    return EOK;
++}
++
++
++static void ipa_subdomains_update_dom_state(struct sss_domain_info *parent,
++                                               int count,
++                                               struct sysdb_attrs **reply)
++{
++    int ret;
++    struct sss_domain_info *dom;
++    char **disabled_domain_sids = NULL;
++
++    ret = ipa_get_disabled_domain_sids(reply, count, reply,
++                                       &disabled_domain_sids);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_disabled_domain_sids failed, "
++                                 "assuming no domain is disabled.\n");
++        disabled_domain_sids = NULL;
++    }
++
++    for (dom = get_next_domain(parent, SSS_GND_DESCEND|SSS_GND_INCLUDE_DISABLED);
++         dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
++         dom = get_next_domain(dom, SSS_GND_INCLUDE_DISABLED)) {
++
++        /* check if domain should be disabled/enabled */
++        ret = ipa_subdomains_check_domain_state(dom, disabled_domain_sids);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to check domain state, "
++                  "state of domain [%s] might be wrong.\n", dom->name);
++        }
++    }
++}
++
+ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
+                                       int count, struct sysdb_attrs **reply,
+                                       bool *changes)
+@@ -1376,7 +1500,7 @@ ipa_subdomains_slave_send(TALLOC_CTX *mem_ctx,
+     errno_t ret;
+     const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID,
+                             IPA_TRUST_DIRECTION, IPA_ADDITIONAL_SUFFIXES,
+-                            NULL };
++                            IPA_SID_BLACKLIST_INCOMING, NULL };
+ 
+     req = tevent_req_create(mem_ctx, &state,
+                             struct ipa_subdomains_slave_state);
+@@ -1530,18 +1654,23 @@ static void ipa_subdomains_slave_search_done(struct tevent_req *subreq)
+                                  "expected.\n");
+     }
+ 
+-    if (!has_changes) {
+-        ret = EOK;
+-        goto done;
++    /* If there are no changes this step can be skipped, but
++     * ipa_subdomains_update_dom_state() must be called after that in all case
++     * to cover existing an newly added domains. Since the domain state is not
++     * handled by a domain flag but by the blacklist has_changes does not
++     * cover the state. */
++    if (has_changes) {
++        ret = ipa_subdom_reinit(state->sd_ctx);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
++            goto done;
++        }
+     }
+ 
+-    ret = ipa_subdom_reinit(state->sd_ctx);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
+-        goto done;
+-    }
++    ipa_subdomains_update_dom_state(state->sd_ctx->be_ctx->domain,
++                                    reply_count, reply);
+ 
+-    if (state->sd_ctx->ipa_id_ctx->server_mode == NULL) {
++    if (!has_changes || state->sd_ctx->ipa_id_ctx->server_mode == NULL) {
+         ret = EOK;
+         goto done;
+     }
+-- 
+2.20.1
+
diff --git a/SOURCES/0095-ipa-ignore-objects-from-disabled-domains-on-the-clie.patch b/SOURCES/0095-ipa-ignore-objects-from-disabled-domains-on-the-clie.patch
new file mode 100644
index 0000000..c5abc27
--- /dev/null
+++ b/SOURCES/0095-ipa-ignore-objects-from-disabled-domains-on-the-clie.patch
@@ -0,0 +1,75 @@
+From cc42fe7daece23c639ba8d147808f1c699d8b6ad Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 12 Sep 2019 14:45:08 +0200
+Subject: [PATCH 95/97] ipa: ignore objects from disabled domains on the client
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It is possible that a domain is already disabled on an IPA client but
+still  active on the server. This might happen e.g. if the version of
+SSSD running on the IPA server does not support disabled domains or if
+SSSD on the IPA client updates the domain data before the IPA server and
+sees a freshly disabled domain more early.
+
+As a result the server is still sending objects from disabled domains in
+the lists of group members or group memberships of a user. The client
+should just ignore those objects.
+
+Related to https://pagure.io/SSSD/sssd/issue/4078
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index b6efbcd34..f1d5768ae 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -637,10 +637,16 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
+             }
+ 
+             if (domain != NULL) {
+-                obj_domain = find_domain_by_name(parent_domain, domain, true);
++                obj_domain = find_domain_by_name_ex(parent_domain, domain, true, SSS_GND_ALL_DOMAINS);
+                 if (obj_domain == NULL) {
+                     DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
+                     return ENOMEM;
++                } else if (sss_domain_get_state(obj_domain) == DOM_DISABLED) {
++                    /* skipping objects from disabled domains */
++                    DEBUG(SSSDBG_TRACE_ALL,
++                          "Skipping object [%s] from disabled domain.\n",
++                          list[c]);
++                    continue;
+                 }
+             } else {
+                 obj_domain = parent_domain;
+@@ -656,6 +662,7 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
+             gc++;
+         }
+     }
++    attrs->ngroups = gc;
+ 
+     tag = ber_peek_tag(ber, &ber_len);
+     DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
+@@ -1567,11 +1574,15 @@ static errno_t process_members(struct sss_domain_info *domain,
+     parent_domain = get_domains_head(domain);
+ 
+     for (c = 0; members[c] != NULL; c++) {
+-        obj_domain = find_domain_by_object_name(parent_domain, members[c]);
++        obj_domain = find_domain_by_object_name_ex(parent_domain, members[c],
++                                                   false, SSS_GND_ALL_DOMAINS);
+         if (obj_domain == NULL) {
+             DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_object_name failed.\n");
+             ret = ENOMEM;
+             goto done;
++        } else if (sss_domain_get_state(obj_domain) == DOM_DISABLED) {
++            /* skip members from disabled domains */
++            continue;
+         }
+ 
+         ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], attrs,
+-- 
+2.20.1
+
diff --git a/SOURCES/0096-sysdb-add-sysdb_subdomain_content_delete.patch b/SOURCES/0096-sysdb-add-sysdb_subdomain_content_delete.patch
new file mode 100644
index 0000000..13916e5
--- /dev/null
+++ b/SOURCES/0096-sysdb-add-sysdb_subdomain_content_delete.patch
@@ -0,0 +1,244 @@
+From a9f03f01b95031f748fdb968ae9c16b9c3d6ed21 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 18 Sep 2019 17:33:55 +0200
+Subject: [PATCH 96/97] sysdb: add sysdb_subdomain_content_delete()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sysdb_subdomain_content_delete() will remove all user and group objects
+from a sub-domain container but not the sub-domain object and the user
+and group container itself.
+
+Related to https://pagure.io/SSSD/sssd/issue/4078
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/db/sysdb.h            |  8 ++++
+ src/db/sysdb_ops.c        | 17 ++++++--
+ src/db/sysdb_subdomains.c | 20 ++++++++-
+ src/tests/sysdb-tests.c   | 88 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 127 insertions(+), 6 deletions(-)
+
+diff --git a/src/db/sysdb.h b/src/db/sysdb.h
+index 0a7e7c4f8..f8a2c87ae 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -557,6 +557,9 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
+ 
+ errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name);
+ 
++errno_t sysdb_subdomain_content_delete(struct sysdb_ctx *sysdb,
++                                       const char *name);
++
+ errno_t sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+                              size_t *range_count,
+                              struct range_info ***range_list);
+@@ -892,6 +895,11 @@ int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
+                            struct ldb_dn *dn,
+                            bool ignore_not_found);
+ 
++int sysdb_delete_recursive_with_filter(struct sysdb_ctx *sysdb,
++                                       struct ldb_dn *dn,
++                                       bool ignore_not_found,
++                                       const char *filter);
++
+ /* Mark entry as expired */
+ errno_t sysdb_mark_entry_as_expired_ldb_dn(struct sss_domain_info *dom,
+                                            struct ldb_dn *ldbdn);
+diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
+index fa3842d8f..262e12380 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -196,9 +196,10 @@ int sysdb_delete_entry(struct sysdb_ctx *sysdb,
+ 
+ /* =Remove-Subentries-From-Sysdb=========================================== */
+ 
+-int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
+-                           struct ldb_dn *dn,
+-                           bool ignore_not_found)
++int sysdb_delete_recursive_with_filter(struct sysdb_ctx *sysdb,
++                                       struct ldb_dn *dn,
++                                       bool ignore_not_found,
++                                       const char *filter)
+ {
+     const char *no_attrs[] = { NULL };
+     struct ldb_message **msgs;
+@@ -219,7 +220,7 @@ int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
+     }
+ 
+     ret = sysdb_search_entry(tmp_ctx, sysdb, dn,
+-                             LDB_SCOPE_SUBTREE, "(distinguishedName=*)",
++                             LDB_SCOPE_SUBTREE, filter,
+                              no_attrs, &msgs_count, &msgs);
+     if (ret) {
+         if (ignore_not_found && ret == ENOENT) {
+@@ -258,6 +259,14 @@ done:
+     return ret;
+ }
+ 
++int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
++                           struct ldb_dn *dn,
++                           bool ignore_not_found)
++{
++    return sysdb_delete_recursive_with_filter(sysdb, dn, ignore_not_found,
++                                              "(distinguishedName=*)");
++}
++
+ 
+ /* =Search-Entry========================================================== */
+ 
+diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
+index af838b44c..0ca6a611f 100644
+--- a/src/db/sysdb_subdomains.c
++++ b/src/db/sysdb_subdomains.c
+@@ -1250,7 +1250,9 @@ done:
+     return ret;
+ }
+ 
+-errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
++static errno_t sysdb_subdomain_delete_with_filter(struct sysdb_ctx *sysdb,
++                                                  const char *name,
++                                                  const char *filter)
+ {
+     TALLOC_CTX *tmp_ctx = NULL;
+     struct ldb_dn *dn;
+@@ -1269,7 +1271,7 @@ errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
+         goto done;
+     }
+ 
+-    ret = sysdb_delete_recursive(sysdb, dn, true);
++    ret = sysdb_delete_recursive_with_filter(sysdb, dn, true, filter);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n");
+         goto done;
+@@ -1280,6 +1282,20 @@ done:
+     return ret;
+ }
+ 
++errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
++{
++    return sysdb_subdomain_delete_with_filter(sysdb, name,
++                                              "(distinguishedName=*)");
++}
++
++errno_t sysdb_subdomain_content_delete(struct sysdb_ctx *sysdb,
++                                       const char *name)
++{
++    const char *filter = "(|("SYSDB_UC")("SYSDB_GC"))";
++
++    return sysdb_subdomain_delete_with_filter(sysdb, name, filter);
++}
++
+ errno_t
+ sysdb_domain_get_domain_resolution_order(TALLOC_CTX *mem_ctx,
+                                          struct sysdb_ctx *sysdb,
+diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
+index 22460d9db..45a278e2a 100644
+--- a/src/tests/sysdb-tests.c
++++ b/src/tests/sysdb-tests.c
+@@ -6204,6 +6204,93 @@ START_TEST(test_sysdb_subdomain_store_user)
+ }
+ END_TEST
+ 
++START_TEST(test_sysdb_subdomain_content_delete)
++{
++    struct sysdb_test_ctx *test_ctx;
++    errno_t ret;
++    struct sss_domain_info *subdomain = NULL;
++    struct ldb_result *results = NULL;
++    struct ldb_dn *base_dn = NULL;
++    struct ldb_dn *check_dn = NULL;
++    struct ldb_dn *check_dom_dn = NULL;
++    struct test_data *data;
++    char *alias;
++
++    ret = setup_sysdb_tests(&test_ctx);
++    fail_if(ret != EOK, "Could not set up the test");
++
++    subdomain = new_subdomain(test_ctx, test_ctx->domain,
++                              testdom[0], testdom[1], testdom[2], testdom[3],
++                              MPG_DISABLED, false, NULL, NULL, 0, NULL, true);
++    fail_unless(subdomain != NULL, "Failed to create new subdomain.");
++    ret = sysdb_subdomain_store(test_ctx->sysdb,
++                                testdom[0], testdom[1], testdom[2], testdom[3],
++                                false, false, NULL, 0, NULL);
++    fail_if(ret != EOK, "Could not set up the test (test subdom)");
++
++    ret = sysdb_update_subdomains(test_ctx->domain, NULL);
++    fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
++                            ret, strerror(ret));
++
++    data = test_data_new_user(test_ctx, 12345);
++    fail_if(data == NULL);
++    data->username = test_asprintf_fqname(data, subdomain, "SubDomUser");
++
++    alias = test_asprintf_fqname(data, subdomain, "subdomuser");
++    fail_if(alias == NULL);
++
++    ret = sysdb_attrs_add_string(data->attrs, SYSDB_NAME_ALIAS, alias);
++    fail_unless(ret == EOK, "sysdb_store_user failed.");
++
++    ret = sysdb_store_user(subdomain, data->username,
++                           NULL, data->uid, 0, "Sub Domain User",
++                           "/home/subdomuser", "/bin/bash",
++                           NULL, data->attrs, NULL, -1, 0);
++    fail_unless(ret == EOK, "sysdb_store_user failed.");
++
++    base_dn =ldb_dn_new(test_ctx, test_ctx->sysdb->ldb, "cn=sysdb");
++    fail_unless(base_dn != NULL);
++
++    check_dn = sysdb_user_dn(data, subdomain, data->username);
++    fail_unless(check_dn != NULL);
++
++    ret = ldb_search(test_ctx->sysdb->ldb, test_ctx, &results, base_dn,
++                     LDB_SCOPE_SUBTREE, NULL, "name=%s", data->username);
++    fail_unless(ret == EOK, "ldb_search failed.");
++    fail_unless(results->count == 1, "Unexpected number of results, "
++                                     "expected [%d], got [%d]",
++                                     1, results->count);
++    fail_unless(ldb_dn_compare(results->msgs[0]->dn, check_dn) == 0,
++                "Unexpected DN returned");
++
++    ret = sysdb_subdomain_content_delete(test_ctx->sysdb, testdom[0]);
++    fail_unless(ret == EOK, "sysdb_subdomain_content_delete failed.");
++
++    /* Check if user is removed */
++    ret = ldb_search(test_ctx->sysdb->ldb, test_ctx, &results, base_dn,
++                     LDB_SCOPE_SUBTREE, NULL, "name=%s", alias);
++    fail_unless(ret == EOK, "ldb_search failed.");
++    fail_unless(results->count == 0, "Unexpected number of results, "
++                                     "expected [%d], got [%d]",
++                                     0, results->count);
++
++    check_dom_dn = ldb_dn_new_fmt(test_ctx, test_ctx->sysdb->ldb,
++                                  SYSDB_DOM_BASE, testdom[0]);
++    fail_unless(check_dom_dn != NULL, "ldb_dn_new_fmt failed.");
++
++    /* Check if domain object is still present */
++    ret = ldb_search(test_ctx->sysdb->ldb, test_ctx, &results, base_dn,
++                     LDB_SCOPE_SUBTREE, NULL, "cn=%s", testdom[0]);
++    fail_unless(ret == EOK, "ldb_search failed.");
++    fail_unless(results->count == 1, "Unexpected number of results, "
++                                     "expected [%d], got [%d]",
++                                     1, results->count);
++    fail_unless(ldb_dn_compare(results->msgs[0]->dn, check_dom_dn) == 0,
++                "Unexpected DN returned");
++
++}
++END_TEST
++
+ START_TEST(test_sysdb_subdomain_user_ops)
+ {
+     struct sysdb_test_ctx *test_ctx;
+@@ -7574,6 +7661,7 @@ Suite *create_sysdb_suite(void)
+     TCase *tc_subdomain = tcase_create("SYSDB sub-domain Tests");
+ 
+     tcase_add_test(tc_subdomain, test_sysdb_subdomain_store_user);
++    tcase_add_test(tc_subdomain, test_sysdb_subdomain_content_delete);
+     tcase_add_test(tc_subdomain, test_sysdb_subdomain_user_ops);
+     tcase_add_test(tc_subdomain, test_sysdb_subdomain_group_ops);
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0097-ipa-delete-content-of-disabled-domains.patch b/SOURCES/0097-ipa-delete-content-of-disabled-domains.patch
new file mode 100644
index 0000000..9d55de0
--- /dev/null
+++ b/SOURCES/0097-ipa-delete-content-of-disabled-domains.patch
@@ -0,0 +1,36 @@
+From 124957a91db25736ce8ea82852db65d8fa243e58 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 18 Sep 2019 18:09:23 +0200
+Subject: [PATCH 97/97] ipa: delete content of disabled domains
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related to https://pagure.io/SSSD/sssd/issue/4078
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ipa/ipa_subdomains.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 2ffc6bf7a..b9ce25063 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -821,6 +821,13 @@ static errno_t ipa_subdomains_check_domain_state(struct sss_domain_info *dom,
+                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_domain_set_enabled failed.\n");
+                 return ret;
+             }
++
++            ret = sysdb_subdomain_content_delete(dom->sysdb, dom->name);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "sysdb_subdomain_content_delete failed.\n");
++                return ret;
++            }
+         }
+     } else {
+         /* enabled domain if it was disabled */
+-- 
+2.20.1
+
diff --git a/SOURCES/0098-ipa-use-LDAP-not-extdom-to-lookup-IPA-users-and-grou.patch b/SOURCES/0098-ipa-use-LDAP-not-extdom-to-lookup-IPA-users-and-grou.patch
new file mode 100644
index 0000000..82785bf
--- /dev/null
+++ b/SOURCES/0098-ipa-use-LDAP-not-extdom-to-lookup-IPA-users-and-grou.patch
@@ -0,0 +1,179 @@
+From fbd38903a3c4985e560e6c670ead84597982242e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 19 Jun 2019 11:40:56 +0200
+Subject: [PATCH] ipa: use LDAP not extdom to lookup IPA users and groups
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Currently when an IPA client is resolving trusted users and groups with
+the help of the extdom plugin it uses the extdom plugin as well to
+lookup IPA objects. This might cause issues if e.g. there is a user in
+IPA with the same name as a group in AD or the other way round.
+
+To solve this and to lower the load on the extdom plugin on the IPA
+server side this patch will lookup IPA object directly from LDAP on the
+IPA server.
+
+Related to https://pagure.io/SSSD/sssd/issue/4073
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 27b141f38dd04d4b69e609a4cc64676a0716226e)
+---
+ src/providers/ipa/ipa_id.c       | 11 +-----
+ src/providers/ipa/ipa_id.h       |  5 +++
+ src/providers/ipa/ipa_s2n_exop.c | 67 ++++++++++++++++++++++++++++++++
+ 3 files changed, 74 insertions(+), 9 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
+index f34692aa2..94d5f9d90 100644
+--- a/src/providers/ipa/ipa_id.c
++++ b/src/providers/ipa/ipa_id.c
+@@ -30,13 +30,6 @@
+ #include "providers/ldap/sdap_async.h"
+ #include "providers/ipa/ipa_id.h"
+ 
+-static struct tevent_req *
+-ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+-                             struct ipa_id_ctx *ipa_ctx,
+-                             struct dp_id_data *ar);
+-
+-static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error);
+-
+ static bool is_object_overridable(struct dp_id_data *ar)
+ {
+     bool ret = false;
+@@ -516,7 +509,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq);
+ static void ipa_id_get_account_info_done(struct tevent_req *subreq);
+ static void ipa_id_get_user_list_done(struct tevent_req *subreq);
+ 
+-static struct tevent_req *
++struct tevent_req *
+ ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+                              struct ipa_id_ctx *ipa_ctx,
+                              struct dp_id_data *ar)
+@@ -1120,7 +1113,7 @@ fail:
+     return;
+ }
+ 
+-static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error)
++int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error)
+ {
+     struct ipa_id_get_account_info_state *state = tevent_req_data(req,
+                                           struct ipa_id_get_account_info_state);
+diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
+index fe9acfeef..c18e709b8 100644
+--- a/src/providers/ipa/ipa_id.h
++++ b/src/providers/ipa/ipa_id.h
+@@ -151,4 +151,9 @@ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+                            struct ldb_message_element *users);
+ int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error);
+ 
++struct tevent_req *
++ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
++                             struct ipa_id_ctx *ipa_ctx,
++                             struct dp_id_data *ar);
++int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error);
+ #endif
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index a07f73200..598b1568e 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -1121,6 +1121,7 @@ struct ipa_s2n_get_list_state {
+ static errno_t ipa_s2n_get_list_step(struct tevent_req *req);
+ static void ipa_s2n_get_list_get_override_done(struct tevent_req *subreq);
+ static void ipa_s2n_get_list_next(struct tevent_req *subreq);
++static void ipa_s2n_get_list_ipa_next(struct tevent_req *subreq);
+ static errno_t ipa_s2n_get_list_save_step(struct tevent_req *req);
+ 
+ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx,
+@@ -1195,6 +1196,7 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req)
+     uint32_t id;
+     char *endptr;
+     bool need_v1 = false;
++    struct dp_id_data *ar;
+ 
+     parent_domain = get_domains_head(state->dom);
+     switch (state->req_input.type) {
+@@ -1222,6 +1224,35 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req)
+ 
+         state->req_input.inp.name = short_name;
+ 
++        if (strcmp(state->obj_domain->name,
++            state->ipa_ctx->sdap_id_ctx->be->domain->name) == 0) {
++            DEBUG(SSSDBG_TRACE_INTERNAL,
++                  "Looking up IPA object [%s] from LDAP.\n",
++                  state->list[state->list_idx]);
++            ret = get_dp_id_data_for_user_name(state,
++                                               state->list[state->list_idx],
++                                               state->obj_domain->name,
++                                               &ar);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "Failed to create lookup date for IPA object [%s].\n",
++                      state->list[state->list_idx]);
++                return ret;
++            }
++            ar->entry_type = state->entry_type;
++
++            subreq = ipa_id_get_account_info_send(state, state->ev,
++                                                  state->ipa_ctx, ar);
++            if (subreq == NULL) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "ipa_id_get_account_info_send failed.\n");
++                return ENOMEM;
++            }
++            tevent_req_set_callback(subreq, ipa_s2n_get_list_ipa_next, req);
++
++            return EOK;
++        }
++
+         break;
+     case REQ_INP_ID:
+         errno = 0;
+@@ -1363,6 +1394,42 @@ fail:
+     return;
+ }
+ 
++static void ipa_s2n_get_list_ipa_next(struct tevent_req *subreq)
++{
++    int ret;
++    int dp_error;
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                      struct tevent_req);
++    struct ipa_s2n_get_list_state *state = tevent_req_data(req,
++                                               struct ipa_s2n_get_list_state);
++
++    ret = ipa_id_get_account_info_recv(subreq, &dp_error);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_id_get_account_info failed: %d %d\n", ret,
++                                 dp_error);
++        goto done;
++    }
++
++    state->list_idx++;
++    if (state->list[state->list_idx] == NULL) {
++        tevent_req_done(req);
++        return;
++    }
++
++    ret = ipa_s2n_get_list_step(req);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_step failed.\n");
++        goto done;
++    }
++
++    return;
++
++done:
++    tevent_req_error(req,ret);
++    return;
++}
++
+ static void ipa_s2n_get_list_get_override_done(struct tevent_req *subreq)
+ {
+     int ret;
+-- 
+2.20.1
+
diff --git a/SOURCES/0099-providers-ipa-add_v1_user_data-amended.patch b/SOURCES/0099-providers-ipa-add_v1_user_data-amended.patch
new file mode 100644
index 0000000..fca0517
--- /dev/null
+++ b/SOURCES/0099-providers-ipa-add_v1_user_data-amended.patch
@@ -0,0 +1,68 @@
+From e294f7351b810ea9180b2e9e0cab47beab18ae25 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Fri, 20 Sep 2019 15:51:38 +0200
+Subject: [PATCH] providers/ipa/: add_v1_user_data() amended
+
+Fixes few mistypes and compilation warning:
+```
+sssd-2.2.3/src/providers/ipa/ipa_s2n_exop.c:665:20: warning: 'gc' may be used uninitialized in this function [-Wmaybe-uninitialized]
+     attrs->ngroups = gc;
+     ~~~~~~~~~~~~~~~^~~~
+```
+
+Related to https://pagure.io/SSSD/sssd/issue/4078
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 39e16cca441d4a6b3affe8f27372c26ed11ac81f)
+---
+ src/providers/ipa/ipa_s2n_exop.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index f1d5768ae..a07f73200 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -620,7 +620,8 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
+     if (attrs->ngroups > 0) {
+         attrs->groups = talloc_zero_array(attrs, char *, attrs->ngroups + 1);
+         if (attrs->groups == NULL) {
+-            DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
++            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
++            attrs->ngroups = 0;
+             ret = ENOMEM;
+             goto done;
+         }
+@@ -639,8 +640,10 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
+             if (domain != NULL) {
+                 obj_domain = find_domain_by_name_ex(parent_domain, domain, true, SSS_GND_ALL_DOMAINS);
+                 if (obj_domain == NULL) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
+-                    return ENOMEM;
++                    DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name_ex failed.\n");
++                    attrs->ngroups = gc;
++                    ret = ENOMEM;
++                    goto done;
+                 } else if (sss_domain_get_state(obj_domain) == DOM_DISABLED) {
+                     /* skipping objects from disabled domains */
+                     DEBUG(SSSDBG_TRACE_ALL,
+@@ -655,14 +658,15 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
+             attrs->groups[gc] = sss_create_internal_fqname(attrs->groups,
+                                                            name, obj_domain->name);
+             if (attrs->groups[gc] == NULL) {
+-                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
++                DEBUG(SSSDBG_OP_FAILURE, "sss_create_internal_fqname failed.\n");
++                attrs->ngroups = gc;
+                 ret = ENOMEM;
+                 goto done;
+             }
+             gc++;
+         }
++        attrs->ngroups = gc;
+     }
+-    attrs->ngroups = gc;
+ 
+     tag = ber_peek_tag(ber, &ber_len);
+     DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
+-- 
+2.20.1
+
diff --git a/SOURCES/0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec b/SOURCES/0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
new file mode 100644
index 0000000..f24afe3
--- /dev/null
+++ b/SOURCES/0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
@@ -0,0 +1,26 @@
+From 8d38a4b28ab7af15406b244910f369ba1aff02db Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 30 Oct 2014 15:59:17 +0100
+Subject: [PATCH 93/93] NOUPSTREAM: Default to root if sssd user is not
+ specified
+
+---
+ src/monitor/monitor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 0dea327213a1ad04b6f69c0ffb0fb87254420796..20b4aef4ee94fd42de1585d7d7c2e01ea01845ac 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -925,7 +925,7 @@ static int get_service_user(struct mt_ctx *ctx)
+ 
+     ret = confdb_get_string(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
+                             CONFDB_MONITOR_USER_RUNAS,
+-                            SSSD_USER, &user_str);
++                            "root", &user_str);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get the user to run as\n");
+         return ret;
+-- 
+1.9.3
+
diff --git a/SOURCES/1000-DOWNSTREAM-Use-OpenSSL-for-the-obfuscation-code.patch b/SOURCES/1000-DOWNSTREAM-Use-OpenSSL-for-the-obfuscation-code.patch
new file mode 100644
index 0000000..8580651
--- /dev/null
+++ b/SOURCES/1000-DOWNSTREAM-Use-OpenSSL-for-the-obfuscation-code.patch
@@ -0,0 +1,69 @@
+From 8232c1005e56393422b0b1e6018e308ebc4fb4c1 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 11 Apr 2019 22:39:03 +0200
+Subject: [PATCH] DOWNSTREAM: Use OpenSSL for the obfuscation code
+
+---
+ Makefile.am                         | 6 ++++++
+ configure.ac                        | 7 +++++++
+ src/util/crypto/nss/nss_obfuscate.c | 5 +++++
+ 3 files changed, 18 insertions(+)
+
+diff --git a/Makefile.am b/Makefile.am
+index 0c24ae664..8b1f4f144 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -954,6 +954,12 @@ else
+         $(NULL)
+ endif
+ 
++if OBF_WITH_LIBCRYPTO
++SSS_CRYPT_SOURCES += src/util/crypto/libcrypto/crypto_obfuscate.c
++SSS_CRYPT_CFLAGS += $(CRYPTO_CFLAGS)
++SSS_CRYPT_LIBS += $(CRYPTO_LIBS)
++endif
++
+ libsss_crypt_la_SOURCES = \
+     $(SSS_CRYPT_SOURCES)
+ libsss_crypt_la_CFLAGS = \
+diff --git a/configure.ac b/configure.ac
+index 9df463d9c..c3b349af4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -391,6 +391,13 @@ if test x$cryptolib = xnss; then
+     AM_CHECK_NSS
+ fi
+ 
++dnl RHEL-specific: We always check for libcrypto because the obfuscation
++dnl feature is only implemented with OpenSSL as the NSS version doesn't
++dnl run in FIPS mode
++AM_CHECK_LIBCRYPTO
++AM_CONDITIONAL([OBF_WITH_LIBCRYPTO], [test x == x])
++AC_DEFINE_UNQUOTED(OBF_WITH_LIBCRYPTO, 1, [Build the obfuscation feature with libcrypt crypto back end])
++
+ if test x$cryptolib = xlibcrypto; then
+     AM_CHECK_LIBCRYPTO
+     m4_include([src/external/p11-kit.m4])
+diff --git a/src/util/crypto/nss/nss_obfuscate.c b/src/util/crypto/nss/nss_obfuscate.c
+index df9c41b3a..bf2a5f418 100644
+--- a/src/util/crypto/nss/nss_obfuscate.c
++++ b/src/util/crypto/nss/nss_obfuscate.c
+@@ -31,6 +31,9 @@
+  */
+ 
+ #include "config.h"
++
++#ifndef OBF_WITH_LIBCRYPTO
++
+ #include <prerror.h>
+ #include <pk11func.h>
+ 
+@@ -326,3 +329,5 @@ done:
+     talloc_free(tmp_ctx);
+     return ret;
+ }
++
++#endif /* OBF_WITH_LIBCRYPTO */
+-- 
+2.19.2
+
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
new file mode 100644
index 0000000..4e9c836
--- /dev/null
+++ b/SPECS/sssd.spec
@@ -0,0 +1,4114 @@
+%global rhel7_minor %(%{__grep} -o "7.[0-9]*" /etc/redhat-release |%{__sed} -s 's/7.//')
+
+# we don't want to provide private python extension libs
+%define __provides_exclude_from %{python_sitearch}/.*\.so$|%{_libdir}/%{name}/modules/libwbclient.so.*$
+%define _hardened_build 1
+
+    %global install_pcscd_polkit_rule 1
+
+# Determine the location of the LDB modules directory
+%global ldb_modulesdir %(pkg-config --variable=modulesdir ldb)
+%global ldb_version 1.2.2
+
+
+%if (0%{?fedora} || 0%{?rhel} >= 7)
+    %global with_cifs_utils_plugin 1
+%else
+    %global with_cifs_utils_plugin_option --disable-cifs-idmap-plugin
+%endif
+
+    %global with_krb5_localauth_plugin 1
+
+%global libwbc_alternatives_version 0.14
+%global libwbc_lib_version %{libwbc_alternatives_version}.0
+%global libwbc_alternatives_suffix %nil
+%if 0%{?__isa_bits} == 64
+%global libwbc_alternatives_suffix -64
+%endif
+
+%global enable_systemtap 1
+%if (0%{?enable_systemtap} == 1)
+    %global enable_systemtap_opt --enable-systemtap
+%endif
+
+%if (0%{?fedora} >= 23 || 0%{?rhel} >= 7)
+    %global with_kcm 1
+    %global with_kcm_option --with-kcm
+%else
+    %global with_kcm_option --without-kcm
+%endif
+
+# Do not try to detect the idmap version on RHEL6 to avoid conflicts between
+# samba and samba4 package
+%if (0%{?fedora} || 0%{?rhel} >= 7)
+    %global detect_idmap_version 1
+%else
+    %global with_idmap_version --with-smb-idmap-interface-version=5
+%endif
+
+Name: sssd
+Version: 1.16.4
+Release: 32%{?dist}
+Group: Applications/System
+Summary: System Security Services Daemon
+License: GPLv3+
+URL: https://pagure.io/SSSD/sssd/
+Source0: https://releases.pagure.org/SSSD/sssd/sssd-%{version}.tar.gz
+BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
+
+### Patches ###
+Patch0001: 0001-Providers-Delay-online-check-on-startup.patch
+Patch0002: 0002-KCM-Fall-back-to-using-the-first-ccache-if-the-defau.patch
+Patch0003: 0003-GPO-Add-option-ad_gpo_ignore_unreadable.patch
+Patch0004: 0004-AD-Allow-configuring-auto_private_groups-per-subdoma.patch
+Patch0005: 0005-ipa-store-sudo-runas-attribute-with-internal-fqname.patch
+Patch0006: 0006-sudo-format-runas-attributes-to-correct-output-name.patch
+Patch0007: 0007-SYSDB-Inherit-cached_auth_timeout-from-the-main-doma.patch
+Patch0008: 0008-krb5-Do-not-use-unindexed-objectCategory-in-a-search.patch
+Patch0009: 0009-SYSDB-Index-the-ccacheFile-attribute.patch
+Patch0010: 0010-krb5-Silence-an-error-message-if-no-cache-entries-ha.patch
+Patch0011: 0011-Util-added-facility-to-load-nss-lib-syms.patch
+Patch0012: 0012-responder-negcache-avoid-calling-nsswitch-NSS-API.patch
+Patch0013: 0013-negcache_files-got-rid-of-large-array-on-stack.patch
+Patch0014: 0014-TESTS-moved-cwrap-test_negcache-to-cmocka-tests.patch
+Patch0015: 0015-ci-sssd.supp-getpwuid-leak-suppression.patch
+Patch0016: 0016-pam-introduce-prompt_config-struct.patch
+Patch0017: 0017-authtok-add-dedicated-type-for-2fa-with-single-strin.patch
+Patch0018: 0018-pam_sss-use-configured-prompting.patch
+Patch0019: 0019-PAM-add-initial-prompting-configuration.patch
+Patch0020: 0020-getsockopt_wrapper-add-support-for-PAM-clients.patch
+Patch0021: 0021-intg-add-test-for-password-prompt-configuration.patch
+Patch0022: 0022-krb5-Write-multiple-dnsnames-into-kdc-info-file.patch
+Patch0023: 0023-krb5-Lookahead-resolving-of-host-names.patch
+Patch0024: 0024-SDAP-Add-sdap_has_deref_support_ex.patch
+Patch0025: 0025-IPA-Use-dereference-for-host-groups-even-if-the-conf.patch
+Patch0026: 0026-PAM-Also-cache-SSS_PAM_PREAUTH.patch
+Patch0027: 0027-winbind-idmap-plugin-update-struct-idmap_domain-to-l.patch
+Patch0028: 0028-DP-add-NULL-check-to-be_ptask_-enable-disable.patch
+Patch0029: 0029-LDAP-Return-the-error-message-from-the-extended-oper.patch
+Patch0030: 0030-SDAP-allow-GSS-SPNEGO-for-LDAP-SASL-bind-as-well.patch
+Patch0031: 0031-sdap-inherit-SDAP_SASL_MECH-if-not-set-explicitly.patch
+Patch0032: 0032-Translation-Update-japanese-translation.patch
+Patch0033: 0033-Translation-Add-missing-newlines-in-the-ja-po-file.patch
+Patch0034: 0034-TESTS-Add-a-unit-test-for-UPNs-stored-by-sss_ncache_.patch
+Patch0035: 0035-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch
+Patch0036: 0036-CACHE-SSSD-doesn-t-clear-cache-entries.patch
+Patch0037: 0037-IPA-Allow-paging-when-fetching-external-groups.patch
+Patch0038: 0038-ad-remove-subdomain-that-has-been-disabled-through-a.patch
+Patch0039: 0039-sysdb-add-sysdb_domain_set_enabled.patch
+Patch0040: 0040-ad-set-enabled-false-attribute-for-subdomains-that-n.patch
+Patch0041: 0041-sysdb-read-and-interpret-domain-s-enabled-attribute.patch
+Patch0042: 0042-sysdb-add-sysdb_list_subdomains.patch
+Patch0043: 0043-ad-remove-all-subdomains-if-only-master-domain-is-en.patch
+Patch0044: 0044-ad-make-ad_enabled_domains-case-insensitive.patch
+Patch0045: 0045-SYSDB-Add-sysdb_search_with_ts_attr.patch
+Patch0046: 0046-BE-search-with-sysdb_search_with_ts_attr.patch
+Patch0047: 0047-BE-Enable-refresh-for-multiple-domains.patch
+Patch0048: 0048-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch
+Patch0049: 0049-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch
+Patch0050: 0050-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch
+Patch0051: 0051-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch
+Patch0052: 0052-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch
+Patch0053: 0053-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch
+Patch0054: 0054-BE-Send-refresh-requests-in-batches.patch
+Patch0055: 0055-BE-Extend-be_ptask_create-with-control-when-to-sched.patch
+Patch0056: 0056-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch
+Patch0057: 0057-AD-Implement-background-refresh-for-AD-domains.patch
+Patch0058: 0058-IPA-Implement-background-refresh-for-IPA-domains.patch
+Patch0059: 0059-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch
+Patch0060: 0060-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch
+Patch0061: 0061-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch
+Patch0062: 0062-MAN-Amend-the-documentation-for-the-background-refre.patch
+Patch0063: 0063-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch
+Patch0064: 0064-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch
+Patch0065: 0065-sss_ptr_hash-add-sss_ptr_get_value-to-make-it-useful.patch
+Patch0066: 0066-sss_ptr_hash-keep-value-pointer-when-destroying-spy.patch
+Patch0067: 0067-autofs-fix-typo-in-test-tool.patch
+Patch0068: 0068-sysdb-add-expiration-time-to-autofs-entries.patch
+Patch0069: 0069-sysdb-add-sysdb_get_autofsentry.patch
+Patch0070: 0070-sysdb-add-enumerationExpireTimestamp.patch
+Patch0071: 0071-sysdb-store-enumeration-expiration-time-in-autofs-ma.patch
+Patch0072: 0072-sysdb-store-original-dn-in-autofs-map.patch
+Patch0073: 0073-sysdb-add-sysdb_del_autofsentry_by_key.patch
+Patch0074: 0074-autofs-move-data-provider-functions-to-responder-com.patch
+Patch0075: 0075-cache_req-add-autofs-map-entries-plugin.patch
+Patch0076: 0076-cache_req-add-autofs-map-by-name-plugin.patch
+Patch0077: 0077-cache_req-add-autofs-entry-by-name-plugin.patch
+Patch0078: 0078-autofs-convert-code-to-cache_req.patch
+Patch0079: 0079-autofs-use-cache_req-to-obtain-single-entry-in-geten.patch
+Patch0080: 0080-autofs-use-cache_req-to-obtain-map-in-setent.patch
+Patch0081: 0081-dp-replace-autofs-handler-with-enumerate-method.patch
+Patch0082: 0082-dp-add-additional-autofs-methods.patch
+Patch0083: 0083-ldap-add-base_dn-to-sdap_search_bases.patch
+Patch0084: 0084-ldap-rename-sdap_autofs_get_map-to-sdap_autofs_enume.patch
+Patch0085: 0085-ldap-implement-autofs-get-map.patch
+Patch0086: 0086-ldap-implement-autofs-get-entry.patch
+Patch0087: 0087-autofs-allow-to-run-only-setent-without-enumeration-.patch
+Patch0088: 0088-autofs-always-refresh-auto.master.patch
+Patch0089: 0089-sysdb-invalidate-also-autofs-entries.patch
+Patch0090: 0090-sss_cache-invalidate-also-autofs-entries.patch
+Patch0091: 0091-CONFDB-Files-domain-if-activated-without-.conf.patch
+Patch0092: 0092-TESTS-adapt-tests-to-enabled-default-files-domain.patch
+PAtch0093: 0093-utils-extend-some-find_domain_-calls-to-search-disab.patch
+Patch0094: 0094-ipa-support-disabled-domains.patch
+Patch0095: 0095-ipa-ignore-objects-from-disabled-domains-on-the-clie.patch
+Patch0096: 0096-sysdb-add-sysdb_subdomain_content_delete.patch
+Patch0097: 0097-ipa-delete-content-of-disabled-domains.patch
+Patch0098: 0098-ipa-use-LDAP-not-extdom-to-lookup-IPA-users-and-grou.patch
+Patch0099: 0099-providers-ipa-add_v1_user_data-amended.patch
+
+#This patch should not be removed in RHEL-7
+Patch999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
+Patch1000: 1000-DOWNSTREAM-Use-OpenSSL-for-the-obfuscation-code.patch
+
+### Dependencies ###
+
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-ldap = %{version}-%{release}
+Requires: sssd-krb5 = %{version}-%{release}
+Requires: sssd-ipa = %{version}-%{release}
+Requires: sssd-ad = %{version}-%{release}
+Requires: sssd-proxy = %{version}-%{release}
+Requires: python-sssdconfig = %{version}-%{release}
+
+%global servicename sssd
+%global sssdstatedir %{_localstatedir}/lib/sss
+%global dbpath %{sssdstatedir}/db
+%global keytabdir %{sssdstatedir}/keytabs
+%global pipepath %{sssdstatedir}/pipes
+%global mcpath %{sssdstatedir}/mc
+%global pubconfpath %{sssdstatedir}/pubconf
+%global gpocachepath %{sssdstatedir}/gpo_cache
+%global secdbpath %{sssdstatedir}/secrets
+%global deskprofilepath %{sssdstatedir}/deskprofile
+
+### Build Dependencies ###
+
+BuildRequires: autoconf
+BuildRequires: automake
+BuildRequires: libtool
+BuildRequires: m4
+BuildRequires: gcc
+BuildRequires: popt-devel
+BuildRequires: libtalloc-devel
+BuildRequires: libtevent-devel
+BuildRequires: libtdb-devel
+
+# Needed since this downstream only fix: rhbz#1524566
+BuildRequires: openssl-devel
+
+# LDB needs a strict version match to build
+BuildRequires: libldb-devel >= %{ldb_version}
+BuildRequires: libdhash-devel >= 0.4.2
+BuildRequires: libcollection-devel
+BuildRequires: libini_config-devel >= 1.3.0
+BuildRequires: dbus-devel
+BuildRequires: dbus-libs
+BuildRequires: openldap-devel
+BuildRequires: pam-devel
+BuildRequires: nss-devel
+BuildRequires: nspr-devel
+BuildRequires: pcre-devel
+BuildRequires: libxslt
+BuildRequires: libxml2
+BuildRequires: docbook-style-xsl
+BuildRequires: krb5-devel >= 1.12
+BuildRequires: c-ares-devel
+BuildRequires: python-devel
+BuildRequires: check-devel
+BuildRequires: doxygen
+BuildRequires: libselinux-devel
+BuildRequires: libsemanage-devel
+BuildRequires: bind-utils
+BuildRequires: keyutils-libs-devel
+BuildRequires: gettext-devel
+BuildRequires: pkgconfig
+BuildRequires: diffstat
+BuildRequires: findutils
+BuildRequires: glib2-devel
+BuildRequires: selinux-policy-targeted
+BuildRequires: libnl3-devel
+BuildRequires: systemd-devel
+%if (0%{?with_cifs_utils_plugin} == 1)
+BuildRequires: cifs-utils-devel
+%endif
+BuildRequires: libnfsidmap-devel
+BuildRequires: samba4-devel >= 4.0.0-59beta2
+%if (0%{?detect_idmap_version} == 1)
+BuildRequires: samba-winbind
+%endif
+BuildRequires: libsmbclient-devel
+BuildRequires: systemtap-sdt-devel
+BuildRequires: jansson-devel
+BuildRequires: http-parser-devel
+BuildRequires: curl-devel
+BuildRequires: libuuid-devel
+BuildRequires: pkgconfig(gdm-pam-extensions)
+
+%description
+Provides a set of daemons to manage access to remote directories and
+authentication mechanisms. It provides an NSS and PAM interface toward
+the system and a pluggable backend system to connect to multiple different
+account sources. It is also the basis to provide client auditing and policy
+services for projects like FreeIPA.
+
+The sssd subpackage is a meta-package that contains the deamon as well as all
+the existing back ends.
+
+%package common
+Summary: Common files for the SSSD
+Group: Applications/System
+License: GPLv3+
+# Conflicts
+Conflicts: selinux-policy < 3.10.0-46
+Conflicts: sssd < 1.10.0-8%{?dist}.beta2
+# Requires
+Requires: sssd-client%{?_isa} = %{version}-%{release}
+Requires: libsss_idmap%{?_isa} = %{version}-%{release}
+Requires: libsss_sudo%{?_isa}  = %{version}-%{release}
+Requires: libsss_autofs%{?_isa} = %{version}-%{release}
+Requires(post): systemd-units chkconfig
+Requires(preun): systemd-units chkconfig
+Requires(postun): systemd-units chkconfig
+# sssd-common owns sssd.service file and is restarted in posttrans
+# libwbclient alternative might break restarting sssd
+# gpo_child -> libsmbclient -> samba-client-libs -> libwbclient
+OrderWithRequires: libwbclient
+OrderWithRequires: sssd-libwbclient
+# Explicitly require RHEL-7.6 versions of the Samba libraries
+# in order to prevent untested combinations of a new SSSD and
+# older libraries. See e.g. rhbz#1593756
+Requires: libtalloc >= 2.1.13-1
+Requires: libtevent >= 0.9.36-1
+Requires: libldb >= 1.3.4-1
+Requires: libtdb >= 1.3.15-1
+
+### Provides ###
+Provides: libsss_sudo-devel = %{version}-%{release}
+Obsoletes: libsss_sudo-devel <= 1.10.0-7%{?dist}.beta1
+
+%description common
+Common files for the SSSD. The common package includes all the files needed
+to run a particular back end, however, the back ends are packaged in separate
+subpackages such as sssd-ldap.
+
+%package client
+Summary: SSSD Client libraries for NSS and PAM
+Group: Applications/System
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Requires(post):  /usr/sbin/alternatives
+Requires(preun): /usr/sbin/alternatives
+
+%description client
+Provides the libraries needed by the PAM and NSS stacks to connect to the SSSD
+service.
+
+%package -n libsss_sudo
+Summary: A library to allow communication between SUDO and SSSD
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_sudo
+A utility library to allow communication between SUDO and SSSD
+
+%package -n libsss_autofs
+Summary: A library to allow communication between Autofs and SSSD
+Group: Development/Libraries
+License: LGPLv3+
+
+%description -n libsss_autofs
+A utility library to allow communication between Autofs and SSSD
+
+%package tools
+Summary: Userspace tools for use with the SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+Requires: python-sss = %{version}-%{release}
+Requires: python-sssdconfig = %{version}-%{release}
+
+%description tools
+Provides userspace tools for manipulating users, groups, and nested groups in
+SSSD when using id_provider = local in /etc/sssd/sssd.conf.
+
+Also provides several other administrative tools:
+    * sss_debuglevel to change the debug level on the fly
+    * sss_seed which pre-creates a user entry for use in kickstarts
+    * sss_obfuscate for generating an obfuscated LDAP password
+    * sssctl -- an sssd status and control utility
+
+%package -n python-sssdconfig
+Summary: SSSD and IPA configuration file manipulation classes and functions
+Group: Applications/System
+License: GPLv3+
+BuildArch: noarch
+
+%description -n python-sssdconfig
+Provides python2 files for manipulation SSSD and IPA configuration files.
+
+%package -n python-sss
+Summary: Python2 bindings for sssd
+Group: Development/Libraries
+License: LGPLv3+
+Requires: sssd-common = %{version}-%{release}
+
+%description -n python-sss
+Provides python2 module for manipulating users, groups, and nested groups in
+SSSD when using id_provider = local in /etc/sssd/sssd.conf.
+
+Also provides several other useful python2 bindings:
+    * function for retrieving list of groups user belongs to.
+    * class for obfuscation of passwords
+
+%package -n python-sss-murmur
+Summary: Python2 bindings for murmur hash function
+Group: Development/Libraries
+License: LGPLv3+
+
+%description -n python-sss-murmur
+Provides python2 module for calculating the murmur hash version 3
+
+%package ldap
+Summary: The LDAP back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+
+%description ldap
+Provides the LDAP back end that the SSSD can utilize to fetch identity data
+from and authenticate against an LDAP server.
+
+%package krb5-common
+Summary: SSSD helpers needed for Kerberos and GSSAPI authentication
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: cyrus-sasl-gssapi%{?_isa}
+Requires: sssd-common = %{version}-%{release}
+
+%description krb5-common
+Provides helper processes that the LDAP and Kerberos back ends can use for
+Kerberos user or host authentication.
+
+%package krb5
+Summary: The Kerberos authentication back end for the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+
+%description krb5
+Provides the Kerberos back end that the SSSD can utilize authenticate
+against a Kerberos server.
+
+%package common-pac
+Summary: Common files needed for supporting PAC processing
+Group: Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+
+%description common-pac
+Provides common files needed by SSSD providers such as IPA and Active Directory
+for handling Kerberos PACs.
+
+%package ipa
+Summary: The IPA back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+Requires: libipa_hbac%{?_isa} = %{version}-%{release}
+Requires: bind-utils
+Requires: sssd-common-pac = %{version}-%{release}
+Requires(pre): shadow-utils
+
+%description ipa
+Provides the IPA back end that the SSSD can utilize to fetch identity data
+from and authenticate against an IPA server.
+
+%package ad
+Summary: The AD back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+Requires: bind-utils
+Requires: sssd-common-pac = %{version}-%{release}
+
+%description ad
+Provides the Active Directory back end that the SSSD can utilize to fetch
+identity data from and authenticate against an Active Directory server.
+
+%package proxy
+Summary: The proxy back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+
+%description proxy
+Provides the proxy back end which can be used to wrap an existing NSS and/or
+PAM modules to leverage SSSD caching.
+
+%package -n libsss_idmap
+Summary: FreeIPA Idmap library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_idmap
+Utility library to convert SIDs to Unix uids and gids
+
+%package -n libsss_idmap-devel
+Summary: FreeIPA Idmap library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_idmap = %{version}-%{release}
+
+%description -n libsss_idmap-devel
+Utility library to SIDs to Unix uids and gids
+
+%package -n libipa_hbac
+Summary: FreeIPA HBAC Evaluator library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libipa_hbac
+Utility library to validate FreeIPA HBAC rules for authorization requests
+
+%package -n libipa_hbac-devel
+Summary: FreeIPA HBAC Evaluator library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libipa_hbac = %{version}-%{release}
+
+%description -n libipa_hbac-devel
+Utility library to validate FreeIPA HBAC rules for authorization requests
+
+%package -n python-libipa_hbac
+Summary: Python2 bindings for the FreeIPA HBAC Evaluator library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libipa_hbac = %{version}-%{release}
+Provides: libipa_hbac-python = %{version}-%{release}
+Obsoletes: libipa_hbac-python < 1.12.90
+
+%description -n python-libipa_hbac
+The python-libipa_hbac contains the bindings so that libipa_hbac can be
+used by Python applications.
+
+%package -n libsss_nss_idmap
+Summary: Library for SID and certificate based lookups
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_nss_idmap
+Utility library for SID and certificate based lookups
+
+%package -n libsss_nss_idmap-devel
+Summary: Library for SID and certificate based lookups
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_nss_idmap = %{version}-%{release}
+
+%description -n libsss_nss_idmap-devel
+Utility library for SID and certificate based lookups
+
+%package -n python-libsss_nss_idmap
+Summary: Python2 bindings for libsss_nss_idmap
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_nss_idmap = %{version}-%{release}
+Provides: libsss_nss_idmap-python = %{version}-%{release}
+Obsoletes: libsss_nss_idmap-python < 1.12.90
+
+%description -n python-libsss_nss_idmap
+The python-libsss_nss_idmap contains the bindings so that libsss_nss_idmap can
+be used by Python applications.
+
+%package dbus
+Summary: The D-Bus responder of the SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+
+%description dbus
+Provides the D-Bus responder of the SSSD, called the InfoPipe, that allows
+the information from the SSSD to be transmitted over the system bus.
+
+%if (0%{?install_pcscd_polkit_rule} == 1)
+%package polkit-rules
+Summary: Rules for polkit integration for SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: polkit >= 0.106
+Requires: sssd-common = %{version}-%{release}
+
+%description polkit-rules
+Provides rules for polkit integration with SSSD. This is required
+for smartcard support.
+%endif
+
+%package -n libsss_simpleifp
+Summary: The SSSD D-Bus responder helper library
+Group: Development/Libraries
+License: GPLv3+
+Requires: sssd-dbus = %{version}-%{release}
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_simpleifp
+Provides library that simplifies D-Bus API for the SSSD InfoPipe responder.
+
+%package -n libsss_simpleifp-devel
+Summary: The SSSD D-Bus responder helper library
+Group: Development/Libraries
+License: GPLv3+
+Requires: dbus-devel
+Requires: libsss_simpleifp = %{version}-%{release}
+
+%description -n libsss_simpleifp-devel
+Provides library that simplifies D-Bus API for the SSSD InfoPipe responder.
+
+%package libwbclient
+Summary: The SSSD libwbclient implementation
+Group: Applications/System
+License: GPLv3+ and LGPLv3+
+Conflicts: libwbclient < 4.1.12
+
+%description libwbclient
+The SSSD libwbclient implementation.
+
+%package libwbclient-devel
+Summary: Development libraries for the SSSD libwbclient implementation
+Group:  Development/Libraries
+License: GPLv3+ and LGPLv3+
+Conflicts: libwbclient-devel < 4.1.12
+
+%description libwbclient-devel
+Development libraries for the SSSD libwbclient implementation.
+
+%package winbind-idmap
+Summary: SSSD's idmap_sss Backend for Winbind
+Group:  Applications/System
+License: GPLv3+ and LGPLv3+
+
+%description winbind-idmap
+The idmap_sss module provides a way for Winbind to call SSSD to map UIDs/GIDs
+and SIDs.
+
+%package -n libsss_certmap
+Summary: SSSD Certficate Mapping Library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_certmap
+Library to map certificates to users based on rules
+
+%package -n libsss_certmap-devel
+Summary: SSSD Certficate Mapping Library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_certmap = %{version}-%{release}
+
+%description -n libsss_certmap-devel
+Library to map certificates to users based on rules
+
+%if (0%{?with_kcm} == 1)
+%package kcm
+Summary: An implementation of a Kerberos KCM server
+Group:  Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+
+%description kcm
+An implementation of a Kerberos KCM server. Use this package if you want to
+use the KCM: Kerberos credentials cache.
+%endif
+
+%prep
+# Update timestamps on the files touched by a patch, to avoid non-equal
+# .pyc/.pyo files across the multilib peers within a build, where "Level"
+# is the patch prefix option (e.g. -p1)
+# Taken from specfile for python-simplejson
+UpdateTimestamps() {
+  Level=$1
+  PatchFile=$2
+
+  # Locate the affected files:
+  for f in $(diffstat $Level -l $PatchFile); do
+    # Set the files to have the same timestamp as that of the patch:
+    touch -r $PatchFile $f
+  done
+}
+
+%setup -q
+
+for p in %patches ; do
+    %__patch -p1 -i $p
+    UpdateTimestamps -p1 $p
+done
+
+%build
+autoreconf -ivf
+
+%configure \
+    --with-test-dir=/dev/shm \
+    --with-db-path=%{dbpath} \
+    --with-mcache-path=%{mcpath} \
+    --with-pipe-path=%{pipepath} \
+    --with-pubconf-path=%{pubconfpath} \
+    --with-gpo-cache-path=%{gpocachepath} \
+    --with-init-dir=%{_initrddir} \
+    --with-krb5-rcache-dir=%{_localstatedir}/cache/krb5rcache \
+    --enable-nsslibdir=%{_libdir} \
+    --enable-pammoddir=%{_libdir}/security \
+    --enable-nfsidmaplibdir=%{_libdir}/libnfsidmap \
+    --disable-static \
+    --disable-rpath \
+    --with-sssd-user=sssd \
+    --with-initscript=systemd \
+    --with-syslog=journald \
+    --enable-sss-default-nss-plugin \
+    %{?with_cifs_utils_plugin_option} \
+    --without-python3-bindings \
+    --with-ad-gpo-default=permissive \
+    %{?enable_polkit_rules_option} \
+    %{?enable_systemtap_opt} \
+    %{?with_kcm_option} \
+    %{?with_idmap_version}
+
+make %{?_smp_mflags} all docs
+make -C po ja.gmo # TODO: Rebuild all gmo files all remove this in next rebase
+
+%check
+export CK_TIMEOUT_MULTIPLIER=10
+make %{?_smp_mflags} check VERBOSE=yes
+unset CK_TIMEOUT_MULTIPLIER
+
+%install
+
+make install DESTDIR=$RPM_BUILD_ROOT
+
+if [ ! -f $RPM_BUILD_ROOT/%{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version} ]
+then
+    echo "Expected libwbclient version not found, please check if version has changed."
+    exit -1
+fi
+
+# Prepare language files
+/usr/lib/rpm/find-lang.sh $RPM_BUILD_ROOT sssd
+
+# Copy default logrotate file
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d
+install -m644 src/examples/logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/sssd
+
+# Make sure SSSD is able to run on read-only root
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rwtab.d
+install -m644 src/examples/rwtab $RPM_BUILD_ROOT%{_sysconfdir}/rwtab.d/sssd
+
+%if (0%{?with_cifs_utils_plugin} == 1)
+# Create directory for cifs-idmap alternative
+# Otherwise this directory could not be owned by sssd-client
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/cifs-utils
+%endif
+
+# Remove .la files created by libtool
+find $RPM_BUILD_ROOT -name "*.la" -exec rm -f {} \;
+
+# Suppress developer-only documentation
+rm -Rf ${RPM_BUILD_ROOT}/%{_docdir}/%{name}
+
+# Older versions of rpmbuild can only handle one -f option
+# So we need to append to the sssd*.lang file
+for file in `ls $RPM_BUILD_ROOT/%{python_sitelib}/*.egg-info 2> /dev/null`
+do
+    echo %{python_sitelib}/`basename $file` >> python_sssdconfig.lang
+done
+
+touch sssd.lang
+for subpackage in sssd_ldap sssd_krb5 sssd_ipa sssd_ad sssd_proxy sssd_tools \
+                  sssd_client sssd_dbus sssd_winbind_idmap \
+                  libsss_certmap sssd_kcm
+do
+    touch $subpackage.lang
+done
+
+for man in `find $RPM_BUILD_ROOT/%{_mandir}/??/man?/ -type f | sed -e "s#$RPM_BUILD_ROOT/%{_mandir}/##"`
+do
+    lang=`echo $man | cut -c 1-2`
+    case `basename $man` in
+        sss_cache*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang
+            ;;
+        sss_ssh*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang
+            ;;
+        sss_*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang
+            ;;
+        sssctl*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang
+            ;;
+        sssd_krb5_*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang
+            ;;
+        pam_sss*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang
+            ;;
+        sssd-ldap*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_ldap.lang
+            ;;
+        sssd-krb5*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_krb5.lang
+            ;;
+        sssd-ipa*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_ipa.lang
+            ;;
+        sssd-ad*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_ad.lang
+            ;;
+        sssd-proxy*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_proxy.lang
+            ;;
+        sssd-ifp*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_dbus.lang
+            ;;
+        sssd-kcm*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_kcm.lang
+            ;;
+        idmap_sss*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_winbind_idmap.lang
+            ;;
+        sss-certmap*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> libsss_certmap.lang
+            ;;
+        *)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang
+            ;;
+    esac
+done
+
+# Print these to the rpmbuild log
+echo "sssd.lang:"
+cat sssd.lang
+
+echo "python_sssdconfig.lang:"
+cat python_sssdconfig.lang
+
+for subpackage in sssd_ldap sssd_krb5 sssd_ipa sssd_ad sssd_proxy sssd_tools \
+                  sssd_client sssd_dbus sssd_winbind_idmap \
+                  libsss_certmap sssd_kcm
+do
+    echo "$subpackage.lang:"
+    cat $subpackage.lang
+done
+
+%files
+%defattr(-,root,root,-)
+%license COPYING
+
+%files common -f sssd.lang
+%defattr(-,root,root,-)
+%license COPYING
+%doc src/examples/sssd-example.conf
+%{_sbindir}/sssd
+%{_unitdir}/sssd.service
+%{_unitdir}/sssd-autofs.socket
+%{_unitdir}/sssd-autofs.service
+%{_unitdir}/sssd-nss.socket
+%{_unitdir}/sssd-nss.service
+%{_unitdir}/sssd-pac.socket
+%{_unitdir}/sssd-pac.service
+%{_unitdir}/sssd-pam.socket
+%{_unitdir}/sssd-pam-priv.socket
+%{_unitdir}/sssd-pam.service
+%{_unitdir}/sssd-ssh.socket
+%{_unitdir}/sssd-ssh.service
+%{_unitdir}/sssd-sudo.socket
+%{_unitdir}/sssd-sudo.service
+%{_unitdir}/sssd-secrets.socket
+%{_unitdir}/sssd-secrets.service
+
+%dir %{_libexecdir}/%{servicename}
+%{_libexecdir}/%{servicename}/sssd_be
+%{_libexecdir}/%{servicename}/sssd_nss
+%{_libexecdir}/%{servicename}/sssd_pam
+%{_libexecdir}/%{servicename}/sssd_autofs
+%{_libexecdir}/%{servicename}/sssd_secrets
+%{_libexecdir}/%{servicename}/sssd_ssh
+%{_libexecdir}/%{servicename}/sssd_sudo
+%{_libexecdir}/%{servicename}/p11_child
+%{_libexecdir}/%{servicename}/sssd_check_socket_activated_responders
+
+%dir %{_libdir}/%{name}
+# The files provider is intentionally packaged in -common
+%{_libdir}/%{name}/libsss_files.so
+%{_libdir}/%{name}/libsss_simple.so
+
+#Internal shared libraries
+%{_libdir}/%{name}/libsss_child.so
+%{_libdir}/%{name}/libsss_crypt.so
+%{_libdir}/%{name}/libsss_cert.so
+%{_libdir}/%{name}/libsss_debug.so
+%{_libdir}/%{name}/libsss_krb5_common.so
+%{_libdir}/%{name}/libsss_ldap_common.so
+%{_libdir}/%{name}/libsss_util.so
+%{_libdir}/%{name}/libsss_semanage.so
+
+# 3rd party application libraries
+%{_libdir}/libnfsidmap/sss.so
+
+%{ldb_modulesdir}/memberof.so
+%{_bindir}/sss_ssh_authorizedkeys
+%{_bindir}/sss_ssh_knownhostsproxy
+%{_sbindir}/sss_cache
+%{_libexecdir}/%{servicename}/sss_signal
+
+%dir %{sssdstatedir}
+%dir %{_localstatedir}/cache/krb5rcache
+%attr(700,sssd,sssd) %dir %{dbpath}
+%attr(775,sssd,sssd) %dir %{mcpath}
+%attr(700,root,root) %dir %{secdbpath}
+%attr(755,root,root) %dir %{deskprofilepath}
+%ghost %attr(0664,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd
+%ghost %attr(0664,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
+%ghost %attr(0664,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups
+%attr(755,sssd,sssd) %dir %{pipepath}
+%attr(750,sssd,root) %dir %{pipepath}/private
+%attr(755,sssd,sssd) %dir %{pubconfpath}
+%attr(755,sssd,sssd) %dir %{gpocachepath}
+%attr(750,sssd,sssd) %dir %{_var}/log/%{name}
+%attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd
+%attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d
+%ghost %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
+%dir %{_sysconfdir}/logrotate.d
+%config(noreplace) %{_sysconfdir}/logrotate.d/sssd
+%dir %{_sysconfdir}/rwtab.d
+%config(noreplace) %{_sysconfdir}/rwtab.d/sssd
+%dir %{_datadir}/sssd
+%{_sysconfdir}/pam.d/sssd-shadowutils
+%{_libdir}/%{name}/conf/sssd.conf
+
+%{_datadir}/sssd/cfg_rules.ini
+%{_datadir}/sssd/sssd.api.conf
+%{_datadir}/sssd/sssd.api.d
+%{_mandir}/man1/sss_ssh_authorizedkeys.1*
+%{_mandir}/man1/sss_ssh_knownhostsproxy.1*
+%{_mandir}/man5/sssd.conf.5*
+%{_mandir}/man5/sssd-files.5*
+%{_mandir}/man5/sssd-simple.5*
+%{_mandir}/man5/sssd-sudo.5*
+%{_mandir}/man5/sssd-session-recording.5*
+%{_mandir}/man5/sssd-secrets.5*
+%{_mandir}/man5/sss_rpcidmapd.5*
+%{_mandir}/man8/sssd.8*
+%{_mandir}/man8/sss_cache.8*
+%if (0%{?enable_systemtap} == 1)
+%dir %{_datadir}/sssd/systemtap
+%{_datadir}/sssd/systemtap/id_perf.stp
+%{_datadir}/sssd/systemtap/nested_group_perf.stp
+%{_datadir}/sssd/systemtap/dp_request.stp
+%dir %{_datadir}/systemtap
+%dir %{_datadir}/systemtap/tapset
+%{_datadir}/systemtap/tapset/sssd.stp
+%{_datadir}/systemtap/tapset/sssd_functions.stp
+%{_mandir}/man5/sssd-systemtap.5*
+%endif
+
+%if (0%{?install_pcscd_polkit_rule} == 1)
+%files polkit-rules
+%{_datadir}/polkit-1/rules.d/*
+%endif
+
+%files ldap -f sssd_ldap.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libdir}/%{name}/libsss_ldap.so
+%{_mandir}/man5/sssd-ldap.5*
+
+%files krb5-common
+%defattr(-,root,root,-)
+%license COPYING
+%attr(755,sssd,sssd) %dir %{pubconfpath}/krb5.include.d
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child
+
+%files krb5 -f sssd_krb5.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libdir}/%{name}/libsss_krb5.so
+%{_mandir}/man5/sssd-krb5.5*
+
+%files common-pac
+%defattr(-,root,root,-)
+%license COPYING
+%{_libexecdir}/%{servicename}/sssd_pac
+
+%files ipa -f sssd_ipa.lang
+%defattr(-,root,root,-)
+%license COPYING
+%attr(700,sssd,sssd) %dir %{keytabdir}
+%{_libdir}/%{name}/libsss_ipa.so
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child
+%{_mandir}/man5/sssd-ipa.5*
+
+%files ad -f sssd_ad.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libdir}/%{name}/libsss_ad.so
+%{_libexecdir}/%{servicename}/gpo_child
+%{_mandir}/man5/sssd-ad.5*
+
+%files proxy
+%defattr(-,root,root,-)
+%license COPYING
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/proxy_child
+%{_libdir}/%{name}/libsss_proxy.so
+
+%files dbus -f sssd_dbus.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libexecdir}/%{servicename}/sssd_ifp
+%{_mandir}/man5/sssd-ifp.5*
+%{_unitdir}/sssd-ifp.service
+# InfoPipe DBus plumbing
+%{_sysconfdir}/dbus-1/system.d/org.freedesktop.sssd.infopipe.conf
+%{_datadir}/dbus-1/system-services/org.freedesktop.sssd.infopipe.service
+
+%files -n libsss_simpleifp
+%defattr(-,root,root,-)
+%{_libdir}/libsss_simpleifp.so.*
+
+%files -n libsss_simpleifp-devel
+%defattr(-,root,root,-)
+%doc sss_simpleifp_doc/html
+%{_includedir}/sss_sifp.h
+%{_includedir}/sss_sifp_dbus.h
+%{_libdir}/libsss_simpleifp.so
+%{_libdir}/pkgconfig/sss_simpleifp.pc
+
+%files client -f sssd_client.lang
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libnss_sss.so.2
+%{_libdir}/security/pam_sss.so
+%{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
+%{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
+%if (0%{?with_cifs_utils_plugin} == 1)
+%dir %{_libdir}/cifs-utils
+%{_libdir}/cifs-utils/cifs_idmap_sss.so
+%dir %{_sysconfdir}/cifs-utils
+%ghost %{_sysconfdir}/cifs-utils/idmap-plugin
+%endif
+%if (0%{?with_krb5_localauth_plugin} == 1)
+%dir %{_libdir}/%{name}
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/sssd_krb5_localauth_plugin.so
+%endif
+%{_mandir}/man8/pam_sss.8*
+%{_mandir}/man8/sssd_krb5_locator_plugin.8*
+
+%files -n libsss_sudo
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING
+%{_libdir}/libsss_sudo.so*
+
+%files -n libsss_autofs
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/libsss_autofs.so
+
+%files tools -f sssd_tools.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_sbindir}/sss_useradd
+%{_sbindir}/sss_userdel
+%{_sbindir}/sss_usermod
+%{_sbindir}/sss_groupadd
+%{_sbindir}/sss_groupdel
+%{_sbindir}/sss_groupmod
+%{_sbindir}/sss_groupshow
+%{_sbindir}/sss_obfuscate
+%{_sbindir}/sss_override
+%{_sbindir}/sss_debuglevel
+%{_sbindir}/sss_seed
+%{_sbindir}/sssctl
+%{_mandir}/man8/sss_groupadd.8*
+%{_mandir}/man8/sss_groupdel.8*
+%{_mandir}/man8/sss_groupmod.8*
+%{_mandir}/man8/sss_groupshow.8*
+%{_mandir}/man8/sss_useradd.8*
+%{_mandir}/man8/sss_userdel.8*
+%{_mandir}/man8/sss_usermod.8*
+%{_mandir}/man8/sss_obfuscate.8*
+%{_mandir}/man8/sss_override.8*
+%{_mandir}/man8/sss_debuglevel.8*
+%{_mandir}/man8/sss_seed.8*
+%{_mandir}/man8/sssctl.8*
+
+%files -n python-sssdconfig -f python_sssdconfig.lang
+%defattr(-,root,root,-)
+%dir %{python_sitelib}/SSSDConfig
+%{python_sitelib}/SSSDConfig/*.py*
+
+%files -n python-sss
+%defattr(-,root,root,-)
+%{python_sitearch}/pysss.so
+
+%files -n python-sss-murmur
+%defattr(-,root,root,-)
+%{python_sitearch}/pysss_murmur.so
+
+%files -n libsss_idmap
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_idmap.so.*
+
+%files -n libsss_idmap-devel
+%defattr(-,root,root,-)
+%doc idmap_doc/html
+%{_includedir}/sss_idmap.h
+%{_libdir}/libsss_idmap.so
+%{_libdir}/pkgconfig/sss_idmap.pc
+
+%files -n libipa_hbac
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libipa_hbac.so.*
+
+%files -n libipa_hbac-devel
+%defattr(-,root,root,-)
+%doc hbac_doc/html
+%{_includedir}/ipa_hbac.h
+%{_libdir}/libipa_hbac.so
+%{_libdir}/pkgconfig/ipa_hbac.pc
+
+%files -n libsss_nss_idmap
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_nss_idmap.so.*
+
+%files -n libsss_nss_idmap-devel
+%defattr(-,root,root,-)
+%doc nss_idmap_doc/html
+%{_includedir}/sss_nss_idmap.h
+%{_libdir}/libsss_nss_idmap.so
+%{_libdir}/pkgconfig/sss_nss_idmap.pc
+
+%files -n python-libsss_nss_idmap
+%defattr(-,root,root,-)
+%{python_sitearch}/pysss_nss_idmap.so
+
+%files -n python-libipa_hbac
+%defattr(-,root,root,-)
+%{python_sitearch}/pyhbac.so
+
+%files libwbclient
+%defattr(-,root,root,-)
+%dir %{_libdir}/%{name}
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/libwbclient.so.*
+
+%files libwbclient-devel
+%defattr(-,root,root,-)
+%{_includedir}/wbclient_sssd.h
+%{_libdir}/%{name}/modules/libwbclient.so
+%{_libdir}/pkgconfig/wbclient_sssd.pc
+
+%files winbind-idmap -f sssd_winbind_idmap.lang
+%dir %{_libdir}/samba/idmap
+%{_libdir}/samba/idmap/sss.so
+%{_mandir}/man8/idmap_sss.8*
+
+%files -n libsss_certmap -f libsss_certmap.lang
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_certmap.so.*
+%{_mandir}/man5/sss-certmap.5*
+
+%files -n libsss_certmap-devel
+%defattr(-,root,root,-)
+%doc certmap_doc/html
+%{_includedir}/sss_certmap.h
+%{_libdir}/libsss_certmap.so
+%{_libdir}/pkgconfig/sss_certmap.pc
+
+%pre ipa
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%pre krb5-common
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%if (0%{?with_kcm} == 1)
+%files kcm -f sssd_kcm.lang
+%{_libexecdir}/%{servicename}/sssd_kcm
+%dir %{_datadir}/sssd-kcm
+%{_datadir}/sssd-kcm/kcm_default_ccache
+%{_unitdir}/sssd-kcm.socket
+%{_unitdir}/sssd-kcm.service
+%{_mandir}/man8/sssd-kcm.8*
+%endif
+
+%pre common
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+/bin/systemctl is-active --quiet sssd.service && touch /var/tmp/sssd_is_running || :
+
+%post common
+%systemd_post sssd.service
+%systemd_post sssd-autofs.socket
+%systemd_post sssd-nss.socket
+%systemd_post sssd-pac.socket
+%systemd_post sssd-pam.socket
+%systemd_post sssd-pam-priv.socket
+%systemd_post sssd-secrets.socket
+%systemd_post sssd-ssh.socket
+%systemd_post sssd-sudo.socket
+
+%preun common
+%systemd_preun sssd.service
+%systemd_preun sssd-autofs.socket
+%systemd_preun sssd-nss.socket
+%systemd_preun sssd-pac.socket
+%systemd_preun sssd-pam.socket
+%systemd_preun sssd-pam-priv.socket
+%systemd_preun sssd-secrets.socket
+%systemd_preun sssd-ssh.socket
+%systemd_preun sssd-sudo.socket
+
+%postun common
+%systemd_postun_with_restart sssd-autofs.socket
+%systemd_postun_with_restart sssd-autofs.service
+%systemd_postun_with_restart sssd-nss.socket
+%systemd_postun_with_restart sssd-nss.service
+%systemd_postun_with_restart sssd-pac.socket
+%systemd_postun_with_restart sssd-pac.service
+%systemd_postun_with_restart sssd-pam.socket
+%systemd_postun_with_restart sssd-pam-priv.socket
+%systemd_postun_with_restart sssd-pam.service
+%systemd_postun_with_restart sssd-secrets.socket
+%systemd_postun_with_restart sssd-secrets.service
+%systemd_postun_with_restart sssd-ssh.socket
+%systemd_postun_with_restart sssd-ssh.service
+%systemd_postun_with_restart sssd-sudo.socket
+%systemd_postun_with_restart sssd-sudo.service
+
+%post dbus
+%systemd_post sssd-ifp.service
+
+%preun dbus
+%systemd_preun sssd-ifp.service
+
+%postun dbus
+%systemd_postun_with_restart sssd-ifp.service
+
+%if (0%{?with_kcm} == 1)
+%post kcm
+%systemd_post sssd-kcm.socket
+
+%preun kcm
+%systemd_preun sssd-kcm.socket
+
+%postun kcm
+%systemd_postun_with_restart sssd-kcm.socket
+%systemd_postun_with_restart sssd-kcm.service
+%endif
+
+%if (0%{?with_cifs_utils_plugin} == 1)
+%post client
+/sbin/ldconfig
+/usr/sbin/alternatives --install /etc/cifs-utils/idmap-plugin cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so 20
+
+%preun client
+if [ $1 -eq 0 ] ; then
+        /usr/sbin/alternatives --remove cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so
+fi
+%else
+%post client -p /sbin/ldconfig
+%endif
+
+%postun client -p /sbin/ldconfig
+
+%post -n libsss_sudo -p /sbin/ldconfig
+
+%postun -n libsss_sudo -p /sbin/ldconfig
+
+%post -n libipa_hbac -p /sbin/ldconfig
+
+%postun -n libipa_hbac -p /sbin/ldconfig
+
+%post -n libsss_idmap -p /sbin/ldconfig
+
+%postun -n libsss_idmap -p /sbin/ldconfig
+
+%post -n libsss_nss_idmap -p /sbin/ldconfig
+
+%postun -n libsss_nss_idmap -p /sbin/ldconfig
+
+%post -n libsss_simpleifp -p /sbin/ldconfig
+
+%postun -n libsss_simpleifp -p /sbin/ldconfig
+
+%post -n libsss_certmap -p /sbin/ldconfig
+
+%postun -n libsss_certmap -p /sbin/ldconfig
+
+%post libwbclient
+%{_sbindir}/update-alternatives \
+    --install %{_libdir}/libwbclient.so.%{libwbc_alternatives_version} \
+              libwbclient.so.%{libwbc_alternatives_version}%{libwbc_alternatives_suffix} \
+              %{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version} 20
+/sbin/ldconfig
+
+%preun libwbclient
+if [ $1 -eq 0 ]; then
+    %{_sbindir}/update-alternatives \
+        --remove libwbclient.so.%{libwbc_alternatives_version}%{libwbc_alternatives_suffix} \
+                 %{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version}
+fi
+/sbin/ldconfig
+
+%post libwbclient-devel
+%{_sbindir}/update-alternatives --install %{_libdir}/libwbclient.so \
+                                libwbclient.so%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so 20
+
+%preun libwbclient-devel
+if [ $1 -eq 0 ]; then
+        %{_sbindir}/update-alternatives --remove \
+                                libwbclient.so%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so
+fi
+
+%posttrans common
+systemctl try-restart sssd >/dev/null 2>&1 || :
+# After changing order of sssd-common and *libwbclient,
+# older version of sssd will restart sssd.service in postun scriptlet
+# It failed due to missing alternative to libwbclient. Start it again.
+/bin/systemctl is-active --quiet sssd.service || {
+    if [ -f /var/tmp/sssd_is_running ]; then
+        systemctl start sssd.service >/dev/null 2>&1;
+        rm -f /var/tmp/sssd_is_running;
+    fi
+}
+
+%changelog
+* Sun Sep 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-32
+- Resolves: rhbz#1530741 - Trusted domain user logins succeed after using ipa
+                           trustdomain-disable
+
+* Sun Sep 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-31
+- Resolves: rhbz#1746878 - Let IPA client read IPA objects via LDAP and not
+                           a extdom plugin when resolving trusted users and
+                           groups
+
+* Fri Sep 20 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-30
+- Resolves: rhbz#1530741 - Trusted domain user logins succeed after using
+                           ipa trustdomain-disable
+
+* Fri Sep 20 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-29
+- Resolves: rhbz#1713352 - Implicit files domain gets activated when no
+                           sssd.conf present and sssd is started
+
+* Thu Sep 19 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-28
+- Resolves: rhbz#1206221 - sssd should not always read entire autofs map from
+                           ldap
+
+* Thu Sep 19 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-27
+- Resolves: rhbz#1657978 - SSSD is not refreshing cached user data for the
+                           ipa sub-domain in a IPA/AD trust
+
+* Thu Sep 5 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-26
+- Resolves: rhbz#1541172 - ad_enabled_domains does not disable old subdomain
+                           after a restart until a timer removes it
+
+* Thu Sep 5 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-25
+- Resolves: rhbz#1738674 - Paging not enabled when fetching external groups,
+                           limits the number of external groups to 2000
+
+* Thu Sep 5 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-24
+- Resolves: rhbz#1650018 - SSSD doesn't clear cache entries for IDs
+                           below min_id
+
+* Thu Sep 5 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-23
+- Resolves: rhbz#1724088 - negative cache does not use values from
+                           'filter_users' config option for known domains
+
+* Wed Aug 14 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-22
+- Resolves: rhbz#1422618 - sssd does not failover to another IPA
+                           server if just the KDC service fails 
+- Just bumping the version to work around "build already exists"
+
+* Fri Jun 07 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-21
+- Resolves: rhbz#1714952 - [sssd] RHEL 7.7 Tier 0 Localization
+- Rebuild japanese gmo file explicitly
+
+* Fri Jun 07 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-20
+- Resolves: rhbz#1714952 - [sssd] RHEL 7.7 Tier 0 Localization
+
+* Tue May 28 2019 Jakub Hrozek <jhrozek@redhat.com> - 1.16.4-19
+- Resolves: rhbz#1707959 - sssd does not properly check GSS-SPNEGO
+
+* Tue May 28 2019 Jakub Hrozek <jhrozek@redhat.com> - 1.16.4-18
+- Resolves: rhbz#1710286 - The server error message is not returned if
+                           password change fails
+
+* Tue May 28 2019 Jakub Hrozek <jhrozek@redhat.com> - 1.16.4-17
+- Resolves: rhbz#1711832 - The files provider does not handle resetOffline
+                           properly
+
+* Mon May 20 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-16
+- Resolves: rhbz#1707759 - Error accessing files on samba share randomly
+
+* Mon May 20 2019 Jakub Hrozek <jhrozek@redhat.com> - 1.16.4-15
+- Resolves: rhbz#1685581 - Extend cached_auth_timeout to cover subdomains
+                           /trusts
+
+* Mon Apr 15 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-14
+- Resolves: rhbz#1684979 - The HBAC code requires dereference to be enabled
+                           and fails otherwise
+
+* Mon Apr 15 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-12
+- Resolves: rhbz#1576524 - RHEL STIG pointing sssd Packaging issue
+                         - This was partially fixed by the rebase, but one
+                           spec file change was missing.
+
+* Mon Apr 15 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-12
+- Resolves: rhbz#1524566 - FIPS mode breaks using pysss.so (sss_obfuscate)
+
+* Thu Apr 04 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-11
+- Resolves: rhbz#1350012 - kinit / sssd kerberos fail over
+- Resolves: rhbz#720688 - [RFE] return multiple server addresses to the
+                          Kerberos locator plugin
+
+* Thu Apr 04 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-10
+- Resolves: rhbz#1402056 - [RFE] Make 2FA prompting configurable
+
+* Thu Apr 04 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-9
+- Resolves: rhbz#1666819 - SSSD can trigger a NSS lookup when parsing the
+                           filter_users/groups lists on startup, this can
+                           block the startup
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-8
+- Resolves: rhbz#1645461 - Slow ldb search causes blocking during startup
+                           which might cause the registration to time out
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-7
+- Resolves: rhbz#1685581 - Extend cached_auth_timeout to cover
+                           subdomains / trusts
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-6
+- Resolves: rhbz#1671138 - User is unable to perform sudo as a user on IPA
+                           Server, even though `sudo -l` shows permissions
+                           to do so
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-5
+- Resolves: rhbz#1657806 - [RFE]: Optionally disable generating auto private
+                           groups for subdomains of an AD provider
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-4
+- Resolves: rhbz#1641131 - [RFE] Need an option in SSSD so that it will skip
+                           GPOs that have groupPolicyContainers, unreadable
+                           by SSSD.
+- Resolves: rhbz#1660874 - CVE-2018-16838 sssd: improper implementation of
+                           GPOs due to too restrictive permissions [rhel-7]
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-3
+- Resolves: rhbz#1631656 - KCM: kinit: Matching credential not found while
+                           getting default ccache
+
+* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-2
+- Resolves: rhbz#1406678 - sssd service is starting before network service
+- Resolves: rhbz#1616853 - SSSD always boots in Offline mode
+
+* Thu Mar 21 2019 Michal Židek <mzidek@redhat.com> - 1.16.4-1
+- Resolves: rhbz#1658994 - Rebase SSSD to 1.16.x
+
+* Wed Mar 20 2019 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-17
+- Resolves: rhbz#1603311 - Enable generating user private groups only for
+                           users with uid == gid where gid does not
+                           correspond to a real LDAP group
+
+* Wed Nov 28 2018 Michal Židek <mzidek@redhat.com> - 1.16.2-16
+- Resolves: rhbz#1602172 - SSSD's LDAP authentication provider does not work
+                           if ID provider is authenticated with GSSAPI 
+
+* Thu Nov 15 2018 Michal Židek <mzidek@redhat.com> - 1.16.2-15
+- Resolves: rhbz#1622109 -  SSSD not fetching all sudo rules from AD
+
+* Wed Nov 14 2018 Michal Židek <mzidek@redhat.com> - 1.16.2-14
+- Resolves: rhbz#1619706 - sssd only sets the SELinux login context if it
+                           differs from the default
+
+* Wed Sep  5 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-13
+- Resolves: rhbz#1593756 - sssd needs to require a newer version of
+                           libtalloc and libtevent to avoid an issue
+                           in GPO processing
+
+* Thu Aug  9 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-12
+- Resolves: rhbz#1610667 - sssd_ssh leaks file descriptors when more than one certificate is converted into an SSH key
+- Resolves: rhbz#1583360 - The IPA selinux provider can return an error if SELinux is completely disabled
+
+* Thu Aug  2 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-11
+- Resolves: rhbz#1602781 - Local users failed to login with same password
+
+* Wed Aug  1 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-10
+- Resolves: rhbz#1586127 - Spurious check in the sssd nss memcache can cause the memory cache to be skipped
+
+* Thu Jul 26 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-9
+- Resolves: rhbz#1522928 - sssd doesn't allow user with expired password
+
+* Thu Jul 26 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-8
+- Resolves: rhbz#1607313 - When sssd is running as non-root user, the sudo pipe is created as sssd:sssd but then the private pipe ownership fails
+
+* Fri Jul 13 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-7
+- Resolves: rhbz#1600822 - SSSD bails out saving desktop profiles in case an invalid profile is found
+
+* Wed Jul 11 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-6
+- Resolves: rhbz#1582975 - The search filter for detecting POSIX attributes in global catalog is too broad and can cause a high load on the servers
+
+* Fri Jun 29 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-5
+- Resolves: rhbz#1583725 - SSSD AD uses LDAP filter to detect POSIX attributes stored in AD GC also for regular AD DC queries
+- Resolves: rhbz#1416528 - sssd in cross realm trust configuration should be able to use AD KDCs from a client site defined in sssd.conf or a snippet
+- Resolves: rhbz#1592964 - Groups go missing with PAC enabled in sssd
+
+* Mon Jun 25 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-4
+- Resolves: rhbz#1590603 - EMBARGOED CVE-2018-10852 sssd: information leak from the sssd-sudo responder [rhel-7]
+- Resolves: rhbz#1450778 - Full information regarding priority of lookup of principal in keytab not in man page
+
+* Fri Jun 22 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-3
+- Resolves: rhbz#1494690 - kdcinfo files are not created for subdomains of a directly joined AD client
+- Resolves: rhbz#1583343 - Login with sshkeys stored in ipa not working after update to RHEL-7.5
+- Resolves: rhbz#1527662 - Handle conflicting e-mail addresses more gracefully
+- Resolves: rhbz#1509691 - Document how to change the regular expression for SSSD so that group names with an @-sign can be parsed
+
+* Fri Jun 22 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-2
+- Related: rhbz#1558498 - Rebase sssd to the latests upstream release of the 1.16 branch
+
+* Mon Jun 11 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-1
+- Resolves: rhbz#1558498 - Rebase sssd to the latests upstream release of the 1.16 branch
+- Resolves: rhbz#1523019 - Reset password with two factor authentication fails
+- Resolves: rhbz#1534749 - Requesting an AD user's private group and then the user itself returns an emty homedir
+- Resolves: rhbz#1537272 - SSH public key authentication keeps working after keys are removed from ID view
+- Resolves: rhbz#1537279 - Certificate is not removed from cache when it's removed from the override
+- Resolves: rhbz#1562025 - externalUser sudo attribute must be fully-qualified
+- Resolves: rhbz#1577335 - /usr/libexec/sssd/sssd_autofs SIGABRT crash daily
+- Resolves: rhbz#1508530 - How should sudo behave without sudoHost attribute?
+- Resolves: rhbz#1546754 - The man page of sss_ssh_authorizedkeys can be enhanced to better explain how the keys are retrieved and how X.509 certificates can be used
+- Resolves: rhbz#1572790 - getgrgid/getpwuid fails in setups with multiple domains if the first domain uses mid_id/max_id
+- Resolves: rhbz#1561562 - sssd not honoring dyndns_server if the DNS update process is terminated with a signal
+- Resolves: rhbz#1583251 - home dir disappear in sssd cache on the IPA master for AD users
+- Resolves: rhbz#1514061 - ID override GID from Default Trust View is not properly resolved in case domain resolution order is set
+- Resolves: rhbz#1571466 - Utilizing domain_resolution_order in sssd.conf breaks SELinux user map
+- Resolves: rhbz#1571526 - SSSD with ID provider 'ad' should give a warning in case the ldap schema is manually changed to something different than 'ad'.
+
+* Thu May 31 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-25
+- Resolves: rhbz#1547782 - The SSSD IPA provider allocates information about external groups on a long lived memory context, causing memory growth of the sssd_be process
+
+* Sat May 19 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-24
+- Related: rhbz#1578291 - Samba can not register sss idmap module because it's using an outdated SMB_IDMAP_INTERFACE_VERSION
+
+* Fri May 18 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-23
+- Resolves: rhbz#1578291 - Samba can not register sss idmap module because it's using an outdated SMB_IDMAP_INTERFACE_VERSION
+
+* Fri May 18 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-22
+- Resolves: rhbz#1516266 - Give a more detailed debug and system-log message if krb5_init_context() failed
+- Resolves: rhbz#1503802 - Smartcard authentication fails if SSSD is offline and 'krb5_store_password_if_offline = True'
+- Resolves: rhbz#1385665 - Incorrect error code returned from krb5_child (updated)
+- Resolves: rhbz#1547234 - SSSD's GPO code ignores ad_site option
+- Resolves: rhbz#1459348 - extend sss-certmap man page regarding priority processing
+- Resolves: rhbz#1220767 - Group renaming issue when "id_provider = ldap" is set
+- Resolves: rhbz#1538555 - crash in nss_protocol_fill_netgrent. sssd_nss[19234]: segfault at 80 ip 000055612688c2a0 sp 00007ffddf9b9cd0 error 4 in sssd_nss[55612687e000+39000]
+
+* Wed Apr 25 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.0-21
+- Resolves: rhbz#1565774 - After updating to RHEL 7.5 failing to clear the sssd cache
+
+* Fri Apr 20 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-20
+- Resolves: rhbz#1566782 - memory management issue in the sssd_nss_ex interface can cause the ns-slapd process on IPA server to crash
+
+* Wed Feb 21 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19
+- Related: rhbzrhbz#1544943 - sssd goes offline when renewing expired ticket
+
+* Wed Feb 21 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-18
+- Resolves: rhbz#1543348 - sssd_be consumes more memory on RHEL 7.4 systems.
+- Resolves: rhbz#1544943 - sssd goes offline when renewing expired ticket
+
+* Mon Feb 19 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-17
+- Resolves: rhbz#1523282 - sssd used wrong search base with wrong AD
+                           server
+
+* Tue Feb  6 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-16
+- Resolves: rhbz#1538643 - SSSD crashes when retrieving a Desktop Profile
+                           with no specific host/hostgroup set
+- Related: rhbz#1441908 - SELINUX: Use getseuserbyname to get IPA seuser
+- Related: rhbz#1327705 - [RFE] Automatic creation of user private groups
+                          on RHEL clients joined to AD via sssd [RHEL 7]
+
+* Wed Jan 24 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-15
+- Resolves: rhbz#1517971 - AD Domain goes offline immediately during
+                           subdomain initialization - IPA AD Trust
+- Related: rhbz#1482555 - sysdb index improvements - missing ghost
+                          attribute indexing, unneeded objectclass index
+                          etc..
+- Related: rhbz#1327705 - [RFE] Automatic creation of user private groups
+                          on RHEL clients joined to AD via sssd [RHEL 7]
+- Resolves: rhbz#1527149 - AD provider - AD BUILTIN groups are cached with
+                           gidNumber = 0
+- Related: rhbz#1461899 - Loading enterprise principals doesn't work with
+                          a primed cache
+- Related: rhbz#1473571 - ipa-extdom-extop plugin can exhaust DS worker
+                          threads
+
+* Fri Dec 15 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-14
+- Resolves: rhbz#1525644 - dbus-send unable to find user by CAC cert
+
+* Thu Dec 14 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-13
+- Resolves: rhbz#1523010 - IPA user able to authenticate with revoked cert
+                           on smart card
+
+* Mon Dec 11 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-12
+- Resolves: rhbz#1512027 - NSS by-id requests are not checked against
+                           max_id/min_id ranges before triggering the
+                           backend
+
+* Fri Dec 08 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-11
+- Related: rhbz#1507614 - Improve Smartcard integration if multiple
+                          certificates or multiple mapped identities are
+                          available
+- Resolves: rhbz#1523010 - IPA user able to authenticate with revoked
+                           cert on smart card
+- Resolves: rhbz#1520984 - getent output is not showing home directory
+                           for IPA AD trusted user
+- Related: rhbz#1473571 - ipa-extdom-extop plugin can exhaust DS worker
+                          threads
+
+* Wed Dec 06 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-10
+- Resolves: rhbz#1421194 - SSSD doesn't use AD global catalog for
+                           gidnumber lookup, resulting in unacceptable
+                           delay for large forests
+
+* Fri Dec 01 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-9
+- Resolves: rhbz#1482231 - sssd_nss consumes more memory until
+                           restarted or machine swaps
+- Resolves: rhbz#1512508 - SSSD fails to fetch group information after
+                           switching IPA client to a non-default view
+
+* Thu Nov 30 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-8
+- Resolves: rhbz#1490120 - SSSD complaining about corrupted mmap cache
+                           and logging error in /var/log/messages and
+                           /var/log/sssd/sssd_nss.log
+
+* Mon Nov 27 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-7
+- Resolves: rhbz#1272214 - [RFE] Create a local per system report about
+                           who can access that IDM client (attestation)
+- Resolves: rhbz#1482555 - sysdb index improvements - missing ghost
+                           attribute indexing, unneeded objectclass index
+                           etc..
+- Resolves: rhbz#888739 -  Enumerating large number of users makes sssd_be
+                           hog the cpu for a long time.
+- Resolves: rhbz#1373547 - SSSD performance issue with malloc and brk
+                           calls
+- Resolves: rhbz#1472255 - Improve SSSD performance in the 7.5 release
+
+* Tue Nov 14 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-6
+- Related: rhbz#1460724 - SYSLOG_IDENTIFIER is different
+- Related: rhbz#1432010 - SSSD ships a drop-in configuration snippet in
+                          /etc/systemd/system
+- Related: rhbz#1507614 - Improve Smartcard integration if multiple
+                          certificates or multiple mapped identities are
+                          available
+
+* Mon Nov 13 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-5
+- Resolves: rhbz#1507614 - Improve Smartcard integration if multiple
+                           certificates or multiple mapped identities are
+                           available
+- Related: rhbz#1499659 - CVE-2017-12173 sssd: unsanitized input when
+                          searching in local cache database [rhel-7.5]
+- Resolves: rhbz#1408294 - SSSD authentication fails when two IPA
+                           accounts share an email address without a
+                           clear way to debug the problem
+- Resolves: rhbz#1502686 - crash - /usr/libexec/sssd/sssd_nss in
+                           nss_setnetgrent_timeout
+
+* Sun Nov 12 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-4
+- Related: rhbz#1460724 - SYSLOG_IDENTIFIER is different
+- Related: rhbz#1459609 - When sssd is configured with id_provider proxy
+                          and auth_provider ldap, login fails if the LDAP
+                          server is not allowing anonymous binds.
+
+* Mon Nov 06 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-3
+- Resolves: rhbz#1473571 - ipa-extdom-extop plugin can exhaust DS worker
+                           threads
+
+* Fri Nov 03 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-2
+- Resolves: rhbz#1484376 - [RFE] Add a configuration option to SSSD to
+                           disable the memory cache
+- Resolves: rhbz#1327705 - Automatic creation of user private groups on
+                           RHEL clients joined to AD via sssd [RHEL 7]
+- Resolves: rhbz#1505277 - Race condition between refreshing the cr_domain
+                           list and a request that is using the list can
+                           cause a segfault is sssd_nss
+- Resolves: rhbz#1462343 - document information on why SSSD does not use
+                           host-based security filtering when processing
+                           AD GPOs
+- Resolves: rhbz#1498734 - sssd_be stuck in an infinite loop after
+                           completing full refresh of sudo rules
+- Resolves: rhbz#1400614 - [RFE] sssd should remember DNS sites from
+                           first search
+- Resolves: rhbz#1460724 - SYSLOG_IDENTIFIER is different
+- Resolves: rhbz#1459609 - When sssd is configured with id_provider proxy
+                           and auth_provider ldap, login fails if the LDAP
+                           server is not allowing anonymous binds.
+
+* Fri Oct 20 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-1
+- Resolves: rhbz#1469791 - Rebase SSSD to version 1.16+
+- Resolves: rhbz#1132264 - Allow sssd to retrieve sudo rules of local
+                           users whose sudo rules stored in ldap server
+- Resolves: rhbz#1301740 - sssd can be marked offline if a trusted domain
+                           is not reachable
+- Resolves: rhbz#1399262 - Use TCP for kerberos with AD by default
+- Resolves: rhbz#1416150 - RFE: Log to syslog when sssd cannot contact
+                           servers, goes offline
+- Resolves: rhbz#1441908 - SELINUX: Use getseuserbyname to get IPA seuser
+- Resolves: rhbz#1454559 - python-sssdconfig doesn't parse hexadecimal debug
+                           _level, resulting in set_option():
+                           /usr/lib/python2.7/site-packages/SSSDConfig/__init__.py
+                           killed by TypeError
+- Resolves: rhbz#1456968 - MAN: document that attribute 'provider' is not
+                           allowed in section 'secrets'
+- Resolves: rhbz#1460689 - KCM/secrets: Storing many secrets in a rapid
+                           succession segfaults the secrets responder
+- Resolves: rhbz#1464049 - Idle nss file descriptors should be closed
+- Resolves: rhbz#1468610 - sssd_be is utilizing more CPU during sudo rules
+                           refresh
+- Resolves: rhbz#1474711 - Querying the AD domain for external domain's ID can
+                           mark the AD domain offline
+- Resolves: rhbz#1479398 - samba shares with sssd authentication broken on 7.4
+- Resolves: rhbz#1479983 - id root triggers an LDAP lookup
+- Resolves: rhbz#1489895 - Issues with certificate mapping rules
+- Resolves: rhbz#1490501 - sssd incorrectly checks 'try_inotify' thinking it is
+                           the wrong section
+- Resolves: rhbz#1490913 - MAN: Document that full_name_format must be set if
+                           the output of trusted domains user resolution should
+                           be shortnames only
+- Resolves: rhbz#1499659 - CVE-2017-12173 sssd: unsanitized input when
+                           searching in local cache database [rhel-7.5]
+- Resolves: rhbz#1461899 - Loading enterprise principals doesn't work with a
+                           primed cache
+- Resolves: rhbz#1482674 - SUDO doesn't work for IPA users on IPA clients after
+                           applying ID Views for them in IPA server
+- Resolves: rhbz#1486053 - Accessing IdM kerberos ticket fails while id mapping
+                           is applied
+- Resolves: rhbz#1486786 - sssd going in offline mode due to sudo search filter.
+- Resolves: rhbz#1500087 - SSSD creates bad override search filter due to AD
+                           Trust object with parenthesis
+- Resolves: rhbz#1502713 - SSSD can crash due to ABI changes in libldb >= 1.2.0
+                           (1.1.30)
+- Resolves: rhbz#1461462 - sssd_client: add mutex protected call to the PAC
+                           responder
+- Resolves: rhbz#1489666 - Combination sssd-ad and postfix recieve incorrect
+                           mail with asterisks or spaces
+- Resolves: rhbz#1525052 - sssd_krb5_localauth_plugin fails to fallback to otheri
+                           localname rules
+
+* Tue Oct 17 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-51
+- Require the 7.5 libldb version which broke ABI
+- Related: rhbz#1469791 - Rebase SSSD to version 1.16+
+
+* Wed Jun 21 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-50
+- Resolves: rhbz#1457926 - Wrong search base used when SSSD is directly
+                           connected to AD child domain
+
+* Wed Jun 21 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-49
+- Resolves: rhbz#1450107 - SSSD doesn't handle conflicts between users
+                           from trusted domains with the same name when
+                           shortname user resolution is enabled
+
+* Fri Jun 16 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-48
+- Resolves: rhbz#1459846 - krb5: properly handle 'password expired'
+                           information retured by the KDC during
+                           PKINIT/Smartcard authentication
+
+* Thu Jun 15 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-47
+- Resolves: rhbz#1430415 - ldap_purge_cache_timeout in RHEL7.3 invalidate
+                           most of the entries once the cleanup task kicks in
+
+* Thu Jun 15 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-46
+- Resolves: rhbz#1455254 - Make domain available as user attribute
+
+* Thu Jun  8 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-45
+- Resolves: rhbz#1449731 - IPA client cannot change AD Trusted User password
+
+* Thu Jun  8 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-44
+- Resolves: rhbz#1457927 - getent failed to fetch netgroup information
+                           after changing default_domain_suffix to
+                           ADdomin in /etc/sssd/sssd.conf
+
+* Mon Jun  5 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-43
+- Resolves: rhbz#1440132 - fiter_users and filter_groups stop working
+                           properly in v 1.15
+
+* Mon Jun  5 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-42
+- Resolves: rhbz#1449728 - LDAP to IPA migration doesn't work in master
+
+* Mon Jun  5 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-41
+- Resolves: rhbz#1445445 - Smart card login fails if same cert mapped to
+                           IdM user and AD user
+
+* Mon Jun  5 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-40
+- Resolves: rhbz#1449729 - org.freedesktop.sssd.infopipe.GetUserGroups
+                           does not resolve groups into names with AD
+
+* Thu Jun  1 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-39
+- Resolves: rhbz#1450094 - Properly support IPA's promptusername config
+                           option
+
+* Thu Jun  1 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-38
+- Resolves: rhbz#1457644 - Segfault in access_provider = krb5 is set in
+                           sssd.conf due to an off-by-one error when
+                           constructing the child send buffer
+- Resolves: rhbz#1456531 - Option name typos are not detected with validator
+                           function of sssctl config-check command in domain
+                           sections
+
+* Fri May 26 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-37
+- Resolves: rhbz#1428906 - sssd intermittently failing to resolve groups
+                           for an AD user in IPA-AD trust environment.
+
+* Fri May 26 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-36
+- Resolves: rhbz#1389796 - Smartcard authentication with UPN as logon name
+                           might fail
+- Fix Coverity issues in patches for rhbz#1445445
+
+* Wed May 24 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-35
+- Resolves: rhbz#1445445 - Smart card login fails if same cert mapped to
+                           IdM user and AD user
+
+* Wed May 24 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-34
+- Resolves: rhbz#1446302 - crash in sssd-kcm due to a race-condition
+                           between two concurrent requests
+
+* Tue May 23 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-33
+- Resolves: rhbz#1389796 - Smartcard authentication with UPN as logon name might fail
+
+* Tue May 23 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-32
+- Resolves: rhbz#1306707 - Need better debug message when krb5_child
+                           returns an unhandled error, leading to a
+                           System Error PAM code
+
+* Mon May 22 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-31
+- Resolves: rhbz#1446535 - Group resolution does not work in subdomain
+                           without ad_server option
+
+* Wed May  17 2017 Sumit Bose <sbose@redhat.com> - 1.15.2-30
+- Resolves: rhbz#1449726 - sss_nss_getlistbycert() does not return results from
+                           multiple domains
+- Resolves: rhbz#1447098 - sssd unable to search dbus for ipa user by
+                           certificate
+- Additional patch for rhbz#1440132
+
+* Thu May  11 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-29
+- Reapply patch by Lukas Slebodnik to fix upgrade issues with libwbclient
+- Resolves: rhbz#1439457 - SSSD does not start after upgrade from 7.3 to 7.4 
+- Resolves: rhbz#1449107 - error: %pre(sssd-common-1.15.2-26.el7.x86_64)
+                           scriptlet failed, exit status 3
+
+* Thu May 11 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-28
+- Resolves: rhbz#1440132 - fiter_users and filter_groups stop working
+                           properly in v 1.15
+- Also apply an additional patch for rhbz#1441545
+
+* Thu May  4 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-25
+- Resolves: rhbz#1445445 - Smart card login fails if same cert mapped to
+                           IdM user and AD user
+
+* Wed May  3 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-24
+- Resolves: rhbz#1434992 - Wrong pam return code for user from subdomain
+                           with ad_access_filter
+
+* Wed May  3 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.2-23
+- Resolves: rhbz#1430494 - expect sss_ssh_authorizedkeys and
+                           sss_ssh_knownhostsproxy manuals to be packaged
+                           into sssd-common package
+
+* Tue May  2 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-22
+- Resolves: rhbz#1427749 - SSSD in server mode iterates over all domains
+                           for group-by-GID requests, causing unnecessary
+                           searches
+
+* Tue May  2 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-21
+- Resolves: rhbz#1446139 - Infopipe method ListByCertificate does not
+                           return the users with overrides
+
+* Tue May  2 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-20
+- Resolves: rhbz#1441545 - With multiple subdomain sections id command
+                           output for user is not displayed for both domains
+
+* Tue May  2 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-19
+- Resolves: rhbz#1428866 - Using ad_enabled_domains configuration option
+                           in sssd.conf causes nameservice lookups to fail.
+
+* Tue May  2 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-18
+- Remove an unused variable from the sssd-secrets responder
+- Related: rhbz#1398701 - [sssd-secrets] https proxy talks plain http
+- Improve two DEBUG messages in the client trust code to aid troubleshooting
+- Fix standalone application domains
+- Related: rhbz#1425891 - Support delivering non-POSIX users and groups
+                          through the IFP and PAM interfaces
+
+* Wed Apr 26 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-17
+- Allow completely server-side unqualified name resolution if the domain order is set,
+  do not require any client-side changes
+- Related: rhbz#1330196 - [RFE] Short name input format with SSSD for users from
+                          all domains when domain autodiscovery is used or when
+                          IPA client resolves trusted AD domain users
+
+* Mon Apr 24 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-16
+- Resolves: rhbz#1402532 - D-Bus interface of sssd is giving inappropriate
+                           group information for trusted AD users
+
+* Thu Apr 13 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-15
+- Resolves: rhbz#1431858 - Wrong principal found with ad provider and long
+                           host name
+
+* Wed Apr 12 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-14
+- Resolves: rhbz#1415167 - pam_acct_mgmt with pam_sss.so fails in
+                           unprivileged container unless
+                           selinux_provider = none is used
+
+* Wed Apr 12 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-13
+- Resolves: rhbz#1438388 - [abrt] [faf] sssd: unknown function():
+                           /usr/libexec/sssd/sssd_pam killed by 6
+
+* Tue Apr 11 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-12
+- Resolves: rhbz#1432112 - sssctl config-check does not give any error
+                           when default configuration file is not present
+
+* Tue Apr 11 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-11
+- Resolves: rhbz#1438374 - [abrt] [faf] sssd: vfprintf():
+                           /usr/libexec/sssd/sssd_be killed by 11
+
+* Tue Apr 11 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-10
+- Resolves: rhbz#1427195 - sssd_nss consumes more memory until restarted
+                           or machine swaps
+
+* Mon Apr 10 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-9
+- Resolves: rhbz#1414023 - Create troubleshooting tool to determine if a
+                           failure is in SSSD or not when using layered
+                           products like RH-SSO/CFME etc
+
+* Thu Mar 30 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-8
+- Resolves: rhbz#1398701 - [sssd-secrets] https proxy talks plain http
+
+* Thu Mar 30 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-7
+- Fix off-by-one error in the KCM responder
+- Related: rhbz#1396012 - [RFE] KCM ccache daemon in SSSD
+
+* Thu Mar 30 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-6
+- Resolves: rhbz#1425891 - Support delivering non-POSIX users and groups
+                           through the IFP and PAM interfaces
+
+* Wed Mar 29 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-5
+- Resolves: rhbz#1434991 - Issue processing ssh keys from certificates in
+                           ssh respoder
+
+* Wed Mar 29 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-4
+- Resolves: rhbz#1330196 - [RFE] Short name input format with SSSD for
+                           users from all domains when domain autodiscovery
+                           is used or when IPA client resolves trusted AD
+                           domain users
+- Also backport some buildtime fixes for the KCM responder
+- Related: rhbz#1396012 - [RFE] KCM ccache daemon in SSSD
+
+* Mon Mar 27 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-3
+- Resolves: rhbz#1396012 - [RFE] KCM ccache daemon in SSSD
+
+* Thu Mar 23 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-2
+- Resolves: rhbz#1340711 - [RFE] Use one smartcard and certificate for
+                           authentication to distinct logon accounts
+
+* Wed Mar 15 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.2-1
+- Update to upstream 1.15.2
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_2.html
+- Resolves: rhbz#1418728 - IPA - sudo does not handle associated conflict
+                           entries
+- Resolves: rhbz#1386748 - sssd doesn't update PTR records if A/PTR zones
+                           are configured as non-secure and secure
+- Resolves: rhbz#1214491 - [RFE] Make it possible to configure AD subdomain
+                           in the SSSD server mode
+
+* Thu Mar  9 2017 Fabiano Fidêncio <fidencio@redhat.com> - 1.15.1-2
+- Drop "NOUPSTREAM: Bundle http-parser" patch
+  Related: rhbz#1393819 - New package: http-parser
+
+* Sat Mar  4 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.1-1
+- Update to upstream 1.15.1
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_1.html
+- Resolves: rhbz#1327085 - Don't prompt for password if there is already
+                           one on the stack
+- Resolves: rhbz#1378722 - [RFE] Make GETSIDBYNAME and GETORIGBYNAME
+                           request aware of UPNs and aliases
+- Resolves: rhbz#1405075 - [RFE] Add PKINIT support to SSSD Kerberos provider
+- Resolves: rhbz#1416526 - Need correction in sssd-krb5 man page
+- Resolves: rhbz#1418752 - pam_sss crashes in do_pam_conversation if no
+                           conversation function is provided by the
+                           client app
+- Resolves: rhbz#1419356 - Fails to accept any sudo rules if there are
+                           two user entries in an ldap role with the same
+                           sudo user
+- Resolves: rhbz#1421622 - SSSD - Users/Groups are cached as mixed-case
+                           resulting in users unable to sign in
+
+* Wed Feb  1 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.0-2
+- Fix several packaging issues, notably the p11_child is no longer setuid
+  and the libwbclient used a wrong version number in the symlink
+
+* Mon Jan 30 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.0-1
+- Update to upstream 1.15.0
+- Resolves: rhbz#1393824 - Rebase SSSD to version 1.15
+- Resolves: rhbz#1407960 - wbcLookupSid() fails in pdomain is NULL
+- Resolves: rhbz#1406437 - sssctl netgroup-show Cannot allocate memory
+- Resolves: rhbz#1400422 - Use-after free in resolver in case the fd is
+                           writeable and readable at the same time
+- Resolves: rhbz#1393085 - bz - ldap group names don't resolve after
+                           upgrading sssd to 1.14.0 if ldap_nesting_level is set to 0
+- Resolves: rhbz#1392444 - sssd_be keeps crashing
+- Resolves: rhbz#1392441 - sssd fails to start after upgrading to RHEL 7.3
+- Resolves: rhbz#1382602 - autofs map resolution doesn't work offline
+- Resolves: rhbz#1380436 - sudo: ignore case on case insensitive domains
+- Resolves: rhbz#1378251 - Typo In SSSD-AD Man Page
+- Resolves: rhbz#1373427 - Clock skew makes SSSD return System Error
+- Resolves: rhbz#1306707 - Need better handling of "Server not found in
+                           Kerberos database"
+- Resolves: rhbz#1297462 - Don't include 'enable_only=sssd' in the localauth
+                           plugin config
+
+* Mon Nov  7 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-46
+- Resolves: rhbz#1382598 - IPA: Uninitialized variable during subdomain check
+
+* Mon Nov  7 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-45
+- Resolves: rhbz#1378911 - No supplementary groups are resolved for users
+                           in nested OUs when domain stanza differs from AD
+                           domain
+
+* Mon Nov  7 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-44
+- Resolves: rhbz#1372075 - AD provider: SSSD does not retrieve a domain-local
+                           group with the AD provider when following AGGUDLP
+                           group structure across domains
+
+* Tue Sep 20 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-43
+- Resolves: rhbz#1376831 - sssd-common is missing dependency on sssd-sudo
+
+* Fri Sep 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-42
+- Resolves: rhbz#1371631 - login using gdm calls for gdm-smartcard when
+                           smartcard authentication is not enabled
+
+* Wed Sep 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-41
+- Resolves: rhbz#1373420 - sss_override fails to export
+
+* Wed Sep 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-40
+- Resolves: rhbz#1375299 - sss_groupshow <user> fails with error "No such
+                           group in local domain. Printing groups only
+                           allowed in local domain"
+
+* Wed Sep 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-39
+- Resolves: rhbz#1375182 - SSSD goes offline when the LDAP server returns
+                           sizelimit exceeded
+
+* Mon Sep 12 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-38
+- Resolves: rhbz#1372753 - Access denied for user when access_provider =
+                           krb5 is set in sssd.conf
+
+* Mon Sep 12 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-37
+- Resolves: rhbz#1373444 - unable to create group in sssd cache
+- Resolves: rhbz#1373577 - unable to add local user in sssd to a group in sssd
+
+* Wed Sep  7 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-36
+- Resolves: rhbz#1369118 - Don't enable the default shadowtils domain in RHEL
+
+* Mon Sep  5 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-35
+- Fix permissions for the private pipe directory
+- Resolves: rhbz#1362716 - selinux avc denial for vsftp login as ipa user
+
+* Fri Sep  2 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-34
+- Resolves: rhbz#1371977 - resolving IPA nested user groups is broken in 1.14
+
+* Fri Sep  2 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-33
+- Resolves: rhbz#1368496 - sssd is not able to authenticate with alias
+
+* Fri Sep  2 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-32
+- Resolves: rhbz#1371152 - SSSD qualifies principal twice in IPA-AD trust
+                           if the principal attribute doesn't exist on the
+                           AD side
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-31
+- Apply forgotten patch
+- Resolves: rhbz#1368496 - sssd is not able to authenticate with alias
+- Resolves: rhbz#1366470 - sssd: throw away the timestamp cache if
+                           re-initializing the persistent cache
+- Fix deleting non-existent secret
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-30
+- Resolves: rhbz#1362716 - selinux avc denial for vsftp login as ipa user
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-29
+- Resolves: rhbz#1368496 - sssd is not able to authenticate with alias
+
+* Fri Aug 26 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-28
+- Resolves: rhbz#1364033 - sssd exits if clock is adjusted backwards
+                           after boot
+
+* Fri Aug 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-27
+- Resolves: rhbz#1362023 - SSSD fails to start when ldap_user_extra_attrs
+                           contains mail
+
+* Fri Aug 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-26
+- Resolves: rhbz#1368324 - libsss_autofs.so is packaged in two packages
+                           sssd-common and libsss_autofs
+
+* Fri Aug 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-25
+- Fix RPM scriptlet plumbing for the sssd-secrets responder
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Wed Aug 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-24
+- Add socket-activation plumbing for the sssd-secrets responder
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Wed Aug 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-23
+- Own the secrets directory
+- Related: rhbz#1311056 - Add a Secrets as a Service component
+
+* Wed Aug 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-22
+- Resolves: rhbz#1268874 - Add an option to disable checking for trusted
+                           domains in the subdomains provider
+
+* Tue Aug 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-21
+- Resolves: rhbz#1271280 - sssd stores and returns incorrect information
+                           about empty netgroup (ldap-server: 389-ds)
+
+* Tue Aug 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-20
+- Resolves: rhbz#1290500 - [feat] command to manually list
+                           fo_add_server_to_list information
+
+* Tue Aug 16 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-19
+- Add several small fixes related to the config API
+- Related: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Thu Aug 11 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-18
+- Resolves: rhbz#1349900 - gpo search errors out and gpo_cache file is
+                           never created
+
+* Wed Aug 10 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-17
+- Fix regressions in the simple access provider
+- Resolves: rhbz#1360806 - sssd does not start if sub-domain user is used
+                           with simple access provider
+- Apply a number of specfile patches to better match the upstream spefile
+- Related: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+
+* Wed Aug 10 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-16
+- Cherry-pick patches from upstream that fix several regressions
+- Avoid checking local users in all cases
+- Resolves: rhbz#1353951 - sssd_pam leaks file descriptors
+
+* Mon Aug  8 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-15
+- Resolves: rhbz#1364118 - [abrt] [faf] sssd: unknown function():
+                           /usr/libexec/sssd/sssd_nss killed by 11
+- Resolves: rhbz#1361563 - Wrong pam error code returned for password
+                           change in offline mode
+
+* Fri Jul 29 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-14
+- Resolves: rhbz#1309745 - Support multiple principals for IPA users
+
+* Fri Jul 29 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-13
+- Resolves: rhbz#1304992 - Handle overriden name of members in the
+                           memberUid attribute
+
+* Wed Jul 27 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-12
+- handle unresolvable sites more gracefully
+- Resolves: rhbz#1346011 - sssd is looking at a server in the GC of a
+                           subdomain, not the root domain.
+- fix compilation warnings in unit tests
+
+* Wed Jul 27 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-11
+- fix capaths output
+- Resolves: rhbz#1344940 - GSSAPI error causes failures for child domain
+                           user logins across IPA - AD trust
+- also fix Coverity issues in the secrets responder and suppress noisy
+  debug messages when setting the timestamp cache
+
+* Tue Jul 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-10
+- Resolves: rhbz#1356577 - sssctl: Time stamps without time zone information
+
+* Tue Jul 19 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-9
+- Resolves: rhbz#1354414 - New or modified ID-View User overrides are not
+                           visible unless rm -f /var/lib/sss/db/*cache*
+
+* Mon Jul 18 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-8
+- Resolves: rhbz#1211631 - [RFE] Support of UPN for IdM trusted domains
+
+* Thu Jul 14 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-7
+- Resolves: rhbz#1350520 - [abrt] sssd-common: ipa_dyndns_update_send():
+                           sssd_be killed by SIGSEGV
+
+* Wed Jul 13 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-6
+- Resolves: rhbz#1349882 - sssd does not work under non-root user
+- Also cherry-pick a few patches from upstream to fix config schema
+- Related: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Wed Jul 13 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-5
+- Sync a few minor patches from upstream
+- Fix sssctl manpage
+- Fix nss-tests unit test on big-endian machines
+- Fix several issues in the config schema
+- Related: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Wed Jul 13 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-4
+- Bundle http-parser
+- Resolves: rhbz#1311056 - Add a Secrets as a Service component
+
+* Tue Jul 12 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-3
+- Sync a few minor patches from upstream
+- Fix a failover issue
+- Resolves: rhbz#1334749 - sssd fails to mark a connection as bad on
+                           searches that time out
+
+* Mon Jul 11 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-2
+- Explicitly BuildRequire newer ding-libs
+- Resolves: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+
+* Fri Jul  8 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0-1
+- New upstream release 1.14.0
+- Resolves: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+- Resolves: rhbz#835492 - [RFE] SSSD admin tool request - force reload
+- Resolves: rhbz#1072458 - [RFE] SSSD configuration file test tool (sssd_check)
+- Resolves: rhbz#1278691 - Please fix rfc2307 autofs schema defaults
+- Resolves: rhbz#1287209 - default_domain_suffix Appended to User Name
+- Resolves: rhbz#1300663 - Improve sudo protocol to support configurations
+                           with default_domain_suffix
+- Resolves: rhbz#1312275 - Support authentication indicators from IPA
+
+* Thu Jun 30 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0beta1-2
+- Resolves: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+- Resolves: rhbz#790113 - [RFE] "include" directive in sssd.conf
+- Resolves: rhbz#874985 - [RFE] AD provider support for automount lookups
+- Resolves: rhbz#879333 - [RFE] SSSD admin tool request - status overview
+- Resolves: rhbz#1140022 - [RFE]Allow sssd to add a new option that would
+                           specify which server to update DNS with
+- Resolves: rhbz#1290380 - RFE: Improve SSSD performance in large
+                           environments
+- Resolves: rhbz#883886 - sssd: incorrect checks on length values during
+                          packet decoding
+- Resolves: rhbz#988207 - sssd does not detail which line in configuration
+                          is invalid
+- Resolves: rhbz#1007969 - sssd_cache does not remove have an option to
+                           remove the sssd database
+- Resolves: rhbz#1103249 - PAC responder needs much time to process large
+                           group lists
+- Resolves: rhbz#1118257 - Users in ipa groups, added to netgroups are
+                           not resovable
+- Resolves: rhbz#1269018 - Too much logging from sssd_be
+- Resolves: rhbz#1293695 - sssd mixup nested group from AD trusted domains
+- Resolves: rhbz#1308935 - After removing certificate from user in IPA
+                           and even after sss_cache, FindByCertificate
+                           still finds the user
+- Resolves: rhbz#1315766 - SSSD PAM module does not support multiple
+                           password prompts (e.g. Password + Token) with sudo
+- Resolves: rhbz#1316164 - SSSD fails to process GPO from Active Directory
+- Resolves: rhbz#1322458 - sssd_be[11010]: segfault at 0 ip 00007ff889ff61bb
+                           sp 00007ffc7d66a3b0 error 4 in
+                           libsss_ipa.so[7ff889fcf000+5d000]
+
+* Mon Jun 20 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.14.0alpha-1
+- Resolves: rhbz#1290381 - Rebase SSSD to 1.14.x in RHEL-7.3
+- The rebase includes fixes for the following bugzillas:
+- Resolves: rhbz#789477 - [RFE] SUDO: Support the IPA schema
+- Resolves: rhbz#1059972 - RFE: SSSD: Automatically assign new slices for
+                           any AD domain
+- Resolves: rhbz#1233200 - man sssd.conf should clarify details about
+                           subdomain_inherit option.
+- Resolves: rhbz#1238144 - Need better libhbac debuging added to sssd
+- Resolves: rhbz#1265366 - sss_override segfaults when accidentally adding
+                           --help flag to some commands
+- Resolves: rhbz#1269512 - sss_override: memory violation
+- Resolves: rhbz#1278566 - crash in sssd when non-Englsh locale is used
+                           and pam_strerror prints non-ASCII characters
+- Resolves: rhbz#1283686 - groups get deleted from the cache
+- Resolves: rhbz#1290378 - Smart Cards: Certificate in the ID View
+- Resolves: rhbz#1292238 - extreme memory usage in libnfsidmap sss.so
+                           plug-in when resolving groups with many members
+- Resolves: rhbz#1292456 - sssd_be AD segfaults on missing A record
+- Resolves: rhbz#1294670 - Local users with local sudo rules causes
+                           LDAP queries
+- Resolves: rhbz#1296618 - Properly remove OriginalMemberOf attribute in
+                           SSSD cache if user has no secondary groups anymore
+- Resolves: rhbz#1299553 - Cannot retrieve users after upgrade from 1.12
+                           to 1.13
+- Resolves: rhbz#1302821 - Cannot start sssd after switching to non-root
+- Resolves: rhbz#1310877 - [RFE] Support Automatic Renewing of Kerberos
+                           Host Keytabs
+- Resolves: rhbz#1313014 - sssd is not closing sockets properly
+- Resolves: rhbz#1318996 - SSSD does not fail over to next GC
+- Resolves: rhbz#1327270 - local overrides: issues with sub-domain users
+                           and mixed case names
+- Resolves: rhbz#1342547 - sssd-libwbclient: wbcSidsToUnixIds should not
+                           fail on lookup errors
+
+* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-50
+- Build the PAC plugin with krb5-1.14
+- Related: rhbz#1336688 - sssd tries to resolve global catalog servers
+                          from AD forest sub-domains in AD-IPA trust setup
+
+* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-49
+- Resolves: rhbz#1336688 - sssd tries to resolve global catalog servers
+                           from AD forest sub-domains in AD-IPA trust setup
+
+* Tue May 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-48
+- Resolves: rhbz#1290853 - [sssd] Trusted (AD) user's info stays in sssd
+                           cache for much more than expected.
+
+* Mon May 23 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-47
+- Resolves: rhbz#1336706 - sssd_nss memory usage keeps growing when trying
+                           to retrieve non-existing netgroups
+
+* Tue May 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-46
+- Resolves: rhbz#1296902 - In IPA-AD trust environment access is granted
+                           to AD user even if the user is disabled on AD.
+
+* Tue May 17 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-45
+- Resolves: rhbz#1334159 - IPA provider crashes if a netgroup from a
+                           trusted domain is requested
+
+* Mon Apr 18 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-44
+- Resolves: rhbz#1308913 - sssd be memory leak in sssd's memberof plugin
+- More patches from upstream related to the memory leak
+
+* Fri Apr  1 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-43
+- Resolves: rhbz#1308913 - sssd be memory leak in sssd's memberof plugin
+
+* Wed Feb 24 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-42
+- Resolves: rhbz#1300740 - [RFE] IPA: resolve external group memberships
+                           of IPA groups during getgrnam and getgrgid
+
+* Tue Nov 24 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-41
+- Resolves: rhbz#1284814  - sssd: [sysdb_add_user] (0x0400): Error: 17
+
+* Wed Oct 14 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-40
+- Resolves: rhbz#1270827 - local overrides: don't contact server with
+                           overridden name/id
+
+* Wed Oct  7 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-39
+- Resolves: rhbz#1267837 - sssd_be crashed in ipa_srv_ad_acct_lookup_step
+
+* Wed Oct  7 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-38
+- Resolves: rhbz#1267176 - Memory leak / possible DoS with krb auth.
+
+* Wed Oct  7 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-37
+- Resolves: rhbz#1267836 - PAM responder crashed if user was not set
+
+* Wed Sep 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-36
+- Resolves: rhbz#1266107 - AD: Conditional jump or move depends on
+                           uninitialised value
+
+* Wed Sep 23 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-35
+- Resolves: rhbz#1250135 - Detect re-established trusts in the IPA
+                           subdomain code
+
+* Tue Sep 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-34
+- Fix a Coverity warning in dyndns code
+- Resolves: rhbz#1261155 - nsupdate exits on first GSSAPI error instead
+                           of processing other commands
+* Tue Sep 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-33
+- Resolves: rhbz#1261155 - nsupdate exits on first GSSAPI error instead
+                           of processing other commands
+
+* Tue Sep 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-32
+- Resolves: rhbz#1263735 - Could not resolve AD user from root domain
+
+* Tue Sep 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-31
+- Remove -d from sss_override manpage
+- Related: rhbz#1259512 - sss_override : The local override user is not found
+
+* Tue Sep 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-30
+- Patches required for better handling of failover with one-way trusts
+- Related: rhbz#1250135 - Detect re-established trusts in the IPA subdomain
+                          code
+
+* Fri Sep 18 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-29
+- Resolves: rhbz#1263587 - sss_override --name doesn't work with RFC2307
+                           and ghost users
+
+* Fri Sep 18 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-28
+- Resolves: rhbz#1259512 - sss_override : The local override user is not found
+
+* Fri Sep 18 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-27
+- Resolves: rhbz#1260027 - sssd_be memory leak with sssd-ad in GPO code
+
+* Tue Sep  1 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-26
+- Resolves: rhbz#1256398 - sssd cannot resolve user names containing
+                           backslash with ldap provider
+
+* Tue Aug 25 2015 Martin Kosek <mkosek@redhat.com> - 1.13.0-25
+- Resolves: rhbz#1254189 - sss_override contains an extra parameter --debug
+                           but is not listed in the man page or in
+                           the arguments help
+
+* Thu Aug 20 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-24
+- Resolves: rhbz#1254518 - Fix crash in nss responder
+
+* Thu Aug 20 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-23
+- Support import/export for local overrides
+- Support FQDNs for local overrides
+- Resolves: rhbz#1254184 - sss_override does not work correctly when
+                           'use_fully_qualified_names = True'
+
+* Tue Aug 18 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-22
+- Resolves: rhbz#1244950 - Add index for 'objectSIDString' and maybe to
+                           other cache attributes
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-21
+- Resolves: rhbz#1250415 - sssd: p11_child hardening
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-20
+- Related: rhbz#1250135 - Detect re-established trusts in the IPA
+                          subdomain code
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-19
+- Resolves: rhbz#1202724 - [RFE] Add a way to lookup users based on CAC
+                           identity certificates
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-18
+- Resolves: rhbz#1232950 - [IPA/IdM] sudoOrder not honored as expected
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-17
+- Fix wildcard_limit=0
+- Resolves: rhbz#1206571 - [RFE] Expose D-BUS interface
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-16
+- Fix race condition in invalidating the memory cache
+- Related: rhbz#1206575 - [RFE] The fast memory cache should cache initgroups
+
+* Mon Aug 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-15
+- Resolves: rhbz#1249015 - KDC proxy not working with SSSD krb5_use_kdcinfo
+                           enabled
+
+* Thu Aug  6 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-14
+- Bump release number
+- Related: rhbz#1246489 - sss_obfuscate fails with "ImportError: No module
+                          named pysss"
+
+* Thu Aug  6 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-13
+- Fix missing dependency of sssd-tools
+- Resolves: rhbz#1246489 - sss_obfuscate fails with "ImportError: No module
+                           named pysss"
+
+* Wed Aug  5 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-12
+- More memory cache related fixes
+- Related: rhbz#1206575 - [RFE] The fast memory cache should cache initgroups
+
+* Tue Aug  4 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-11
+- Remove binary blob from SC patches as patch(1) can't handle those
+- Related: rhbz#854396 - [RFE] Support for smart cards
+
+* Tue Aug  4 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-10
+- Resolves: rhbz#1244949 - getgrgid for user's UID on a trust client
+                           prevents getpw*
+
+* Tue Aug  4 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-9
+- Fix memory cache integration tests
+- Resolves: rhbz#1206575 - [RFE] The fast memory cache should cache initgroups
+- Resolves: rhbz#854396 - [RFE] Support for smart cards
+
+* Tue Jul 28 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-8
+- Remove OTP from PAM stack correctly
+- Related: rhbz#1200873 - [RFE] Allow smart multi step prompting when
+                          user logs in with password and token code from IPA
+- Handle sssd-owned keytabs when sssd runs as root
+- Related: rhbz#1205144 - RFE: Support one-way trusts for IPA
+
+* Mon Jul 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-7
+- Resolves: rhbz#1183747 - [FEAT] UID and GID mapping on individual clients
+
+* Fri Jul 24 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-6
+- Resolves: rhbz#1206565 - [RFE] Add dualstack and multihomed support
+- Resolves: rhbz#1187146 - If v4 address exists, will not create nonexistant
+                           v6 in ipa domain
+
+* Fri Jul 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-5
+- Resolves: rhbz#1242942 - well-known SID check is broken for NetBIOS prefixes
+
+* Fri Jul 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-4
+- Resolves: rhbz#1234722 - sssd ad provider fails to start in rhel7.2
+
+* Thu Jul 16 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-3
+- Add support for InfoPipe wildcard requests
+- Resolves: rhbz#1206571 - [RFE] Expose D-BUS interface
+
+* Mon Jul  6 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-2
+- Also package the initgr memcache
+- Related: rhbz#1205554 - Rebase SSSD to 1.13.x
+
+* Mon Jul  6 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0-1
+- Rebase to 1.13.0 upstream
+- Related: rhbz#1205554 - Rebase SSSD to 1.13.x
+- Resolves: rhbz#910187 - [RFE] authenticate against cache in SSSD
+- Resolves: rhbz#1206575 - [RFE] The fast memory cache should cache initgroups
+
+* Wed Jul  1 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0.3alpha
+- Don't default to SSSD user
+- Related: rhbz#1205554 - Rebase SSSD to 1.13.x
+
+* Tue Jun 23 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0.2alpha
+- Related: rhbz#1205554 - Rebase SSSD to 1.13.x
+- GPO default should be permissve
+
+* Mon Jun 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.13.0.1alpha
+- Resolves: rhbz#1205554 - Rebase SSSD to 1.13.x
+- Relax the libldb requirement
+- Resolves: rhbz#1221992 - sssd_be segfault at 0 ip sp error 6 in
+                           libtevent.so.0.9.21
+- Resolves: rhbz#1221839 - SSSD group enumeration inconsistent due to
+                           binary SIDs
+- Resolves: rhbz#1219285 - Unable to resolve group memberships for AD
+                           users when using sssd-1.12.2-58.el7_1.6.x86_64
+                           client in combination with
+                           ipa-server-3.0.0-42.el6.x86_64 with AD Trust
+- Resolves: rhbz#1217559 - [RFE] Support GPOs from different domain controllers
+- Resolves: rhbz#1217350 - ignore_group_members doesn't work for subdomains
+- Resolves: rhbz#1217127 - Override for IPA users with login does not list
+                           user all groups
+- Resolves: rhbz#1216285 - autofs provider fails when default_domain_suffix
+                           and use_fully_qualified_names set
+- Resolves: rhbz#1214719 - Group resolution is inconsistent with group
+                           overrides
+- Resolves: rhbz#1214718 - Overridde with --login fails trusted adusers
+                           group membership resolution
+- Resolves: rhbz#1214716 - idoverridegroup for ipa group with --group-name
+                           does not work
+- Resolves: rhbz#1214337 - Overrides with --login work in second attempt
+- Resolves: rhbz#1212489 - Disable the cleanup task by default
+- Resolves: rhbz#1211830 - external users do not resolve with
+                           "default_domain_suffix" set in IPA server sssd.conf
+- Resolves: rhbz#1210854 - Only set the selinux context if the context
+                           differs from the local one
+- Resolves: rhbz#1209483 - When using id_provider=proxy with
+                           auth_provider=ldap, it does not work as expected
+- Resolves: rhbz#1209374 - Man sssd-ad(5) lists Group Policy Management
+                           Editor naming for some policies but not for all
+- Resolves: rhbz#1208507 - sysdb sudo search doesn't escape special characters
+- Resolves: rhbz#1206571 - [RFE] Expose D-BUS interface
+- Resolves: rhbz#1206566 - SSSD does not update Dynamic DNS records if
+                           the IPA domain differs from machine hostname's
+                           domain
+- Resolves: rhbz#1206189 - [bug] sssd always appends default_domain_suffix
+                           when checking for host keys
+- Resolves: rhbz#1204203 - sssd crashes intermittently
+- Resolves: rhbz#1203945 - [FJ7.0 Bug]: getgrent returns error because
+                           sss is written in nsswitch.conf as default
+- Resolves: rhbz#1203642 - GPO access control looks for computer object
+                           in user's domain only
+- Resolves: rhbz#1202245 - SSSD's HBAC processing is not permissive enough
+                           with broken replication entries
+- Resolves: rhbz#1201271 - sssd_nss segfaults if initgroups request is by
+                           UPN and doesn't find anything
+- Resolves: rhbz#1200873 - [RFE] Allow smart multi step prompting when
+                           user logs in with password and token code from IPA
+- Resolves: rhbz#1199541 - Read and use the TTL value when resolving a
+                           SRV query
+- Resolves: rhbz#1199533 - [RFE] Implement background refresh for users,
+                           groups or other cache objects
+- Resolves: rhbz#1199445 - Does sssd-ad use the most suitable attribute
+                           for group name?
+- Resolves: rhbz#1198477 - ccname_file_dummy is not unlinked on error
+- Resolves: rhbz#1187103 - [RFE] User's home directories are not taken
+                           from AD when there is an IPA trust with AD
+- Resolves: rhbz#1185536 - In ipa-ad trust, with 'default_domain_suffix' set
+                           to AD domain, IPA user are not able to log unless
+                           use_fully_qualified_names is set
+- Resolves: rhbz#1175760 - [RFE] Have OpenLDAP lock out ssh keys when
+                           account naturally expires
+- Resolves: rhbz#1163806 - [RFE]ad provider dns_discovery_domain option:
+                           kerberos discovery is not using this option
+- Resolves: rhbz#1205160 - Complain loudly if backend doesn't start due
+                           to missing or invalid keytab
+
+* Wed Apr 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-61
+- Resolves: rhbz#1226119 - Properly handle AD's binary objectGUID
+
+* Wed Apr 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-60
+- Filter out domain-local groups during AD initgroups operation
+- Related: rhbz#1201840 - SSSD downloads too much information when fetching
+                          information about groups
+
+* Wed Apr 22 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-59
+- Resolves: rhbz#1201840 - 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#1202170 - sssd_be segfault on IPA(when auth with AD
+                           trusted domain) client at
+                           src/providers/ipa/ipa_s2n_exop.c:1605
+
+* Tue Mar 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.5
+- Resolves: rhbz#1202170 - sssd_be segfault on IPA(when auth with AD
+                           trusted domain) client at
+                           src/providers/ipa/ipa_s2n_exop.c:1605
+
+* Tue Mar 17 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.4
+- Handle case where there is no default and no rules
+- Resolves: rhbz#1192314 - With empty ipaselinuxusermapdefault security
+                           context on client is staff_u
+
+* Thu Mar  5 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.3
+- Set a pointer in ldap_child to NULL to avoid warnings
+- Related: rhbz#1198759 - ccname_file_dummy is not unlinked on error
+
+* Thu Mar  5 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.2
+- Resolves: rhbz#1199143 - With empty ipaselinuxusermapdefault security
+                           context on client is staff_u
+
+* Thu Mar  5 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-58.1
+- Resolves: rhbz#1198759 - ccname_file_dummy is not unlinked on error
+
+* Tue Feb  3 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-57
+- Run the restart in sssd-common posttrans
+- Explicitly require libwbclient
+- Resolves: rhbz#1187113 - sssd deamon was not running after RHEL 7.1 upgrade
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-56
+- Resolves: rhbz#1187113 - sssd deamon was not running after RHEL 7.1 upgrade
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-55
+- Fix endianess bug in fill_id()
+- Related: rhbz#1109331 - [RFE] Allow SSSD to be used with smbd shares
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-54
+- Resolves: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Fri Jan 30 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-53
+- Resolves: rhbz#1187192 - IPA initgroups don't work correctly in
+                           non-default view
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-52
+- Resolves: rhbz#1184982 - Need to set different umask in selinux_child
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-51
+- Bump the release number
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-50
+- Add a patch dependency
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-49
+- Process ghost members only once
+- Fix processing of universal groups with members from different domains
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Tue Jan 27 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-48
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Fri Jan 23 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-47
+- Resolves: rhbz#1185188 - Uncached SIDs cannot be resolved
+
+* Fri Jan 23 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-46
+- Handle GID override in MPG domains
+- Handle views with mixed-case domains
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Wed Jan 21 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-45
+- Open socket to the PAC responder in krb5_child before dropping root
+- Related: rhbz#1184140 - Users saved throug extop don't have the
+                          originalMemberOf attribute
+
+* Tue Jan 20 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-44
+- Resolves: rhbz#1184140 - Users saved throug extop don't have the
+                           originalMemberOf attribute
+
+* Mon Jan 19 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-43
+- Resolves: rhbz#1182183 - pam_sss(sshd:auth): authentication failure with
+                           user from AD
+
+* Wed Jan 14 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-42
+- Resolves: rhbz#889206 - On clock skew sssd returns system error
+
+* Wed Jan 14 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-41
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Tue Jan 13 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-40
+- Resolves: rhbz#1177140 - gpo_child fails if "log level" is enabled in smb.conf
+- Related: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Fri Dec 19 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-39
+- Resolves: rhbz#1175408 - SSSD should not fail authentication when only allow
+                           rules are used
+- Resolves: rhbz#1175705 - sssd-libwbclient conflicts with Samba's and causes
+                           crash in wbinfo
+                           - in addition to the patch libwbclient.so is
+                             filtered out of the Provides list of the package
+
+* Wed Dec 17 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-38
+- Resolves: rhbz#1171215 - Crash in function get_object_from_cache
+- Resolves: rhbz#1171383 - getent fails for posix group with AD users after
+                           login
+- Resolves: rhbz#1171382 - getent of AD universal group fails after group users
+                           login
+- Resolves: rhbz#1170300 - Access is not rejected for disabled domain
+- Resolves: rhbz#1162486 - Error processing external groups with
+                           getgrnam/getgrgid in the server mode
+- Resolves: rhbz#1168904 - gid is overridden by uid in default trust view
+
+* Wed Dec 17 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-37
+- Resolves: rhbz#1169459 - sssd-ad: The man page description to enable GPO HBAC
+                           Policies are unclear
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Mon Dec 15 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-35
+- Rebuild to add several forgotten Patch entries
+- Resolves: rhbz#1173482 - MAN: Document that only user names are checked
+                           for pam_trusted_users
+- Resolves: rhbz#1167324 - pam_sss domains option: User auth should fail
+                           when domains=<emtpy value>
+
+* Sun Dec 14 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-35
+- Remove Coverity warnings in krb5_child code
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Sat Dec 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-34
+- Resolves: rhbz#1173482 - MAN: Document that only user names are checked
+                           for pam_trusted_users
+- Resolves: rhbz#1167324 - pam_sss domains option: User auth should fail
+                           when domains=<emtpy value>
+
+* Sat Dec 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-33
+- Don't error out on chpass with OTPs
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Mon Dec  8 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-32
+- Resolves: rhbz#1124320 - [FJ7.0 Bug]: getgrent returns error because sss
+                           is written in nsswitch.conf as default.
+
+* Mon Dec  8 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-31
+- Resolves: rhbz#1169739 - selinuxusermap rule does not apply to trusted
+                           AD users
+- Enable running unit tests without cmocka
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Dec  3 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-30
+- krb5_child and ldap_child do not call Kerberos calls as root
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Dec  3 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-29
+- Resolves: rhbz#1168735 - The Kerberos provider is not properly views-aware
+
+* Wed Nov 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-28
+- Fix typo in libwbclient-devel alternatives invocation
+- Related: rhbz#1109331 - [RFE] Allow SSSD to be used with smbd shares
+
+* Wed Nov 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-27
+- Resolves: rhbz#1166727 - pam_sss domains option: Untrusted users from
+                           the same domain are allowed to auth.
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-26
+- Handle migrating clients between views
+- Related: rhbz#891984 - [RFE] ID Views: Support migration from the sync
+                         solution to the trust solution
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-25
+- Use alternatives for libwbclient
+- Related: rhbz#1109331 - [RFE] Allow SSSD to be used with smbd shares
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-24
+- Resolves: rhbz#1165794 - sssd does not work with custom value of option
+                           re_expression
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-23
+- Add an option that describes where to put generated krb5 files to
+- Related: rhbz#1135043 - [RFE] Implement localauth plugin for MIT krb5 1.12
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-22
+- Handle IPA group names returned from the extop plugin
+- Related: rhbz#891984 - [RFE] ID Views: Support migration from the sync
+                         solution to the trust solution
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-21
+- Resolves: rhbz#1165792 - automount segfaults in sss_nss_check_header
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-20
+- Resolves: rhbz#1163742 - "debug_timestamps = false" and "debug_microseconds
+                           = true" do not work after enabling journald
+                           with sssd.
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-19
+- Resolves: rhbz#1153593 - Manpage description of case_sensitive=preserving
+                          is incomplete
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-18
+- Support views for IPA users
+- Related: rhbz#891984 - [RFE] ID Views: Support migration from the sync
+                         solution to the trust solution
+
+* Thu Nov 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-17
+- Update man page to clarify TGs should be disabled with a custom search base
+- Related: rhbz#1161741 - TokenGroups for LDAP provider breaks in corner cases
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-16
+- Use upstreamed patches for the rootless sssd
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-15
+- Resolves: rhbz#1153603 - Proxy Provider: Fails to lookup case sensitive
+                           users and groups with case_sensitive=preserving
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-14
+- Resolves: rhbz#1161741 - TokenGroups for LDAP provider breaks in corner cases
+
+* Wed Nov 19 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-13
+- Resolves: rhbz#1162480 - dereferencing failure against openldap server
+
+* Wed Nov 12 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-12
+- Move adding the user from pretrans to pre, copy adding the user to
+  sssd-krb5-common and sssd-ipa as well in order to work around yum
+  ordering issue
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Tue Nov 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-11
+- Resolves: rhbz#1113783 - sssd should run under unprivileged user
+
+* Fri Nov  7 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-10
+- Fix two regressions in the new selinux_child process
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+- Resolves: rhbz#1132365 - Remove password from the PAM stack if OTP is used
+
+* Wed Nov  5 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-9
+- Include the ldap_child and selinux_child patches for rootless sssd
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Nov  5 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-8
+- Support overriding SSH public keys with views
+- Support extended attributes via the extop plugin
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+- Resolves: rhbz#1137010 - disable midpoint refresh for netgroups if ptask
+                           refresh is enabled
+
+* Thu Oct 30 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-7
+- Resolves: rhbz#1153518 - service lookups returned in lowercase with
+                           case_sensitive=preserving
+- Resolves: rhbz#1158809 - Enumeration shows only a single group multiple
+                           times
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-6
+- Include the responder and packaging patches for rootless sssd
+- Related: rhbz#1113783 - sssd should run under unprivileged user
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-5
+- Amend the sssd-ldap man page with info about lockout setup
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+- Resolves: rhbz#1137014 - Shell fallback mechanism in SSSD 
+- Resolves: rhbz#790854 - 4 functions with reference leaks within sssd (src/python/pyhbac.c) 
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-4
+- Fix regressions caused by views patches when SSSD is connected to a
+  pre-4.0 IPA server
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-3
+- Add the low-level server changes for running as unprivileged user
+- Package the libsss_semange library needed for SELinux label changes
+- Related: rhbz#1113783 - sssd should run under unprivileged user 
+- Resolves: rhbz#1113784 - sssd should audit selinux user map changes 
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-2
+- Use libsemanage for SELinux label changes
+- Resolves: rhbz#1113784 - sssd should audit selinux user map changes 
+
+* Mon Oct 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-1
+- Rebase SSSD to 1.12.2
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Thu Oct 09 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-2
+- Sync with upstream
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Thu Sep 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-1
+- Rebuild against ding-libs with fixed SONAME
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Tue Sep  9 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-1
+- Rebase SSSD to 1.12.1
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Fri Sep 05 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-3
+- Require ldb 2.1.17
+- Related: rhbz#1133914 - Rebase libldb to version 1.1.17 or newer
+
+* Fri Aug 08 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-2
+- Fix fully qualified IFP lookups
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Thu Jul 24 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-1
+- Rebase SSSD to 1.12.0
+- Related: rhbz#1109756 - Rebase SSSD to 1.12
+
+* Wed May 21 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-70
+- Squash in upstream review comments about the PAC patch
+- Related: rhbz#1097286 - Expanding home directory fails when the request
+                          comes from the PAC responder
+
+* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-69
+- Backport a patch to allow krb5-utils-test to run as root
+- Related: rhbz#1097286 - Expanding home directory fails when the request
+                          comes from the PAC responder
+
+* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-68
+- Resolves: rhbz#1097286 - Expanding home directory fails when the request
+                           comes from the PAC responder
+
+* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-67
+- Fix a DEBUG message, backport two related fixes
+- Related: rhbz#1090653 - segfault in sssd_be when second domain tree
+                           users are queried while joined to child domain
+
+* Tue May 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-66
+- Resolves: rhbz#1090653 - segfault in sssd_be when second domain tree
+                           users are queried while joined to child domain
+
+* Wed Apr 02 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-65
+- Resolves: rhbz#1082191 - RHEL7 IPA selinuxusermap hbac rule not always
+                           matching
+
+* Wed Apr 02 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-64
+- Resolves: rhbz#1077328 - other subdomains are unavailable when joined
+                           to a subdomain in the ad forest
+
+* Wed Mar 26 2014 Sumit Bose <sbose@redhat.com> - 1.11.2-63
+- Resolves: rhbz#1078877 - Valgrind: Invalid read of int while processing
+                           netgroup
+
+* Wed Mar 26 2014 Sumit Bose <sbose@redhat.com> - 1.11.2-62
+- Resolves: rhbz#1075092 - Password change w/ OTP generates error on success
+
+* Fri Mar 21 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-61
+- Resolves: rhbz#1078840 -  Error during password change
+
+* Thu Mar 13 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-60
+- Resolves: rhbz#1075663 - SSSD should create the SELinux mapping file
+                           with format expected by pam_selinux
+
+* Wed Mar 12 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-59
+- Related: rhbz#1075621 - Add another Kerberos error code to trigger IPA
+                          password migration
+
+* Tue Mar 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-58
+- Related: rhbz#1073635 - IPA SELinux code looks for the host in the wrong
+                          sysdb subdir when a trusted user logs in
+
+* Tue Mar 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-57
+- Related: rhbz#1066096 - not retrieving homedirs of AD users with
+                          posix attributes
+
+* Mon Mar 10 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-56
+- Related: rhbz#1072995 -  AD group inconsistency when using AD provider
+                           in sssd-1.11-40
+
+* Mon Mar 10 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-55
+- Resolves: rhbz#1073631 - sssd fails to handle expired passwords
+                           when OTP is used
+
+* Tue Mar 04 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-54
+- Resolves: rhbz#1072067 - SSSD Does not cache SELinux map from FreeIPA
+                           correctly
+
+* Tue Mar 04 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-53
+- Resolves: rhbz#1071903 - ipa-server-mode: Use lower-case user name
+                           component in home dir path
+
+* Tue Mar 04 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-52
+- Resolves: rhbz#1068725 - Evaluate usage of sudo LDAP provider together
+                           with the AD provider
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-51
+- Fix idmap documentation
+- Bump idmap version info
+- Related: rhbz#1067361 - Check IPA idranges before saving them to the cache
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-50
+- Pull some follow up man page fixes from upstream
+- Related: rhbz#1060389 - Document that `sssd` cache needs to be cleared
+                          manually, if ID mapping configuration changes
+- Related: rhbz#1064908 - MAN: Remove misleading memberof example from
+                          ldap_access_filter example
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-49
+- Resolves: rhbz#1060389 - Document that `sssd` cache needs to be cleared
+                           manually, if ID mapping configuration changes
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-48
+- Resolves: rhbz#1064908 - MAN: Remove misleading memberof example from
+                           ldap_access_filter example
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-47
+- Resolves: rhbz#1068723 - Setting int option to 0 yields the default value
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-46
+- Resolves: rhbz#1067361 - Check IPA idranges before saving them to the cache
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-45
+- Resolves: rhbz#1067476 - SSSD pam module accepts usernames with leading
+                           spaces
+
+* Wed Feb 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-44
+- Resolves: rhbz#1033069 - Configuring two different provider types might
+                           start two parallel enumeration tasks
+
+* Mon Feb 17 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-43
+- Resolves: rhbz#1068640 - 'IPA: Don't call tevent_req_post outside _send'
+                           should be added to RHEL7
+
+* Mon Feb 17 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-42
+- Resolves: rhbz#1063977 - SSSD needs to enable FAST by default
+
+* Mon Feb 17 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-41
+- Resolves: rhbz#1064582 - sss_cache does not reset the SYSDB_INITGR_EXPIRE
+                           attribute when expiring users
+
+* Wed Feb 12 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-40
+- Resolves: rhbz#1033081 - Implement heuristics to detect if POSIX attributes
+                           have been replicated to the Global Catalog or not
+
+* Wed Feb 12 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-39
+- Resolves: rhbz#872177 - [RFE] subdomain homedir template should be
+                          configurable/use flatname by default
+
+* Wed Feb 12 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-38
+- Resolves: rhbz#1059753 - Warn with a user-friendly error message when
+                           permissions on sssd.conf are incorrect
+
+* Wed Jan 29 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-37
+- Resolves: rhbz#1037653 - Enabling ldap_id_mapping doesn't exclude
+                           uidNumber in filter
+
+* Wed Jan 29 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-36
+- Resolves: rhbz#1059253 - Man page states default_shell option supersedes
+                           other shell options but in fact override_shell does.
+- Use the right domain for AD site resolution
+- Related: rhbz#743503 -  [RFE] sssd should support DNS sites
+
+* Wed Jan 29 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-35
+- Resolves: rhbz#1028039 - AD Enumeration reads data from LDAP while
+                           regular lookups connect to GC
+
+* Wed Jan 29 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-34
+- Resolves: rhbz#877438 - sudoNotBefore/sudoNotAfter not supported by sssd
+                          sudoers plugin
+
+* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 1.11.2-33
+- Mass rebuild 2014-01-24
+
+* Fri Jan 24 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-32
+- Resolves: rhbz#1054639 - sssd_be aborts a request if it doesn't match
+                           any configured idmap domain
+
+* Fri Jan 24 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-31
+- Resolves: rhbz#1054899 - explicitly suggest krb5_auth_timeout in a loud
+                           DEBUG message in case Kerberos authentication
+                           times out
+
+* Wed Jan 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-30
+- Resolves: rhbz#1037653 - Enabling ldap_id_mapping doesn't exclude
+                           uidNumber in filter
+
+* Mon Jan 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-29
+- Resolves: rhbz#1051360 - [FJ7.0 Bug]: [REG] sssd_be crashes when
+                           ldap_search_base cannot be parsed.
+- Fix a typo in the man page
+- Related: rhbz#1034920 - RHEL7 sssd not setting IPA AD trusted user homedir
+
+* Mon Jan 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-28
+- Resolves: rhbz#1054639 - sssd_be aborts a request if it doesn't match
+                           any configured idmap domain
+- Fix return value when searching for AD domain flat names
+- Resolves: rhbz#1048102 - Access denied for users from gc domain when
+                           using format DOMAIN\user
+
+* Wed Jan 15 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-27
+- Resolves: rhbz#1034920 - RHEL7 sssd not setting IPA AD trusted user homedir
+
+* Wed Jan 15 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-26
+- Resolves: rhbz#1048102 - Access denied for users from gc domain when
+                           using format DOMAIN\user
+
+* Wed Jan 15 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-25
+- Resolves: rhbz#1053106 - sssd ad trusted sub domain do not inherit
+                           fallbacks and overrides settings
+
+* Thu Jan 09 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-24
+- Resolves: rhbz#1051016 - FAST does not work in SSSD 1.11.2 in Fedora 20
+
+* Thu Jan 09 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-23
+- Resolves: rhbz#1033133 - "System Error" when invalid ad_access_filter
+                            is used
+
+* Thu Jan 09 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-22
+- Resolves: rhbz#1032983 - sssd_be crashes when ad_access_filter uses
+                           FOREST keyword.
+- Fix two memory leaks in the PAC responder (Related: rhbz#991065)
+
+* Wed Jan 08 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-21
+- Resolves: rhbz#1048184 - Group lookup does not return member with multiple
+                           names after user lookup
+
+* Wed Jan 08 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-20
+- Resolves: rhbz#1049533 - Group membership lookup issue
+
+* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 1.11.2-19
+- Mass rebuild 2013-12-27
+
+* Thu Dec 19 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-18
+- Resolves: rhbz#894068 - sss_cache doesn't support subdomains
+
+* Thu Dec 19 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-17
+- Re-initialize subdomains after provider startup
+- Related: rhbz#1038637 - If SSSD starts offline, subdomains list is
+                          never read
+
+* Thu Dec 19 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-16
+- The AD provider is able to resolve group memberships for groups with
+  Global and Universal scope
+- Related: rhbz#1033096 - tokenGroups do not work reliable with Global
+                          Catalog
+
+* Wed Dec 18 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-15
+- Resolves: rhbz#1033096 - tokenGroups do not work reliable with Global
+                           Catalog
+- Resolves: rhbz#1030483 - Individual group search returned multiple
+                           results in GC lookups
+
+* Wed Dec 18 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-14
+- Resolves: rhbz#1040969 - sssd_nss grows memory footprint when netgroups
+                           are requested
+
+* Thu Dec 12 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-13
+- Resolves: rhbz#1023409 - Valgrind sssd "Syscall param
+                           socketcall.sendto(msg) points to uninitialised
+                           byte(s)"
+
+* Thu Dec 12 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-12
+- Resolves: rhbz#1037936 - sssd_be crashes occasionally
+
+* Thu Dec 12 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-11
+- Resolves: rhbz#1038637 - If SSSD starts offline, subdomains list is
+                           never read
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-10
+- Resolves: rhbz#1029631 - sssd_be crashes on manually adding a cleartext
+                           password to ldap_default_authtok
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-9
+- Resolves: rhbz#1036758 - SSSD: Allow for custom attributes in RDN when
+                           using id_provider = proxy
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-8
+- Resolves: rhbz#1034050 - Errors in domain log when saving user to sysdb
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-7
+- Resolves: rhbz#1036157 - sssd can't retrieve auto.master when using the
+                           "default_domain_suffix" option in
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-6
+- Resolves: rhbz#1028057 - Improve detection of the right domain when
+                           processing group with members from several domains
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-5
+- Resolves: rhbz#1033084 - sssd_be segfaults if empty grop is resolved
+                           using ad_matching_rule
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-4
+- Resolves: rhbz#1031562 - Incorrect mention of access_filter in sssd-ad
+                           manpage
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-3
+- Resolves: rhbz#991549 - sssd fails to retrieve netgroups with multiple
+                          CN attributes
+
+* Mon Dec  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-2
+- Skip netgroups that don't provide well-formed triplets
+- Related: rhbz#991549 -  sssd fails to retrieve netgroups with multiple
+                          CN attributes
+
+* Wed Oct 30 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-1
+- New upstream release 1.11.2
+- Remove upstreamed patches
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.2
+- Resolves: rhbz#991065
+
+* Fri Sep 27 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.1-2
+- Resolves: rhbz#1019882 - RHEL7 ipa ad trusted user lookups failed with
+                           sssd_be crash
+- Resolves: rhbz#1002597 - ad: unable to resolve membership when user is
+                           from different domain than group
+
+* Fri Sep 27 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.1-1
+- New upstream release 1.11.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.1
+- Resolves: rhbz#991065 - Rebase SSSD to 1.11.0
+
+* Thu Aug 29 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0-1
+- New upstream release 1.11.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.0
+- Resolves: rhbz#991065
+
+* Fri Aug 02 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0.1beta2
+- New upstream release 1.11 beta 2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.0beta2
+- Related: rhbz#991065
+
+* Wed Jul 31 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.1-5
+- Resolves: #906427 - Do not use %%{_lib} in specfile for the nss and
+                      pam libraries
+
+* Wed Jul 31 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.1-4
+- Resolves: #983587 - sss_debuglevel did not increase verbosity in
+                      sssd_pac.log
+
+* Wed Jul 31 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.1-3
+- Resolves: #983580 - Netgroups should ignore the 'use_fully_qualified_names'
+                      setting
+
+* Wed Jul 31 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.1-2
+- Apply several important fixes from upstream 1.10 branch
+- Related: #966757 - SSSD failover doesn't work if the first DNS server
+                     in resolv.conf is unavailable
+
+* Thu Jul 18 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.1-1
+- New upstream release 1.10.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.1
+
+* Wed Jul 10 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-18
+- Remove libcmocka dependency
+
+* Mon Jul 08 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-17
+- sssd-tools should require sssd-common, not sssd
+
+* Tue Jul 02 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.10.0-16
+- Move sssd_pac to the sssd-ipa and sssd-ad subpackages
+- Trim out RHEL5-specific macros since we don't build on RHEL 5
+- Trim out macros for Fedora older than F18
+- Update libldb requirement to 1.1.16
+- Trim RPM changelog down to the last year
+
+* Tue Jul 02 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.10.0-15
+- Move sssd_pac to the sssd-krb5 subpackage
+
+* Mon Jul 01 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.10.0-14
+- Fix Obsoletes: to account for dist tag
+- Convert post and pre scripts to run on the sssd-common subpackage
+- Remove old conversion from SYSV
+
+* Thu Jun 27 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-13
+- New upstream release 1.10
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0
+
+* Mon Jun 17 2013 Dan Horák <dan[at]danny.cz> - 1.10.0-12.beta2
+- the cmocka toolkit exists only on selected arches
+
+* Sun Jun 16 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-11.beta2
+- Apply a number of patches from upstream to fix issues found post-beta,
+  in particular:
+  -- segfault with a high DEBUG level
+  -- Fix IPA password migration (upstream #1873)
+  -- Fix fail over when retrying SRV resolution (upstream #1886)
+
+* Thu Jun 13 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-10.beta2
+- Only BuildRequire libcmocka on Fedora
+
+* Thu Jun 13 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-9.beta2
+- Fix typo in Requires that prevented an upgrade (#973916)
+- Use a hardcoded version in Conflicts, not less-than-current
+
+* Wed Jun 12 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-8.beta2
+- New upstream release 1.10 beta2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0beta2
+- BuildRequire libcmocka-devel in order to run all upstream tests during build
+- BuildRequire libnl3 instead of libnl1
+- No longer BuildRequire initscripts, we no longer use /sbin/service
+- Remove explicit krb5-libs >= 1.10 requires; this platform doensn't carry any
+  older krb5-libs version
+
+* Thu Jun 06 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-7.beta1
+- Enable hardened build for RHEL7
+
+* Fri May 24 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-6.beta1
+- Apply a couple of patches from upstream git that resolve crashes when
+  ID mapping object was not initialized properly but needed later
+
+* Tue May 14 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-5.beta1
+- Resolves: rhbz#961357 - Missing dyndns_update entry in sssd.conf during
+                          realm join
+- Resolves: rhbz#961278 - Login failure: Enterprise Principal enabled by
+                          default for AD Provider
+- Resolves: rhbz#961251 - sssd does not create user's krb5 ccache dir/file
+                          parent directory when logging in
+
+* Tue May  7 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-4.beta1
+- Explicitly Require libini_config >= 1.0.0.1 to work around a SONAME bug
+  in ding-libs
+- Fix SSH integration with fully-qualified domains
+- Add the ability to dynamically discover the NetBIOS name
+
+* Fri May  3 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-3.beta1
+- New upstream release 1.10 beta1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0beta1
+
+* Wed Apr 17 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-2.alpha1
+- Add a patch to fix krb5 ccache creation issue with krb5 1.11
+
+* Tue Apr  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-1.alpha1
+- New upstream release 1.10 alpha1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0alpha1
+
+* Fri Mar 01 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.9.4-9
+- Split internal helper libraries into a shared object
+- Significantly reduce disk-space usage
+
+* Thu Feb 14 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-8
+- Fix the Kerberos password expiration warning (#912223)
+
+* Thu Feb 14 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-7
+- Do not write out dots in the domain-realm mapping file (#905650)
+
+* Mon Feb 11 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-6
+- Include upstream patch to build with krb5-1.11
+
+* Thu Feb 07 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-5
+- Rebuild against new libldb
+
+* Mon Feb 04 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-4
+- Fix build with new automake versions
+
+* Wed Jan 30 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-3
+- Recreate Kerberos ccache directory if it's missing
+- Resolves: rhbz#853558 - [sssd[krb5_child[PID]]]: Credential cache
+                          directory /run/user/UID/ccdir does not exist
+
+* Tue Jan 29 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-2
+- Fix changelog dates to make F19 rpmbuild happy
+
+* Mon Jan 28 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-1
+- New upstream release 1.9.4
+
+* Thu Dec 06 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.3-1
+- New upstream release 1.9.3
+
+* Tue Oct 30 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-5
+- Resolve groups from AD correctly
+
+* Tue Oct 30 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-4
+- Check the validity of naming context
+
+* Thu Oct 18 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-3
+- Move the sss_cache tool to the main package
+
+* Sun Oct 14 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-2
+- Include the 1.9.2 tarball
+
+* Sun Oct 14 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-1
+- New upstream release 1.9.2
+
+* Sun Oct 07 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.1-1
+- New upstream release 1.9.1
+
+* Wed Oct 03 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-24
+- require the latest libldb
+
+* Tue Sep 25 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-24
+- Use mcpath insted of mcachepath macro to be consistent with
+  upsteam spec file
+
+* Tue Sep 25 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-23
+- New upstream release 1.9.0
+
+* Fri Sep 14 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-22.rc1
+- New upstream release 1.9.0 rc1
+
+* Thu Sep 06 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-21.beta7
+- New upstream release 1.9.0 beta7
+- obsoletes patches #1-#3
+
+* Mon Sep 03 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-20.beta6
+- Rebuild against libldb 1.12
+
+* Tue Aug 28 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-19.beta6
+- Rebuild against libldb 1.11
+
+* Fri Aug 24 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-18.beta6
+- Change the default ccache location to DIR:/run/user/${UID}/krb5cc
+  and patch man page accordingly
+- Resolves: rhbz#851304
+
+* Mon Aug 20 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-17.beta6
+- Rebuild against libldb 1.10
+
+* Fri Aug 17 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-16.beta6
+- Only create the SELinux login file if there are SELinux mappings on
+  the IPA server
+
+* Fri Aug 10 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-14.beta6
+- Don't discard HBAC rule processing result if SELinux is on
+  Resolves: rhbz#846792 (CVE-2012-3462)
+
+* Thu Aug 02 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-13.beta6
+- New upstream release 1.9.0 beta 6
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta6
+- A new option, override_shell was added. If this option is set, all users
+  managed by SSSD will have their shell set to its value.
+- Fixes for the support for setting default SELinux user context from FreeIPA.
+- Fixed a regression introduced in beta 5 that broke LDAP SASL binds
+- The SSSD supports the concept of a Primary Server and a Back Up Server in
+  failover
+- A new command-line tool sss_seed is available to help prime the cache with
+  a user record when deploying a new machine
+- SSSD is now able to discover and save the domain-realm mappings
+  between an IPA server and a trusted Active Directory server.
+- Packaging changes to fix ldconfig usage in subpackages (#843995)
+- Rebuild against libldb 1.1.9
+
+* Fri Jul 27 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.9.0-13.beta5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Thu Jul 19 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-12.beta5
+- New upstream release 1.9.0 beta 5
+- Obsoletes the patch for missing DP_OPTION_TERMINATOR in AD provider options
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta5
+- Many fixes for the support for setting default SELinux user context from
+  FreeIPA, most notably fixed the specificity evaluation
+- Fixed an incorrect default in the krb5_canonicalize option of the AD
+  provider which was preventing password change operation
+- The shadowLastChange attribute value is now correctly updated with the
+  number of days since the Epoch, not seconds
+
+* Mon Jul 16 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-11.beta4
+- Fix broken ARM build
+- Add missing DP_OPTION_TERMINATOR in AD provider options
+
+* Wed Jul 11 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-10.beta4
+- Own several directories create during make install (#839782)
+
+* Wed Jul 11 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-9.beta4
+- New upstream release 1.9.0 beta 4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta4
+- Add a new AD provider to improve integration with Active Directory 2008 R2
+  or later servers
+- SUDO integration was completely rewritten. The new implementation works
+  with multiple domains and uses an improved refresh mechanism to download
+  only the necessary rules
+- The IPA authentication provider now supports subdomains
+- Fixed regression for setups that were setting default_tkt_enctypes
+  manually by reverting a previous workaround.
+
+* Mon Jun 25 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-8.beta3
+- New upstream release 1.9.0 beta 3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta3
+- Add a new PAC responder for dealing with cross-realm Kerberos trusts
+- Terminate idle connections to the NSS and PAM responders
+
+* Wed Jun 20 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-7.beta2
+- Switch unicode library from libunistring to Glib
+- Drop unnecessary explicit Requires on keyutils
+- Guarantee that versioned Requires include the correct architecture
+
+* Mon Jun 18 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-6.beta2
+- Fix accidental disabling of the DIR cache support
+
+* Fri Jun 15 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-5.beta2
+- New upstream release 1.9.0 beta 2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta2
+- Add support for the Kerberos DIR cache for storing multiple TGTs
+  automatically
+- Major performance enhancement when storing large groups in the cache
+- Major performance enhancement when performing initgroups() against Active
+  Directory
+- SSSDConfig data file default locations can now be set during configure for
+  easier packaging
+
+* Tue May 29 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-4.beta1
+- Fix regression in endianness patch
+
+* Tue May 29 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-3.beta1
+- Rebuild SSSD against ding-libs 0.3.0beta1
+- Fix endianness bug in service map protocol
+
+* Thu May 24 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-2.beta1
+- Fix several regressions since 1.5.x
+- Ensure that the RPM creates the /var/lib/sss/mc directory
+- Add support for Netscape password warning expiration control
+- Rebuild against libldb 1.1.6
+
+* Fri May 11 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-1.beta1
+- New upstream release 1.9.0 beta 1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta1
+- Add native support for autofs to the IPA provider
+- Support for ID-mapping when connecting to Active Directory
+- Support for handling very large (> 1500 users) groups in Active Directory
+- Support for sub-domains (will be used for dealing with trust relationships)
+- Add a new fast in-memory cache to speed up lookups of cached data on
+  repeated requests
+
+* Thu May 03 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.3-11
+- New upstream release 1.8.3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.3
+- Numerous manpage and translation updates
+- LDAP: Handle situations where the RootDSE isn't available anonymously
+- LDAP: Fix regression for users using non-standard LDAP attributes for user
+  information
+
+* Mon Apr 09 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.2-10
+- New upstream release 1.8.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.2
+- Several fixes to case-insensitive domain functions
+- Fix for GSSAPI binds when the keytab contains unrelated principals
+- Fixed several segfaults
+- Workarounds added for LDAP servers with unreadable RootDSE
+- SSH knownhostproxy will no longer enter an infinite loop preventing login
+- The provided SYSV init script now starts SSSD earlier at startup and stops
+  it later during shutdown
+- Assorted minor fixes for issues discovered by static analysis tools
+
+* Mon Mar 26 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.1-9
+- Don't duplicate libsss_autofs.so in two packages
+- Set explicit package contents instead of globbing
+
+* Wed Mar 21 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.1-8
+- Fix uninitialized value bug causing crashes throughout the code
+- Resolves: rhbz#804783 - [abrt] Segfault during LDAP 'services' lookup
+
+* Mon Mar 12 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.1-7
+- New upstream release 1.8.1
+- Resolve issue where we could enter an infinite loop trying to connect to an
+  auth server
+- Fix serious issue with complex (3+ levels) nested groups
+- Fix netgroup support for case-insensitivity and aliases
+- Fix serious issue with lookup bundling resulting in requests never
+  completing
+- IPA provider will now check the value of nsAccountLock during pam_acct_mgmt
+  in addition to pam_authenticate
+- Fix several regressions in the proxy provider
+- Resolves: rhbz#743133 - Performance regression with Kerberos authentication
+                          against AD
+- Resolves: rhbz#799031 - --debug option for sss_debuglevel doesn't work
+
+* Tue Feb 28 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-6
+- New upstream release 1.8.0
+- Support for the service map in NSS
+- Support for setting default SELinux user context from FreeIPA
+- Support for retrieving SSH user and host keys from LDAP (Experimental)
+- Support for caching autofs LDAP requests (Experimental)
+- Support for caching SUDO rules (Experimental)
+- Include the IPA AutoFS provider
+- Fixed several memory-corruption bugs
+- Fixed a regression in group enumeration since 1.7.0
+- Fixed a regression in the proxy provider
+- Resolves: rhbz#741981 - Separate Cache Timeouts for SSSD
+- Resolves: rhbz#797968 - sssd_be: The requested tar get is not configured is
+                          logged at each login
+- Resolves: rhbz#754114 - [abrt] sssd-1.6.3-1.fc16: ping_check: Process
+                          /usr/sbin/sssd was killed by signal 11 (SIGSEGV)
+- Resolves: rhbz#743133 - Performance regression with Kerberos authentication
+                          against AD
+- Resolves: rhbz#773706 - SSSD fails during autodetection of search bases for
+                          new LDAP features
+- Resolves: rhbz#786957 - sssd and kerberos should change the default location for create the Credential Cashes to /run/usr/USERNAME/krb5cc
+
+* Wed Feb 22 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-5.beta3
+- Change default kerberos credential cache location to /run/user/<username>
+
+* Wed Feb 15 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-4.beta3
+- New upstream release 1.8.0 beta 3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.0beta3
+- Fixed a regression in group enumeration since 1.7.0
+- Fixed several memory-corruption bugs
+- Finalized the ABI for the autofs support
+- Fixed a regression in the proxy provider
+
+* Fri Feb 10 2012 Petr Pisar <ppisar@redhat.com> - 1.8.0-3.beta2
+- Rebuild against PCRE 8.30
+
+* Mon Feb 06 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-1.beta2
+- New upstream release
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.0beta2
+- Fix two minor manpage bugs
+- Include the IPA AutoFS provider
+
+* Mon Feb 06 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-1.beta1
+- New upstream release
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.0beta1
+- Support for the service map in NSS
+- Support for setting default SELinux user context from FreeIPA
+- Support for retrieving SSH user and host keys from LDAP (Experimental)
+- Support for caching autofs LDAP requests (Experimental)
+- Support for caching SUDO rules (Experimental)
+
+* Wed Feb 01 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-5
+- Resolves: rhbz#773706 - SSSD fails during autodetection of search bases for
+                          new LDAP features - fix netgroups and sudo as well
+
+* Wed Feb 01 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-4
+- Fixes a serious memory hierarchy bug causing unpredictable behavior in the
+  LDAP provider.
+
+* Wed Feb 01 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-3
+- Resolves: rhbz#773706 - SSSD fails during autodetection of search bases for
+                          new LDAP features
+
+* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Thu Dec 22 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-1
+- New upstream release 1.7.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.7.0
+- Support for case-insensitive domains
+- Support for multiple search bases in the LDAP provider
+- Support for the native FreeIPA netgroup implementation
+- Reliability improvements to the process monitor
+- New DEBUG facility with more consistent log levels
+- New tool to change debug log levels without restarting SSSD
+- SSSD will now disconnect from LDAP server when idle
+- FreeIPA HBAC rules can choose to ignore srchost options for significant
+  performance gains
+- Assorted performance improvements in the LDAP provider
+
+* Mon Dec 19 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.4-1
+- New upstream release 1.6.4
+- Rolls up previous patches applied to the 1.6.3 tarball
+- Fixes a rare issue causing crashes in the failover logic
+- Fixes an issue where SSSD would return the wrong PAM error code for users
+  that it does not recognize.
+
+* Wed Dec 07 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-5
+- Rebuild against libldb 1.1.4
+
+* Tue Nov 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-4
+- Resolves: rhbz#753639 - sssd_nss crashes when passed invalid UTF-8 for the
+                          username in getpwnam()
+- Resolves: rhbz#758425 - LDAP failover not working if server refuses
+                          connections
+
+* Thu Nov 24 2011 Jakub Hrozek <jhrozek@redhat.com> - 1.6.3-3
+- Rebuild for libldb 1.1.3
+
+* Thu Nov 10 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-2
+- Resolves: rhbz#752495 - Crash when apply settings
+
+* Fri Nov 04 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-1
+- New upstream release 1.6.3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.6.3
+- Fixes a major cache performance issue introduced in 1.6.2
+- Fixes a potential infinite-loop with certain LDAP layouts
+
+* Wed Oct 26 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.6.2-5
+- Rebuilt for glibc bug#747377
+
+* Sun Oct 23 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-4
+- Change selinux policy requirement to Conflicts: with the old version,
+  rather than Requires: the supported version.
+
+* Fri Oct 21 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-3
+- Add explicit requirement on selinux-policy version to address new SBUS
+  symlinks.
+
+* Wed Oct 19 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-2
+- Remove %%files reference to sss_debuglevel copied from wrong upstreeam
+  spec file.
+
+* Tue Oct 18 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-1
+- Improved handling of users and groups with multi-valued name attributes
+  (aliases)
+- Performance enhancements
+    Initgroups on RFC2307bis/FreeIPA
+    HBAC rule processing
+- Improved process-hang detection and restarting
+- Enabled the midpoint cache refresh by default (fewer cache misses on
+  commonly-used entries)
+- Cleaned up the example configuration
+- New tool to change debug level on the fly
+
+* Mon Aug 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.1-1
+- New upstream release 1.6.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.6.1
+- Fixes a serious issue with LDAP connections when the communication is
+  dropped (e.g. VPN disconnection, waking from sleep)
+- SSSD is now less strict when dealing with users/groups with multiple names
+  when a definitive primary name cannot be determined
+- The LDAP provider will no longer attempt to canonicalize by default when
+  using SASL. An option to re-enable this has been provided.
+- Fixes for non-standard LDAP attribute names (e.g. those used by Active
+  Directory)
+- Three HBAC regressions have been fixed.
+- Fix for an infinite loop in the deref code
+
+* Wed Aug 03 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.0-2
+- Build with _hardened_build macro
+
+* Wed Aug 03 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.0-1
+- New upstream release 1.6.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.6.0
+- Add host access control support for LDAP (similar to pam_host_attr)
+- Finer-grained control on principals used with Kerberos (such as for FAST or
+- validation)
+- Added a new tool sss_cache to allow selective expiring of cached entries
+- Added support for LDAP DEREF and ASQ controls
+- Added access control features for Novell Directory Server
+- FreeIPA dynamic DNS update now checks first to see if an update is needed
+- Complete rewrite of the HBAC library
+- New libraries: libipa_hbac and libipa_hbac-python
+
+* Tue Jul 05 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.11-2
+- New upstream release 1.5.11
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.11
+- Fix a serious regression that prevented SSSD from working with ldaps:// URIs
+- IPA Provider: Fix a bug with dynamic DNS that resulted in the wrong IPv6
+- address being saved to the AAAA record
+
+* Fri Jul 01 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.10-1
+- New upstream release 1.5.10
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.10
+- Fixed a regression introduced in 1.5.9 that could result in blocking calls
+- to LDAP
+
+* Thu Jun 30 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.9-1
+- New upstream release 1.5.9
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.9
+- Support for overriding home directory, shell and primary GID locally
+- Properly honor TTL values from SRV record lookups
+- Support non-POSIX groups in nested group chains (for RFC2307bis LDAP
+- servers)
+- Properly escape IPv6 addresses in the failover code
+- Do not crash if inotify fails (e.g. resource exhaustion)
+- Don't add multiple TGT renewal callbacks (too many log messages)
+
+* Fri May 27 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.8-1
+- New upstream release 1.5.8
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.8
+- Support for the LDAP paging control
+- Support for multiple DNS servers for name resolution
+- Fixes for several group membership bugs
+- Fixes for rare crash bugs
+
+* Mon May 23 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.7-3
+- Resolves: rhbz#706740 - Orphaned links on rc0.d-rc6.d
+- Make sure to properly convert to systemd if upgrading from newer
+- updates for Fedora 14
+
+* Mon May 02 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.7-2
+- Fix segfault in TGT renewal
+
+* Fri Apr 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.7-1
+- Resolves: rhbz#700891 - CVE-2011-1758 sssd: automatic TGT renewal overwrites
+-                         cached password with predicatable filename
+
+* Wed Apr 20 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.6.1-1
+- Re-add manpage translations
+
+* Wed Apr 20 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.6-1
+- New upstream release 1.5.6
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.6
+- Fixed a serious memory leak in the memberOf plugin
+- Fixed a regression with the negative cache that caused it to be essentially
+- nonfunctional
+- Fixed an issue where the user's full name would sometimes be removed from
+- the cache
+- Fixed an issue with password changes in the kerberos provider not working
+- with kpasswd
+
+* Wed Apr 20 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-5
+- Resolves: rhbz#697057 - kpasswd fails when using sssd and
+-                         kadmin server != kdc server
+- Upgrades from SysV should now maintain enabled/disabled status
+
+* Mon Apr 18 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-4
+- Fix %%postun
+
+* Thu Apr 14 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-3
+- Fix systemd conversion. Upgrades from SysV to systemd weren't properly
+- enabling the systemd service.
+- Fix a serious memory leak in the memberOf plugin
+- Fix an issue where the user's full name would sometimes be removed
+- from the cache
+
+* Tue Apr 12 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-2
+- Install systemd unit file instead of sysv init script
+
+* Tue Apr 12 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-1
+- New upstream release 1.5.5
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.5
+- Fixes for several crash bugs
+- LDAP group lookups will no longer abort if there is a zero-length member
+- attribute
+- Add automatic fallback to 'cn' if the 'gecos' attribute does not exist
+
+* Thu Mar 24 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.4-1
+- New upstream release 1.5.4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.4
+- Fixes for Active Directory when not all users and groups have POSIX attributes
+- Fixes for handling users and groups that have name aliases (aliases are ignored)
+- Fix group memberships after initgroups in the IPA provider
+
+* Thu Mar 17 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.3-2
+- Resolves: rhbz#683267 - sssd 1.5.1-9 breaks AD authentication
+
+* Fri Mar 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.3-1
+- New upstream release 1.5.3
+- Support for libldb >= 1.0.0
+
+* Thu Mar 10 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.2-1
+- New upstream release 1.5.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.2
+- Fixes for support of FreeIPA v2
+- Fixes for failover if DNS entries change
+- Improved sss_obfuscate tool with better interactive mode
+- Fix several crash bugs
+- Don't attempt to use START_TLS over SSL. Some LDAP servers can't handle this
+- Delete users from the local cache if initgroups calls return 'no such user'
+- (previously only worked for getpwnam/getpwuid)
+- Use new Transifex.net translations
+- Better support for automatic TGT renewal (now survives restart)
+- Netgroup fixes
+
+* Sun Feb 27 2011 Simo Sorce <ssorce@redhat.com> - 1.5.1-9
+- Rebuild sssd against libldb 1.0.2 so the memberof module loads again.
+- Related: rhbz#677425
+
+* Mon Feb 21 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-8
+- Resolves: rhbz#677768 - name service caches names, so id command shows
+-                         recently deleted users
+
+* Fri Feb 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-7
+- Ensure that SSSD builds against libldb-1.0.0 on F15 and later
+- Remove .la for memberOf
+
+* Fri Feb 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-6
+- Fix memberOf install path
+
+* Fri Feb 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-5
+- Add support for libldb 1.0.0
+
+* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.5.1-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Tue Feb 01 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-3
+- Fix nested group member filter sanitization for RFC2307bis
+- Put translated tool manpages into the sssd-tools subpackage
+
+* Thu Jan 27 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-2
+- Restore Requires: cyrus-sasl-gssapi as it is not auto-detected during
+- rpmbuild
+
+* Thu Jan 27 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-1
+- New upstream release 1.5.1
+- Addresses CVE-2010-4341 - DoS in sssd PAM responder can prevent logins
+- Vast performance improvements when enumerate = true
+- All PAM actions will now perform a forced initgroups lookup instead of just
+- a user information lookup
+-   This guarantees that all group information is available to other
+-   providers, such as the simple provider.
+- For backwards-compatibility, DNS lookups will also fall back to trying the
+- SSSD domain name as a DNS discovery domain.
+- Support for more password expiration policies in LDAP
+-    389 Directory Server
+-    FreeIPA
+-    ActiveDirectory
+- Support for ldap_tls_{cert,key,cipher_suite} config options
+-Assorted bugfixes
+
+* Tue Jan 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.0-2
+- CVE-2010-4341 - DoS in sssd PAM responder can prevent logins
+
+* Wed Dec 22 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.5.0-1
+- New upstream release 1.5.0
+- Fixed issues with LDAP search filters that needed to be escaped
+- Add Kerberos FAST support on platforms that support it
+- Reduced verbosity of PAM_TEXT_INFO messages for cached credentials
+- Added a Kerberos access provider to honor .k5login
+- Addressed several thread-safety issues in the sss_client code
+- Improved support for delayed online Kerberos auth
+- Significantly reduced time between connecting to the network/VPN and
+- acquiring a TGT
+- Added feature for automatic Kerberos ticket renewal
+- Provides the kerberos ticket for long-lived processes or cron jobs
+- even when the user logs out
+- Added several new features to the LDAP access provider
+- Support for 'shadow' access control
+- Support for authorizedService access control
+- Ability to mix-and-match LDAP access control features
+- Added an option for a separate password-change LDAP server for those
+- platforms where LDAP referrals are not supported
+- Added support for manpage translations
+
+
+* Thu Nov 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.1-3
+- Solve a shutdown race-condition that sometimes left processes running
+- Resolves: rhbz#606887 - SSSD stops on upgrade
+
+* Tue Nov 16 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.1-2
+- Log startup errors to the syslog
+- Allow cache cleanup to be disabled in sssd.conf
+
+* Mon Nov 01 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.1-1
+- New upstream release 1.4.1
+- Add support for netgroups to the proxy provider
+- Fixes a minor bug with UIDs/GIDs >= 2^31
+- Fixes a segfault in the kerberos provider
+- Fixes a segfault in the NSS responder if a data provider crashes
+- Correctly use sdap_netgroup_search_base
+
+* Mon Oct 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.0-2
+- Fix incorrect tarball URL
+
+* Mon Oct 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.0-1
+- New upstream release 1.4.0
+- Added support for netgroups to the LDAP provider
+- Performance improvements made to group processing of RFC2307 LDAP servers
+- Fixed nested group issues with RFC2307bis LDAP servers without a memberOf plugin
+- Build-system improvements to support Gentoo
+- Split out several libraries into the ding-libs tarball
+- Manpage reviewed and updated
+
+* Mon Oct 04 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-35
+- Fix pre and post script requirements
+
+* Mon Oct 04 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-34
+- Resolves: rhbz#606887 - sssd stops on upgrade
+
+* Fri Oct 01 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-33
+- Resolves: rhbz#626205 - Unable to unlock screen
+
+* Tue Sep 28 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-32
+- Resolves: rhbz#637955 - libini_config-devel needs libcollection-devel but
+-                         doesn't require it
+
+* Thu Sep 16 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-31
+- Resolves: rhbz#632615 - the krb5 locator plugin isn't packaged for multilib
+
+* Tue Aug 24 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-30
+- Resolves: CVE-2010-2940 - sssd allows null password entry to authenticate
+-                           against LDAP
+
+* Thu Jul 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.2.91-21
+- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild
+
+* Fri Jul 09 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.2.91-20
+- New upstream version 1.2.91 (1.3.0rc1)
+- Improved LDAP failover
+- Synchronous sysdb API (provides performance enhancements)
+- Better online reconnection detection
+
+* Mon Jun 21 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.2.1-15
+- New stable upstream version 1.2.1
+- Resolves: rhbz#595529 - spec file should eschew %%define in favor of
+-                         %%global
+- Resolves: rhbz#593644 - Empty list of simple_allow_users causes sssd service
+-                         to fail while restart.
+- Resolves: rhbz#599026 - Makefile typo causes SSSD not to use the kernel
+-                         keyring
+- Resolves: rhbz#599724 - sssd is broken on Rawhide
+
+* Mon May 24 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.2.0-12
+- New stable upstream version 1.2.0
+- Support ServiceGroups for FreeIPA v2 HBAC rules
+- Fix long-standing issue with auth_provider = proxy
+- Better logging for TLS issues in LDAP
+
+* Tue May 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.92-11
+- New LDAP access provider allows for filtering user access by LDAP attribute
+- Reduced default timeout for detecting offline status with LDAP
+- GSSAPI ticket lifetime made configurable
+- Better offline->online transition support in Kerberos
+
+* Fri May 07 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.91-10
+- Release new upstream version 1.1.91
+- Enhancements when using SSSD with FreeIPA v2
+- Support for deferred kinit
+- Support for DNS SRV records for failover
+
+* Fri Apr 02 2010 Simo Sorce <ssorce@redhat.com> - 1.1.1-3
+- Bump up release number to avoid library sub-packages version issues with
+  previous releases.
+
+* Thu Apr 01 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.1-1
+- New upstream release 1.1.1
+- Fixed the IPA provider (which was segfaulting at start)
+- Fixed a bug in the SSSDConfig API causing some options to revert to
+- their defaults
+- This impacted the Authconfig UI
+- Ensure that SASL binds to LDAP auto-retry when interrupted by a signal
+
+* Tue Mar 23 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-2
+- Release SSSD 1.1.0 final
+- Fix two potential segfaults
+- Fix memory leak in monitor
+- Better error message for unusable confdb
+
+* Wed Mar 17 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-1.pre20100317git0ea7f19
+- Release candidate for SSSD 1.1
+- Add simple access provider
+- Create subpackages for libcollection, libini_config, libdhash and librefarray
+- Support IPv6
+- Support LDAP referrals
+- Fix cache issues
+- Better feedback from PAM when offline
+
+* Wed Feb 24 2010 Stephen Gallagehr <sgallagh@redhat.com> - 1.0.5-2
+- Rebuild against new libtevent
+
+* Fri Feb 19 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.5-1
+- Fix licenses in sources and on RPMs
+
+* Mon Jan 25 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.4-1
+- Fix regression on 64-bit platforms
+
+* Fri Jan 22 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.3-1
+- Fixes link error on platforms that do not do implicit linking
+- Fixes double-free segfault in PAM
+- Fixes double-free error in async resolver
+- Fixes support for TCP-based DNS lookups in async resolver
+- Fixes memory alignment issues on ARM processors
+- Manpage fixes
+
+* Thu Jan 14 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.2-1
+- Fixes a bug in the failover code that prevented the SSSD from detecting when it went back online
+- Fixes a bug causing long (sometimes multiple-minute) waits for NSS requests
+- Several segfault bugfixes
+
+* Mon Jan 11 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.1-1
+- Fix CVE-2010-0014
+
+* Mon Dec 21 2009 Stephen Gallagher <sgallagh@redhat.com> - 1.0.0-2
+- Patch SSSDConfig API to address
+- https://bugzilla.redhat.com/show_bug.cgi?id=549482
+
+* Fri Dec 18 2009 Stephen Gallagher <sgallagh@redhat.com> - 1.0.0-1
+- New upstream stable release 1.0.0
+
+* Fri Dec 11 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.99.1-1
+- New upstream bugfix release 0.99.1
+
+* Mon Nov 30 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.99.0-1
+- New upstream release 0.99.0
+
+* Tue Oct 27 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.7.1-1
+- Fix segfault in sssd_pam when cache_credentials was enabled
+- Update the sample configuration
+- Fix upgrade issues caused by data provider service removal
+
+* Mon Oct 26 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.7.0-2
+- Fix upgrade issues from old (pre-0.5.0) releases of SSSD
+
+* Fri Oct 23 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.7.0-1
+- New upstream release 0.7.0
+
+* Thu Oct 15 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.6.1-2
+- Fix missing file permissions for sssd-clients
+
+* Tue Oct 13 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.6.1-1
+- Add SSSDConfig API
+- Update polish translation for 0.6.0
+- Fix long timeout on ldap operation
+- Make dp requests more robust
+
+* Tue Sep 29 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.6.0-1
+- Ensure that the configuration upgrade script always writes the config
+  file with 0600 permissions
+- Eliminate an infinite loop in group enumerations
+
+* Mon Sep 28 2009 Sumit Bose <sbose@redhat.com> - 0.6.0-0
+- New upstream release 0.6.0
+
+* Mon Aug 24 2009 Simo Sorce <ssorce@redhat.com> - 0.5.0-0
+- New upstream release 0.5.0
+
+* Wed Jul 29 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.4.1-4
+- Fix for CVE-2009-2410 - Native SSSD users with no password set could log in
+  without a password. (Patch by Stephen Gallagher)
+
+* Sun Jul 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.4.1-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Mon Jun 22 2009 Simo Sorce <ssorce@redhat.com> - 0.4.1-2
+- Fix a couple of segfaults that may happen on reload
+
+* Thu Jun 11 2009 Simo Sorce <ssorce@redhat.com> - 0.4.1-1
+- add missing configure check that broke stopping the daemon
+- also fix default config to add a missing required option
+
+* Mon Jun  8 2009 Simo Sorce <ssorce@redhat.com> - 0.4.1-0
+- latest upstream release.
+- also add a patch that fixes debugging output (potential segfault)
+
+* Mon Apr 20 2009 Simo Sorce <ssorce@redhat.com> - 0.3.2-2
+- release out of the official 0.3.2 tarball
+
+* Mon Apr 20 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.3.2-1
+- bugfix release 0.3.2
+- includes previous release patches
+- change permissions of the /etc/sssd/sssd.conf to 0600
+
+* Tue Apr 14 2009 Simo Sorce <ssorce@redhat.com> - 0.3.1-2
+- Add last minute bug fixes, found in testing the package
+
+* Mon Apr 13 2009 Simo Sorce <ssorce@redhat.com> - 0.3.1-1
+- Version 0.3.1
+- includes previous release patches
+
+* Mon Apr 13 2009 Simo Sorce <ssorce@redhat.com> - 0.3.0-2
+- Try to fix build adding automake as an explicit BuildRequire
+- Add also a couple of last minute patches from upstream
+
+* Mon Apr 13 2009 Simo Sorce <ssorce@redhat.com> - 0.3.0-1
+- Version 0.3.0
+- Provides file based configuration and lots of improvements
+
+* Tue Mar 10 2009 Simo Sorce <ssorce@redhat.com> - 0.2.1-1
+- Version 0.2.1
+
+* Tue Mar 10 2009 Simo Sorce <ssorce@redhat.com> - 0.2.0-1
+- Version 0.2.0
+
+* Sun Mar 08 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.1.0-5.20090309git691c9b3
+- package git snapshot
+
+* Fri Mar 06 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.1.0-4
+- fixed items found during review
+- added initscript
+
+* Thu Mar 05 2009 Sumit Bose <sbose@redhat.com> - 0.1.0-3
+- added sss_client
+
+* Mon Feb 23 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.1.0-2
+- Small cleanup and fixes in the spec file
+
+* Thu Feb 12 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.1.0-1
+- Initial release (based on version 0.1.0 upstream code)