diff --git a/.gitignore b/.gitignore
index b147e6a..bffaf09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/sssd-2.0.0.tar.gz
+SOURCES/sssd-2.2.0.tar.gz
diff --git a/.sssd.metadata b/.sssd.metadata
index 7f62e35..637397e 100644
--- a/.sssd.metadata
+++ b/.sssd.metadata
@@ -1 +1 @@
-700ff5391bea73c19ddcdf99b25615fd4d284d7b SOURCES/sssd-2.0.0.tar.gz
+6c4ba24eb19a821c69e19675e76f01c94cbd5aa0 SOURCES/sssd-2.2.0.tar.gz
diff --git a/SOURCES/0001-KCM-Don-t-error-out-if-creating-a-new-ID-as-the-firs.patch b/SOURCES/0001-KCM-Don-t-error-out-if-creating-a-new-ID-as-the-firs.patch
deleted file mode 100644
index c6c7fa1..0000000
--- a/SOURCES/0001-KCM-Don-t-error-out-if-creating-a-new-ID-as-the-firs.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From a53590ef89d78d3e065e0f1eb28b641c391b5a18 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 28 Aug 2018 14:47:44 +0200
-Subject: [PATCH] KCM: Don't error out if creating a new ID as the first step
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-We need to handle the case where the nextID operation is ran, but the
-secdb is totally empty, otherwise logins with sssd's krb5_child would
-fail.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3815
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-
-DOWNSTREAM: Resolves: rhbz#1622026 - sssd 2.0 regression: Kerberos authentication fails with the KCM ccache
----
- src/responder/kcm/kcmsrv_ccache_secdb.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
-index 0f1c037caf8c3bda6f3dca7136ed9236862ccdd7..a61d7b15be433e8308acc3dfa35d730247e2e615 100644
---- a/src/responder/kcm/kcmsrv_ccache_secdb.c
-+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
-@@ -595,7 +595,10 @@ static struct tevent_req *ccdb_secdb_nextid_send(TALLOC_CTX *mem_ctx,
-     }
- 
-     ret = sss_sec_list(state, sreq, &keys, &nkeys);
--    if (ret != EOK) {
-+    if (ret == ENOENT) {
-+        keys = NULL;
-+        nkeys = 0;
-+    } else if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               "Cannot list keys [%d]: %s\n",
-               ret, sss_strerror(ret));
--- 
-2.14.4
-
diff --git a/SOURCES/0001-MAN-ldap_user_home_directory-default-missing.patch b/SOURCES/0001-MAN-ldap_user_home_directory-default-missing.patch
new file mode 100644
index 0000000..e0de1f3
--- /dev/null
+++ b/SOURCES/0001-MAN-ldap_user_home_directory-default-missing.patch
@@ -0,0 +1,36 @@
+From 52cdf289ff9b40a203d7f823b8dad85501c7404c Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Wed, 19 Jun 2019 10:15:30 +0200
+Subject: [PATCH 1/2] MAN: ldap_user_home_directory default missing
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The default value of "ldap_user_home_directory" is "homeDirectory"
+but for AD provider it is "unixHomeDirectory"
+
+Resolves:
+https://bugzilla.redhat.com/show_bug.cgi?id=1673443
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+(cherry picked from commit 01ea70fa8cc91f05a726d1dea3c64bd776dc3517)
+---
+ src/man/sssd-ldap.5.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index b6496b50f..f0bc82db5 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -373,7 +373,7 @@
+                             home directory.
+                         </para>
+                         <para>
+-                            Default: homeDirectory
++                            Default: homeDirectory (LDAP and IPA), unixHomeDirectory (AD)
+                         </para>
+                     </listitem>
+                 </varlistentry>
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-PROXY-Return-data-in-output-parameter-if-everything-.patch b/SOURCES/0002-PROXY-Return-data-in-output-parameter-if-everything-.patch
new file mode 100644
index 0000000..0879227
--- /dev/null
+++ b/SOURCES/0002-PROXY-Return-data-in-output-parameter-if-everything-.patch
@@ -0,0 +1,135 @@
+From 59c0d659fc71b47278c2faadaa844e8516454626 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Fri, 28 Jun 2019 16:27:21 +0200
+Subject: [PATCH 2/2] PROXY: Return data in output parameter if everything is
+ OK
+
+The function remove_duplicate_group_members might return EOK also in the middle
+of function but return parameter was not set with right data.
+Processing continued in the function save_group but there was a
+dereference of NULL pointer.
+
+Introduced in: https://pagure.io/SSSD/sssd/issue/3931
+
+Crash:
+  (gdb) bt
+  #0  0x00007fb4ce4a9ac5 in save_group (sysdb=sysdb@entry=0x55c9a0efb230, dom=dom@entry=0x55c9a0efb420, grp=grp@entry=0x55c9a0f370f0, real_name=0x55c9a0f47340 "nobody@ldap",
+      alias=alias@entry=0x0) at src/providers/proxy/proxy_id.c:748
+  #1  0x00007fb4ce4aa600 in get_gr_gid (mem_ctx=mem_ctx@entry=0x55c9a0f38be0, sysdb=sysdb@entry=0x55c9a0efb230, dom=dom@entry=0x55c9a0efb420, gid=99, now=<optimized out>,
+      ctx=<optimized out>) at src/providers/proxy/proxy_id.c:1160
+  #2  0x00007fb4ce4ac9e5 in get_initgr_groups_process (pwd=0x55c9a0f384a0, pwd=0x55c9a0f384a0, dom=0x55c9a0efb420, sysdb=0x55c9a0efb230, ctx=0x55c9a0f048e0, memctx=0x55c9a0f38be0)
+      at src/providers/proxy/proxy_id.c:1553
+  #3  get_initgr (i_name=<optimized out>, dom=0x55c9a0efb420, sysdb=<optimized out>, ctx=0x55c9a0f048e0, mem_ctx=0x55c9a0f38b70) at src/providers/proxy/proxy_id.c:1461
+  #4  proxy_account_info (domain=0x55c9a0efb420, be_ctx=<optimized out>, data=<optimized out>, ctx=0x55c9a0f048e0, mem_ctx=0x55c9a0f38b70) at src/providers/proxy/proxy_id.c:1659
+  #5  proxy_account_info_handler_send (mem_ctx=<optimized out>, id_ctx=0x55c9a0f048e0, data=<optimized out>, params=0x55c9a0f39790) at src/providers/proxy/proxy_id.c:1758
+  #6  0x000055c99fc67677 in file_dp_request (_dp_req=<synthetic pointer>, req=0x55c9a0f39470, request_data=<optimized out>, dp_flags=1, method=DPM_ACCOUNT_HANDLER, target=DPT_ID,
+      name=<optimized out>, domainname=0x55c9a0f39190 "LDAP", provider=0x55c9a0efe0e0, mem_ctx=<optimized out>) at src/providers/data_provider/dp_request.c:250
+  #7  dp_req_send (mem_ctx=0x55c9a0f37b60, provider=provider@entry=0x55c9a0efe0e0, domain=domain@entry=0x55c9a0f39190 "LDAP", name=<optimized out>, target=target@entry=DPT_ID,
+      method=method@entry=DPM_ACCOUNT_HANDLER, dp_flags=dp_flags@entry=1, request_data=0x55c9a0f37c00, _request_name=0x55c9a0f37b60) at src/providers/data_provider/dp_request.c:295
+  #8  0x000055c99fc6a132 in dp_get_account_info_send (mem_ctx=<optimized out>, ev=0x55c9a0eddbc0, sbus_req=<optimized out>, provider=0x55c9a0efe0e0, dp_flags=1,
+      entry_type=<optimized out>, filter=0x55c9a0f358d0 "name=nobody@ldap", domain=0x55c9a0f39190 "LDAP", extra=0x55c9a0f354a0 "") at src/providers/data_provider/dp_target_id.c:528
+  #9  0x00007fb4da35265b in _sbus_sss_invoke_in_uusss_out_qus_step (ev=0x55c9a0eddbc0, te=<optimized out>, tv=..., private_data=<optimized out>) at src/sss_iface/sbus_sss_invokers.c:2847
+  #10 0x00007fb4d9cfb1cf in tevent_common_invoke_timer_handler () from /lib64/libtevent.so.0
+  #11 0x00007fb4d9cfb339 in tevent_common_loop_timer_delay () from /lib64/libtevent.so.0
+  #12 0x00007fb4d9cfc2f9 in epoll_event_loop_once () from /lib64/libtevent.so.0
+  #13 0x00007fb4d9cfa7b7 in std_event_loop_once () from /lib64/libtevent.so.0
+  #14 0x00007fb4d9cf5b5d in _tevent_loop_once () from /lib64/libtevent.so.0
+  #15 0x00007fb4d9cf5d8b in tevent_common_loop_wait () from /lib64/libtevent.so.0
+  #16 0x00007fb4d9cfa757 in std_event_loop_wait () from /lib64/libtevent.so.0
+  #17 0x00007fb4dd955ac3 in server_loop (main_ctx=0x55c9a0edf090) at src/util/server.c:724
+  #18 0x000055c99fc59760 in main (argc=8, argv=<optimized out>) at src/providers/data_provider_be.c:747
+  (gdb) l
+  (gdb) bt
+  #0  0x00007fb4ce4a9ac5 in save_group (sysdb=sysdb@entry=0x55c9a0efb230, dom=dom@entry=0x55c9a0efb420, grp=grp@entry=0x55c9a0f370f0, real_name=0x55c9a0f47340 "nobody@ldap",
+      alias=alias@entry=0x0) at src/providers/proxy/proxy_id.c:748
+  #1  0x00007fb4ce4aa600 in get_gr_gid (mem_ctx=mem_ctx@entry=0x55c9a0f38be0, sysdb=sysdb@entry=0x55c9a0efb230, dom=dom@entry=0x55c9a0efb420, gid=99, now=<optimized out>,
+      ctx=<optimized out>) at src/providers/proxy/proxy_id.c:1160
+  #2  0x00007fb4ce4ac9e5 in get_initgr_groups_process (pwd=0x55c9a0f384a0, pwd=0x55c9a0f384a0, dom=0x55c9a0efb420, sysdb=0x55c9a0efb230, ctx=0x55c9a0f048e0, memctx=0x55c9a0f38be0)
+      at src/providers/proxy/proxy_id.c:1553
+  #3  get_initgr (i_name=<optimized out>, dom=0x55c9a0efb420, sysdb=<optimized out>, ctx=0x55c9a0f048e0, mem_ctx=0x55c9a0f38b70) at src/providers/proxy/proxy_id.c:1461
+  #4  proxy_account_info (domain=0x55c9a0efb420, be_ctx=<optimized out>, data=<optimized out>, ctx=0x55c9a0f048e0, mem_ctx=0x55c9a0f38b70) at src/providers/proxy/proxy_id.c:1659
+  #5  proxy_account_info_handler_send (mem_ctx=<optimized out>, id_ctx=0x55c9a0f048e0, data=<optimized out>, params=0x55c9a0f39790) at src/providers/proxy/proxy_id.c:1758
+  #6  0x000055c99fc67677 in file_dp_request (_dp_req=<synthetic pointer>, req=0x55c9a0f39470, request_data=<optimized out>, dp_flags=1, method=DPM_ACCOUNT_HANDLER, target=DPT_ID,
+      name=<optimized out>, domainname=0x55c9a0f39190 "LDAP", provider=0x55c9a0efe0e0, mem_ctx=<optimized out>) at src/providers/data_provider/dp_request.c:250
+  #7  dp_req_send (mem_ctx=0x55c9a0f37b60, provider=provider@entry=0x55c9a0efe0e0, domain=domain@entry=0x55c9a0f39190 "LDAP", name=<optimized out>, target=target@entry=DPT_ID,
+      method=method@entry=DPM_ACCOUNT_HANDLER, dp_flags=dp_flags@entry=1, request_data=0x55c9a0f37c00, _request_name=0x55c9a0f37b60) at src/providers/data_provider/dp_request.c:295
+  #8  0x000055c99fc6a132 in dp_get_account_info_send (mem_ctx=<optimized out>, ev=0x55c9a0eddbc0, sbus_req=<optimized out>, provider=0x55c9a0efe0e0, dp_flags=1,
+      entry_type=<optimized out>, filter=0x55c9a0f358d0 "name=nobody@ldap", domain=0x55c9a0f39190 "LDAP", extra=0x55c9a0f354a0 "") at src/providers/data_provider/dp_target_id.c:528
+  #9  0x00007fb4da35265b in _sbus_sss_invoke_in_uusss_out_qus_step (ev=0x55c9a0eddbc0, te=<optimized out>, tv=..., private_data=<optimized out>) at src/sss_iface/sbus_sss_invokers.c:2847
+  #10 0x00007fb4d9cfb1cf in tevent_common_invoke_timer_handler () from /lib64/libtevent.so.0
+  #11 0x00007fb4d9cfb339 in tevent_common_loop_timer_delay () from /lib64/libtevent.so.0
+  #12 0x00007fb4d9cfc2f9 in epoll_event_loop_once () from /lib64/libtevent.so.0
+  #13 0x00007fb4d9cfa7b7 in std_event_loop_once () from /lib64/libtevent.so.0
+  #14 0x00007fb4d9cf5b5d in _tevent_loop_once () from /lib64/libtevent.so.0
+  #15 0x00007fb4d9cf5d8b in tevent_common_loop_wait () from /lib64/libtevent.so.0
+  #16 0x00007fb4d9cfa757 in std_event_loop_wait () from /lib64/libtevent.so.0
+  #17 0x00007fb4dd955ac3 in server_loop (main_ctx=0x55c9a0edf090) at src/util/server.c:724
+  #18 0x000055c99fc59760 in main (argc=8, argv=<optimized out>) at src/providers/data_provider_be.c:747
+  (gdb) l
+  733         ret = remove_duplicate_group_members(tmp_ctx, grp, &ngroup);
+  734         if (ret != EOK) {
+  735             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to remove duplicate group member     s\n");
+  736             goto done;
+  737         }
+  738
+  739         DEBUG_GR_MEM(SSSDBG_TRACE_LIBS, ngroup);
+  740
+  741         ret = sysdb_transaction_start(sysdb);
+  742         if (ret != EOK) {
+  743             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+  744             goto done;
+  745         }
+  746         in_transaction = true;
+  747
+  748         if (ngroup->gr_mem && ngroup->gr_mem[0]) {
+  749             attrs = sysdb_new_attrs(tmp_ctx);
+  750             if (!attrs) {
+  751                 DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error?!\n");
+  752                 ret = ENOMEM;
+  (gdb) p ngroup
+  $1 = (struct group *) 0x0
+  743             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+  744             goto done;
+  745         }
+  746         in_transaction = true;
+  747
+  748         if (ngroup->gr_mem && ngroup->gr_mem[0]) {
+  749             attrs = sysdb_new_attrs(tmp_ctx);
+  750             if (!attrs) {
+  751                 DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error?!\n");
+  752                 ret = ENOMEM;
+  (gdb) p ngroup
+  $1 = (struct group *) 0x0
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/4036
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4037
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit e1b678c0cce73494d986610920b03956c1dbb62a)
+---
+ src/providers/proxy/proxy_id.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
+index e1be29076..91105ce5a 100644
+--- a/src/providers/proxy/proxy_id.c
++++ b/src/providers/proxy/proxy_id.c
+@@ -698,10 +698,12 @@ static errno_t remove_duplicate_group_members(TALLOC_CTX *mem_ctx,
+     }
+     grp->gr_mem[i] = NULL;
+ 
+-    *_grp = talloc_steal(mem_ctx, grp);
+     ret = EOK;
+ 
+ done:
++    if (ret == EOK) {
++        *_grp = talloc_steal(mem_ctx, grp);
++    }
+     talloc_zfree(tmp_ctx);
+ 
+     return ret;
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-sbus-register-filter-on-new-connection.patch b/SOURCES/0002-sbus-register-filter-on-new-connection.patch
deleted file mode 100644
index 69e00c2..0000000
--- a/SOURCES/0002-sbus-register-filter-on-new-connection.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 929a2b84cbb63312c2d797ab7048003c6f5e0c71 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 5 Sep 2018 15:08:52 +0200
-Subject: [PATCH] sbus: register filter on new connection
-
-The filter is not again registered on new connection when the old connection
-was lost. This caused a segfault when the router is destroyed during shutdown.
-
-It also would not allow to recieve and process any messages as the filter
-function is needed for that. However, this was not very visible with
-current sssd architecture.
-
-Steps to reproduce:
-1. Run SSSD
-2. pkill sssd_be
-3. Wait for responders to reconnect to backend
-4. Shutdown SSSD
-5. It will crash without this patch
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3821
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 55d5b43543b5ef62322fe635fe8108410cb4ea77)
----
- src/sbus/router/sbus_router.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/sbus/router/sbus_router.c b/src/sbus/router/sbus_router.c
-index 24c2c76475c130343eb4319a76dfa91f40d2958d..d31cef1b4c253b927b1b8e1c3d7daef14eb26dd6 100644
---- a/src/sbus/router/sbus_router.c
-+++ b/src/sbus/router/sbus_router.c
-@@ -364,6 +364,13 @@ errno_t
- sbus_router_reset(struct sbus_connection *conn)
- {
-     errno_t ret;
-+    bool bret;
-+
-+    bret = sbus_router_filter_add(conn->router);
-+    if (!bret) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register message filter!\n");
-+        return EFAULT;
-+    }
-
-     ret = sbus_router_reset_listeners(conn);
-     if (ret != EOK) {
---
-2.14.4
diff --git a/SOURCES/0003-LDAP-failover-does-not-work-on-non-responsive-ldaps.patch b/SOURCES/0003-LDAP-failover-does-not-work-on-non-responsive-ldaps.patch
new file mode 100644
index 0000000..1053167
--- /dev/null
+++ b/SOURCES/0003-LDAP-failover-does-not-work-on-non-responsive-ldaps.patch
@@ -0,0 +1,80 @@
+From 5afd3f6030a78d1c3631c645955c0804b7e7abce Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Mon, 24 Jun 2019 15:58:09 +0200
+Subject: [PATCH 3/4] LDAP: failover does not work on non-responsive ldaps
+
+In case ldaps:// is used, then establishing the secure socket is
+a sychronous operation. If there's nothing on the other end, then
+the process would be stuck waiting in for the crypto library
+to finish.
+
+Here we set socket read/write timeout so the operation can finish
+in reasonable time with an error. The ldap_network_timeout
+option is used for this timeout.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/2878
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/util/sss_sockets.c | 26 ++++++++++++++++++++++++--
+ 1 file changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
+index 5e9be9ebd..0e4d8df8a 100644
+--- a/src/util/sss_sockets.c
++++ b/src/util/sss_sockets.c
+@@ -74,10 +74,11 @@ static errno_t set_fcntl_flags(int fd, int fd_flags, int fl_flags)
+     return EOK;
+ }
+ 
+-static errno_t set_fd_common_opts(int fd)
++static errno_t set_fd_common_opts(int fd, int timeout)
+ {
+     int dummy = 1;
+     int ret;
++    struct timeval tv;
+ 
+     /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
+      * failures are ignored.*/
+@@ -97,6 +98,27 @@ static errno_t set_fd_common_opts(int fd)
+                   strerror(ret));
+     }
+ 
++    if (timeout > 0) {
++        /* Set socket read & write timeout */
++        tv = tevent_timeval_set(timeout, 0);
++
++        ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
++        if (ret != 0) {
++            ret = errno;
++            DEBUG(SSSDBG_FUNC_DATA,
++                  "setsockopt SO_RCVTIMEO failed.[%d][%s].\n", ret,
++                  strerror(ret));
++        }
++
++        ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
++        if (ret != 0) {
++            ret = errno;
++            DEBUG(SSSDBG_FUNC_DATA,
++                  "setsockopt SO_SNDTIMEO failed.[%d][%s].\n", ret,
++                  strerror(ret));
++        }
++    }
++
+     return EOK;
+ }
+ 
+@@ -264,7 +286,7 @@ struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
+         goto fail;
+     }
+ 
+-    ret = set_fd_common_opts(state->sd);
++    ret = set_fd_common_opts(state->sd, timeout);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_common_opts failed.\n");
+         goto fail;
+-- 
+2.20.1
+
diff --git a/SOURCES/0003-sysdb-extract-sysdb_ldb_msg_attr_to_certmap_info-cal.patch b/SOURCES/0003-sysdb-extract-sysdb_ldb_msg_attr_to_certmap_info-cal.patch
deleted file mode 100644
index 4ed5198..0000000
--- a/SOURCES/0003-sysdb-extract-sysdb_ldb_msg_attr_to_certmap_info-cal.patch
+++ /dev/null
@@ -1,260 +0,0 @@
-From d5b15619809b169dca96af648c24f927e85d0e4b Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 29 Jun 2018 17:49:50 +0200
-Subject: [PATCH 03/19] sysdb: extract sysdb_ldb_msg_attr_to_certmap_info()
- call
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 7c619ae08f05a7595d15cf11b64461a7d19cfaa7)
----
- src/db/sysdb.h         |   4 ++
- src/db/sysdb_certmap.c | 191 ++++++++++++++++++++++++++++---------------------
- 2 files changed, 112 insertions(+), 83 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index d72af5a05009d80af0226c52736fbba6641d30fd..cb04e1b60546bd5de968eaf67ea5d2fc2b5e24ba 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -702,6 +702,10 @@ errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb,
-                              struct certmap_info **certmaps,
-                              bool user_name_hint);
- 
-+errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-+                                           struct ldb_message *msg,
-+                                           struct certmap_info **certmap);
-+
- errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-                           struct certmap_info ***certmaps,
-                           bool *user_name_hint);
-diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
-index 6d83ba0884fbacfd068a5b24bd9c7627b70680f5..e61cc05cc0c056a78965ff5989bd46aac2a44b3d 100644
---- a/src/db/sysdb_certmap.c
-+++ b/src/db/sysdb_certmap.c
-@@ -262,19 +262,119 @@ done:
-     return ret;
- }
- 
-+errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-+                                           struct ldb_message *msg,
-+                                           struct certmap_info **certmap)
-+{
-+    int ret;
-+    size_t d;
-+    size_t num_values;
-+    struct certmap_info *map = NULL;
-+    const char *tmp_str;
-+    uint64_t tmp_uint;
-+    struct ldb_message_element *tmp_el;
-+
-+
-+    map = talloc_zero(mem_ctx, struct certmap_info);
-+    if (map == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    tmp_str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+    if (tmp_str == NULL) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n",
-+                                    ldb_dn_get_linearized(msg->dn));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    map->name = talloc_strdup(map, tmp_str);
-+    if (map->name == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    tmp_str = ldb_msg_find_attr_as_string(msg, SYSDB_CERTMAP_MAPPING_RULE,
-+                                          NULL);
-+    if (tmp_str != NULL) {
-+        map->map_rule = talloc_strdup(map, tmp_str);
-+        if (map->map_rule == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    tmp_str = ldb_msg_find_attr_as_string(msg, SYSDB_CERTMAP_MATCHING_RULE,
-+                                          NULL);
-+    if (tmp_str != NULL) {
-+        map->match_rule = talloc_strdup(map, tmp_str);
-+        if (map->match_rule == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    tmp_uint = ldb_msg_find_attr_as_uint64(msg, SYSDB_CERTMAP_PRIORITY,
-+                                           (uint64_t) -1);
-+    if (tmp_uint != (uint64_t) -1) {
-+        if (tmp_uint > UINT32_MAX) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n",
-+                                     (unsigned long) tmp_uint);
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        map->priority = (uint32_t) tmp_uint;
-+    }
-+
-+    tmp_el = ldb_msg_find_element(msg, SYSDB_CERTMAP_DOMAINS);
-+    if (tmp_el != NULL) {
-+        num_values = tmp_el->num_values;
-+    } else {
-+        num_values = 0;
-+    }
-+
-+    map->domains = talloc_zero_array(map, const char *, num_values + 1);
-+    if (map->domains == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    for (d = 0; d < num_values; d++) {
-+        map->domains[d] = talloc_strndup(map->domains,
-+                                         (char *) tmp_el->values[d].data,
-+                                         tmp_el->values[d].length);
-+        if (map->domains[d] == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    }
-+
-+    *certmap = map;
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(map);
-+    }
-+
-+    return ret;
-+}
-+
- errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-                           struct certmap_info ***certmaps, bool *user_name_hint)
- {
-     size_t c;
--    size_t d;
-     struct ldb_dn *container_dn = NULL;
-     int ret;
-     struct certmap_info **maps = NULL;
-     TALLOC_CTX *tmp_ctx = NULL;
-     struct ldb_result *res;
--    const char *tmp_str;
--    uint64_t tmp_uint;
--    struct ldb_message_element *tmp_el;
-     const char *attrs[] = {SYSDB_NAME,
-                            SYSDB_CERTMAP_PRIORITY,
-                            SYSDB_CERTMAP_MATCHING_RULE,
-@@ -283,7 +383,6 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-                            NULL};
-     const char *config_attrs[] = {SYSDB_CERTMAP_USER_NAME_HINT,
-                                   NULL};
--    size_t num_values;
-     bool hint = false;
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -332,86 +431,12 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-     }
- 
-     for (c = 0; c < res->count; c++) {
--        maps[c] = talloc_zero(maps, struct certmap_info);
--        if (maps[c] == NULL) {
--            ret = ENOMEM;
-+        ret = sysdb_ldb_msg_attr_to_certmap_info(maps, res->msgs[c], &maps[c]);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "sysdb_ldb_msg_attr_to_certmap_info failed.\n");
-             goto done;
-         }
--        tmp_str = ldb_msg_find_attr_as_string(res->msgs[c], SYSDB_NAME, NULL);
--        if (tmp_str == NULL) {
--            DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n",
--                                       ldb_dn_get_linearized(res->msgs[c]->dn));
--            ret = EINVAL;
--            goto done;
--        }
--
--        maps[c]->name = talloc_strdup(maps, tmp_str);
--        if (maps[c]->name == NULL) {
--            ret = ENOMEM;
--            goto done;
--        }
--
--        tmp_str = ldb_msg_find_attr_as_string(res->msgs[c],
--                                              SYSDB_CERTMAP_MAPPING_RULE, NULL);
--        if (tmp_str != NULL) {
--            maps[c]->map_rule = talloc_strdup(maps, tmp_str);
--            if (maps[c]->map_rule == NULL) {
--                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
--                ret = ENOMEM;
--                goto done;
--            }
--        }
--
--        tmp_str = ldb_msg_find_attr_as_string(res->msgs[c],
--                                              SYSDB_CERTMAP_MATCHING_RULE, NULL);
--        if (tmp_str != NULL) {
--            maps[c]->match_rule = talloc_strdup(maps, tmp_str);
--            if (maps[c]->match_rule == NULL) {
--                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
--                ret = ENOMEM;
--                goto done;
--            }
--        }
--
--        tmp_uint = ldb_msg_find_attr_as_uint64(res->msgs[c],
--                                               SYSDB_CERTMAP_PRIORITY,
--                                               (uint64_t) -1);
--        if (tmp_uint != (uint64_t) -1) {
--            if (tmp_uint > UINT32_MAX) {
--                DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n",
--                                         (unsigned long) tmp_uint);
--                ret = EINVAL;
--                goto done;
--            }
--
--            maps[c]->priority = (uint32_t) tmp_uint;
--        }
--
--        tmp_el = ldb_msg_find_element(res->msgs[c], SYSDB_CERTMAP_DOMAINS);
--        if (tmp_el != NULL) {
--            num_values = tmp_el->num_values;
--        } else {
--            num_values = 0;
--        }
--
--        maps[c]->domains = talloc_zero_array(maps[c], const char *,
--                                             num_values + 1);
--        if (maps[c]->domains == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
--            ret = ENOMEM;
--            goto done;
--        }
--
--        for (d = 0; d < num_values; d++) {
--            maps[c]->domains[d] = talloc_strndup(maps[c]->domains,
--                                            (char *) tmp_el->values[d].data,
--                                            tmp_el->values[d].length);
--            if (maps[c]->domains[d] == NULL) {
--                DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
--                ret = ENOMEM;
--                goto done;
--            }
--        }
-     }
- 
-     ret = EOK;
--- 
-2.14.4
-
diff --git a/SOURCES/0004-sudo-use-proper-datetime-for-default-modifyTimestamp.patch b/SOURCES/0004-sudo-use-proper-datetime-for-default-modifyTimestamp.patch
new file mode 100644
index 0000000..0fb3dab
--- /dev/null
+++ b/SOURCES/0004-sudo-use-proper-datetime-for-default-modifyTimestamp.patch
@@ -0,0 +1,69 @@
+From d15c205bed16f5d138ce5c9335ed9f4aa7d4c25c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Wed, 17 Jul 2019 11:57:23 +0200
+Subject: [PATCH 4/4] sudo: use proper datetime for default modifyTimestamp
+ value
+
+The current default was simply "1", however OpenLDAP server was unable
+to compare modifyTimestamp attribute to simple number. A proper datetime
+is required by OpenLDAP.
+
+It worked correctly on 389-ds.
+
+Steps to reproduce:
+1. install openldap server
+2. run sssd
+3. there are no sudo rules on the server and there are no cached objects
+4. you'll see in the logs that sudo smart refresh uses `(&(&(objectclass=sudoRole)(modifyTimestamp>=1))...` filter (`1` instead of proper datetime value)
+
+The minimum accepted value by OpenLDAP is 00000101000000Z, as both month and day can not be zero.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4046
+---
+ src/providers/ldap/sdap_sudo_shared.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c
+index d2f24ed6e..93a977626 100644
+--- a/src/providers/ldap/sdap_sudo_shared.c
++++ b/src/providers/ldap/sdap_sudo_shared.c
+@@ -123,11 +123,24 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx,
+ static char *
+ sdap_sudo_new_usn(TALLOC_CTX *mem_ctx,
+                   unsigned long usn,
+-                  const char *leftover)
++                  const char *leftover,
++                  bool supports_usn)
+ {
+     const char *str = leftover == NULL ? "" : leftover;
+     char *newusn;
+ 
++    /* This is a fresh start and server uses modifyTimestamp. We need to
++     * provide proper datetime value. */
++    if (!supports_usn && usn == 0) {
++        newusn = talloc_strdup(mem_ctx, "00000101000000Z");
++        if (newusn == NULL) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Unable to change USN value (OOM)!\n");
++            return NULL;
++        }
++
++        return newusn;
++    }
++
+     /* We increment USN number so that we can later use simplify filter
+      * (just usn >= last+1 instead of usn >= last && usn != last).
+      */
+@@ -178,7 +191,8 @@ sdap_sudo_set_usn(struct sdap_server_opts *srv_opts,
+         srv_opts->last_usn = usn_number;
+     }
+ 
+-    newusn = sdap_sudo_new_usn(srv_opts, srv_opts->last_usn, endptr);
++    newusn = sdap_sudo_new_usn(srv_opts, srv_opts->last_usn, endptr,
++                               srv_opts->supports_usn);
+     if (newusn == NULL) {
+         return;
+     }
+-- 
+2.20.1
+
diff --git a/SOURCES/0004-sysdb_ldb_msg_attr_to_certmap_info-set-SSS_CERTMAP_M.patch b/SOURCES/0004-sysdb_ldb_msg_attr_to_certmap_info-set-SSS_CERTMAP_M.patch
deleted file mode 100644
index 38fc538..0000000
--- a/SOURCES/0004-sysdb_ldb_msg_attr_to_certmap_info-set-SSS_CERTMAP_M.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 2c5808cfe71b221f66ccdb993abe76161d543d5b Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 3 Jul 2018 11:30:07 +0200
-Subject: [PATCH 04/19] sysdb_ldb_msg_attr_to_certmap_info: set
- SSS_CERTMAP_MIN_PRIO
-
-Make sure that priority is always set.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit d1dd7f7703b4f40d2fbb830e28969b31b8a1673e)
----
- src/db/sysdb_certmap.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
-index e61cc05cc0c056a78965ff5989bd46aac2a44b3d..0bb7ebcade649631ef50e4d62f4ba85fb32c7aa4 100644
---- a/src/db/sysdb_certmap.c
-+++ b/src/db/sysdb_certmap.c
-@@ -22,6 +22,7 @@
- 
- #include "util/util.h"
- #include "db/sysdb_private.h"
-+#include "lib/certmap/sss_certmap.h"
- 
- static errno_t sysdb_create_certmap_container(struct sysdb_ctx *sysdb,
-                                               bool user_name_hint)
-@@ -327,6 +328,8 @@ errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-         }
- 
-         map->priority = (uint32_t) tmp_uint;
-+    } else {
-+        map->priority = SSS_CERTMAP_MIN_PRIO;
-     }
- 
-     tmp_el = ldb_msg_find_element(msg, SYSDB_CERTMAP_DOMAINS);
--- 
-2.14.4
-
diff --git a/SOURCES/0005-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch b/SOURCES/0005-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch
new file mode 100644
index 0000000..9d2aad4
--- /dev/null
+++ b/SOURCES/0005-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch
@@ -0,0 +1,126 @@
+From e7e212b49bbd357129aab410cbbd5c7b1b0965a2 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 24 Jun 2019 14:01:02 +0200
+Subject: [PATCH] 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>
+---
+ 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 7ab8a0981..9d4bdde14 100644
+--- a/src/tests/cmocka/test_negcache.c
++++ b/src/tests/cmocka/test_negcache.c
+@@ -637,7 +637,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[] = {
+@@ -752,6 +752,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/0005-sysdb-add-attr_map-attribute-to-sysdb_ldb_msg_attr_t.patch b/SOURCES/0005-sysdb-add-attr_map-attribute-to-sysdb_ldb_msg_attr_t.patch
deleted file mode 100644
index c67b895..0000000
--- a/SOURCES/0005-sysdb-add-attr_map-attribute-to-sysdb_ldb_msg_attr_t.patch
+++ /dev/null
@@ -1,141 +0,0 @@
-From 11878ac29dd0abaad1daad2772e32f1db6f84e3d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 29 Jun 2018 18:13:59 +0200
-Subject: [PATCH 05/19] sysdb: add attr_map attribute to
- sysdb_ldb_msg_attr_to_certmap_info()
-
-Allow more flexible attribute mapping in
-sysdb_ldb_msg_attr_to_certmap_info()
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 0bf709ad348ca115443bd21e4e369abd5d7698c4)
----
- src/db/sysdb.h         |  1 +
- src/db/sysdb_certmap.c | 39 +++++++++++++++++++++++++++++++--------
- 2 files changed, 32 insertions(+), 8 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index cb04e1b60546bd5de968eaf67ea5d2fc2b5e24ba..2187947dcd74df0511b33ac5823df38a05713e4a 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -704,6 +704,7 @@ errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb,
- 
- errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-                                            struct ldb_message *msg,
-+                                           const char **attr_map,
-                                            struct certmap_info **certmap);
- 
- errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
-index 0bb7ebcade649631ef50e4d62f4ba85fb32c7aa4..e37f1ba830f297137991c7757af9c7c4e17b2813 100644
---- a/src/db/sysdb_certmap.c
-+++ b/src/db/sysdb_certmap.c
-@@ -263,8 +263,19 @@ done:
-     return ret;
- }
- 
-+enum certmap_info_member {
-+    SSS_CMIM_NAME = 0,
-+    SSS_CMIM_MAPPING_RULE,
-+    SSS_CMIM_MATCHING_RULE,
-+    SSS_CMIM_PRIORITY,
-+    SSS_CMIM_DOMAINS,
-+
-+    SSS_CMIM_SENTINEL
-+};
-+
- errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-                                            struct ldb_message *msg,
-+                                           const char **attr_map,
-                                            struct certmap_info **certmap)
- {
-     int ret;
-@@ -275,13 +286,24 @@ errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-     uint64_t tmp_uint;
-     struct ldb_message_element *tmp_el;
- 
-+    if (msg == NULL || attr_map == NULL || certmap == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid input.\n");
-+        return EINVAL;
-+    }
-+
-+    for (d = 0; d < SSS_CMIM_SENTINEL; d++) {
-+        if (attr_map[d] == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Invalid attribute map");
-+            return EINVAL;
-+        }
-+    }
- 
-     map = talloc_zero(mem_ctx, struct certmap_info);
-     if (map == NULL) {
-         return ENOMEM;
-     }
- 
--    tmp_str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-+    tmp_str = ldb_msg_find_attr_as_string(msg, attr_map[SSS_CMIM_NAME], NULL);
-     if (tmp_str == NULL) {
-         DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n",
-                                     ldb_dn_get_linearized(msg->dn));
-@@ -295,7 +317,7 @@ errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    tmp_str = ldb_msg_find_attr_as_string(msg, SYSDB_CERTMAP_MAPPING_RULE,
-+    tmp_str = ldb_msg_find_attr_as_string(msg, attr_map[SSS_CMIM_MAPPING_RULE],
-                                           NULL);
-     if (tmp_str != NULL) {
-         map->map_rule = talloc_strdup(map, tmp_str);
-@@ -306,7 +328,7 @@ errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-         }
-     }
- 
--    tmp_str = ldb_msg_find_attr_as_string(msg, SYSDB_CERTMAP_MATCHING_RULE,
-+    tmp_str = ldb_msg_find_attr_as_string(msg, attr_map[SSS_CMIM_MATCHING_RULE],
-                                           NULL);
-     if (tmp_str != NULL) {
-         map->match_rule = talloc_strdup(map, tmp_str);
-@@ -317,7 +339,7 @@ errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-         }
-     }
- 
--    tmp_uint = ldb_msg_find_attr_as_uint64(msg, SYSDB_CERTMAP_PRIORITY,
-+    tmp_uint = ldb_msg_find_attr_as_uint64(msg, attr_map[SSS_CMIM_PRIORITY],
-                                            (uint64_t) -1);
-     if (tmp_uint != (uint64_t) -1) {
-         if (tmp_uint > UINT32_MAX) {
-@@ -332,7 +354,7 @@ errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
-         map->priority = SSS_CERTMAP_MIN_PRIO;
-     }
- 
--    tmp_el = ldb_msg_find_element(msg, SYSDB_CERTMAP_DOMAINS);
-+    tmp_el = ldb_msg_find_element(msg, attr_map[SSS_CMIM_DOMAINS]);
-     if (tmp_el != NULL) {
-         num_values = tmp_el->num_values;
-     } else {
-@@ -379,9 +401,9 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-     TALLOC_CTX *tmp_ctx = NULL;
-     struct ldb_result *res;
-     const char *attrs[] = {SYSDB_NAME,
--                           SYSDB_CERTMAP_PRIORITY,
--                           SYSDB_CERTMAP_MATCHING_RULE,
-                            SYSDB_CERTMAP_MAPPING_RULE,
-+                           SYSDB_CERTMAP_MATCHING_RULE,
-+                           SYSDB_CERTMAP_PRIORITY,
-                            SYSDB_CERTMAP_DOMAINS,
-                            NULL};
-     const char *config_attrs[] = {SYSDB_CERTMAP_USER_NAME_HINT,
-@@ -434,7 +456,8 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-     }
- 
-     for (c = 0; c < res->count; c++) {
--        ret = sysdb_ldb_msg_attr_to_certmap_info(maps, res->msgs[c], &maps[c]);
-+        ret = sysdb_ldb_msg_attr_to_certmap_info(maps, res->msgs[c], attrs,
-+                                                 &maps[c]);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE,
-                   "sysdb_ldb_msg_attr_to_certmap_info failed.\n");
--- 
-2.14.4
-
diff --git a/SOURCES/0006-confdb-add-confdb_certmap_to_sysdb.patch b/SOURCES/0006-confdb-add-confdb_certmap_to_sysdb.patch
deleted file mode 100644
index 210f90d..0000000
--- a/SOURCES/0006-confdb-add-confdb_certmap_to_sysdb.patch
+++ /dev/null
@@ -1,168 +0,0 @@
-From 861302754636745a9b60aa3946a749b779d4ef06 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 2 Jul 2018 10:38:54 +0200
-Subject: [PATCH 06/19] confdb: add confdb_certmap_to_sysdb()
-
-Add a function to write certificate mapping and matching rules from the
-config database to the cache of a domain.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit d9cc38008a51a8a5189904f175e4d10cbde4a974)
----
- src/confdb/confdb.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/confdb/confdb.h | 23 +++++++++++++
- 2 files changed, 122 insertions(+)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index 22068cacccc90d83047b148513b58618f176dd9a..7de0fb3cc7031767d748bd4fb739a3376fd364e3 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -2196,3 +2196,102 @@ done:
-     talloc_free(tmp_ctx);
-     return ret;
- }
-+
-+static errno_t confdb_get_all_certmaps(TALLOC_CTX *mem_ctx,
-+                                       struct confdb_ctx *cdb,
-+                                       struct sss_domain_info *dom,
-+                                       struct certmap_info ***_certmap_list)
-+{
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    struct ldb_dn *dn = NULL;
-+    struct ldb_result *res = NULL;
-+    /* The attributte order is important, because it is used in
-+     * sysdb_ldb_msg_attr_to_certmap_info and must match
-+     * enum certmap_info_member. */
-+    static const char *attrs[] = { CONFDB_CERTMAP_NAME,
-+                                   CONFDB_CERTMAP_MAPRULE,
-+                                   CONFDB_CERTMAP_MATCHRULE,
-+                                   CONFDB_CERTMAP_PRIORITY,
-+                                   CONFDB_CERTMAP_DOMAINS,
-+                                   NULL};
-+    struct certmap_info **certmap_list = NULL;
-+    size_t c;
-+    int ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", dom->name,
-+                                                       CONFDB_CERTMAP_BASEDN);
-+    if (dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL,
-+                     attrs, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    certmap_list = talloc_zero_array(tmp_ctx, struct certmap_info *,
-+                                     res->count + 1);
-+    if (certmap_list == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    for (c = 0; c < res->count; c++) {
-+        ret = sysdb_ldb_msg_attr_to_certmap_info(certmap_list, res->msgs[c],
-+                                                 attrs, &certmap_list[c]);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "sysdb_ldb_msg_attr_to_certmap_info failed.\n");
-+            goto done;
-+        }
-+    }
-+
-+    *_certmap_list = talloc_steal(mem_ctx, certmap_list);
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
-+                            struct sss_domain_info *dom)
-+{
-+    int ret;
-+    TALLOC_CTX *tmp_ctx;
-+    struct certmap_info **certmap_list;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = confdb_get_all_certmaps(tmp_ctx, cdb, dom, &certmap_list);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "confdb_get_all_certmaps failed.\n");
-+        goto done;
-+    }
-+
-+    ret = sysdb_update_certmap(dom->sysdb, certmap_list, false /* TODO */);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed.\n");
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 22665013aba1f768b7ecd38df9261b84807f70b8..2aae93a278eb62e9b8a18885f06d66b20f269f60 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -265,6 +265,15 @@
- #define CONFDB_KCM_SOCKET "socket_path"
- #define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
- 
-+/* Certificate mapping rules */
-+#define CONFDB_CERTMAP_BASEDN "cn=certmap,cn=config"
-+#define CONFDB_CERTMAP_NAME "cn"
-+#define CONFDB_CERTMAP_MAPRULE "maprule"
-+#define CONFDB_CERTMAP_MATCHRULE "matchrule"
-+#define CONFDB_CERTMAP_DOMAINS "domains"
-+#define CONFDB_CERTMAP_PRIORITY "priority"
-+
-+
- struct confdb_ctx;
- struct config_file_ctx;
- 
-@@ -662,6 +671,20 @@ int confdb_get_sub_sections(TALLOC_CTX *mem_ctx,
-                             const char *section,
-                             char ***sections,
-                             int *num_sections);
-+
-+/**
-+ * @brief Convenience function to write the certificate mapping and matching
-+ * rules from the configuration database to the cache of a domain
-+ *
-+ * @param[in] cdb The connection object to the confdb
-+ * @param[in] dom Target domain where to rules should be written to
-+ *
-+ * @return 0 - Successfully retrieved the entry (or used the default)
-+ * @return ENOMEM - There was insufficient memory to complete the operation
-+ * @return EINVAL - Typically internal processing error
-+ */
-+int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
-+                            struct sss_domain_info *dom);
- /**
-  * @}
-  */
--- 
-2.14.4
-
diff --git a/SOURCES/0006-p11_child-prefer-better-digest-function-if-card-supp.patch b/SOURCES/0006-p11_child-prefer-better-digest-function-if-card-supp.patch
new file mode 100644
index 0000000..b46cf3d
--- /dev/null
+++ b/SOURCES/0006-p11_child-prefer-better-digest-function-if-card-supp.patch
@@ -0,0 +1,147 @@
+From 7f0a8f5060b28dc35e152d7290b583de99361d80 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 2 Jul 2019 17:11:50 +0200
+Subject: [PATCH 6/7] p11_child: prefer better digest function if card supports
+ it
+
+To improve FIPS compliance and security in general p11_child now checks
+which message digest functions (hashes) are support for RSA keys and
+tries to use the highest bit length supported.
+
+For EC keys sha512 is used unconditionally.
+
+Related to https://pagure.io/SSSD/sssd/issue/4039
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/p11_child/p11_child_openssl.c | 87 +++++++++++++++++++++++++++++--
+ 1 file changed, 82 insertions(+), 5 deletions(-)
+
+diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
+index 007f58c52..7233f39fd 100644
+--- a/src/p11_child/p11_child_openssl.c
++++ b/src/p11_child/p11_child_openssl.c
+@@ -1097,7 +1097,75 @@ static int rs_to_seq(TALLOC_CTX *mem_ctx, CK_BYTE *rs_sig, CK_ULONG rs_sig_len,
+     return EOK;
+ }
+ 
++static CK_RV get_preferred_rsa_mechanism(TALLOC_CTX *mem_ctx,
++                                         CK_FUNCTION_LIST *module,
++                                         CK_SLOT_ID slot_id,
++                                         CK_MECHANISM_TYPE *preferred_mechanism,
++                                         const EVP_MD **preferred_evp_md)
++{
++    CK_ULONG count;
++    CK_MECHANISM_TYPE *mechanism_list = NULL;
++    CK_RV rv;
++    size_t c;
++    size_t m;
++    struct prefs {
++        CK_MECHANISM_TYPE mech;
++        const char *mech_name;
++        const EVP_MD *evp_md;
++        const char *md_name;
++    } prefs[] = {
++        { CKM_SHA512_RSA_PKCS, "CKM_SHA512_RSA_PKCS", EVP_sha512(), "sha512" },
++        { CKM_SHA384_RSA_PKCS, "CKM_SHA384_RSA_PKCS", EVP_sha384(), "sha384" },
++        { CKM_SHA256_RSA_PKCS, "CKM_SHA256_RSA_PKCS", EVP_sha256(), "sha256" },
++        { CKM_SHA224_RSA_PKCS, "CKM_SHA224_RSA_PKCS", EVP_sha224(), "sha224" },
++        { CKM_SHA1_RSA_PKCS,   "CKM_SHA1_RSA_PKCS",   EVP_sha1(),   "sha1" },
++        { 0, NULL }
++    };
++
++    *preferred_mechanism = CKM_SHA1_RSA_PKCS;
++    *preferred_evp_md = EVP_sha1();
++
++    rv = module->C_GetMechanismList(slot_id, NULL, &count);
++    if (rv == CKR_OK && count > 0) {
++        mechanism_list = talloc_size(mem_ctx,
++                                     count * sizeof(CK_MECHANISM_TYPE));
++        if (mechanism_list != NULL) {
++            rv = module->C_GetMechanismList(slot_id, mechanism_list, &count);
++            if (rv == CKR_OK) {
++                if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
++                    for (m = 0; m < count; m++) {
++                        DEBUG(SSSDBG_TRACE_ALL, "Found mechanism [%lu].\n",
++                                                mechanism_list[m]);
++                    }
++                }
++                for (c = 0; prefs[c].mech != 0; c++) {
++                    for (m = 0; m < count; m++) {
++                        if (prefs[c].mech == mechanism_list[m]) {
++                            *preferred_mechanism = prefs[c].mech;
++                            *preferred_evp_md = prefs[c].evp_md;
++                            DEBUG(SSSDBG_FUNC_DATA,
++                                  "Using PKCS#11 mechanism [%lu][%s] and "
++                                  "local message digest [%s].\n",
++                                  *preferred_mechanism, prefs[c].mech_name,
++                                  prefs[c].md_name);
++                            break;
++                        }
++                    }
++                    if (m != count) {
++                        break;
++                    }
++                }
++            }
++        }
++    }
++
++    talloc_free(mechanism_list);
++
++    return rv;
++}
++
+ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
++                     CK_SLOT_ID slot_id,
+                      struct cert_list *cert)
+ {
+     CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
+@@ -1108,6 +1176,7 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
+       {CKA_ID, NULL, 0}
+     };
+     CK_MECHANISM mechanism = { CK_UNAVAILABLE_INFORMATION, NULL, 0 };
++    CK_MECHANISM_TYPE preferred_mechanism;
+     CK_OBJECT_HANDLE priv_key_object;
+     CK_ULONG object_count;
+     CK_BYTE random_value[128];
+@@ -1157,15 +1226,23 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
+ 
+     switch (get_key_type(module, session, priv_key_object)) {
+     case CKK_RSA:
+-        DEBUG(SSSDBG_TRACE_ALL, "Found RSA key using CKM_SHA1_RSA_PKCS.\n");
+-        mechanism.mechanism = CKM_SHA1_RSA_PKCS;
+-        evp_md = EVP_sha1();
++        rv = get_preferred_rsa_mechanism(cert, module, slot_id,
++                                         &preferred_mechanism, &evp_md);
++        if (rv != CKR_OK) {
++            DEBUG(SSSDBG_OP_FAILURE, "get_preferred_rsa_mechanism failed, "
++                                     "using default CKM_SHA1_RSA_PKCS.\n");
++            preferred_mechanism = CKM_SHA1_RSA_PKCS;
++            evp_md = EVP_sha1();
++        }
++        DEBUG(SSSDBG_TRACE_ALL, "Found RSA key using mechanism [%lu].\n",
++                                preferred_mechanism);
++        mechanism.mechanism = preferred_mechanism;
+         card_does_hash = true;
+         break;
+     case CKK_EC:
+         DEBUG(SSSDBG_TRACE_ALL, "Found ECC key using CKM_ECDSA.\n");
+         mechanism.mechanism = CKM_ECDSA;
+-        evp_md = EVP_sha1();
++        evp_md = EVP_sha512();
+         card_does_hash = false;
+         break;
+     case CK_UNAVAILABLE_INFORMATION:
+@@ -1662,7 +1739,7 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
+             goto done;
+         }
+ 
+-        ret = sign_data(module, session, cert_list);
++        ret = sign_data(module, session, slot_id, cert_list);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "sign_data failed.\n");
+             ret = EACCES;
+-- 
+2.20.1
+
diff --git a/SOURCES/0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch b/SOURCES/0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch
deleted file mode 100644
index a838fe7..0000000
--- a/SOURCES/0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From cfdabe874c62267bccd3a7b26d16118f9c183c3a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 2 Jul 2018 12:20:53 +0200
-Subject: [PATCH 07/19] AD/LDAP: read certificate mapping rules from config
- file
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 15301db1dc1e5e2aafc1805a30e3b28756218c9b)
----
- src/providers/ad/ad_init.c     | 16 ++++++++++++++++
- src/providers/ldap/ldap_init.c | 16 ++++++++++++++++
- 2 files changed, 32 insertions(+)
-
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index 637efb761c1cf87b0a2c2b1c19b00ea0bbbe161f..a9085717c5334c2c7dbc48c856cee336ab63d7b0 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -419,6 +419,22 @@ static errno_t ad_init_misc(struct be_ctx *be_ctx,
-         return ret;
-     }
- 
-+    ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to initialize certificate mapping rules. "
-+              "Authentication with certificates/Smartcards might not work "
-+              "as expected.\n");
-+        /* not fatal, ignored */
-+    }
-+
-+    ret = sdap_init_certmap(sdap_id_ctx, sdap_id_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to initialized certificate mapping.\n");
-+        return ret;
-+    }
-+
-     return EOK;
- }
- 
-diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
-index 44b3e9ab3dec828b5350ac9e52e56e125084cbac..95e65612369e3e4840f5ffedfe2812d17149c6da 100644
---- a/src/providers/ldap/ldap_init.c
-+++ b/src/providers/ldap/ldap_init.c
-@@ -438,6 +438,22 @@ static errno_t ldap_init_misc(struct be_ctx *be_ctx,
-               "[%d]: %s\n", ret, sss_strerror(ret));
-     }
- 
-+    ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to initialize certificate mapping rules. "
-+              "Authentication with certificates/Smartcards might not work "
-+              "as expected.\n");
-+        /* not fatal, ignored */
-+    }
-+
-+    ret = sdap_init_certmap(id_ctx, id_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to initialized certificate mapping.\n");
-+        return ret;
-+    }
-+
-     return EOK;
- }
- 
--- 
-2.14.4
-
diff --git a/SOURCES/0007-p11_child-fix-a-memory-leak-and-other-memory-mangeme.patch b/SOURCES/0007-p11_child-fix-a-memory-leak-and-other-memory-mangeme.patch
new file mode 100644
index 0000000..6abe806
--- /dev/null
+++ b/SOURCES/0007-p11_child-fix-a-memory-leak-and-other-memory-mangeme.patch
@@ -0,0 +1,49 @@
+From 60748f69d9e21cf4cfd0655a0d7b81a715e9ae04 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 2 Jul 2019 21:58:15 +0200
+Subject: [PATCH 7/7] p11_child: fix a memory leak and other memory mangement
+ issues
+
+EVP_MD_CTX_create() was called without matching EVP_MD_CTX_destroy().
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/p11_child/p11_child_openssl.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
+index 7233f39fd..64d2d759c 100644
+--- a/src/p11_child/p11_child_openssl.c
++++ b/src/p11_child/p11_child_openssl.c
+@@ -986,9 +986,9 @@ static int do_hash(TALLOC_CTX *mem_ctx, const EVP_MD *evp_md,
+ 
+ done:
+ 
++    EVP_MD_CTX_free(md_ctx);
+     if (ret != EOK) {
+         free(out);
+-        EVP_MD_CTX_free(md_ctx);
+     }
+ 
+     return ret;
+@@ -1187,7 +1187,7 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
+     CK_RV rv;
+     CK_RV rv_f;
+     EVP_PKEY *cert_pub_key = NULL;
+-    EVP_MD_CTX *md_ctx;
++    EVP_MD_CTX *md_ctx = NULL;
+     int ret;
+     const EVP_MD *evp_md = NULL;
+     CK_BYTE *hash_val = NULL;
+@@ -1358,6 +1358,8 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
+     ret = EOK;
+ 
+ done:
++    EVP_MD_CTX_destroy(md_ctx);
++    talloc_free(hash_val);
+     talloc_free(signature);
+     EVP_PKEY_free(cert_pub_key);
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0008-man-fix-description-of-dns_resolver_op_timeout.patch b/SOURCES/0008-man-fix-description-of-dns_resolver_op_timeout.patch
new file mode 100644
index 0000000..e8624ce
--- /dev/null
+++ b/SOURCES/0008-man-fix-description-of-dns_resolver_op_timeout.patch
@@ -0,0 +1,36 @@
+From 7b4635c8428917ced63954f2c3c70491b45d7870 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 11 Jun 2019 13:49:13 +0200
+Subject: [PATCH 08/12] man: fix description of dns_resolver_op_timeout
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3217
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/man/include/failover.xml | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/man/include/failover.xml b/src/man/include/failover.xml
+index cd6fd4d79..11ff86a38 100644
+--- a/src/man/include/failover.xml
++++ b/src/man/include/failover.xml
+@@ -77,7 +77,13 @@
+                     </term>
+                     <listitem>
+                         <para>
+-                            How long would SSSD talk to a single DNS server.
++                            Time in seconds to tell how long would SSSD try
++                            to resolve single DNS query (e.g. resolution of a
++                            hostname or an SRV record) before trying the next
++                            hostname or discovery domain.
++                        </para>
++                        <para>
++                            Default: 6
+                         </para>
+                     </listitem>
+                 </varlistentry>
+-- 
+2.20.1
+
diff --git a/SOURCES/0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch b/SOURCES/0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch
deleted file mode 100644
index 0ca43a2..0000000
--- a/SOURCES/0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 357323d3312d4f2c6a2bbbea03f2296e3368e45a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 3 Jul 2018 11:31:12 +0200
-Subject: [PATCH 08/19] sysdb: sysdb_certmap_add() handle domains more flexible
-
-sysdb_ldb_msg_attr_to_certmap_info() creates an empty list if there are
-no domains defined, sysdb_certmap_add() should be able to handle both a
-missing or an empty domains list.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 06f7005d38d164879b727708feff80004b422f91)
----
- src/db/sysdb_certmap.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
-index e37f1ba830f297137991c7757af9c7c4e17b2813..0bcc54c4d1eb0ede7de088e3e945a48f1549c88c 100644
---- a/src/db/sysdb_certmap.c
-+++ b/src/db/sysdb_certmap.c
-@@ -131,7 +131,7 @@ static errno_t sysdb_certmap_add(struct sysdb_ctx *sysdb,
-         }
-     }
- 
--    if (certmap->domains != NULL) {
-+    if (certmap->domains != NULL && certmap->domains[0] != NULL) {
-         for (c = 0; certmap->domains[c] != NULL; c++);
-         el = talloc_zero(tmp_ctx, struct ldb_message_element);
-         if (el == NULL) {
--- 
-2.14.4
-
diff --git a/SOURCES/0009-confdb-add-special-handling-for-rules-for-the-files-.patch b/SOURCES/0009-confdb-add-special-handling-for-rules-for-the-files-.patch
deleted file mode 100644
index ad0e621..0000000
--- a/SOURCES/0009-confdb-add-special-handling-for-rules-for-the-files-.patch
+++ /dev/null
@@ -1,132 +0,0 @@
-From db2ca398ef66d73bf04d4cf45a327a8472ce834e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 6 Jul 2018 15:17:10 +0200
-Subject: [PATCH 09/19] confdb: add special handling for rules for the files
- provider
-
-To make the configuration more simple there are some special assumption
-for local users, i.e. user managed by the files provider.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 9386ef605ffbc03abe2bc273efddbc099441fe3b)
----
- src/confdb/confdb.c              | 59 ++++++++++++++++++++++++++++++++++++++++
- src/confdb/confdb.h              |  1 +
- src/providers/files/files_init.c | 10 +++++++
- 3 files changed, 70 insertions(+)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index 7de0fb3cc7031767d748bd4fb739a3376fd364e3..6370a0411d98b6611dd384e9ab0de1d580be9c2d 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -2197,6 +2197,56 @@ done:
-     return ret;
- }
- 
-+static errno_t certmap_local_check(struct ldb_message *msg)
-+{
-+    const char *rule_name;
-+    const char *tmp_str;
-+    int ret;
-+
-+    rule_name = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_NAME, NULL);
-+    if (rule_name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Certficate mapping rule [%s] has no name.",
-+                                   ldb_dn_get_linearized(msg->dn));
-+        return EINVAL;
-+    }
-+
-+    tmp_str = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_DOMAINS, NULL);
-+    if (tmp_str != NULL) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "Option [%s] is ignored for local certmap rules.\n",
-+              CONFDB_CERTMAP_DOMAINS);
-+    }
-+
-+    tmp_str = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_MAPRULE, NULL);
-+    if (tmp_str != NULL) {
-+        if (tmp_str[0] != '(' || tmp_str[strlen(tmp_str) - 1] != ')') {
-+            DEBUG(SSSDBG_CONF_SETTINGS,
-+                  "Mapping rule must be in braces (...).\n");
-+            return EINVAL;
-+        }
-+        DEBUG(SSSDBG_TRACE_ALL, "Using [%s] mapping rule of [%s].\n",
-+                                tmp_str, ldb_dn_get_linearized(msg->dn));
-+        return EOK;
-+    }
-+
-+    tmp_str = talloc_asprintf(msg, "(%s)", rule_name);
-+    if (tmp_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
-+        return ENOMEM;
-+    }
-+    ret = ldb_msg_add_string(msg, CONFDB_CERTMAP_MAPRULE, tmp_str);
-+    if (ret != LDB_SUCCESS) {
-+        talloc_free(discard_const(tmp_str));
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
-+        return EIO;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "Using [%s] as mapping rule for [%s].\n",
-+                            tmp_str, ldb_dn_get_linearized(msg->dn));
-+
-+    return EOK;
-+}
-+
- static errno_t confdb_get_all_certmaps(TALLOC_CTX *mem_ctx,
-                                        struct confdb_ctx *cdb,
-                                        struct sss_domain_info *dom,
-@@ -2245,6 +2295,15 @@ static errno_t confdb_get_all_certmaps(TALLOC_CTX *mem_ctx,
-     }
- 
-     for (c = 0; c < res->count; c++) {
-+        if (is_files_provider(dom)) {
-+            ret = certmap_local_check(res->msgs[c]);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_CONF_SETTINGS,
-+                      "Invalid certificate mapping [%s] for local user, "
-+                      "ignored.\n", ldb_dn_get_linearized(res->msgs[c]->dn));
-+                continue;
-+            }
-+        }
-         ret = sysdb_ldb_msg_attr_to_certmap_info(certmap_list, res->msgs[c],
-                                                  attrs, &certmap_list[c]);
-         if (ret != EOK) {
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 2aae93a278eb62e9b8a18885f06d66b20f269f60..625d156267ebf5f59e3974663256acfbb5f3b027 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -685,6 +685,7 @@ int confdb_get_sub_sections(TALLOC_CTX *mem_ctx,
-  */
- int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
-                             struct sss_domain_info *dom);
-+
- /**
-  * @}
-  */
-diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c
-index 746c04af1d766b4da623196d3ff6ebc99ca6efef..c793bed9cc99db958b50ed9f6d69a2f8f337b409 100644
---- a/src/providers/files/files_init.c
-+++ b/src/providers/files/files_init.c
-@@ -189,6 +189,16 @@ int sssm_files_init(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
-+    ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to initialize certificate mapping rules. "
-+              "Authentication with certificates/Smartcards might not work "
-+              "as expected.\n");
-+        /* not fatal, ignored */
-+    }
-+
-+
-     *_module_data = ctx;
-     ret = EOK;
- done:
--- 
-2.14.4
-
diff --git a/SOURCES/0009-man-fix-description-of-dns_resolver_timeout.patch b/SOURCES/0009-man-fix-description-of-dns_resolver_timeout.patch
new file mode 100644
index 0000000..4f486f4
--- /dev/null
+++ b/SOURCES/0009-man-fix-description-of-dns_resolver_timeout.patch
@@ -0,0 +1,31 @@
+From 3807de1d97fc87cf7c25af264a8b1bbabdef54e2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 11 Jun 2019 13:49:33 +0200
+Subject: [PATCH 09/12] man: fix description of dns_resolver_timeout
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3217
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/man/include/failover.xml | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/man/include/failover.xml b/src/man/include/failover.xml
+index 11ff86a38..7b451d831 100644
+--- a/src/man/include/failover.xml
++++ b/src/man/include/failover.xml
+@@ -98,6 +98,9 @@
+                             include several steps, such as resolving DNS SRV
+                             queries or locating the site.
+                         </para>
++                        <para>
++                            Default: 6
++                        </para>
+                     </listitem>
+                 </varlistentry>
+             </variablelist>
+-- 
+2.20.1
+
diff --git a/SOURCES/0010-failover-add-dns_resolver_server_timeout-option.patch b/SOURCES/0010-failover-add-dns_resolver_server_timeout-option.patch
new file mode 100644
index 0000000..2abfcaf
--- /dev/null
+++ b/SOURCES/0010-failover-add-dns_resolver_server_timeout-option.patch
@@ -0,0 +1,276 @@
+From 99e2a107f01c625cb59cb88589db87294176d6c6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 11 Jun 2019 13:37:23 +0200
+Subject: [PATCH 10/12] failover: add dns_resolver_server_timeout option
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3217
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/config/SSSDConfig/__init__.py.in |  1 +
+ src/config/SSSDConfigTest.py         |  2 ++
+ src/config/cfg_rules.ini             |  1 +
+ src/config/etc/sssd.api.conf         |  1 +
+ src/man/include/failover.xml         | 17 ++++++++++++++++-
+ src/providers/data_provider.h        |  1 +
+ src/providers/data_provider_fo.c     |  3 +++
+ src/resolv/async_resolv.c            | 10 ++++++----
+ src/resolv/async_resolv.h            |  2 +-
+ src/tests/cmocka/test_fo_srv.c       |  4 ++--
+ src/tests/cmocka/test_resolv_fake.c  |  2 +-
+ src/tests/fail_over-tests.c          |  2 +-
+ src/tests/resolv-tests.c             |  2 +-
+ 13 files changed, 37 insertions(+), 11 deletions(-)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 9642fe6ba..2d1214e16 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -171,6 +171,7 @@ option_strings = {
+     'entry_cache_timeout' : _('Entry cache timeout length (seconds)'),
+     'lookup_family_order' : _('Restrict or prefer a specific address family when performing DNS lookups'),
+     'account_cache_expiration' : _('How long to keep cached entries after last successful login (days)'),
++    'dns_resolver_server_timeout' : _('How long should SSSD talk to single DNS server before trying next server (miliseconds)'),
+     'dns_resolver_timeout' : _('How long to wait for replies from DNS when resolving servers (seconds)'),
+     'dns_discovery_domain' : _('The domain part of service discovery DNS query'),
+     'override_gid' : _('Override GID value from the identity provider with this value'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 727df71ab..82b1a9700 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -606,6 +606,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'refresh_expired_interval',
+             'lookup_family_order',
+             'account_cache_expiration',
++            'dns_resolver_server_timeout',
+             'dns_resolver_timeout',
+             'dns_discovery_domain',
+             'dyndns_update',
+@@ -976,6 +977,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'refresh_expired_interval',
+             'account_cache_expiration',
+             'lookup_family_order',
++            'dns_resolver_server_timeout',
+             'dns_resolver_timeout',
+             'dns_discovery_domain',
+             'dyndns_update',
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 929e6149a..a2efb3a67 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -367,6 +367,7 @@ option = account_cache_expiration
+ option = pwd_expiration_warning
+ option = filter_users
+ option = filter_groups
++option = dns_resolver_server_timeout
+ option = dns_resolver_timeout
+ option = dns_discovery_domain
+ option = override_gid
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index c6d6690fb..288b1cfe7 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -170,6 +170,7 @@ account_cache_expiration = int, None, false
+ pwd_expiration_warning = int, None, false
+ filter_users = list, str, false
+ filter_groups = list, str, false
++dns_resolver_server_timeout = int, None, false
+ dns_resolver_timeout = int, None, false
+ dns_discovery_domain = str, None, false
+ override_gid = int, None, false
+diff --git a/src/man/include/failover.xml b/src/man/include/failover.xml
+index 7b451d831..f2a01b933 100644
+--- a/src/man/include/failover.xml
++++ b/src/man/include/failover.xml
+@@ -71,6 +71,20 @@
+             </citerefentry>,
+             manual page.
+             <variablelist>
++                <varlistentry>
++                    <term>
++                        dns_resolver_server_timeout
++                    </term>
++                    <listitem>
++                        <para>
++                            Time in milliseconds that sets how long would SSSD
++                            talk to a single DNS server before trying next one.
++                        </para>
++                        <para>
++                            Default: 2000
++                        </para>
++                    </listitem>
++                </varlistentry>
+                 <varlistentry>
+                     <term>
+                         dns_resolver_op_timeout
+@@ -111,7 +125,8 @@
+             <quote>ldap_opt_timeout></quote> timeout should be set to
+             a larger value than <quote>dns_resolver_timeout</quote>
+             which in turn should be set to a larger value than
+-            <quote>dns_resolver_op_timeout</quote>.
++            <quote>dns_resolver_op_timeout</quote> which should be larger
++            than <quote>dns_resolver_server_timeout</quote>.
+         </para>
+     </refsect2>
+ </refsect1>
+diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
+index a0a21cc12..2d10dbb5b 100644
+--- a/src/providers/data_provider.h
++++ b/src/providers/data_provider.h
+@@ -265,6 +265,7 @@ enum dp_res_opts {
+     DP_RES_OPT_FAMILY_ORDER,
+     DP_RES_OPT_RESOLVER_TIMEOUT,
+     DP_RES_OPT_RESOLVER_OP_TIMEOUT,
++    DP_RES_OPT_RESOLVER_SERVER_TIMEOUT,
+     DP_RES_OPT_DNS_DOMAIN,
+ 
+     DP_RES_OPTS /* attrs counter */
+diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
+index 473b667e5..a7af3e2a5 100644
+--- a/src/providers/data_provider_fo.c
++++ b/src/providers/data_provider_fo.c
+@@ -833,6 +833,7 @@ static struct dp_option dp_res_default_opts[] = {
+     { "lookup_family_order", DP_OPT_STRING, { "ipv4_first" }, NULL_STRING },
+     { "dns_resolver_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+     { "dns_resolver_op_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
++    { "dns_resolver_server_timeout", DP_OPT_NUMBER, { .number = 2000 }, NULL_NUMBER },
+     { "dns_discovery_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+@@ -894,6 +895,8 @@ errno_t be_res_init(struct be_ctx *ctx)
+     ret = resolv_init(ctx, ctx->ev,
+                       dp_opt_get_int(ctx->be_res->opts,
+                                      DP_RES_OPT_RESOLVER_OP_TIMEOUT),
++                      dp_opt_get_int(ctx->be_res->opts,
++                                     DP_RES_OPT_RESOLVER_SERVER_TIMEOUT),
+                       &ctx->be_res->resolv);
+     if (ret != EOK) {
+         talloc_zfree(ctx->be_res);
+diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c
+index 01d835ec9..00b9531d4 100644
+--- a/src/resolv/async_resolv.c
++++ b/src/resolv/async_resolv.c
+@@ -60,8 +60,6 @@
+ #define DNS_RR_LEN(r)                   DNS__16BIT((r) + 8)
+ #define DNS_RR_TTL(r)                   DNS__32BIT((r) + 4)
+ 
+-#define RESOLV_TIMEOUTMS  2000
+-
+ enum host_database default_host_dbs[] = { DB_FILES, DB_DNS, DB_SENTINEL };
+ 
+ struct fd_watch {
+@@ -83,6 +81,9 @@ struct resolv_ctx {
+     /* Time in milliseconds before canceling a DNS request */
+     int timeout;
+ 
++    /* Time in milliseconds for communication with single DNS server. */
++    int ares_timeout;
++
+     /* The timeout watcher periodically calls ares_process_fd() to check
+      * if our pending requests didn't timeout. */
+     int pending_requests;
+@@ -423,7 +424,7 @@ recreate_ares_channel(struct resolv_ctx *ctx)
+      */
+     options.sock_state_cb = fd_event;
+     options.sock_state_cb_data = ctx;
+-    options.timeout = RESOLV_TIMEOUTMS;
++    options.timeout = ctx->ares_timeout;
+     /* Only affects ares_gethostbyname */
+     options.lookups = discard_const("f");
+     options.tries = 1;
+@@ -450,7 +451,7 @@ recreate_ares_channel(struct resolv_ctx *ctx)
+ 
+ int
+ resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
+-            int timeout, struct resolv_ctx **ctxp)
++            int timeout, int ares_timeout, struct resolv_ctx **ctxp)
+ {
+     int ret;
+     struct resolv_ctx *ctx;
+@@ -467,6 +468,7 @@ resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
+ 
+     ctx->ev_ctx = ev_ctx;
+     ctx->timeout = timeout;
++    ctx->ares_timeout = ares_timeout;
+ 
+     ret = recreate_ares_channel(ctx);
+     if (ret != EOK) {
+diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h
+index 90ed03707..d83a7be44 100644
+--- a/src/resolv/async_resolv.h
++++ b/src/resolv/async_resolv.h
+@@ -52,7 +52,7 @@
+ struct resolv_ctx;
+ 
+ int resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
+-                int timeout, struct resolv_ctx **ctxp);
++                int timeout, int ares_timeout, struct resolv_ctx **ctxp);
+ 
+ void resolv_reread_configuration(struct resolv_ctx *ctx);
+ 
+diff --git a/src/tests/cmocka/test_fo_srv.c b/src/tests/cmocka/test_fo_srv.c
+index a11ebbb54..c13cf3a69 100644
+--- a/src/tests/cmocka/test_fo_srv.c
++++ b/src/tests/cmocka/test_fo_srv.c
+@@ -49,7 +49,7 @@ struct resolv_ctx {
+ 
+ /* mock resolver interface. The resolver test is separate */
+ int resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
+-                int timeout, struct resolv_ctx **ctxp)
++                int timeout, int ares_timeout, struct resolv_ctx **ctxp)
+ {
+     *ctxp = talloc(mem_ctx, struct resolv_ctx);
+     return EOK;
+@@ -230,7 +230,7 @@ static int test_fo_setup(void **state)
+     assert_non_null(test_ctx->ctx);
+ 
+     ret = resolv_init(test_ctx, test_ctx->ctx->ev,
+-                      TEST_RESOLV_TIMEOUT, &test_ctx->resolv);
++                      TEST_RESOLV_TIMEOUT, 2000, &test_ctx->resolv);
+     assert_non_null(test_ctx->resolv);
+ 
+     memset(&fopts, 0, sizeof(fopts));
+diff --git a/src/tests/cmocka/test_resolv_fake.c b/src/tests/cmocka/test_resolv_fake.c
+index 4cb3d4027..0f4011a39 100644
+--- a/src/tests/cmocka/test_resolv_fake.c
++++ b/src/tests/cmocka/test_resolv_fake.c
+@@ -240,7 +240,7 @@ static int test_resolv_fake_setup(void **state)
+     assert_non_null(test_ctx->ctx);
+ 
+     ret = resolv_init(test_ctx, test_ctx->ctx->ev,
+-                      TEST_DEFAULT_TIMEOUT, &test_ctx->resolv);
++                      TEST_DEFAULT_TIMEOUT, 2000, &test_ctx->resolv);
+     assert_int_equal(ret, EOK);
+ 
+     *state = test_ctx;
+diff --git a/src/tests/fail_over-tests.c b/src/tests/fail_over-tests.c
+index 5312b2772..b2269ef3b 100644
+--- a/src/tests/fail_over-tests.c
++++ b/src/tests/fail_over-tests.c
+@@ -73,7 +73,7 @@ setup_test(void)
+         fail("Could not init tevent context");
+     }
+ 
+-    ret = resolv_init(ctx, ctx->ev, 5, &ctx->resolv);
++    ret = resolv_init(ctx, ctx->ev, 5, 2000, &ctx->resolv);
+     if (ret != EOK) {
+         talloc_free(ctx);
+         fail("Could not init resolv context");
+diff --git a/src/tests/resolv-tests.c b/src/tests/resolv-tests.c
+index 4a2b3b904..bc4cd7cc1 100644
+--- a/src/tests/resolv-tests.c
++++ b/src/tests/resolv-tests.c
+@@ -76,7 +76,7 @@ static int setup_resolv_test(int timeout, struct resolv_test_ctx **ctx)
+         return EFAULT;
+     }
+ 
+-    ret = resolv_init(test_ctx, test_ctx->ev, timeout, &test_ctx->resolv);
++    ret = resolv_init(test_ctx, test_ctx->ev, timeout, 2000, &test_ctx->resolv);
+     if (ret != EOK) {
+         fail("Could not init resolv context");
+         talloc_free(test_ctx);
+-- 
+2.20.1
+
diff --git a/SOURCES/0010-files-add-support-for-Smartcard-authentication.patch b/SOURCES/0010-files-add-support-for-Smartcard-authentication.patch
deleted file mode 100644
index 41d3d62..0000000
--- a/SOURCES/0010-files-add-support-for-Smartcard-authentication.patch
+++ /dev/null
@@ -1,415 +0,0 @@
-From f92bac7b528d5caf797162ecb4d21f1f7652a49a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 9 Jul 2018 18:37:46 +0200
-Subject: [PATCH 10/19] files: add support for Smartcard authentication
-
-To support certificate based authentication the files provider must be
-able to map a certificate to a user during a BE_REQ_BY_CERT request.
-
-Additionally the authentication request should be handled by the PAM
-responder code which is responsible for the local Smartcard
-authentication. To be consistent with the other backend an authentication
-handler is added to the files provider which unconditionally returns the
-offline error code telling the PAM responder to handle the
-authentication if it has access to the needed credentials.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 275eeed24adc31f3df51cf278f509a4be76a3a3c)
----
- Makefile.am                         |   2 +
- src/providers/files/files_auth.c    |  69 +++++++++++++
- src/providers/files/files_certmap.c | 186 ++++++++++++++++++++++++++++++++++++
- src/providers/files/files_id.c      |  20 ++++
- src/providers/files/files_init.c    |  21 +++-
- src/providers/files/files_private.h |  17 ++++
- 6 files changed, 314 insertions(+), 1 deletion(-)
- create mode 100644 src/providers/files/files_auth.c
- create mode 100644 src/providers/files/files_certmap.c
-
-diff --git a/Makefile.am b/Makefile.am
-index d313957722a1d6be90ee2f91bf2613a39657a6a1..85952818c9a8efd957ce99f4595b251265cc5417 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -4270,6 +4270,8 @@ libsss_proxy_la_LDFLAGS = \
- libsss_files_la_SOURCES = \
-     src/providers/files/files_init.c \
-     src/providers/files/files_id.c \
-+    src/providers/files/files_auth.c \
-+    src/providers/files/files_certmap.c \
-     src/providers/files/files_ops.c \
-     src/util/inotify.c \
-     $(NULL)
-diff --git a/src/providers/files/files_auth.c b/src/providers/files/files_auth.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..b71de6971f89a94af0a457f77206c5a7fb3af4ea
---- /dev/null
-+++ b/src/providers/files/files_auth.c
-@@ -0,0 +1,69 @@
-+/*
-+    SSSD
-+
-+    files_auth.c - PAM operations on the files provider
-+
-+    Copyright (C) 2018 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 <security/pam_modules.h>
-+
-+#include "providers/data_provider/dp.h"
-+#include "providers/data_provider.h"
-+#include "providers/files/files_private.h"
-+#include "util/cert.h"
-+
-+struct files_auth_ctx {
-+    struct pam_data *pd;
-+};
-+
-+struct tevent_req *
-+files_auth_handler_send(TALLOC_CTX *mem_ctx,
-+                        void *unused,
-+                        struct pam_data *pd,
-+                        struct dp_req_params *params)
-+{
-+    struct files_auth_ctx *state;
-+    struct tevent_req *req;
-+
-+    req = tevent_req_create(mem_ctx, &state, struct files_auth_ctx);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-+        return NULL;
-+    }
-+
-+    state->pd = pd;
-+    state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
-+
-+    tevent_req_done(req);
-+    tevent_req_post(req, params->ev);
-+    return req;
-+}
-+
-+errno_t files_auth_handler_recv(TALLOC_CTX *mem_ctx,
-+                                struct tevent_req *req,
-+                                struct pam_data **_data)
-+{
-+    struct files_auth_ctx *state = NULL;
-+
-+    state = tevent_req_data(req, struct files_auth_ctx);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    *_data = talloc_steal(mem_ctx, state->pd);
-+
-+    return EOK;
-+}
-diff --git a/src/providers/files/files_certmap.c b/src/providers/files/files_certmap.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..7d90a1fecf5c3eedbd9c8570ad6195bde49159d9
---- /dev/null
-+++ b/src/providers/files/files_certmap.c
-@@ -0,0 +1,186 @@
-+/*
-+    SSSD
-+
-+    files_init.c - Initialization of the files provider
-+
-+    Copyright (C) 2018 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include "providers/files/files_private.h"
-+#include "util/util.h"
-+#include "util/cert.h"
-+#include "lib/certmap/sss_certmap.h"
-+
-+struct priv_sss_debug {
-+    int level;
-+};
-+
-+static void ext_debug(void *private, const char *file, long line,
-+                      const char *function, const char *format, ...)
-+{
-+    va_list ap;
-+    struct priv_sss_debug *data = private;
-+    int level = SSSDBG_OP_FAILURE;
-+
-+    if (data != NULL) {
-+        level = data->level;
-+    }
-+
-+    if (DEBUG_IS_SET(level)) {
-+        va_start(ap, format);
-+        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
-+                      format, ap);
-+        va_end(ap);
-+    }
-+}
-+
-+errno_t files_init_certmap(TALLOC_CTX *mem_ctx, struct files_id_ctx *id_ctx)
-+{
-+    int ret;
-+    bool hint;
-+    struct certmap_info **certmap_list = NULL;
-+    size_t c;
-+
-+    ret = sysdb_get_certmap(mem_ctx, id_ctx->be->domain->sysdb,
-+                            &certmap_list, &hint);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
-+        goto done;
-+    }
-+
-+    if (certmap_list == NULL || *certmap_list == NULL) {
-+        DEBUG(SSSDBG_TRACE_ALL, "No certmap data, nothing to do.\n");
-+        ret = EOK;
-+        goto done;
-+    }
-+
-+    ret = sss_certmap_init(mem_ctx, ext_debug, NULL, &id_ctx->sss_certmap_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n");
-+        goto done;
-+    }
-+
-+    for (c = 0; certmap_list[c] != NULL; c++) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Trying to add rule [%s][%d][%s][%s].\n",
-+                                certmap_list[c]->name,
-+                                certmap_list[c]->priority,
-+                                certmap_list[c]->match_rule,
-+                                certmap_list[c]->map_rule);
-+
-+        ret = sss_certmap_add_rule(id_ctx->sss_certmap_ctx,
-+                                   certmap_list[c]->priority,
-+                                   certmap_list[c]->match_rule,
-+                                   certmap_list[c]->map_rule,
-+                                   certmap_list[c]->domains);
-+        if (ret != 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "sss_certmap_add_rule failed for rule [%s] "
-+                  "with error [%d][%s], skipping. "
-+                  "Please check for typos and if rule syntax is supported.\n",
-+                  certmap_list[c]->name, ret, sss_strerror(ret));
-+            continue;
-+        }
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(certmap_list);
-+
-+    return ret;
-+}
-+
-+errno_t files_map_cert_to_user(struct files_id_ctx *id_ctx,
-+                               struct dp_id_data *data)
-+{
-+    errno_t ret;
-+    char *filter;
-+    char *user;
-+    struct ldb_message *msg = NULL;
-+    struct sysdb_attrs *attrs = NULL;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, data->filter_value, "",
-+                                         id_ctx->sss_certmap_ctx,
-+                                         id_ctx->domain, &filter);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "sss_cert_derb64_to_ldap_filter failed.\n");
-+        goto done;
-+    }
-+    if (filter == NULL || filter[0] != '('
-+                       || filter[strlen(filter) - 1] != ')') {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "sss_cert_derb64_to_ldap_filter returned bad filter [%s].\n",
-+              filter);
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    filter[strlen(filter) - 1] = '\0';
-+    user = sss_create_internal_fqname(tmp_ctx, &filter[1],
-+                                      id_ctx->domain->name);
-+    if (user == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_create_internal_fqname failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    DEBUG(SSSDBG_TRACE_ALL, "Certificate mapped to user: [%s].\n", user);
-+
-+    ret = sysdb_search_user_by_name(tmp_ctx, id_ctx->domain, user, NULL, &msg);
-+    if (ret == EOK) {
-+        attrs = sysdb_new_attrs(tmp_ctx);
-+        if (attrs == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_MAPPED_CERT,
-+                                          data->filter_value);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n");
-+            goto done;
-+        }
-+
-+        ret = sysdb_set_entry_attr(id_ctx->domain->sysdb, msg->dn, attrs,
-+                                   SYSDB_MOD_ADD);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n");
-+            goto done;
-+        }
-+    } else if (ret == ENOENT) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Mapped user [%s] not found.\n", user);
-+        ret = EOK;
-+        goto done;
-+    } else {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-diff --git a/src/providers/files/files_id.c b/src/providers/files/files_id.c
-index 41314c66b1e435b51fe0b9bc18779c11ad261773..f6f8c7311be5fd9511ff4d417975b3195678d053 100644
---- a/src/providers/files/files_id.c
-+++ b/src/providers/files/files_id.c
-@@ -87,6 +87,26 @@ files_account_info_handler_send(TALLOC_CTX *mem_ctx,
-                        ? true \
-                        : false;
-         break;
-+    case BE_REQ_BY_CERT:
-+        if (data->filter_type != BE_FILTER_CERT) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Unexpected filter type for lookup by cert: %d\n",
-+                  data->filter_type);
-+            ret = EINVAL;
-+            goto immediate;
-+        }
-+        if (id_ctx->sss_certmap_ctx == NULL) {
-+            DEBUG(SSSDBG_TRACE_ALL, "Certificate mapping not configured.\n");
-+            ret = EOK;
-+            goto immediate;
-+        }
-+
-+        ret = files_map_cert_to_user(id_ctx, data);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "files_map_cert_to_user failed");
-+        }
-+        goto immediate;
-+        break;
-     default:
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "Unexpected entry type: %d\n", data->entry_type & BE_REQ_TYPE_MASK);
-diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c
-index c793bed9cc99db958b50ed9f6d69a2f8f337b409..1ce4bcf2728004d043c1d26b97aa7c41fb81e181 100644
---- a/src/providers/files/files_init.c
-+++ b/src/providers/files/files_init.c
-@@ -196,9 +196,16 @@ int sssm_files_init(TALLOC_CTX *mem_ctx,
-               "Authentication with certificates/Smartcards might not work "
-               "as expected.\n");
-         /* not fatal, ignored */
-+    } else {
-+        ret = files_init_certmap(ctx, ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "files_init_certmap failed. "
-+                  "Authentication with certificates/Smartcards might not work "
-+                  "as expected.\n");
-+            /* not fatal, ignored */
-+        }
-     }
- 
--
-     *_module_data = ctx;
-     ret = EOK;
- done:
-@@ -234,3 +241,15 @@ int sssm_files_id_init(TALLOC_CTX *mem_ctx,
- 
-     return EOK;
- }
-+
-+int sssm_files_auth_init(TALLOC_CTX *mem_ctx,
-+                         struct be_ctx *be_ctx,
-+                         void *module_data,
-+                         struct dp_method *dp_methods)
-+{
-+    dp_set_method(dp_methods, DPM_AUTH_HANDLER,
-+                  files_auth_handler_send, files_auth_handler_recv, NULL, void,
-+                  struct pam_data, struct pam_data *);
-+
-+    return EOK;
-+}
-diff --git a/src/providers/files/files_private.h b/src/providers/files/files_private.h
-index f44e6d4584e5bd593ef77147b649341c3ace42ed..fd178193086672e7f5ef9541eb81eb462366d824 100644
---- a/src/providers/files/files_private.h
-+++ b/src/providers/files/files_private.h
-@@ -38,6 +38,7 @@ struct files_id_ctx {
-     struct be_ctx *be;
-     struct sss_domain_info *domain;
-     struct files_ctx *fctx;
-+    struct sss_certmap_ctx *sss_certmap_ctx;
- 
-     const char **passwd_files;
-     const char **group_files;
-@@ -71,4 +72,20 @@ errno_t files_account_info_handler_recv(TALLOC_CTX *mem_ctx,
- void files_account_info_finished(struct files_id_ctx *id_ctx,
-                                  int req_type,
-                                  errno_t ret);
-+
-+/* files_auth.c */
-+struct tevent_req *files_auth_handler_send(TALLOC_CTX *mem_ctx,
-+                                           void *unused,
-+                                           struct pam_data *pd,
-+                                           struct dp_req_params *params);
-+
-+errno_t files_auth_handler_recv(TALLOC_CTX *mem_ctx,
-+                                struct tevent_req *req,
-+                                struct pam_data **_data);
-+
-+/* files_certmap.c */
-+errno_t files_init_certmap(TALLOC_CTX *mem_ctx, struct files_id_ctx *id_ctx);
-+
-+errno_t files_map_cert_to_user(struct files_id_ctx *id_ctx,
-+                               struct dp_id_data *data);
- #endif /* __FILES_PRIVATE_H_ */
--- 
-2.14.4
-
diff --git a/SOURCES/0011-failover-change-default-timeouts.patch b/SOURCES/0011-failover-change-default-timeouts.patch
new file mode 100644
index 0000000..b47979e
--- /dev/null
+++ b/SOURCES/0011-failover-change-default-timeouts.patch
@@ -0,0 +1,120 @@
+From e97ff0adb62c89cfc7e75858b7e592e0303720b0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Tue, 11 Jun 2019 14:01:17 +0200
+Subject: [PATCH 11/12] failover: change default timeouts
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3217
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/man/include/failover.xml     | 6 +++---
+ src/man/sssd-ldap.5.xml          | 2 +-
+ src/providers/ad/ad_opts.c       | 2 +-
+ src/providers/data_provider_fo.c | 4 ++--
+ src/providers/ipa/ipa_opts.c     | 2 +-
+ src/providers/ldap/ldap_opts.c   | 2 +-
+ 6 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/src/man/include/failover.xml b/src/man/include/failover.xml
+index f2a01b933..288d91807 100644
+--- a/src/man/include/failover.xml
++++ b/src/man/include/failover.xml
+@@ -81,7 +81,7 @@
+                             talk to a single DNS server before trying next one.
+                         </para>
+                         <para>
+-                            Default: 2000
++                            Default: 1000
+                         </para>
+                     </listitem>
+                 </varlistentry>
+@@ -97,7 +97,7 @@
+                             hostname or discovery domain.
+                         </para>
+                         <para>
+-                            Default: 6
++                            Default: 2
+                         </para>
+                     </listitem>
+                 </varlistentry>
+@@ -113,7 +113,7 @@
+                             queries or locating the site.
+                         </para>
+                         <para>
+-                            Default: 6
++                            Default: 4
+                         </para>
+                     </listitem>
+                 </varlistentry>
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index f0bc82db5..c205aea64 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1432,7 +1432,7 @@
+                             StartTLS operation.
+                         </para>
+                         <para>
+-                            Default: 6
++                            Default: 8
+                         </para>
+                     </listitem>
+                 </varlistentry>
+diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
+index 978c395ef..3f7ec08b1 100644
+--- a/src/providers/ad/ad_opts.c
++++ b/src/providers/ad/ad_opts.c
+@@ -65,7 +65,7 @@ struct dp_option ad_def_ldap_opts[] = {
+     { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
+     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+     { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+-    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
++    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 8 }, NULL_NUMBER },
+     { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING },
+     { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
+diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
+index a7af3e2a5..c634b8d49 100644
+--- a/src/providers/data_provider_fo.c
++++ b/src/providers/data_provider_fo.c
+@@ -832,8 +832,8 @@ void _be_fo_set_port_status(struct be_ctx *ctx,
+ static struct dp_option dp_res_default_opts[] = {
+     { "lookup_family_order", DP_OPT_STRING, { "ipv4_first" }, NULL_STRING },
+     { "dns_resolver_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+-    { "dns_resolver_op_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+-    { "dns_resolver_server_timeout", DP_OPT_NUMBER, { .number = 2000 }, NULL_NUMBER },
++    { "dns_resolver_op_timeout", DP_OPT_NUMBER, { .number = 3 }, NULL_NUMBER },
++    { "dns_resolver_server_timeout", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER },
+     { "dns_discovery_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     DP_OPTION_TERMINATOR
+ };
+diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
+index c38a7da0e..7974cb8ea 100644
+--- a/src/providers/ipa/ipa_opts.c
++++ b/src/providers/ipa/ipa_opts.c
+@@ -76,7 +76,7 @@ struct dp_option ipa_def_ldap_opts[] = {
+     { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
+     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+     { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+-    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
++    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 8 }, NULL_NUMBER },
+     { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING },
+     { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
+diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
+index dc56f0712..616934a21 100644
+--- a/src/providers/ldap/ldap_opts.c
++++ b/src/providers/ldap/ldap_opts.c
+@@ -36,7 +36,7 @@ struct dp_option default_basic_opts[] = {
+     { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
+     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+     { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+-    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
++    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 8 }, NULL_NUMBER },
+     { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING },
+     { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+     { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
+-- 
+2.20.1
+
diff --git a/SOURCES/0011-responder-make-sure-SSS_DP_CERT-is-passed-to-files-p.patch b/SOURCES/0011-responder-make-sure-SSS_DP_CERT-is-passed-to-files-p.patch
deleted file mode 100644
index be4740f..0000000
--- a/SOURCES/0011-responder-make-sure-SSS_DP_CERT-is-passed-to-files-p.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From c250beca50dbebc0cf1e90cdc1c871e9eeca922d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 9 Jul 2018 18:45:21 +0200
-Subject: [PATCH 11/19] responder: make sure SSS_DP_CERT is passed to files
- provider
-
-Currently the files provider is only contacted once in a while to update
-the full cache with fresh data from the passwd file. To allow rule based
-certificate mapping the lookup by certificate request must be always
-send to the file provider so that it can evaluate the rules and add the
-certificate to cached entry of the matching user.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 9fdc5f1d87a133885e6a22810a7eb980c60dcb55)
----
- src/responder/common/responder_dp.c | 20 +++++++++++++-------
- 1 file changed, 13 insertions(+), 7 deletions(-)
-
-diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c
-index 878aa1d73be0ccc56afb79303b61cd5cffe7b5e0..39f0f20c506c7ed63b271461f982ebb4f84afce7 100644
---- a/src/responder/common/responder_dp.c
-+++ b/src/responder/common/responder_dp.c
-@@ -34,15 +34,17 @@ sss_dp_account_files_params(struct sss_domain_info *dom,
-                             enum sss_dp_acct_type *_type_out,
-                             const char **_opt_name_out)
- {
--    if (sss_domain_get_state(dom) != DOM_INCONSISTENT) {
-+    if (type_in != SSS_DP_CERT) {
-+        if (sss_domain_get_state(dom) != DOM_INCONSISTENT) {
-+            DEBUG(SSSDBG_TRACE_INTERNAL,
-+                  "The entries in the files domain are up-to-date\n");
-+            return EOK;
-+        }
-+
-         DEBUG(SSSDBG_TRACE_INTERNAL,
--              "The entries in the files domain are up-to-date\n");
--        return EOK;
-+              "Domain files is not consistent, issuing update\n");
-     }
- 
--    DEBUG(SSSDBG_TRACE_INTERNAL,
--          "Domain files is not consistent, issuing update\n");
--
-     switch(type_in) {
-     case SSS_DP_USER:
-     case SSS_DP_GROUP:
-@@ -56,12 +58,16 @@ sss_dp_account_files_params(struct sss_domain_info *dom,
-         *_type_out = type_in;
-         *_opt_name_out = DP_REQ_OPT_FILES_INITGR;
-         return EAGAIN;
-+    case SSS_DP_CERT:
-+        /* Let the backend handle certificate mapping for local users */
-+        *_type_out = type_in;
-+        *_opt_name_out = opt_name_in;
-+        return EAGAIN;
-     /* These are not handled by the files provider, just fall back */
-     case SSS_DP_NETGR:
-     case SSS_DP_SERVICES:
-     case SSS_DP_SECID:
-     case SSS_DP_USER_AND_GROUP:
--    case SSS_DP_CERT:
-     case SSS_DP_WILDCARD_USER:
-     case SSS_DP_WILDCARD_GROUP:
-         return EOK;
--- 
-2.14.4
-
diff --git a/SOURCES/0012-PAM-add-certificate-matching-rules-from-all-domains.patch b/SOURCES/0012-PAM-add-certificate-matching-rules-from-all-domains.patch
deleted file mode 100644
index 2dea1b9..0000000
--- a/SOURCES/0012-PAM-add-certificate-matching-rules-from-all-domains.patch
+++ /dev/null
@@ -1,167 +0,0 @@
-From 3d2a1323cc24a2af3a0ebaa4bb6096ae49c3a12d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 9 Jul 2018 18:56:26 +0200
-Subject: [PATCH 12/19] PAM: add certificate matching rules from all domains
-
-Currently the PAM responder only reads the certificate mapping and
-matching rules from the first domain. To support Smartcard
-authentication for local and remote users all configured domains must be
-taken into account.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit d42f44d54453d3ddb54875374c1b61dc1e7cd821)
----
- src/responder/pam/pamsrv.h     |  2 +-
- src/responder/pam/pamsrv_cmd.c |  2 +-
- src/responder/pam/pamsrv_p11.c | 77 +++++++++++++++++++++++++++---------------
- 3 files changed, 51 insertions(+), 30 deletions(-)
-
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index d189cccbaa1db7c00d03cf138b290c7ce99ca9a9..5d877566fc7bacced4f6385f1eae344a9e6d8bd4 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -114,7 +114,7 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
- bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd);
- 
- errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
--                                struct certmap_info **certmap_list);
-+                                struct sss_domain_info *domains);
- 
- errno_t
- pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index a6bb2897b7b78ba6cc239adeea020e7ef49629cd..ed9ad57bd6d8c4eda30d8e18f83aeea96474551f 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1737,7 +1737,7 @@ static void pam_forwarder_cb(struct tevent_req *req)
-         goto done;
-     }
- 
--    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains->certmaps);
-+    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               "p11_refresh_certmap_ctx failed, "
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index bf722074384d9cadd2303b71b5823b0bf47be081..ffa6787e967488ac408ce0f0a11b96066c29b630 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -142,11 +142,14 @@ static void ext_debug(void *private, const char *file, long line,
- }
- 
- errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
--                                struct certmap_info **certmap_list)
-+                                struct sss_domain_info *domains)
- {
-     int ret;
-     struct sss_certmap_ctx *sss_certmap_ctx = NULL;
-     size_t c;
-+    struct sss_domain_info *dom;
-+    bool certmap_found = false;
-+    struct certmap_info **certmap_list;
- 
-     ret = sss_certmap_init(pctx, ext_debug, NULL, &sss_certmap_ctx);
-     if (ret != EOK) {
-@@ -154,7 +157,15 @@ errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
-         goto done;
-     }
- 
--    if (certmap_list == NULL || *certmap_list == NULL) {
-+    DLIST_FOR_EACH(dom, domains) {
-+        certmap_list = dom->certmaps;
-+        if (certmap_list != NULL && *certmap_list != NULL) {
-+            certmap_found = true;
-+            break;
-+        }
-+    }
-+
-+    if (!certmap_found) {
-         /* Try to add default matching rule */
-         ret = sss_certmap_add_rule(sss_certmap_ctx, SSS_CERTMAP_MIN_PRIO,
-                                    CERT_AUTH_DEFAULT_MATCHING_RULE, NULL, NULL);
-@@ -166,24 +177,32 @@ errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
-         goto done;
-     }
- 
--    for (c = 0; certmap_list[c] != NULL; c++) {
--        DEBUG(SSSDBG_TRACE_ALL,
--              "Trying to add rule [%s][%d][%s][%s].\n",
--              certmap_list[c]->name, certmap_list[c]->priority,
--              certmap_list[c]->match_rule, certmap_list[c]->map_rule);
--
--        ret = sss_certmap_add_rule(sss_certmap_ctx, certmap_list[c]->priority,
--                                   certmap_list[c]->match_rule,
--                                   certmap_list[c]->map_rule,
--                                   certmap_list[c]->domains);
--        if (ret != 0) {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "sss_certmap_add_rule failed for rule [%s] "
--                  "with error [%d][%s], skipping. "
--                  "Please check for typos and if rule syntax is supported.\n",
--                  certmap_list[c]->name, ret, sss_strerror(ret));
-+    DLIST_FOR_EACH(dom, domains) {
-+        certmap_list = dom->certmaps;
-+        if (certmap_list == NULL || *certmap_list == NULL) {
-             continue;
-         }
-+
-+        for (c = 0; certmap_list[c] != NULL; c++) {
-+            DEBUG(SSSDBG_TRACE_ALL,
-+                  "Trying to add rule [%s][%d][%s][%s].\n",
-+                  certmap_list[c]->name, certmap_list[c]->priority,
-+                  certmap_list[c]->match_rule, certmap_list[c]->map_rule);
-+
-+            ret = sss_certmap_add_rule(sss_certmap_ctx,
-+                                       certmap_list[c]->priority,
-+                                       certmap_list[c]->match_rule,
-+                                       certmap_list[c]->map_rule,
-+                                       certmap_list[c]->domains);
-+            if (ret != 0) {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "sss_certmap_add_rule failed for rule [%s] "
-+                      "with error [%d][%s], skipping. "
-+                      "Please check for typos and if rule syntax is supported.\n",
-+                      certmap_list[c]->name, ret, sss_strerror(ret));
-+                continue;
-+            }
-+        }
-     }
- 
-     ret = EOK;
-@@ -204,19 +223,21 @@ errno_t p11_child_init(struct pam_ctx *pctx)
-     int ret;
-     struct certmap_info **certmaps;
-     bool user_name_hint;
--    struct sss_domain_info *dom = pctx->rctx->domains;
-+    struct sss_domain_info *dom;
- 
--    ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
--        return ret;
-+    DLIST_FOR_EACH(dom, pctx->rctx->domains) {
-+        ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
-+            return ret;
-+        }
-+
-+        dom->user_name_hint = user_name_hint;
-+        talloc_free(dom->certmaps);
-+        dom->certmaps = certmaps;
-     }
- 
--    dom->user_name_hint = user_name_hint;
--    talloc_free(dom->certmaps);
--    dom->certmaps = certmaps;
--
--    ret = p11_refresh_certmap_ctx(pctx, dom->certmaps);
-+    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n");
-         return ret;
--- 
-2.14.4
-
diff --git a/SOURCES/0012-config-add-dns_resolver_op_timeout-to-option-list.patch b/SOURCES/0012-config-add-dns_resolver_op_timeout-to-option-list.patch
new file mode 100644
index 0000000..da4c0e0
--- /dev/null
+++ b/SOURCES/0012-config-add-dns_resolver_op_timeout-to-option-list.patch
@@ -0,0 +1,76 @@
+From 049f3906b9ef2041b5e1df666bd570379ae60718 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
+Date: Mon, 8 Jul 2019 11:35:28 +0200
+Subject: [PATCH 12/12] config: add dns_resolver_op_timeout to option list
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3217
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/config/SSSDConfig/__init__.py.in | 1 +
+ src/config/SSSDConfigTest.py         | 2 ++
+ src/config/cfg_rules.ini             | 1 +
+ src/config/etc/sssd.api.conf         | 1 +
+ 4 files changed, 5 insertions(+)
+
+diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
+index 2d1214e16..ea7995410 100644
+--- a/src/config/SSSDConfig/__init__.py.in
++++ b/src/config/SSSDConfig/__init__.py.in
+@@ -172,6 +172,7 @@ option_strings = {
+     'lookup_family_order' : _('Restrict or prefer a specific address family when performing DNS lookups'),
+     'account_cache_expiration' : _('How long to keep cached entries after last successful login (days)'),
+     'dns_resolver_server_timeout' : _('How long should SSSD talk to single DNS server before trying next server (miliseconds)'),
++    'dns_resolver_op_timeout' : _('How long should keep trying to resolve single DNS query (seconds)'),
+     'dns_resolver_timeout' : _('How long to wait for replies from DNS when resolving servers (seconds)'),
+     'dns_discovery_domain' : _('The domain part of service discovery DNS query'),
+     'override_gid' : _('Override GID value from the identity provider with this value'),
+diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
+index 82b1a9700..95dfd677d 100755
+--- a/src/config/SSSDConfigTest.py
++++ b/src/config/SSSDConfigTest.py
+@@ -607,6 +607,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'lookup_family_order',
+             'account_cache_expiration',
+             'dns_resolver_server_timeout',
++            'dns_resolver_op_timeout',
+             'dns_resolver_timeout',
+             'dns_discovery_domain',
+             'dyndns_update',
+@@ -978,6 +979,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
+             'account_cache_expiration',
+             'lookup_family_order',
+             'dns_resolver_server_timeout',
++            'dns_resolver_op_timeout',
+             'dns_resolver_timeout',
+             'dns_discovery_domain',
+             'dyndns_update',
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index a2efb3a67..30040b595 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -368,6 +368,7 @@ option = pwd_expiration_warning
+ option = filter_users
+ option = filter_groups
+ option = dns_resolver_server_timeout
++option = dns_resolver_op_timeout
+ option = dns_resolver_timeout
+ option = dns_discovery_domain
+ option = override_gid
+diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
+index 288b1cfe7..4a069f2db 100644
+--- a/src/config/etc/sssd.api.conf
++++ b/src/config/etc/sssd.api.conf
+@@ -171,6 +171,7 @@ pwd_expiration_warning = int, None, false
+ filter_users = list, str, false
+ filter_groups = list, str, false
+ dns_resolver_server_timeout = int, None, false
++dns_resolver_op_timeout = int, None, false
+ dns_resolver_timeout = int, None, false
+ dns_discovery_domain = str, None, false
+ override_gid = int, None, false
+-- 
+2.20.1
+
diff --git a/SOURCES/0013-doc-add-certificate-mapping-section-to-man-page.patch b/SOURCES/0013-doc-add-certificate-mapping-section-to-man-page.patch
deleted file mode 100644
index e6641ce..0000000
--- a/SOURCES/0013-doc-add-certificate-mapping-section-to-man-page.patch
+++ /dev/null
@@ -1,183 +0,0 @@
-From ad3c2c6f89d3d07c5e901706c796de41d160d3bb Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 3 Sep 2018 18:38:42 +0200
-Subject: [PATCH 13/19] doc: add certificate mapping section to man page
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 0c739e969a617bdb4c06cdfd63772bf6d283c518)
----
- src/man/sssd.conf.5.xml | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 149 insertions(+)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 881ffc6ab389fec2b85d675f43b951ca5fa0f2fc..04143f199685b7703abe1b5bb82b6c33230e6c72 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -3299,6 +3299,135 @@ ldap_user_extra_attrs = phone:telephoneNumber
-         </para>
-     </refsect1>
- 
-+    <refsect1 id='certmap'>
-+        <title>CERTIFICATE MAPPING SECTION</title>
-+        <para>
-+            To allow authentication with Smartcards and certificates SSSD must
-+            be able to map certificates to users. This can be done by adding the
-+            full certificate to the LDAP object of the user or to a local
-+            override. While using the full certificate is required to use the
-+            Smartcard authentication feature of SSH (see
-+                <citerefentry>
-+                    <refentrytitle>sss_ssh_authorizedkeys</refentrytitle>
-+                    <manvolnum>8</manvolnum>
-+                </citerefentry>
-+            for details) it might be cumbersome or not even possible to do this
-+            for the general case where local services use PAM for
-+            authentication.
-+        </para>
-+        <para>
-+            To make the mapping more flexible mapping and matching rules were
-+            added to SSSD (see
-+                <citerefentry>
-+                    <refentrytitle>sss-certmap</refentrytitle>
-+                    <manvolnum>5</manvolnum>
-+                </citerefentry>
-+            for details).
-+        </para>
-+        <para>
-+            A mapping and matching rule can be added to the SSSD configuration
-+            in a section on its own with a name like
-+            <quote>[certmap/<replaceable>DOMAIN_NAME</replaceable>/<replaceable>RULE_NAME</replaceable>]</quote>.
-+            In this section the following options are allowed:
-+        </para>
-+        <variablelist>
-+            <varlistentry>
-+                <term>matchrule (string)</term>
-+                <listitem>
-+                    <para>
-+                        Only certificates from the Smartcard which matches this
-+                        rule will be processed, all others are ignored.
-+                    </para>
-+                    <para>
-+                        Default: KRB5:&lt;EKU&gt;clientAuth, i.e. only
-+                        certificates which have the Extended Key Usage
-+                        <quote>clientAuth</quote>
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>maprule (string)</term>
-+                <listitem>
-+                    <para>
-+                        Defines how the user is found for a given certificate.
-+                    </para>
-+                    <para>
-+                        Default:
-+                        <itemizedlist>
-+                            <listitem>
-+                                <para>LDAP:(userCertificate;binary={cert!bin})
-+                                for LDAP based providers like
-+                                <quote>ldap</quote>, <quote>AD</quote> or
-+                                <quote>ipa</quote>.</para>
-+                            </listitem>
-+                            <listitem>
-+                                <para>The RULE_NAME for the <quote>files</quote>
-+                                provider which tries to find a user with the
-+                                same name.</para>
-+                            </listitem>
-+                        </itemizedlist>
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>domains (string)</term>
-+                <listitem>
-+                    <para>
-+                        Comma separated list of domain names the rule should be
-+                        applied. By default a rule is only valid in the domain
-+                        configured in sssd.conf. If the provider supports
-+                        subdomains this option can be used to add the rule to
-+                        subdomains as well.
-+                    </para>
-+                    <para>
-+                        Default: the configured domain in sssd.conf
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>priority (integer)</term>
-+                <listitem>
-+                    <para>
-+                        Unsigned integer value defining the priority of the
-+                        rule. The higher the number the lower the priority.
-+                        <quote>0</quote> stands for the highest priority while
-+                        <quote>4294967295</quote> is the lowest.
-+                    </para>
-+                    <para>
-+                        Default: the lowest priority
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+        </variablelist>
-+        <para>
-+            To make the configuration simple and reduce the amount of
-+            configuration options the <quote>files</quote> provider has some
-+            special properties:
-+            <itemizedlist>
-+                <listitem>
-+                    <para>
-+                        if maprule is not set the RULE_NAME name is assumed to
-+                        be the name of the matching user
-+                    </para>
-+                </listitem>
-+                <listitem>
-+                    <para>
-+                        if a maprule is used both a single user name or a
-+                        template like
-+                        <quote>{subject_rfc822_name.short_name}</quote> must
-+                        be in braces like e.g. <quote>(username)</quote> or
-+                        <quote>({subject_rfc822_name.short_name})</quote>
-+                    </para>
-+                </listitem>
-+                <listitem>
-+                    <para>
-+                        the <quote>domains</quote> option is ignored
-+                    </para>
-+                </listitem>
-+            </itemizedlist>
-+        </para>
-+    </refsect1>
-+
-     <refsect1 id='example'>
-         <title>EXAMPLES</title>
-         <para>
-@@ -3341,6 +3470,26 @@ enumerate = False
- <programlisting>
- [domain/ipa.com/child.ad.com]
- use_fully_qualified_names = false
-+</programlisting>
-+        </para>
-+        <para>
-+            3. The following example shows the configuration for two certificate
-+            mapping rules. The first is valid for the configured domain
-+            <quote>my.domain</quote> and additionally for the subdomains
-+            <quote>your.domain</quote> and uses the full certificate in the
-+            search filter. The second example is valid for the domain
-+            <quote>files</quote> where it is assumed the files provider is used
-+            for this domain and contains a matching rule for the local user
-+            <quote>myname</quote>.
-+<programlisting>
-+[certmap/my.domain/rule_name]
-+matchrule = &lt;ISSUER&gt;^CN=My-CA,DC=MY,DC=DOMAIN$
-+maprule = (userCertificate;binary={cert!bin})
-+domains = my.domain, your.domain
-+priority = 10
-+
-+[certmap/files/myname]
-+matchrule = &lt;ISSUER&gt;^CN=My-CA,DC=MY,DC=DOMAIN$&lt;SUBJECT&gt;^CN=User.Name,DC=MY,DC=DOMAIN$
- </programlisting>
-         </para>
-     </refsect1>
--- 
-2.14.4
-
diff --git a/SOURCES/0013-pam_sss-Add-missing-colon-to-the-PIN-prompt.patch b/SOURCES/0013-pam_sss-Add-missing-colon-to-the-PIN-prompt.patch
new file mode 100644
index 0000000..b9c83c6
--- /dev/null
+++ b/SOURCES/0013-pam_sss-Add-missing-colon-to-the-PIN-prompt.patch
@@ -0,0 +1,33 @@
+From db46cd0890057be1f72173a2ca2ae040bcf46c9a Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Wed, 31 Jul 2019 12:20:42 +0200
+Subject: [PATCH] pam_sss: Add missing colon to the PIN prompt
+
+This can be noticed in the sudo prompt, when the system is configured
+to authenticate users using smart cards.
+
+Resolves: Pagure#4049
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+---
+ src/sss_client/pam_sss.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
+index 6bcda23da..cfd3e3731 100644
+--- a/src/sss_client/pam_sss.c
++++ b/src/sss_client/pam_sss.c
+@@ -1609,7 +1609,7 @@ static int prompt_2fa_single(pam_handle_t *pamh, struct pam_items *pi,
+     return PAM_SUCCESS;
+ }
+ 
+-#define SC_PROMPT_FMT "PIN for %s"
++#define SC_PROMPT_FMT "PIN for %s: "
+ 
+ #ifndef discard_const
+ #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+-- 
+2.20.1
+
diff --git a/SOURCES/0014-intg-user-default-locale.patch b/SOURCES/0014-intg-user-default-locale.patch
deleted file mode 100644
index 1e94700..0000000
--- a/SOURCES/0014-intg-user-default-locale.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 2ea286d7c11f7106d2f7d513f9211a7620fbdcb0 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Sep 2018 22:12:02 +0200
-Subject: [PATCH 14/19] intg: user default locale
-
-Some checks depend on english error messages so checks should be always
-run with the default locale.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 16941c47a6f0fc2f1679725d55cde221f3c3a6ef)
----
- src/tests/intg/Makefile.am | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
-index 65da9ca170f57d1aa736c217f311992bdf53d2a1..6f7605bd4edbf26ef3ce97acea74fc92216eede9 100644
---- a/src/tests/intg/Makefile.am
-+++ b/src/tests/intg/Makefile.am
-@@ -126,6 +126,7 @@ 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) \
--- 
-2.14.4
-
diff --git a/SOURCES/0014-pam-make-sure-p11_child.log-has-the-right-permission.patch b/SOURCES/0014-pam-make-sure-p11_child.log-has-the-right-permission.patch
new file mode 100644
index 0000000..5b723b4
--- /dev/null
+++ b/SOURCES/0014-pam-make-sure-p11_child.log-has-the-right-permission.patch
@@ -0,0 +1,39 @@
+From e9091aba9c0cbcc1f00f5f0656c200554cc485a3 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 2 Aug 2019 13:44:18 +0200
+Subject: [PATCH 14/16] pam: make sure p11_child.log has the right permissions
+
+If SSSD runs a unprivileged user we should make sure the log files for
+child processes have the right permission so that the child process can
+write to them.
+
+Related to https://pagure.io/SSSD/sssd/issue/4056
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/pam/pamsrv.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
+index 38db6fc9b..4f5b9b664 100644
+--- a/src/responder/pam/pamsrv.c
++++ b/src/responder/pam/pamsrv.c
+@@ -399,6 +399,15 @@ int main(int argc, const char *argv[])
+         }
+     }
+ 
++    /* server_setup() might switch to an unprivileged user, so the permissions
++     * for p11_child.log have to be fixed first. */
++    ret = chown_debug_file("p11_child", uid, gid);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot chown the p11_child debug file, "
++              "debugging might not work!\n");
++    }
++
+     ret = server_setup("sssd[pam]", 0, uid, gid, CONFDB_PAM_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) return 2;
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0015-PAM-use-better-PAM-error-code-for-failed-Smartcard-a.patch b/SOURCES/0015-PAM-use-better-PAM-error-code-for-failed-Smartcard-a.patch
deleted file mode 100644
index 39c3c91..0000000
--- a/SOURCES/0015-PAM-use-better-PAM-error-code-for-failed-Smartcard-a.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 8948c89c132d31c8cffd55d60e46a506eb00bbd2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Sep 2018 22:16:50 +0200
-Subject: [PATCH 15/19] PAM: use better PAM error code for failed Smartcard
- authentication
-
-If the user enters a wrong PIN the PAM responder currently returns
-PAM_USER_UNKNOWN better is PAM_AUTH_ERR.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 442ae7b1d0704cdd667d4f1ba4c165ce3f3ffed4)
----
- src/responder/pam/pamsrv_cmd.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index ed9ad57bd6d8c4eda30d8e18f83aeea96474551f..817f3c5134ba4c7358ffb4fbf3c6008fa23ffe0e 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1436,7 +1436,9 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
-             if (pd->cmd == SSS_PAM_AUTHENTICATE) {
-                 DEBUG(SSSDBG_CRIT_FAILURE,
-                       "No certificate returned, authentication failed.\n");
--                ret = ENOENT;
-+                preq->pd->pam_status = PAM_AUTH_ERR;
-+                pam_reply(preq);
-+                return;
-             } else {
-                 ret = pam_check_user_search(preq);
-             }
--- 
-2.14.4
-
diff --git a/SOURCES/0015-ssh-make-sure-p11_child.log-has-the-right-permission.patch b/SOURCES/0015-ssh-make-sure-p11_child.log-has-the-right-permission.patch
new file mode 100644
index 0000000..73cc906
--- /dev/null
+++ b/SOURCES/0015-ssh-make-sure-p11_child.log-has-the-right-permission.patch
@@ -0,0 +1,40 @@
+From 8119ee216a9471ed2f01b16ed17068f5dc8b83cb Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 5 Aug 2019 17:04:14 +0200
+Subject: [PATCH 15/16] ssh: make sure p11_child.log has the right permissions
+
+If SSSD runs a unprivileged user we should make sure the log files for
+child processes have the right permission so that the child process can
+write to them.
+
+Related to https://pagure.io/SSSD/sssd/issue/4056
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/ssh/sshsrv.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index ef2c9d01b..07397834c 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -187,6 +187,16 @@ int main(int argc, const char *argv[])
+ 
+     sss_set_logger(opt_logger);
+ 
++    /* server_setup() might switch to an unprivileged user, so the permissions
++     * for p11_child.log have to be fixed first. We might call p11_child to
++     * validate certificates. */
++    ret = chown_debug_file("p11_child", uid, gid);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Cannot chown the p11_child debug file, "
++              "debugging might not work!\n");
++    }
++
+     ret = server_setup("sssd[ssh]", 0, uid, gid,
+                        CONFDB_SSH_CONF_ENTRY, &main_ctx);
+     if (ret != EOK) {
+-- 
+2.20.1
+
diff --git a/SOURCES/0016-BE-make-sure-child-log-files-have-the-right-permissi.patch b/SOURCES/0016-BE-make-sure-child-log-files-have-the-right-permissi.patch
new file mode 100644
index 0000000..77515ac
--- /dev/null
+++ b/SOURCES/0016-BE-make-sure-child-log-files-have-the-right-permissi.patch
@@ -0,0 +1,61 @@
+From 9339c445b4b98a28146ff834fec2af42bd3a6340 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 5 Aug 2019 17:05:00 +0200
+Subject: [PATCH 16/16] BE: make sure child log files have the right
+ permissions
+
+If SSSD runs a unprivileged user we should make sure the log files for
+child processes have the right permission so that the child process can
+write to them.
+
+Related to https://pagure.io/SSSD/sssd/issue/4056
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/providers/data_provider_be.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 6dce8286d..ce00231ff 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -554,6 +554,27 @@ done:
+     return ret;
+ }
+ 
++static void fix_child_log_permissions(uid_t uid, gid_t gid)
++{
++    int ret;
++    const char *child_names[] = { "krb5_child",
++                                  "ldap_child",
++                                  "selinux_child",
++                                  "ad_gpo_child",
++                                  "proxy_child",
++                                  NULL };
++    size_t c;
++
++    for (c = 0; child_names[c] != NULL; c++) {
++        ret = chown_debug_file(child_names[c], uid, gid);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Cannot chown the [%s] debug file, "
++                  "debugging might not work!\n", child_names[c]);
++        }
++    }
++}
++
+ static void dp_initialized(struct tevent_req *req)
+ {
+     struct tevent_signal *tes;
+@@ -609,6 +630,8 @@ static void dp_initialized(struct tevent_req *req)
+               "Cannot chown the debug files, debugging might not work!\n");
+     }
+ 
++    fix_child_log_permissions(be_ctx->uid, be_ctx->gid);
++
+     ret = become_user(be_ctx->uid, be_ctx->gid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FUNC_DATA,
+-- 
+2.20.1
+
diff --git a/SOURCES/0016-test_ca-test-library-only-for-readable.patch b/SOURCES/0016-test_ca-test-library-only-for-readable.patch
deleted file mode 100644
index 6e71fd2..0000000
--- a/SOURCES/0016-test_ca-test-library-only-for-readable.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From a29359146455ed7e468a20ce4ad50afbb2b567b5 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 10 Sep 2018 22:03:55 +0200
-Subject: [PATCH 16/19] test_ca: test library only for readable
-
-On Debian libraries typically do not have the execute-bit set so it is
-better to only check for readability.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 91aea762d02731193eb66a00b930ff1fe8bc5ab8)
----
- src/external/test_ca.m4 | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/external/test_ca.m4 b/src/external/test_ca.m4
-index 2cdb3c750cc5b024165a0d4a1a578605792183f7..bb4872698fa291bb651bdf61da1b721cae01bc13 100644
---- a/src/external/test_ca.m4
-+++ b/src/external/test_ca.m4
-@@ -58,7 +58,7 @@ AC_DEFUN([AM_CHECK_TEST_CA],
-             AC_MSG_NOTICE([Could not find p11tool])
-         fi
- 
--        AM_CONDITIONAL([BUILD_TEST_CA], [test -x "$OPENSSL" -a -x "$SSH_KEYGEN" -a -x "$SOFTHSM2_PATH" -a -x "$SOFTHSM2_UTIL" -a -x "$P11TOOL"])
-+        AM_CONDITIONAL([BUILD_TEST_CA], [test -x "$OPENSSL" -a -x "$SSH_KEYGEN" -a -r "$SOFTHSM2_PATH" -a -x "$SOFTHSM2_UTIL" -a -x "$P11TOOL"])
-     fi
- 
-     AM_COND_IF([BUILD_TEST_CA],
--- 
-2.14.4
-
diff --git a/SOURCES/0017-MAN-Get-rid-of-sssd-secrets-reference.patch b/SOURCES/0017-MAN-Get-rid-of-sssd-secrets-reference.patch
new file mode 100644
index 0000000..ca0e6d0
--- /dev/null
+++ b/SOURCES/0017-MAN-Get-rid-of-sssd-secrets-reference.patch
@@ -0,0 +1,41 @@
+From ca02a20c16a1249a8fcecad31e915bf64df77cc9 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 5 Oct 2018 13:17:14 +0200
+Subject: [PATCH 17/23] MAN: Get rid of sssd-secrets reference
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3685
+
+There were some stray references to the secrets responder in the
+sssd-kcm manual page.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/man/sssd-kcm.8.xml | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
+index fff8b0a16..90b9ad09c 100644
+--- a/src/man/sssd-kcm.8.xml
++++ b/src/man/sssd-kcm.8.xml
+@@ -58,11 +58,9 @@
+                 </listitem>
+                 <listitem>
+                     <para>
+-                        the SSSD implementation stores the ccaches in the SSSD
+-                        <citerefentry>
+-                            <refentrytitle>sssd-secrets</refentrytitle><manvolnum>5</manvolnum>
+-                        </citerefentry>
+-                        secrets store, allowing the ccaches to survive KCM server restarts or machine reboots.
++                        the SSSD implementation stores the ccaches in a database,
++                        typically located at <replaceable>/var/lib/sss/secrets</replaceable>
++                        allowing the ccaches to survive KCM server restarts or machine reboots.
+                     </para>
+                 </listitem>
+             </itemizedlist>
+-- 
+2.20.1
+
diff --git a/SOURCES/0017-test_ca-set-a-password-PIN-to-nss-databases.patch b/SOURCES/0017-test_ca-set-a-password-PIN-to-nss-databases.patch
deleted file mode 100644
index 6df5716..0000000
--- a/SOURCES/0017-test_ca-set-a-password-PIN-to-nss-databases.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From fe6b3578e97e44ec92ff6f3f28f97893ed0d41f6 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Sep 2018 22:17:47 +0200
-Subject: [PATCH 17/19] test_ca: set a password/PIN to nss databases
-
-To make sure the PIN is properly checked during tests the NSS databases
-need a password.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit a45a410dc7fa7cf84bcac541e693ee8781e25431)
----
- src/tests/test_CA/Makefile.am | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/src/tests/test_CA/Makefile.am b/src/tests/test_CA/Makefile.am
-index 0c7099390f0d0c74a4a22d2b721c0b19a4113190..1bce2c36633b2d1df65c29258f8ee163a4bfce9e 100644
---- a/src/tests/test_CA/Makefile.am
-+++ b/src/tests/test_CA/Makefile.am
-@@ -33,7 +33,7 @@ endif
- ca_all: clean serial SSSD_test_CA.pem $(certs) $(certs_h) $(pubkeys) $(pubkeys_h) $(pkcs12) $(extra)
- 
- $(pwdfile):
--	@echo "12345678" > $@
-+	@echo "123456" > $@
- 
- SSSD_test_CA.pem: $(openssl_ca_key) $(openssl_ca_config) serial
- 	$(OPENSSL) req -batch -config ${openssl_ca_config} -x509 -new -nodes -key $< -sha256 -days 1024 -set_serial 0 -extensions v3_ca -out $@
-@@ -65,18 +65,18 @@ SSSD_test_cert_pubsshkey_%.h: SSSD_test_cert_pubsshkey_%.pub
- # - src/tests/cmocka/test_pam_srv.c
- p11_nssdb: SSSD_test_cert_pkcs12_0001.pem SSSD_test_CA.pem $(pwdfile)
- 	mkdir $@
--	$(CERTUTIL) -d sql:./$@ -N --empty-password
--	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem
--	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile)
-+	$(CERTUTIL) -d sql:./$@ -N -f $(pwdfile)
-+	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem -f $(pwdfile)
-+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile) -k $(pwdfile)
- 
- # This nss db is used in
- # - src/tests/cmocka/test_pam_srv.c
- p11_nssdb_2certs: SSSD_test_cert_pkcs12_0001.pem SSSD_test_cert_pkcs12_0002.pem SSSD_test_CA.pem $(pwdfile)
- 	mkdir $@
--	$(CERTUTIL) -d sql:./$@ -N --empty-password
--	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem
--	$(PK12UTIL) -d sql:./$@ p11_nssdb -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile)
--	$(PK12UTIL) -d sql:./$@ p11_nssdb -i SSSD_test_cert_pkcs12_0002.pem -w $(pwdfile)
-+	$(CERTUTIL) -d sql:./$@ -N -f $(pwdfile)
-+	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem -f $(pwdfile)
-+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile) -k $(pwdfile)
-+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0002.pem -w $(pwdfile) -k $(pwdfile)
- 
- # The softhsm2 PKCS#11 setups are used in
- # - src/tests/cmocka/test_pam_srv.c
--- 
-2.14.4
-
diff --git a/SOURCES/0018-MAN-Document-that-it-is-enough-to-systemctl-restart-.patch b/SOURCES/0018-MAN-Document-that-it-is-enough-to-systemctl-restart-.patch
new file mode 100644
index 0000000..5520efa
--- /dev/null
+++ b/SOURCES/0018-MAN-Document-that-it-is-enough-to-systemctl-restart-.patch
@@ -0,0 +1,51 @@
+From 84eca2e812f8a8684a35b4cd0c262660930e0d40 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 30 Nov 2018 13:15:58 +0100
+Subject: [PATCH 18/23] MAN: Document that it is enough to systemctl restart
+ sssd-kcm.service lately
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3862
+
+We forgot to amend the man page after implementing the sssd-kcm service
+reload.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/man/sssd-kcm.8.xml | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
+index 90b9ad09c..4e4aaa38e 100644
+--- a/src/man/sssd-kcm.8.xml
++++ b/src/man/sssd-kcm.8.xml
+@@ -162,12 +162,17 @@ systemctl restart sssd-kcm.service
+         <title>CONFIGURATION OPTIONS</title>
+         <para>
+             The KCM service is configured in the <quote>kcm</quote>
+-            section of the sssd.conf file. Please note that currently,
+-            is it not sufficient to restart the sssd-kcm service, because
+-            the sssd configuration is only parsed and read to an internal
+-            configuration database by the sssd service. Therefore you
+-            must restart the sssd service if you change anything in the
+-            <quote>kcm</quote> section of sssd.conf.
++            section of the sssd.conf file. Please note that because
++            the KCM service is typically socket-activated, it is
++            enough to just restart the <quote>sssd-kcm</quote> service
++            after changing options in the <quote>kcm</quote> section
++            of sssd.conf:
++            <programlisting>
++systemctl restart sssd-kcm.service
++            </programlisting>
++        </para>
++        <para>
++            The KCM service is configured in the <quote>kcm</quote>
+             For a detailed syntax reference, refer to the <quote>FILE FORMAT</quote> section of the
+             <citerefentry>
+                 <refentrytitle>sssd.conf</refentrytitle>
+-- 
+2.20.1
+
diff --git a/SOURCES/0018-getsockopt_wrapper-add-support-for-PAM-clients.patch b/SOURCES/0018-getsockopt_wrapper-add-support-for-PAM-clients.patch
deleted file mode 100644
index c520c4d..0000000
--- a/SOURCES/0018-getsockopt_wrapper-add-support-for-PAM-clients.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-From 0b519a28b4ed63153adbabb64e1446652bb8b879 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Sep 2018 22:19:26 +0200
-Subject: [PATCH 18/19] 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 from commit d332c8a0e7a4c7f0b3ee1b2110145a23cbd61c2a)
----
- src/tests/intg/getsockopt_wrapper.c | 34 ++++++++++++++++++++++++++++++++++
- 1 file changed, 34 insertions(+)
-
-diff --git a/src/tests/intg/getsockopt_wrapper.c b/src/tests/intg/getsockopt_wrapper.c
-index 510912346709f57e3fffcbc15a684ccb0b2e90bf..2f508892dec1c00dd73c3a9e5cfdb08bb17e48a0 100644
---- a/src/tests/intg/getsockopt_wrapper.c
-+++ b/src/tests/intg/getsockopt_wrapper.c
-@@ -45,6 +45,23 @@ static bool is_secrets_socket(int fd)
-     return NULL != strstr(unix_socket->sun_path, "secrets.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 uid_t fake_secret_peer(uid_t orig_id)
- {
-     char *val;
-@@ -57,6 +74,21 @@ static uid_t fake_secret_peer(uid_t orig_id)
-     return atoi(val);
- }
- 
-+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;
-@@ -84,6 +116,8 @@ int getsockopt(int sockfd, int level, int optname,
-             cr->uid = 0;
-         } else if (is_secrets_socket(sockfd)) {
-             cr->uid = fake_secret_peer(cr->uid);
-+        } else if (peer_is_private_pam(sockfd)) {
-+            fake_peer_uid_gid(&cr->uid, &cr->gid);
-         }
-     }
- 
--- 
-2.14.4
-
diff --git a/SOURCES/0019-SECRETS-Use-different-option-names-from-secrets-and-.patch b/SOURCES/0019-SECRETS-Use-different-option-names-from-secrets-and-.patch
new file mode 100644
index 0000000..4afec42
--- /dev/null
+++ b/SOURCES/0019-SECRETS-Use-different-option-names-from-secrets-and-.patch
@@ -0,0 +1,280 @@
+From f74b97860ec7c66df01ed2b719d29a138c958081 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 26 Nov 2018 13:44:08 +0100
+Subject: [PATCH 19/23] SECRETS: Use different option names from secrets and
+ KCM for quota options
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3386
+
+With the separate secrets responder, the quotas for the /secrets and
+/kcm hives were configurable in a sub-section of the [secrets] sssd.conf
+section using the same option -- the /secrets vs. /kcm distinction was
+made using the subsection name.
+
+With the standalone KCM responder writing directly to the database, it
+makes sense to have options with more descriptive names better suitable
+for the KCM usage. For that we need the options for secrets quotas and
+kcm quotas to be named differently.
+
+For now, the patch only passes the option name to sss_sec_get_quota()
+and sss_sec_get_hive_config() together with the default value in an
+instance of a new structure sss_sec_quota_opt. The secrets responder
+still uses the same option names for backwards compatibility.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/responder/secrets/secsrv.c | 70 ++++++++++++++++++++++++++--------
+ src/util/secrets/config.c      | 40 +++++++++----------
+ src/util/secrets/secrets.h     | 21 ++++++----
+ 3 files changed, 88 insertions(+), 43 deletions(-)
+
+diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c
+index 2de93dedc..e783e231d 100644
+--- a/src/responder/secrets/secsrv.c
++++ b/src/responder/secrets/secsrv.c
+@@ -47,6 +47,39 @@ static void adjust_global_quota(struct sec_ctx *sctx,
+ static int sec_get_config(struct sec_ctx *sctx)
+ {
+     int ret;
++    struct sss_sec_quota_opt dfl_sec_nest_level = {
++        .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL,
++        .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
++    };
++    struct sss_sec_quota_opt dfl_sec_max_secrets = {
++        .opt_name = CONFDB_SEC_MAX_SECRETS,
++        .default_value = DEFAULT_SEC_MAX_SECRETS,
++    };
++    struct sss_sec_quota_opt dfl_sec_max_uid_secrets = {
++        .opt_name = CONFDB_SEC_MAX_UID_SECRETS,
++        .default_value = DEFAULT_SEC_MAX_UID_SECRETS,
++    };
++    struct sss_sec_quota_opt dfl_sec_max_payload_size = {
++        .opt_name = CONFDB_SEC_MAX_PAYLOAD_SIZE,
++        .default_value = DEFAULT_SEC_MAX_PAYLOAD_SIZE,
++    };
++
++    struct sss_sec_quota_opt dfl_kcm_nest_level = {
++        .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL,
++        .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
++    };
++    struct sss_sec_quota_opt dfl_kcm_max_secrets = {
++        .opt_name = CONFDB_SEC_MAX_SECRETS,
++        .default_value = DEFAULT_SEC_KCM_MAX_SECRETS,
++    };
++    struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = {
++        .opt_name = CONFDB_SEC_MAX_UID_SECRETS,
++        .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS,
++    };
++    struct sss_sec_quota_opt dfl_kcm_max_payload_size = {
++        .opt_name = CONFDB_SEC_MAX_PAYLOAD_SIZE,
++        .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE,
++    };
+ 
+     ret = confdb_get_int(sctx->rctx->cdb,
+                          sctx->rctx->confdb_service_path,
+@@ -65,15 +98,12 @@ static int sec_get_config(struct sec_ctx *sctx)
+     sctx->max_payload_size = 1;
+ 
+     /* Read the global quota first -- this should be removed in a future release */
+-    /* Note that this sets the defaults for the sec_config quota to be used
+-     * in sec_get_hive_config()
+-     */
+     ret = sss_sec_get_quota(sctx->rctx->cdb,
+                             sctx->rctx->confdb_service_path,
+-                            DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
+-                            DEFAULT_SEC_MAX_SECRETS,
+-                            DEFAULT_SEC_MAX_UID_SECRETS,
+-                            DEFAULT_SEC_MAX_PAYLOAD_SIZE,
++                            &dfl_sec_nest_level,
++                            &dfl_sec_max_secrets,
++                            &dfl_sec_max_uid_secrets,
++                            &dfl_sec_max_payload_size,
+                             &sctx->sec_config.quota);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+@@ -81,13 +111,23 @@ static int sec_get_config(struct sec_ctx *sctx)
+         goto fail;
+     }
+ 
++    /* Use the global quota values as defaults for the secrets/secrets section */
++    dfl_sec_nest_level.default_value = \
++                                sctx->sec_config.quota.containers_nest_level;
++    dfl_sec_max_secrets.default_value = \
++                                sctx->sec_config.quota.max_secrets;
++    dfl_sec_max_uid_secrets.default_value = \
++                                sctx->sec_config.quota.max_uid_secrets;
++    dfl_sec_max_payload_size.default_value = \
++                                sctx->sec_config.quota.max_payload_size;
++
+     /* Read the per-hive configuration */
+     ret = sss_sec_get_hive_config(sctx->rctx->cdb,
+                                  "secrets",
+-                                 sctx->sec_config.quota.containers_nest_level,
+-                                 sctx->sec_config.quota.max_secrets,
+-                                 sctx->sec_config.quota.max_uid_secrets,
+-                                 sctx->sec_config.quota.max_payload_size,
++                                 &dfl_sec_nest_level,
++                                 &dfl_sec_max_secrets,
++                                 &dfl_sec_max_uid_secrets,
++                                 &dfl_sec_max_payload_size,
+                                  &sctx->sec_config);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+@@ -98,10 +138,10 @@ static int sec_get_config(struct sec_ctx *sctx)
+ 
+     ret = sss_sec_get_hive_config(sctx->rctx->cdb,
+                                   "kcm",
+-                                  DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
+-                                  DEFAULT_SEC_KCM_MAX_SECRETS,
+-                                  DEFAULT_SEC_KCM_MAX_UID_SECRETS,
+-                                  DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE,
++                                  &dfl_kcm_nest_level,
++                                  &dfl_kcm_max_secrets,
++                                  &dfl_kcm_max_uid_secrets,
++                                  &dfl_kcm_max_payload_size,
+                                   &sctx->kcm_config);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+diff --git a/src/util/secrets/config.c b/src/util/secrets/config.c
+index cb286121f..f5dac0b21 100644
+--- a/src/util/secrets/config.c
++++ b/src/util/secrets/config.c
+@@ -24,10 +24,10 @@
+ 
+ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+                           const char *section_config_path,
+-                          int default_max_containers_nest_level,
+-                          int default_max_num_secrets,
+-                          int default_max_num_uid_secrets,
+-                          int default_max_payload,
++                          struct sss_sec_quota_opt *dfl_max_containers_nest_level,
++                          struct sss_sec_quota_opt *dfl_max_num_secrets,
++                          struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
++                          struct sss_sec_quota_opt *dfl_max_payload,
+                           struct sss_sec_quota *quota)
+ {
+     int ret;
+@@ -38,8 +38,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+ 
+     ret = confdb_get_int(cdb,
+                          section_config_path,
+-                         CONFDB_SEC_CONTAINERS_NEST_LEVEL,
+-                         default_max_containers_nest_level,
++                         dfl_max_containers_nest_level->opt_name,
++                         dfl_max_containers_nest_level->default_value,
+                          &quota->containers_nest_level);
+ 
+     if (ret != EOK) {
+@@ -51,8 +51,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+ 
+     ret = confdb_get_int(cdb,
+                          section_config_path,
+-                         CONFDB_SEC_MAX_SECRETS,
+-                         default_max_num_secrets,
++                         dfl_max_num_secrets->opt_name,
++                         dfl_max_num_secrets->default_value,
+                          &quota->max_secrets);
+ 
+     if (ret != EOK) {
+@@ -64,8 +64,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+ 
+     ret = confdb_get_int(cdb,
+                          section_config_path,
+-                         CONFDB_SEC_MAX_UID_SECRETS,
+-                         default_max_num_uid_secrets,
++                         dfl_max_num_uid_secrets->opt_name,
++                         dfl_max_num_uid_secrets->default_value,
+                          &quota->max_uid_secrets);
+ 
+     if (ret != EOK) {
+@@ -77,8 +77,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+ 
+     ret = confdb_get_int(cdb,
+                          section_config_path,
+-                         CONFDB_SEC_MAX_PAYLOAD_SIZE,
+-                         default_max_payload,
++                         dfl_max_payload->opt_name,
++                         dfl_max_payload->default_value,
+                          &quota->max_payload_size);
+ 
+     if (ret != EOK) {
+@@ -93,10 +93,10 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+ 
+ errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb,
+                                 const char *hive_name,
+-                                int default_max_containers_nest_level,
+-                                int default_max_num_secrets,
+-                                int default_max_num_uid_secrets,
+-                                int default_max_payload,
++                                struct sss_sec_quota_opt *dfl_max_containers_nest_level,
++                                struct sss_sec_quota_opt *dfl_max_num_secrets,
++                                struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
++                                struct sss_sec_quota_opt *dfl_max_payload,
+                                 struct sss_sec_hive_config *hive_config)
+ {
+     int ret;
+@@ -122,10 +122,10 @@ errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb,
+ 
+     ret = sss_sec_get_quota(cdb,
+                             confdb_section,
+-                            default_max_containers_nest_level,
+-                            default_max_num_secrets,
+-                            default_max_num_uid_secrets,
+-                            default_max_payload,
++                            dfl_max_containers_nest_level,
++                            dfl_max_num_secrets,
++                            dfl_max_num_uid_secrets,
++                            dfl_max_payload,
+                             &hive_config->quota);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
+index 01abfe542..31164bd86 100644
+--- a/src/util/secrets/secrets.h
++++ b/src/util/secrets/secrets.h
+@@ -47,6 +47,11 @@ struct sss_sec_ctx;
+ 
+ struct sss_sec_req;
+ 
++struct sss_sec_quota_opt {
++    const char *opt_name;
++    int default_value;
++};
++
+ struct sss_sec_quota {
+     int max_secrets;
+     int max_uid_secrets;
+@@ -98,18 +103,18 @@ bool sss_sec_req_is_list(struct sss_sec_req *req);
+ 
+ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
+                           const char *section_config_path,
+-                          int default_max_containers_nest_level,
+-                          int default_max_num_secrets,
+-                          int default_max_num_uid_secrets,
+-                          int default_max_payload,
++                          struct sss_sec_quota_opt *dfl_max_containers_nest_level,
++                          struct sss_sec_quota_opt *dfl_max_num_secrets,
++                          struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
++                          struct sss_sec_quota_opt *dfl_max_payload,
+                           struct sss_sec_quota *quota);
+ 
+ errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb,
+                                 const char *hive_name,
+-                                int default_max_containers_nest_level,
+-                                int default_max_num_secrets,
+-                                int default_max_num_uid_secrets,
+-                                int default_max_payload,
++                                struct sss_sec_quota_opt *dfl_max_containers_nest_level,
++                                struct sss_sec_quota_opt *dfl_max_num_secrets,
++                                struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
++                                struct sss_sec_quota_opt *dfl_max_payload,
+                                 struct sss_sec_hive_config *hive_config);
+ 
+ #endif /* __SECRETS_H_ */
+-- 
+2.20.1
+
diff --git a/SOURCES/0019-intg-add-Smartcard-authentication-tests.patch b/SOURCES/0019-intg-add-Smartcard-authentication-tests.patch
deleted file mode 100644
index f7912ec..0000000
--- a/SOURCES/0019-intg-add-Smartcard-authentication-tests.patch
+++ /dev/null
@@ -1,331 +0,0 @@
-From 6155a267d399d111706c4496c3877e216936c3b2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 7 Sep 2018 22:26:21 +0200
-Subject: [PATCH 19/19] intg: add Smartcard authentication tests
-
-Two test for Smartcard authentication of a local user, i.e. a user
-managed by the files provider, are added. One for a successful
-authentication, the other for a failed authentication with a wrong PIN.
-
-Related to https://pagure.io/SSSD/sssd/issue/3500
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 657f3b89bca9adfb13f0867c91f1d76845d2d6dd)
----
- configure.ac                         |   1 +
- contrib/ci/deps.sh                   |   2 +
- contrib/sssd.spec.in                 |   1 +
- src/external/cwrap.m4                |   5 ++
- src/external/intgcheck.m4            |   1 +
- src/tests/intg/Makefile.am           |  24 ++++++-
- src/tests/intg/test_pam_responder.py | 131 ++++++++++++++++++++++++++++++++---
- 7 files changed, 155 insertions(+), 10 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index 1aac65f4d85b9974adc5ba3e5196b00be5d279f1..891610e14490a4e78e1e95e63c18d9c6a9a8afb4 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -488,6 +488,7 @@ AM_CONDITIONAL([HAVE_CHECK], [test x$have_check != x])
- AM_CHECK_CMOCKA
- AM_CHECK_UID_WRAPPER
- AM_CHECK_NSS_WRAPPER
-+AM_CHECK_PAM_WRAPPER
- AM_CHECK_TEST_CA
- 
- # Check if the user wants SSSD to be compiled with systemtap probes
-diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh
-index 5906e5332ba99ce137174f3630e269b8c561f996..c04c7aab03f78185d96000142a71001ab52a66a7 100644
---- a/contrib/ci/deps.sh
-+++ b/contrib/ci/deps.sh
-@@ -46,6 +46,7 @@ if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then
-         pyldb
-         rpm-build
-         uid_wrapper
-+        pam_wrapper
-         python-requests
-         curl-devel
-         krb5-server
-@@ -117,6 +118,7 @@ if [[ "$DISTRO_BRANCH" == -debian-* ]]; then
-         fakeroot
-         libnss-wrapper
-         libuid-wrapper
-+        libpam-wrapper
-         python-pytest
-         python-ldap
-         python-ldb
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index 5ebd51f41f60cfdcd1d65c1c58dea4b296fd1ed1..26fae6d68dbe4d14f85ddf34bb4871bc34db3b3d 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -237,6 +237,7 @@ BuildRequires: selinux-policy-targeted
- BuildRequires: libcmocka-devel >= 1.0.0
- BuildRequires: uid_wrapper
- BuildRequires: nss_wrapper
-+BuildRequires: pam_wrapper
- 
- # Test CA requires openssl independent if SSSD is build with NSS or openssl,
- # openssh is needed for ssh-keygen and NSS builds need nss-tools for certutil.
-diff --git a/src/external/cwrap.m4 b/src/external/cwrap.m4
-index b8489cc765f34f3bc6ad4e4b7e69626f6ea8060e..6e3487c13f734e311a2262b0f71495167489c710 100644
---- a/src/external/cwrap.m4
-+++ b/src/external/cwrap.m4
-@@ -28,3 +28,8 @@ AC_DEFUN([AM_CHECK_NSS_WRAPPER],
- [
-     AM_CHECK_WRAPPER(nss_wrapper, HAVE_NSS_WRAPPER)
- ])
-+
-+AC_DEFUN([AM_CHECK_PAM_WRAPPER],
-+[
-+    AM_CHECK_WRAPPER(pam_wrapper, HAVE_PAM_WRAPPER)
-+])
-diff --git a/src/external/intgcheck.m4 b/src/external/intgcheck.m4
-index 60a7bf306ddefd748cf9bac62d3767e7512b6d64..c14f66978b8087586cf1c5ac2d60a07e4f90d45d 100644
---- a/src/external/intgcheck.m4
-+++ b/src/external/intgcheck.m4
-@@ -22,6 +22,7 @@ AC_DEFUN([SSS_ENABLE_INTGCHECK_REQS], [
-     if test x"$enable_intgcheck_reqs" = xyes; then
-         SSS_INTGCHECK_REQ([HAVE_UID_WRAPPER], [uid_wrapper])
-         SSS_INTGCHECK_REQ([HAVE_NSS_WRAPPER], [nss_wrapper])
-+        SSS_INTGCHECK_REQ([HAVE_PAM_WRAPPER], [pam_wrapper])
-         SSS_INTGCHECK_REQ([HAVE_SLAPD], [slapd])
-         SSS_INTGCHECK_REQ([HAVE_LDAPMODIFY], [ldapmodify])
-         SSS_INTGCHECK_REQ([HAVE_FAKEROOT], [fakeroot])
-diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
-index 6f7605bd4edbf26ef3ce97acea74fc92216eede9..bb3a7f01ae4f79fa05cd661993e8f9872ecd0450 100644
---- a/src/tests/intg/Makefile.am
-+++ b/src/tests/intg/Makefile.am
-@@ -105,13 +105,29 @@ 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)/$@
-+
- 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
- 	pipepath="$(DESTDIR)$(pipepath)"; \
- 	if test $${#pipepath} -gt 80; then \
- 	    echo "error: Pipe directory path too long," \
-@@ -131,12 +147,18 @@ intgcheck-installed: config.py passwd group
- 	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 cf6fff2db7ba9c9c69e1dd9abe5663a02cedd72e..c6d048cd342838fe312287eaffff734e30ba9e1c 100644
---- a/src/tests/intg/test_pam_responder.py
-+++ b/src/tests/intg/test_pam_responder.py
-@@ -27,31 +27,44 @@ import signal
- import errno
- import subprocess
- import time
--import pytest
-+import shutil
- 
- import config
- 
--from util import unindent
-+import pytest
- 
-+from intg.util import unindent
-+from intg.files_ops import passwd_ops_setup
- 
--def format_pam_cert_auth_conf():
-+USER1 = dict(name='user1', passwd='x', uid=10001, gid=20001,
-+             gecos='User for tests',
-+             dir='/home/user1',
-+             shell='/bin/bash')
-+
-+
-+def format_pam_cert_auth_conf(config):
-     """Format a basic SSSD configuration"""
-     return unindent("""\
-         [sssd]
-+        debug_level = 10
-         domains = auth_only
--        services = pam
-+        services = pam, nss
- 
-         [nss]
-+        debug_level = 10
- 
-         [pam]
-         pam_cert_auth = True
-+        pam_p11_allowed_services = +pam_sss_service
-+        pam_cert_db_path = {config.PAM_CERT_DB_PATH}
-         debug_level = 10
- 
-         [domain/auth_only]
--        id_provider = ldap
--        auth_provider = ldap
--        chpass_provider = ldap
--        access_provider = ldap
-+        debug_level = 10
-+        id_provider = files
-+
-+        [certmap/auth_only/user1]
-+        matchrule = <SUBJECT>.*CN=SSSD test cert 0001.*
-     """).format(**locals())
- 
- 
-@@ -79,6 +92,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")
- 
-@@ -116,12 +131,41 @@ def create_sssd_fixture(request):
-     request.addfinalizer(cleanup_sssd_process)
- 
- 
-+def create_nssdb():
-+    os.mkdir(config.SYSCONFDIR + "/pki")
-+    os.mkdir(config.SYSCONFDIR + "/pki/nssdb")
-+    if subprocess.call(["certutil", "-N", "-d",
-+                        "sql:" + config.SYSCONFDIR + "/pki/nssdb/",
-+                        "--empty-password"]) != 0:
-+        raise Exception("certutil failed")
-+
-+    pkcs11_txt = open(config.SYSCONFDIR + "/pki/nssdb/pkcs11.txt", "w")
-+    pkcs11_txt.write("library=libsoftokn3.so\nname=soft\n" +
-+                     "parameters=configdir='sql:" + config.ABS_BUILDDIR +
-+                     "/../test_CA/p11_nssdb' " +
-+                     "dbSlotDescription='SSSD Test Slot' " +
-+                     "dbTokenDescription='SSSD Test Token' " +
-+                     "secmod='secmod.db' flags=readOnly)\n\n")
-+    pkcs11_txt.close()
-+
-+
-+def cleanup_nssdb():
-+    shutil.rmtree(config.SYSCONFDIR + "/pki")
-+
-+
-+def create_nssdb_fixture(request):
-+    create_nssdb()
-+    request.addfinalizer(cleanup_nssdb)
-+
-+
- @pytest.fixture
- def simple_pam_cert_auth(request):
-     """Setup SSSD with pam_cert_auth=True"""
--    conf = format_pam_cert_auth_conf()
-+    config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
-+    conf = format_pam_cert_auth_conf(config)
-     create_conf_fixture(request, conf)
-     create_sssd_fixture(request)
-+    create_nssdb_fixture(request)
-     return None
- 
- 
-@@ -129,3 +173,72 @@ 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_wrapper_setup(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")
-+
-+
-+def test_sc_auth_wrong_pin(simple_pam_cert_auth, pam_wrapper_setup,
-+                           passwd_ops_setup):
-+
-+    passwd_ops_setup.useradd(**USER1)
-+    current_env = os.environ.copy()
-+    current_env['PAM_WRAPPER'] = "1"
-+    current_env['SSSD_INTG_PEER_UID'] = "0"
-+    current_env['SSSD_INTG_PEER_GID'] = "0"
-+    current_env['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
-+
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-+                               "--action=auth", "--service=pam_sss_service"],
-+                              universal_newlines=True,
-+                              env=current_env, 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("pam_authenticate for user [user1]: " +
-+                    "Authentication failure") != -1
-+
-+
-+def test_sc_auth(simple_pam_cert_auth, pam_wrapper_setup, passwd_ops_setup):
-+
-+    passwd_ops_setup.useradd(**USER1)
-+    current_env = os.environ.copy()
-+    current_env['PAM_WRAPPER'] = "1"
-+    current_env['SSSD_INTG_PEER_UID'] = "0"
-+    current_env['SSSD_INTG_PEER_GID'] = "0"
-+    current_env['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
-+
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-+                               "--action=auth", "--service=pam_sss_service"],
-+                              universal_newlines=True,
-+                              env=current_env, stdin=subprocess.PIPE,
-+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-+
-+    try:
-+        out, err = sssctl.communicate(input="123456")
-+    except:
-+        sssctl.kill()
-+        out, err = sssctl.communicate()
-+
-+    sssctl.stdin.close()
-+    sssctl.stdout.close()
-+
-+    if sssctl.wait() != 0:
-+        raise Exception("sssctl failed")
-+
-+    assert err.find("pam_authenticate for user [user1]: Success") != -1
--- 
-2.14.4
-
diff --git a/SOURCES/0020-SECRETS-Don-t-limit-the-global-number-of-ccaches.patch b/SOURCES/0020-SECRETS-Don-t-limit-the-global-number-of-ccaches.patch
new file mode 100644
index 0000000..a05c43e
--- /dev/null
+++ b/SOURCES/0020-SECRETS-Don-t-limit-the-global-number-of-ccaches.patch
@@ -0,0 +1,51 @@
+From 940002ca21abde53ad81df622d1f4dd3b5e8e014 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 30 Nov 2018 13:34:22 +0100
+Subject: [PATCH 20/23] SECRETS: Don't limit the global number of ccaches
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3386
+
+In the KCM context, the global number of ccaches would limit the number
+of users who can store their ccaches in the KCM deamon.
+
+In more detail, the options have the following semantics with KCM:
+    - DEFAULT_SEC_KCM_MAX_SECRETS - global number of secrets, would
+    cover both how many ccaches can a user store, but this is better
+    served with DEFAULT_SEC_KCM_MAX_UID_SECRETS
+
+    - DEFAULT_SEC_KCM_MAX_UID_SECRETS - how many 'principals' can a user
+    kinit with
+
+    - DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE - the payload size of service
+    tickets
+
+With the above in mind, I think the most important limits are
+max_uid_secrets to limit and the payload size to constraint how much
+space can a user occupy and it doesn't make much sense to limit the
+global quota.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/util/secrets/secrets.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
+index 31164bd86..9cf397516 100644
+--- a/src/util/secrets/secrets.h
++++ b/src/util/secrets/secrets.h
+@@ -39,7 +39,7 @@
+  * but the secret size must be large because one secret in the /kcm
+  * hive holds the whole ccache which consists of several credentials
+  */
+-#define DEFAULT_SEC_KCM_MAX_SECRETS      256
++#define DEFAULT_SEC_KCM_MAX_SECRETS      0          /* unlimited */
+ #define DEFAULT_SEC_KCM_MAX_UID_SECRETS  64
+ #define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0020-sbus-dectect-python-binary-for-sbus_generate.sh.patch b/SOURCES/0020-sbus-dectect-python-binary-for-sbus_generate.sh.patch
deleted file mode 100644
index bd0e5ee..0000000
--- a/SOURCES/0020-sbus-dectect-python-binary-for-sbus_generate.sh.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From 8b43e5149d9726de3a573ba8b4e44fd68b328f92 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 10 Sep 2018 15:40:14 +0200
-Subject: [PATCH] sbus: dectect python binary for sbus_generate.sh
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-We already detect python2 and python3 binaries during configure. With
-this patch PYTHON_EXEC is set to the python3 binary if python3 bindings
-are generated and to the python2 binary otherwise. With the help of an
-environment variable sbus_generate.sh is made aware of it.
-
-Related to https://pagure.io/SSSD/sssd/issue/3807
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit b03179ead11db7dbfd6a00d3eeef3dac0990f826)
----
- Makefile.am                             | 4 ++--
- configure.ac                            | 8 ++++++++
- sbus_generate.sh => sbus_generate.sh.in | 2 +-
- 3 files changed, 11 insertions(+), 3 deletions(-)
- rename sbus_generate.sh => sbus_generate.sh.in (93%)
-
-diff --git a/Makefile.am b/Makefile.am
-index 85952818c9a8efd957ce99f4595b251265cc5417..1602ec6236799015fa7fd9f1707cb2bcdb20e07b 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1019,14 +1019,14 @@ libsss_cert_la_LDFLAGS = \
-     $(NULL)
- 
- generate-sbus-code:
--	$(srcdir)/sbus_generate.sh $(abs_srcdir)
-+	$(builddir)/sbus_generate.sh $(abs_srcdir)
- 
- .PHONY: generate-sbus-code
- 
- BUILT_SOURCES += generate-sbus-code
- 
- EXTRA_DIST += \
--    sbus_generate.sh \
-+    sbus_generate.sh.in \
-     src/sbus/codegen/dbus.xml \
-     src/sbus/codegen/sbus_CodeGen.py \
-     src/sbus/codegen/sbus_DataType.py \
-diff --git a/configure.ac b/configure.ac
-index 891610e14490a4e78e1e95e63c18d9c6a9a8afb4..5816b04c6651ee9cd4ddfae9a1cb0ab44f3ea4e0 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -373,6 +373,13 @@ them please use argument --without-python3-bindings when running configure.])])
-     SSS_CLEAN_PYTHON_VARIABLES
- fi
- 
-+if test x$HAVE_PYTHON3_BINDINGS = x1; then
-+    PYTHON_EXEC=$PYTHON3
-+else
-+    PYTHON_EXEC=$PYTHON2
-+fi
-+AC_SUBST(PYTHON_EXEC)
-+
- AM_CONDITIONAL([BUILD_PYTHON_BINDINGS],
-                [test x"$with_python2_bindings" = xyes \
-                      -o x"$with_python3_bindings" = xyes])
-@@ -525,4 +532,5 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
-                  src/config/setup.py
-                  src/systemtap/sssd.stp
-                  src/config/SSSDConfig/__init__.py])
-+AC_CONFIG_FILES([sbus_generate.sh], [chmod +x sbus_generate.sh])
- AC_OUTPUT
-diff --git a/sbus_generate.sh b/sbus_generate.sh.in
-similarity index 93%
-rename from sbus_generate.sh
-rename to sbus_generate.sh.in
-index 338fd9d3387d6d4694e08de3d537d6a54e78a560..b2c695e700901bcff77ebbe2d1887cd572ec5e52 100755
---- a/sbus_generate.sh
-+++ b/sbus_generate.sh.in
-@@ -13,7 +13,7 @@ generate() {
- 
-     echo "Generating sbus code for: $XML"
- 
--    python $CODEGEN --sbus sbus --util util \
-+    @PYTHON_EXEC@ $CODEGEN --sbus sbus --util util \
-         --headers "$HEADERS" \
-         --dest "$SRCDIR/src/$DEST" \
-         --fileprefix "sbus_${PREFIX}_" \
--- 
-2.14.4
-
diff --git a/SOURCES/0021-CONFDB-Skip-local-domain-if-not-supported.patch b/SOURCES/0021-CONFDB-Skip-local-domain-if-not-supported.patch
deleted file mode 100644
index 1f608ec..0000000
--- a/SOURCES/0021-CONFDB-Skip-local-domain-if-not-supported.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From fea818f425178931cce9cbaccae9070e462d5659 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Tue, 18 Sep 2018 15:23:54 +0200
-Subject: [PATCH] CONFDB: Skip 'local' domain if not supported
-
-When SSSD is built without the support for local
-domain, we should gracegully skip local domains
-and let other domains start.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3828
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 10fa27eddb9bbe135277d587c6a2de4b311da6df)
----
- src/confdb/confdb.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index 6370a0411d98b6611dd384e9ab0de1d580be9c2d..954c3ba766617f7cfcf637d9143c891bd998d7ff 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -945,8 +945,14 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
-         goto done;
-     }
- 
--    if (local_provider_is_built()
--            && strcasecmp(domain->provider, "local") == 0) {
-+    if (strcasecmp(domain->provider, "local") == 0) {
-+        if (!local_provider_is_built()) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "ID provider 'local' no longer supported, disabling\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-         /* If this is the local provider, we need to ensure that
-          * no other provider was specified for other types, since
-          * the local provider cannot load them.
--- 
-2.14.4
-
diff --git a/SOURCES/0021-KCM-Pass-confdb-context-to-the-ccache-db-initializat.patch b/SOURCES/0021-KCM-Pass-confdb-context-to-the-ccache-db-initializat.patch
new file mode 100644
index 0000000..964b175
--- /dev/null
+++ b/SOURCES/0021-KCM-Pass-confdb-context-to-the-ccache-db-initializat.patch
@@ -0,0 +1,176 @@
+From f00db73d7bbf312e3e2a772b8b10895d5460b989 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 28 Nov 2018 21:24:08 +0100
+Subject: [PATCH 21/23] KCM: Pass confdb context to the ccache db
+ initialization
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3386
+
+The libsecrets back end needs to read the quota options from confdb,
+therefore it needs to know the section and access the confdb handle.
+
+These parameters are unused for other ccache back end types, but they
+are harmless and IMO it makes more sense to keep the ccache back end
+abstract.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/responder/kcm/kcm.c                   | 14 ++++++++++++--
+ src/responder/kcm/kcmsrv_ccache.c         |  4 +++-
+ src/responder/kcm/kcmsrv_ccache.h         |  2 ++
+ src/responder/kcm/kcmsrv_ccache_be.h      |  4 +++-
+ src/responder/kcm/kcmsrv_ccache_mem.c     |  4 +++-
+ src/responder/kcm/kcmsrv_ccache_secdb.c   |  6 +++---
+ src/responder/kcm/kcmsrv_ccache_secrets.c |  4 +++-
+ 7 files changed, 29 insertions(+), 9 deletions(-)
+
+diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
+index 005dd168f..045c7801f 100644
+--- a/src/responder/kcm/kcm.c
++++ b/src/responder/kcm/kcm.c
+@@ -170,6 +170,8 @@ static int kcm_data_destructor(void *ptr)
+ 
+ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
++                                           struct confdb_ctx *cdb,
++                                           const char *confdb_service_path,
+                                            enum kcm_ccdb_be cc_be)
+ {
+     struct kcm_resp_ctx *kcm_data;
+@@ -181,7 +183,11 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
+         return NULL;
+     }
+ 
+-    kcm_data->db = kcm_ccdb_init(kcm_data, ev, cc_be);
++    kcm_data->db = kcm_ccdb_init(kcm_data,
++                                 ev,
++                                 cdb,
++                                 confdb_service_path,
++                                 cc_be);
+     if (kcm_data->db == NULL) {
+         talloc_free(kcm_data);
+         return NULL;
+@@ -235,7 +241,11 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx,
+         goto fail;
+     }
+ 
+-    kctx->kcm_data = kcm_data_setup(kctx, ev, kctx->cc_be);
++    kctx->kcm_data = kcm_data_setup(kctx,
++                                    ev,
++                                    kctx->rctx->cdb,
++                                    kctx->rctx->confdb_service_path,
++                                    kctx->cc_be);
+     if (kctx->kcm_data == NULL) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "fatal error initializing responder data\n");
+diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
+index e7800662a..085cc4464 100644
+--- a/src/responder/kcm/kcmsrv_ccache.c
++++ b/src/responder/kcm/kcmsrv_ccache.c
+@@ -229,6 +229,8 @@ struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd)
+ 
+ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
+                                struct tevent_context *ev,
++                               struct confdb_ctx *cdb,
++                               const char *confdb_service_path,
+                                enum kcm_ccdb_be cc_be)
+ {
+     errno_t ret;
+@@ -270,7 +272,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
+         return NULL;
+     }
+ 
+-    ret = ccdb->ops->init(ccdb);
++    ret = ccdb->ops->init(ccdb, cdb, confdb_service_path);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize ccache database\n");
+         talloc_free(ccdb);
+diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
+index 0fd33325f..199b75b16 100644
+--- a/src/responder/kcm/kcmsrv_ccache.h
++++ b/src/responder/kcm/kcmsrv_ccache.h
+@@ -125,6 +125,8 @@ struct kcm_ccdb;
+  */
+ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
+                                struct tevent_context *ev,
++                               struct confdb_ctx *cdb,
++                               const char *confdb_service_path,
+                                enum kcm_ccdb_be cc_be);
+ 
+ /*
+diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h
+index 7315f6435..166af3a76 100644
+--- a/src/responder/kcm/kcmsrv_ccache_be.h
++++ b/src/responder/kcm/kcmsrv_ccache_be.h
+@@ -30,7 +30,9 @@
+ #include "responder/kcm/kcmsrv_ccache.h"
+ 
+ typedef errno_t
+-(*ccdb_init_fn)(struct kcm_ccdb *db);
++(*ccdb_init_fn)(struct kcm_ccdb *db,
++                struct confdb_ctx *cdb,
++                const char *confdb_service_path);
+ 
+ typedef struct tevent_req *
+ (*ccdb_nextid_send_fn)(TALLOC_CTX *mem_ctx,
+diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c
+index 38bc2050d..35955b2f4 100644
+--- a/src/responder/kcm/kcmsrv_ccache_mem.c
++++ b/src/responder/kcm/kcmsrv_ccache_mem.c
+@@ -151,7 +151,9 @@ static int ccwrap_destructor(void *ptr)
+     return 0;
+ }
+ 
+-static errno_t ccdb_mem_init(struct kcm_ccdb *db)
++static errno_t ccdb_mem_init(struct kcm_ccdb *db,
++                             struct confdb_ctx *cdb,
++                             const char *confdb_service_path)
+ {
+     struct ccdb_mem *memdb = NULL;
+ 
+diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
+index c68f53f97..d0d9a7e4c 100644
+--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
++++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
+@@ -520,7 +520,9 @@ done:
+     return ret;
+ }
+ 
+-static errno_t ccdb_secdb_init(struct kcm_ccdb *db)
++static errno_t ccdb_secdb_init(struct kcm_ccdb *db,
++                               struct confdb_ctx *cdb,
++                               const char *confdb_service_path)
+ {
+     struct ccdb_secdb *secdb = NULL;
+     errno_t ret;
+@@ -530,8 +532,6 @@ static errno_t ccdb_secdb_init(struct kcm_ccdb *db)
+         return ENOMEM;
+     }
+ 
+-    /* TODO: read configuration from the config file, adjust quotas */
+-
+     ret = sss_sec_init(db, NULL, &secdb->sctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c
+index 93be4fafa..6fa2a6dcc 100644
+--- a/src/responder/kcm/kcmsrv_ccache_secrets.c
++++ b/src/responder/kcm/kcmsrv_ccache_secrets.c
+@@ -659,7 +659,9 @@ static errno_t sec_get_ccache_recv(struct tevent_req *req,
+ /*
+  * The actual sssd-secrets back end
+  */
+-static errno_t ccdb_sec_init(struct kcm_ccdb *db)
++static errno_t ccdb_sec_init(struct kcm_ccdb *db,
++                             struct confdb_ctx *cdb,
++                             const char *confdb_service_path)
+ {
+     struct ccdb_sec *secdb = NULL;
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0022-KCM-Configurable-quotas-for-the-secdb-ccache-back-en.patch b/SOURCES/0022-KCM-Configurable-quotas-for-the-secdb-ccache-back-en.patch
new file mode 100644
index 0000000..495e3e2
--- /dev/null
+++ b/SOURCES/0022-KCM-Configurable-quotas-for-the-secdb-ccache-back-en.patch
@@ -0,0 +1,179 @@
+From f024b5e46b62ad49f0099ed8db8155e7ea475639 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 28 Nov 2018 21:22:22 +0100
+Subject: [PATCH 22/23] KCM: Configurable quotas for the secdb ccache back end
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3386
+
+Exposes three new options for the [kcm] responder to set the global
+ccache limit, the per-uid ccache limit and the payload size.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/confdb/confdb.h                     |  3 ++
+ src/config/cfg_rules.ini                |  3 ++
+ src/man/sssd-kcm.8.xml                  | 37 +++++++++++++++
+ src/responder/kcm/kcmsrv_ccache_secdb.c | 61 ++++++++++++++++++++++++-
+ 4 files changed, 103 insertions(+), 1 deletion(-)
+
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index d09d6b4c3..727841659 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -266,6 +266,9 @@
+ #define CONFDB_KCM_CONF_ENTRY "config/kcm"
+ #define CONFDB_KCM_SOCKET "socket_path"
+ #define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
++#define CONFDB_KCM_MAX_CCACHES "max_ccaches"
++#define CONFDB_KCM_MAX_UID_CCACHES "max_uid_ccaches"
++#define CONFDB_KCM_MAX_CCACHE_SIZE "max_ccache_size"
+ 
+ /* Certificate mapping rules */
+ #define CONFDB_CERTMAP_BASEDN "cn=certmap,cn=config"
+diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
+index 30040b595..59d6cc512 100644
+--- a/src/config/cfg_rules.ini
++++ b/src/config/cfg_rules.ini
+@@ -312,6 +312,9 @@ option = description
+ option = socket_path
+ option = ccache_storage
+ option = responder_idle_timeout
++option = max_ccaches
++option = max_uid_ccaches
++option = max_ccache_size
+ 
+ # Session recording
+ [rule/allowed_session_recording_options]
+diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
+index 4e4aaa38e..2f66e56a4 100644
+--- a/src/man/sssd-kcm.8.xml
++++ b/src/man/sssd-kcm.8.xml
+@@ -201,6 +201,43 @@ systemctl restart sssd-kcm.service
+                     </para>
+                 </listitem>
+             </varlistentry>
++            <varlistentry>
++                <term>max_ccaches (integer)</term>
++                <listitem>
++                    <para>
++                        How many credential caches does the KCM database allow
++                        for all users.
++                    </para>
++                    <para>
++                        Default: 0 (unlimited, only the per-UID quota is enforced)
++                    </para>
++                </listitem>
++            </varlistentry>
++            <varlistentry>
++                <term>max_uid_ccaches (integer)</term>
++                <listitem>
++                    <para>
++                        How many credential caches does the KCM database allow
++                        per UID. This is equivalent to <quote>with how many
++                        principals you can kinit</quote>.
++                    </para>
++                    <para>
++                        Default: 64
++                    </para>
++                </listitem>
++            </varlistentry>
++            <varlistentry>
++                <term>max_ccache_size (integer)</term>
++                <listitem>
++                    <para>
++                        How big can a credential cache be per ccache. Each
++                        service ticket accounts into this quota.
++                    </para>
++                    <para>
++                        Default: 65536
++                    </para>
++                </listitem>
++            </varlistentry>
+         </variablelist>
+     </refsect1>
+ 
+diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
+index d0d9a7e4c..dc9cefb32 100644
+--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
++++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
+@@ -526,13 +526,72 @@ static errno_t ccdb_secdb_init(struct kcm_ccdb *db,
+ {
+     struct ccdb_secdb *secdb = NULL;
+     errno_t ret;
++    struct sss_sec_hive_config **kcm_section_quota;
++    struct sss_sec_quota_opt dfl_kcm_nest_level = {
++        .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL,
++        .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
++    };
++    struct sss_sec_quota_opt dfl_kcm_max_secrets = {
++        .opt_name = CONFDB_KCM_MAX_CCACHES,
++        .default_value = DEFAULT_SEC_KCM_MAX_SECRETS,
++    };
++    struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = {
++        .opt_name = CONFDB_KCM_MAX_UID_CCACHES,
++        .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS,
++    };
++    struct sss_sec_quota_opt dfl_kcm_max_payload_size = {
++        .opt_name = CONFDB_KCM_MAX_CCACHE_SIZE,
++        .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE,
++    };
++
+ 
+     secdb = talloc_zero(db, struct ccdb_secdb);
+     if (secdb == NULL) {
+         return ENOMEM;
+     }
+ 
+-    ret = sss_sec_init(db, NULL, &secdb->sctx);
++    kcm_section_quota = talloc_zero_array(secdb,
++                                          struct sss_sec_hive_config *,
++                                          2);
++    if (kcm_section_quota == NULL) {
++        talloc_free(secdb);
++        return ENOMEM;
++    }
++
++    kcm_section_quota[0] = talloc_zero(kcm_section_quota,
++                                       struct sss_sec_hive_config);
++    if (kcm_section_quota == NULL) {
++        talloc_free(secdb);
++        return ENOMEM;
++    }
++    kcm_section_quota[0]->hive_name = "kcm";
++
++    ret = sss_sec_get_quota(cdb,
++                            confdb_service_path,
++                            &dfl_kcm_nest_level,
++                            &dfl_kcm_max_secrets,
++                            &dfl_kcm_max_uid_secrets,
++                            &dfl_kcm_max_payload_size,
++                            &kcm_section_quota[0]->quota);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_FATAL_FAILURE,
++              "Failed to get KCM global quotas [%d]: %s\n",
++              ret, sss_strerror(ret));
++        talloc_free(secdb);
++        return ret;
++    }
++
++    if (kcm_section_quota[0]->quota.max_uid_secrets > 0) {
++        /* Even cn=default is considered a secret that adds up to
++         * the quota. To avoid off-by-one-confusion, increase
++         * the quota by two to 1) account for the cn=default object
++         * and 2) always allow writing to cn=defaults even if we
++         * are exactly at the quota limit
++         */
++        kcm_section_quota[0]->quota.max_uid_secrets += 2;
++    }
++
++    ret = sss_sec_init(db, kcm_section_quota, &secdb->sctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Cannot initialize the security database\n");
+-- 
+2.20.1
+
diff --git a/SOURCES/0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch b/SOURCES/0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch
deleted file mode 100644
index 3b1da28..0000000
--- a/SOURCES/0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch
+++ /dev/null
@@ -1,145 +0,0 @@
-From 06c13c32faff1d9dcb5156f496a4848bfe1f1462 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 23 Aug 2018 13:55:51 +0200
-Subject: [PATCH 22/28] SELINUX: Always add SELinux user to the semanage
- database if it doesn't exist
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Previously, we tried to optimize too much and only set the SELinux user
-to Linux user mapping in case the SELinux user was different from the
-system default. But this doesn't work for the case where the Linux user
-has a non-standard home directory, because then SELinux would not have
-any idea that this user's home directory should be labeled as a home
-directory.
-
-This patch relaxes the optimization in the sense that on the first
-login, the SELinux context is saved regardless of whether it is the same
-as the default or different.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3819
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit 945865ae16120ffade267227ca48cefd58822fd2)
----
- src/providers/ipa/selinux_child.c | 10 ++++++++--
- src/util/sss_semanage.c           | 30 ++++++++++++++++++++++++++++++
- src/util/util.h                   |  1 +
- src/util/util_errors.c            |  1 +
- src/util/util_errors.h            |  1 +
- 5 files changed, 41 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
-index d061417a5a30aacb231d973fa1aa7ddab869fc51..925591ec902d3b6f3b687fcb4a5f160b1b1d9a8d 100644
---- a/src/providers/ipa/selinux_child.c
-+++ b/src/providers/ipa/selinux_child.c
-@@ -176,13 +176,16 @@ static bool seuser_needs_update(const char *username,
-
-     ret = sss_get_seuser(username, &db_seuser, &db_mls_range);
-     DEBUG(SSSDBG_TRACE_INTERNAL,
--          "getseuserbyname: ret: %d seuser: %s mls: %s\n",
-+          "sss_get_seuser: ret: %d seuser: %s mls: %s\n",
-           ret, db_seuser ? db_seuser : "unknown",
-           db_mls_range ? db_mls_range : "unknown");
-     if (ret == EOK && db_seuser && db_mls_range &&
-             strcmp(db_seuser, seuser) == 0 &&
-             strcmp(db_mls_range, mls_range) == 0) {
--        needs_update = false;
-+        ret = sss_seuser_exists(username);
-+        if (ret == EOK) {
-+            needs_update = false;
-+        }
-     }
-     /* OR */
-     if (ret == ERR_SELINUX_NOT_MANAGED) {
-@@ -191,6 +194,9 @@ static bool seuser_needs_update(const char *username,
-
-     free(db_seuser);
-     free(db_mls_range);
-+    DEBUG(SSSDBG_TRACE_FUNC,
-+          "The SELinux user does %sneed an update\n",
-+          needs_update ? "" : "not ");
-     return needs_update;
- }
-
-diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
-index bcce57b603bd1c4d5c6465dbb5cc7a3fbe72412d..aea03852ac07dd344b6170d7ec2a030f30e0f202 100644
---- a/src/util/sss_semanage.c
-+++ b/src/util/sss_semanage.c
-@@ -248,6 +248,36 @@ done:
-     return ret;
- }
-
-+int sss_seuser_exists(const char *linuxuser)
-+{
-+    int ret;
-+    int exists;
-+    semanage_seuser_key_t *sm_key = NULL;
-+    semanage_handle_t *sm_handle = NULL;
-+
-+    ret = sss_semanage_init(&sm_handle);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    ret = semanage_seuser_key_create(sm_handle, linuxuser, &sm_key);
-+    if (ret < 0) {
-+        sss_semanage_close(sm_handle);
-+        return EIO;
-+    }
-+
-+    ret = semanage_seuser_exists(sm_handle, sm_key, &exists);
-+    semanage_seuser_key_free(sm_key);
-+    sss_semanage_close(sm_handle);
-+    if (ret < 0) {
-+        return EIO;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "seuser exists: %s\n", exists ? "yes" : "no");
-+
-+    return exists ? EOK : ERR_SELINUX_USER_NOT_FOUND;
-+}
-+
- int sss_get_seuser(const char *linuxuser,
-                    char **selinuxuser,
-                    char **level)
-diff --git a/src/util/util.h b/src/util/util.h
-index 867acf26fff18becb01397697ea6dde2961d9ece..59e7a96ba58aa9400166514064922d25fb713deb 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -663,6 +663,7 @@ int sss_del_seuser(const char *login_name);
- int sss_get_seuser(const char *linuxuser,
-                    char **selinuxuser,
-                    char **level);
-+int sss_seuser_exists(const char *linuxuser);
-
- /* convert time from generalized form to unix time */
- errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time);
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 920a178615bef081c9fd035570e661ba6438350a..5f8a2a29ab5af44432c01a85c02f61ece3cdc8b5 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -75,6 +75,7 @@ struct err_string error_to_str[] = {
-     { "LDAP search returned a referral" }, /* ERR_REFERRAL */
-     { "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */
-     { "SELinux is not managed by libsemanage" }, /* ERR_SELINUX_NOT_MANAGED */
-+    { "SELinux user does not exist" }, /* ERR_SELINUX_USER_NOT_FOUND */
-     { "Username format not allowed by re_expression" }, /* ERR_REGEX_NOMATCH */
-     { "Time specification not supported" }, /* ERR_TIMESPEC_NOT_SUPPORTED */
-     { "Invalid SSSD configuration detected" }, /* ERR_INVALID_CONFIG */
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index 5a509362616248ec3f688e28996ec4b6e25ee131..c6731d4f999bdadcef2bb65a6be199d0db009674 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -97,6 +97,7 @@ enum sssd_errors {
-     ERR_REFERRAL,
-     ERR_SELINUX_CONTEXT,
-     ERR_SELINUX_NOT_MANAGED,
-+    ERR_SELINUX_USER_NOT_FOUND,
-     ERR_REGEX_NOMATCH,
-     ERR_TIMESPEC_NOT_SUPPORTED,
-     ERR_INVALID_CONFIG,
---
-2.14.4
diff --git a/SOURCES/0023-MAN-Document-that-PAM-stack-contains-the-systemd-use.patch b/SOURCES/0023-MAN-Document-that-PAM-stack-contains-the-systemd-use.patch
new file mode 100644
index 0000000..24d44c3
--- /dev/null
+++ b/SOURCES/0023-MAN-Document-that-PAM-stack-contains-the-systemd-use.patch
@@ -0,0 +1,36 @@
+From 820151f3813f08c704cb87a99988fe39f9f48a8d Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 4 Jul 2019 10:22:25 +0200
+Subject: [PATCH] MAN: Document that PAM stack contains the systemd-user
+ service in the account phase in RHEL-8
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3932
+
+Reviewed-by: Tomas Halman <thalman@redhat.com>
+---
+ src/man/sssd-ldap.5.xml | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index c205aea64..aca0f9e72 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -834,6 +834,14 @@
+                             ldap_user_authorized_service option
+                             to work.
+                         </para>
++                        <para>
++                            Some distributions (such as Fedora-29+ or RHEL-8)
++                            always include the <quote>systemd-user</quote> PAM
++                            service as part of the login process. Therefore when
++                            using service-based access control, the
++                            <quote>systemd-user</quote> service might need to be
++                            added to the list of allowed services.
++                        </para>
+                         <para>
+                             Default: authorizedService
+                         </para>
+-- 
+2.20.1
+
diff --git a/SOURCES/0023-proxy-access-provider-directly-not-through-be_ctx.patch b/SOURCES/0023-proxy-access-provider-directly-not-through-be_ctx.patch
deleted file mode 100644
index 2ac0feb..0000000
--- a/SOURCES/0023-proxy-access-provider-directly-not-through-be_ctx.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 61c442994706365c177a62799194e62ec46f3ae0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 5 Sep 2018 13:35:54 +0200
-Subject: [PATCH 23/28] proxy: access provider directly not through be_ctx
-
-Modules are initialized as part of dp_init_send() but be_ctx->provider is set
-only after this request is finished therefore it is not available here.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3812
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 4ffe3ab9023ff858410256bc5c38a03d9cd88cf9)
----
- src/providers/proxy/proxy_init.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
-index cf4f82e1246f08e2dbecd986a044500eee912b13..98c6dd1798dbf98419db71004cb55fcf21f58f81 100644
---- a/src/providers/proxy/proxy_init.c
-+++ b/src/providers/proxy/proxy_init.c
-@@ -192,6 +192,7 @@ static errno_t proxy_auth_conf(TALLOC_CTX *mem_ctx,
-
- static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx,
-                                    struct be_ctx *be_ctx,
-+                                   struct data_provider *provider,
-                                    struct proxy_auth_ctx **_auth_ctx)
- {
-     struct proxy_auth_ctx *auth_ctx;
-@@ -213,7 +214,7 @@ static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
-
--    ret = proxy_client_init(dp_sbus_conn(be_ctx->provider), auth_ctx);
-+    ret = proxy_client_init(dp_sbus_conn(provider), auth_ctx);
-     if (ret != EOK) {
-         goto done;
-     }
-@@ -273,7 +274,7 @@ errno_t sssm_proxy_init(TALLOC_CTX *mem_ctx,
-
-     /* Initialize auth_ctx since one of the access, auth or chpass is set. */
-
--    ret = proxy_init_auth_ctx(mem_ctx, be_ctx, &auth_ctx);
-+    ret = proxy_init_auth_ctx(mem_ctx, be_ctx, provider, &auth_ctx);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create auth context [%d]: %s\n",
-               ret, sss_strerror(ret));
---
-2.14.4
diff --git a/SOURCES/0024-Don-t-qualify-users-from-files-domain-when-default_d.patch b/SOURCES/0024-Don-t-qualify-users-from-files-domain-when-default_d.patch
new file mode 100644
index 0000000..c288f24
--- /dev/null
+++ b/SOURCES/0024-Don-t-qualify-users-from-files-domain-when-default_d.patch
@@ -0,0 +1,119 @@
+From 41da9ddfd084024ba9ca20b6d3c0b531c0473231 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 2 Aug 2019 12:07:51 +0200
+Subject: [PATCH] Don't qualify users from files domain when
+ default_domain_suffix is set
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4052
+
+The files domain should always be non-qualified. The usual rules like
+qualification of all domains except the one set with
+default_domain_suffix should not apply.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/confdb/confdb.c                   |  7 ++++--
+ src/man/sssd.conf.5.xml               |  8 ++++++-
+ src/tests/intg/test_files_provider.py | 31 +++++++++++++++++++++++++++
+ 3 files changed, 43 insertions(+), 3 deletions(-)
+
+diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
+index f6fdbc3aa..be65310dc 100644
+--- a/src/confdb/confdb.c
++++ b/src/confdb/confdb.c
+@@ -1049,7 +1049,8 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+ 
+     /* Determine if user/group names will be Fully Qualified
+      * in NSS interfaces */
+-    if (default_domain != NULL) {
++    if (default_domain != NULL
++             && is_files_provider(domain) == false) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+               "Default domain suffix set. Changing default for "
+               "use_fully_qualified_names to True.\n");
+@@ -1064,7 +1065,9 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+         goto done;
+     }
+ 
+-    if (default_domain != NULL && domain->fqnames == false) {
++    if (default_domain != NULL
++            && domain->fqnames == false
++            && is_files_provider(domain) == false) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "Invalid configuration detected (default_domain_suffix is used "
+               "while use_fully_qualified_names was set to false).\n");
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 304a6a170..c81012357 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -412,7 +412,13 @@
+                                 to log in. Setting this option changes default
+                                 of use_fully_qualified_names to True. It is not
+                                 allowed to use this option together with
+-                                use_fully_qualified_names set to False.
++                                use_fully_qualified_names set to False. One
++                                exception from this rule are domains with
++                                <quote>id_provider=files</quote> that always try
++                                to match the behaviour of nss_files
++                                and therefore their output is not
++                                qualified even when the default_domain_suffix
++                                option is used.
+                             </para>
+                             <para>
+                                 Default: not set
+diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py
+index 784bfa91f..9f3aad994 100644
+--- a/src/tests/intg/test_files_provider.py
++++ b/src/tests/intg/test_files_provider.py
+@@ -310,6 +310,22 @@ def domain_resolution_order(request):
+     return None
+ 
+ 
++@pytest.fixture
++def default_domain_suffix(request):
++    conf = unindent("""\
++        [sssd]
++        domains             = files
++        services            = nss
++        default_domain_suffix = foo
++
++        [domain/files]
++        id_provider = files
++    """).format(**locals())
++    create_conf_fixture(request, conf)
++    create_sssd_fixture(request)
++    return None
++
++
+ @pytest.fixture
+ def override_homedir_and_shell(request):
+     conf = unindent("""\
+@@ -1206,6 +1222,21 @@ def test_files_with_domain_resolution_order(add_user_with_canary,
+     check_user(USER1)
+ 
+ 
++def test_files_with_default_domain_suffix(add_user_with_canary,
++                                          default_domain_suffix):
++    """
++    Test that when using domain_resolution_order the user won't be using
++    its fully-qualified name.
++    """
++    ret = poll_canary(call_sssd_getpwuid, CANARY["uid"])
++    if ret is False:
++        return NssReturnCode.NOTFOUND, None
++
++    res, found_user = call_sssd_getpwuid(USER1["uid"])
++    assert res == NssReturnCode.SUCCESS
++    assert found_user == USER1
++
++
+ def test_files_with_override_homedir(add_user_with_canary,
+                                      override_homedir_and_shell):
+     res, user = sssd_getpwnam_sync(USER1["name"])
+-- 
+2.20.1
+
diff --git a/SOURCES/0024-dp-set-be_ctx-provider-as-part-of-dp_init-request.patch b/SOURCES/0024-dp-set-be_ctx-provider-as-part-of-dp_init-request.patch
deleted file mode 100644
index cef0070..0000000
--- a/SOURCES/0024-dp-set-be_ctx-provider-as-part-of-dp_init-request.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-From 65c689876b89e1ae2a1d214d509e8ef4a611cd4c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 5 Sep 2018 13:51:55 +0200
-Subject: [PATCH 24/28] dp: set be_ctx->provider as part of dp_init request
-
-Backend context is overused inside sssd code even during its initialization.
-Some parts of initialization code requires access to be_ctx->provider so we
-must make it available as soon as possible.
-
-Better solution would be to always use 'provider' directly in initialization
-but this makes it safer for any future changes as one does not have to keep
-in mind when it is safe to use be_ctx->provider and when not. Now it is
-always safe.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3812
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 4c5a1afa0df41aac05d34455c6e54a6f52a8dd28)
----
- src/providers/data_provider/dp.c | 21 +++++++++++++--------
- src/providers/data_provider/dp.h |  1 -
- src/providers/data_provider_be.c |  2 +-
- src/providers/proxy/proxy_init.c |  2 +-
- 4 files changed, 15 insertions(+), 11 deletions(-)
-
-diff --git a/src/providers/data_provider/dp.c b/src/providers/data_provider/dp.c
-index fd19d2803334726d0b59e76cc6c936a62d72d5e5..bd003c8b3e2919409941c11b3f1aa76ed074da7d 100644
---- a/src/providers/data_provider/dp.c
-+++ b/src/providers/data_provider/dp.c
-@@ -120,6 +120,7 @@ static int dp_destructor(struct data_provider *provider)
- }
-
- struct dp_init_state {
-+    struct be_ctx *be_ctx;
-     struct data_provider *provider;
-     char *sbus_name;
- };
-@@ -158,6 +159,7 @@ dp_init_send(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
-
-+    state->be_ctx = be_ctx;
-     state->provider->ev = ev;
-     state->provider->uid = uid;
-     state->provider->gid = gid;
-@@ -224,12 +226,14 @@ static void dp_init_done(struct tevent_req *subreq)
-     sbus_server_set_on_connection(state->provider->sbus_server,
-                                   dp_client_init, state->provider);
-
-+    /* be_ctx->provider must be accessible from modules and targets */
-+    state->be_ctx->provider = talloc_steal(state->be_ctx, state->provider);
-+
-     ret = dp_init_modules(state->provider, &state->provider->modules);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP modules "
-               "[%d]: %s\n", ret, sss_strerror(ret));
--        tevent_req_error(req, ret);
--        return;
-+        goto done;
-     }
-
-     ret = dp_init_targets(state->provider, state->provider->be_ctx,
-@@ -237,25 +241,27 @@ static void dp_init_done(struct tevent_req *subreq)
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP targets "
-               "[%d]: %s\n", ret, sss_strerror(ret));
--        tevent_req_error(req, ret);
--        return;
-+        goto done;
-     }
-
-     ret = dp_init_interface(state->provider);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP interface "
-               "[%d]: %s\n", ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_zfree(state->be_ctx->provider);
-         tevent_req_error(req, ret);
--        return;
-     }
-
-     tevent_req_done(req);
--    return;
- }
-
- errno_t dp_init_recv(TALLOC_CTX *mem_ctx,
-                      struct tevent_req *req,
--                     struct data_provider **_provider,
-                      const char **_sbus_name)
- {
-     struct dp_init_state *state;
-@@ -263,7 +269,6 @@ errno_t dp_init_recv(TALLOC_CTX *mem_ctx,
-
-     TEVENT_REQ_RETURN_ON_ERROR(req);
-
--    *_provider = talloc_steal(mem_ctx, state->provider);
-     *_sbus_name = talloc_steal(mem_ctx, state->sbus_name);
-
-     return EOK;
-diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
-index 33e6e6567bc56ac8ac8180edca01e8d937d0d39d..0028eb1cbdcb7e9db004a8c9c2f6c13b317cae7d 100644
---- a/src/providers/data_provider/dp.h
-+++ b/src/providers/data_provider/dp.h
-@@ -117,7 +117,6 @@ dp_init_send(TALLOC_CTX *mem_ctx,
-
- errno_t dp_init_recv(TALLOC_CTX *mem_ctx,
-                      struct tevent_req *req,
--                     struct data_provider **_provider,
-                      const char **_sbus_name);
-
- bool _dp_target_enabled(struct data_provider *provider,
-diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
-index 670ddb477cb7363b5f831e8b7b50b6b7f39c6289..6d2477e34b02ae84d241714b72296c62a2560bb1 100644
---- a/src/providers/data_provider_be.c
-+++ b/src/providers/data_provider_be.c
-@@ -541,7 +541,7 @@ static void dp_initialized(struct tevent_req *req)
-
-     be_ctx = tevent_req_callback_data(req, struct be_ctx);
-
--    ret = dp_init_recv(be_ctx, req, &be_ctx->provider, &be_ctx->sbus_name);
-+    ret = dp_init_recv(be_ctx, req, &be_ctx->sbus_name);
-     talloc_zfree(req);
-     if (ret !=  EOK) {
-         goto done;
-diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
-index 98c6dd1798dbf98419db71004cb55fcf21f58f81..32343a3bf52df866708a69f3f4364a4c65c1d3c6 100644
---- a/src/providers/proxy/proxy_init.c
-+++ b/src/providers/proxy/proxy_init.c
-@@ -214,7 +214,7 @@ static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
-
--    ret = proxy_client_init(dp_sbus_conn(provider), auth_ctx);
-+    ret = proxy_client_init(dp_sbus_conn(be_ctx->provider), auth_ctx);
-     if (ret != EOK) {
-         goto done;
-     }
---
-2.14.4
diff --git a/SOURCES/0025-pam-fix-loop-in-Smartcard-authentication.patch b/SOURCES/0025-pam-fix-loop-in-Smartcard-authentication.patch
new file mode 100644
index 0000000..d193fb7
--- /dev/null
+++ b/SOURCES/0025-pam-fix-loop-in-Smartcard-authentication.patch
@@ -0,0 +1,42 @@
+From 5574de0f87e72d85547add9a48f9ac0def27f47d Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 2 Aug 2019 13:43:49 +0200
+Subject: [PATCH] pam: fix loop in Smartcard authentication
+
+If 'try_cert_auth' or 'require_cert_auth' options are used and a wrong
+PIN is entered the PAM responder might end in an endless loop. This
+patch uses a flag to avoid the loop and makes sure that during
+authentication the error code causing the loop is not returned.
+
+Related to https://pagure.io/SSSD/sssd/issue/4051
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/responder/pam/pamsrv_cmd.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
+index 89bdb78a1..72412204b 100644
+--- a/src/responder/pam/pamsrv_cmd.c
++++ b/src/responder/pam/pamsrv_cmd.c
+@@ -814,6 +814,7 @@ static void pam_reply(struct pam_auth_req *preq)
+           pd->pam_status, pam_strerror(NULL, pd->pam_status));
+ 
+     if (pd->cmd == SSS_PAM_AUTHENTICATE
++            && !preq->cert_auth_local
+             && (pd->pam_status == PAM_AUTHINFO_UNAVAIL
+                 || pd->pam_status == PAM_NO_MODULE_DATA
+                 || pd->pam_status == PAM_BAD_ITEM)
+@@ -1475,7 +1476,8 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
+                   "No certificate found and no logon name given, " \
+                   "authentication not possible.\n");
+             ret = ENOENT;
+-        } else if (pd->cli_flags & PAM_CLI_FLAGS_TRY_CERT_AUTH) {
++        } else if (pd->cmd == SSS_PAM_PREAUTH
++                        && (pd->cli_flags & PAM_CLI_FLAGS_TRY_CERT_AUTH)) {
+             DEBUG(SSSDBG_TRACE_ALL,
+                   "try_cert_auth flag set but no certificate available, "
+                   "request finished.\n");
+-- 
+2.20.1
+
diff --git a/SOURCES/0025-sbus-read-destination-after-sender-is-set.patch b/SOURCES/0025-sbus-read-destination-after-sender-is-set.patch
deleted file mode 100644
index 30364d0..0000000
--- a/SOURCES/0025-sbus-read-destination-after-sender-is-set.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From d47b031bc09b43fe2002fd5c737969b733b4789b Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 12 Sep 2018 13:21:11 +0200
-Subject: [PATCH 25/28] sbus: read destination after sender is set
-
-dbus_message_set_sender may reallocate internal fields which will yield pointer
-obtained by dbus_message_get_* invalid.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 9245bf1afe6767a0412212bc0040e606ee850e7d)
----
- src/sbus/server/sbus_server_handler.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/src/sbus/server/sbus_server_handler.c b/src/sbus/server/sbus_server_handler.c
-index c300d81e1272fdb3d042491680ba9b678e00fbb1..d4e454780a29e321b322dced4b4c0ec7110233ad 100644
---- a/src/sbus/server/sbus_server_handler.c
-+++ b/src/sbus/server/sbus_server_handler.c
-@@ -148,9 +148,6 @@ sbus_server_filter(DBusConnection *dbus_conn,
-         return DBUS_HANDLER_RESULT_HANDLED;
-     }
-
--    destination = dbus_message_get_destination(message);
--    type = dbus_message_get_type(message);
--
-     conn = dbus_connection_get_data(dbus_conn, server->data_slot);
-     if (conn == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown connection!\n");
-@@ -173,6 +170,11 @@ sbus_server_filter(DBusConnection *dbus_conn,
-         return DBUS_HANDLER_RESULT_HANDLED;
-     }
-
-+    /* Set sender may reallocate internal fields so this needs to be read
-+     * after we call dbus_message_set_sender(). */
-+    destination = dbus_message_get_destination(message);
-+    type = dbus_message_get_type(message);
-+
-     if (type == DBUS_MESSAGE_TYPE_SIGNAL) {
-         return sbus_server_route_signal(server, conn, message, destination);
-     }
---
-2.14.4
diff --git a/SOURCES/0026-SYSDB-Add-sysdb_search_with_ts_attr.patch b/SOURCES/0026-SYSDB-Add-sysdb_search_with_ts_attr.patch
new file mode 100644
index 0000000..e0d1c3c
--- /dev/null
+++ b/SOURCES/0026-SYSDB-Add-sysdb_search_with_ts_attr.patch
@@ -0,0 +1,592 @@
+From f46afb46a1705d41e21451cd0adf6981936b21c1 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 28 May 2019 14:56:05 +0200
+Subject: [PATCH 26/48] 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>
+---
+ 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 89b0d9571..28801e030 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1181,6 +1181,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 59fb227a4..55ba62140 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 58544d826..53603b30e 100644
+--- a/src/db/sysdb_private.h
++++ b/src/db/sysdb_private.h
+@@ -252,6 +252,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/0026-sbus-do-not-try-to-remove-signal-listeners-when-disc.patch b/SOURCES/0026-sbus-do-not-try-to-remove-signal-listeners-when-disc.patch
deleted file mode 100644
index ec4f920..0000000
--- a/SOURCES/0026-sbus-do-not-try-to-remove-signal-listeners-when-disc.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 6c90ff0c0f8e4dce2d80cad8a042b2658bf68205 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 12 Sep 2018 13:22:34 +0200
-Subject: [PATCH 26/28] sbus: do not try to remove signal listeners when
- disconnecting
-
-This may cause some troubles if the dbus connection was dropped
-as dbus will try to actually send the messages. Also when the
-connectin is being freed, tevent integration is already disabled
-so there is no point in doing this.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit b821ee3ca93beb94a7a9b22b6f7a205e4900212e)
----
- src/sbus/router/sbus_router_hash.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/sbus/router/sbus_router_hash.c b/src/sbus/router/sbus_router_hash.c
-index 186dc613fc7874bfcce3f832c1c2299a217381d9..2d407b2fba12b6b57eed896e7154f85b0a65dcde 100644
---- a/src/sbus/router/sbus_router_hash.c
-+++ b/src/sbus/router/sbus_router_hash.c
-@@ -384,6 +384,10 @@ sbus_router_listeners_delete_cb(hash_entry_t *item,
-         return;
-     }
-
-+    if (conn->disconnecting) {
-+        return;
-+    }
-+
-     /* If we still have the D-Bus connection available, we try to unregister
-      * the previously registered listener when its removed from table. */
-
---
-2.14.4
diff --git a/SOURCES/0027-BE-search-with-sysdb_search_with_ts_attr.patch b/SOURCES/0027-BE-search-with-sysdb_search_with_ts_attr.patch
new file mode 100644
index 0000000..c65ca44
--- /dev/null
+++ b/SOURCES/0027-BE-search-with-sysdb_search_with_ts_attr.patch
@@ -0,0 +1,69 @@
+From a5cd021e92695ccf45be92e5b05394f46ccebd2e Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 28 May 2019 14:56:15 +0200
+Subject: [PATCH 27/48] 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>
+---
+ 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/0027-sbus-free-watch_fd-fdevent-explicitly.patch b/SOURCES/0027-sbus-free-watch_fd-fdevent-explicitly.patch
deleted file mode 100644
index 8fd0972..0000000
--- a/SOURCES/0027-sbus-free-watch_fd-fdevent-explicitly.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 5db4c971b5a8c5753cb3790c9551f8cfb277dad7 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 12 Sep 2018 13:24:27 +0200
-Subject: [PATCH 27/28] sbus: free watch_fd->fdevent explicitly
-
-We never reproduced this with gdb but valgrind shows invalid read in sbus_watch_handler
-after the watch_fd was freed. This should not be needed since watch_fd is memory parent
-of fdevent but it seems to help.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit f1f9af528f71f42ac41bb7a272f4f7d940fd3a0f)
----
- src/sbus/connection/sbus_watch.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/sbus/connection/sbus_watch.c b/src/sbus/connection/sbus_watch.c
-index 3898311dfc3508edafa5ecc0488b3977cb290773..0e4bd01d10f74e9524d33ca46bd5d9bb31d591fb 100644
---- a/src/sbus/connection/sbus_watch.c
-+++ b/src/sbus/connection/sbus_watch.c
-@@ -280,6 +280,7 @@ sbus_watch_remove(DBusWatch *dbus_watch, void *data)
-
-     if (watch_fd->dbus_watch.read == NULL
-             && watch_fd->dbus_watch.write == NULL) {
-+        talloc_free(watch_fd->fdevent);
-         talloc_free(watch_fd);
-     }
- }
---
-2.14.4
diff --git a/SOURCES/0028-BE-Enable-refresh-for-multiple-domains.patch b/SOURCES/0028-BE-Enable-refresh-for-multiple-domains.patch
new file mode 100644
index 0000000..e1f65f7
--- /dev/null
+++ b/SOURCES/0028-BE-Enable-refresh-for-multiple-domains.patch
@@ -0,0 +1,34 @@
+From b90b9c79eab4110ba626d0a3f94f70ab6dd80735 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 24 Apr 2019 21:09:53 +0200
+Subject: [PATCH 28/48] 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>
+---
+ 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/0028-doc-remove-local-provider-reference-from-manpages.patch b/SOURCES/0028-doc-remove-local-provider-reference-from-manpages.patch
deleted file mode 100644
index aa12719..0000000
--- a/SOURCES/0028-doc-remove-local-provider-reference-from-manpages.patch
+++ /dev/null
@@ -1,139 +0,0 @@
-From d6cc81b7f8b40575d146b2fa7d33c8a03c6253da Mon Sep 17 00:00:00 2001
-From: Tomas Halman <thalman@redhat.com>
-Date: Thu, 27 Sep 2018 16:03:40 +0200
-Subject: [PATCH 28/28] doc: remove local provider reference from manpages
-
-Introduce new condition for documentation build. Related part of
-documentation is excluded, if build is done without local provider.
-
-Resolves https://pagure.io/SSSD/sssd/issue/3826
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit de8c9caf61e7b971cda9563cc5851ea222db5830)
----
- src/man/Makefile.am         |  6 +++++-
- src/man/include/seealso.xml | 44 +++++++++++++++++++++++---------------------
- src/man/sssd.conf.5.xml     | 15 +++++++++------
- 3 files changed, 37 insertions(+), 28 deletions(-)
-
-diff --git a/src/man/Makefile.am b/src/man/Makefile.am
-index b4c20d8cf9574523c6d9c6aa631fe38979e54582..54a30d10f79eabf06353d6870da6ae38dcd980c1 100644
---- a/src/man/Makefile.am
-+++ b/src/man/Makefile.am
-@@ -51,7 +51,11 @@ CRYPTO_CONDS = ;with_nss
- else
- CRYPTO_CONDS = ;with_openssl
- endif
--CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(CRYPTO_CONDS)
-+if BUILD_LOCAL_PROVIDER
-+LOCAL_PROVIDER_CONDS = ;enable_local_provider
-+endif
-+
-+CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(CRYPTO_CONDS)$(LOCAL_PROVIDER_CONDS)
-
-
- #Special Rules:
-diff --git a/src/man/include/seealso.xml b/src/man/include/seealso.xml
-index 52798e460e0a00ab436a4f4fa071cee104e1bb8b..f324b663717c44e8efdaae0409e28d04b9300ae7 100644
---- a/src/man/include/seealso.xml
-+++ b/src/man/include/seealso.xml
-@@ -44,27 +44,29 @@
-             <citerefentry>
-                 <refentrytitle>sss_debuglevel</refentrytitle><manvolnum>8</manvolnum>
-             </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_groupadd</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_groupdel</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_groupshow</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_groupmod</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_useradd</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_userdel</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
--            <citerefentry>
--                <refentrytitle>sss_usermod</refentrytitle><manvolnum>8</manvolnum>
--            </citerefentry>,
-+            <phrase condition="enable_local_provider">
-+                <citerefentry>
-+                    <refentrytitle>sss_groupadd</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+                <citerefentry>
-+                    <refentrytitle>sss_groupdel</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+                <citerefentry>
-+                    <refentrytitle>sss_groupshow</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+                <citerefentry>
-+                    <refentrytitle>sss_groupmod</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+                <citerefentry>
-+                    <refentrytitle>sss_useradd</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+                <citerefentry>
-+                    <refentrytitle>sss_userdel</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+                <citerefentry>
-+                    <refentrytitle>sss_usermod</refentrytitle><manvolnum>8</manvolnum>
-+                </citerefentry>,
-+            </phrase>
-             <citerefentry>
-                 <refentrytitle>sss_obfuscate</refentrytitle><manvolnum>8</manvolnum>
-             </citerefentry>,
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 04143f199685b7703abe1b5bb82b6c33230e6c72..c1e38950f99cb8df4c59fe10866632030d3c6f25 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -2179,7 +2179,7 @@ pam_p11_allowed_services = +my_pam_service, -login
-                         <para>
-                             <quote>proxy</quote>: Support a legacy NSS provider.
-                         </para>
--                        <para>
-+                        <para condition="enable_local_provider">
-                             <quote>local</quote>: SSSD internal provider for
-                             local users (DEPRECATED).
-                         </para>
-@@ -2324,7 +2324,7 @@ pam_p11_allowed_services = +my_pam_service, -login
-                         <para>
-                             <quote>proxy</quote> for relaying authentication to some other PAM target.
-                         </para>
--                        <para>
-+                        <para condition="enable_local_provider">
-                             <quote>local</quote>: SSSD internal provider for
-                             local users
-                         </para>
-@@ -2836,9 +2836,12 @@ pam_p11_allowed_services = +my_pam_service, -login
-                     <term>case_sensitive (string)</term>
-                     <listitem>
-                         <para>
--                            Treat user and group names as case sensitive. At
--                            the moment, this option is not supported in
--                            the local provider. Possible option values are:
-+                            Treat user and group names as case sensitive.
-+                            <phrase condition="enable_local_provider">
-+                                At the moment, this option is not supported in
-+                                the local provider.
-+                            </phrase>
-+                            Possible option values are:
-                         <variablelist>
-                             <varlistentry>
-                                 <term>True</term>
-@@ -3148,7 +3151,7 @@ ldap_user_extra_attrs = phone:telephoneNumber
- </programlisting>
-         </refsect2>
-
--        <refsect2 id='local_domain'>
-+        <refsect2 id='local_domain' condition="enable_local_provider">
-             <title>The local domain section</title>
-             <para>
-                 This section contains settings for domain that stores users and
---
-2.14.4
diff --git a/SOURCES/0029-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch b/SOURCES/0029-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch
new file mode 100644
index 0000000..005a505
--- /dev/null
+++ b/SOURCES/0029-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch
@@ -0,0 +1,111 @@
+From 47c33b9c8b8613956ed4687d58e26cb9fe7dc9eb Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 May 2019 22:32:13 +0200
+Subject: [PATCH 29/48] 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>
+---
+ 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 db62efdc6..a1e7999c7 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -454,7 +454,6 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+                         struct confdb_ctx *cdb)
+ {
+-    uint32_t refresh_interval;
+     struct tevent_req *req;
+     struct be_ctx *be_ctx;
+     char *str = NULL;
+@@ -545,19 +544,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;
+-        }
+-    }
+-
+     req = dp_init_send(be_ctx, be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid);
+     if (req == NULL) {
+         ret = ENOMEM;
+-- 
+2.20.1
+
diff --git a/SOURCES/0029-confdb-log-an-error-when-domain-is-misconfigured.patch b/SOURCES/0029-confdb-log-an-error-when-domain-is-misconfigured.patch
deleted file mode 100644
index f8120b9..0000000
--- a/SOURCES/0029-confdb-log-an-error-when-domain-is-misconfigured.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From c0d527f9ea9786712b86b5b51c6dab074a66342d Mon Sep 17 00:00:00 2001
-From: Tomas Halman <thalman@redhat.com>
-Date: Mon, 1 Oct 2018 15:49:06 +0200
-Subject: [PATCH] confdb: log an error when domain is misconfigured
-
-We need to inform user that there is misconfiguration
-and particular domain will not be started.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3827
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 081b18e75c746f9a2ad1fb412c825293090311f8)
----
- src/confdb/confdb.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index 954c3ba766617f7cfcf637d9143c891bd998d7ff..2f3d90087e640f77835400b11184b684852d7fda 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -39,6 +39,9 @@
- #define SAME_DOMAINS_ERROR_MSG "Domain '%s' is the same as or differs only "\
-                                "in case from domain '%s'.\n"
- 
-+#define RETRIEVE_DOMAIN_ERROR_MSG "Error (%d [%s]) retrieving domain [%s], "\
-+                                  "skipping!\n"
-+
- static char *prepend_cn(char *str, int *slen, const char *comp, int clen)
- {
-     char *ret;
-@@ -1522,8 +1525,12 @@ int confdb_get_domains(struct confdb_ctx *cdb,
-         ret = confdb_get_domain_internal(cdb, cdb, domlist[i], &domain);
-         if (ret) {
-             DEBUG(SSSDBG_FATAL_FAILURE,
--                  "Error (%d [%s]) retrieving domain [%s], skipping!\n",
-+                  RETRIEVE_DOMAIN_ERROR_MSG,
-                   ret, sss_strerror(ret), domlist[i]);
-+            sss_log(SSS_LOG_CRIT,
-+                    RETRIEVE_DOMAIN_ERROR_MSG,
-+                    ret, sss_strerror(ret), domlist[i]);
-+
-             continue;
-         }
- 
--- 
-2.14.4
-
diff --git a/SOURCES/0030-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch b/SOURCES/0030-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch
new file mode 100644
index 0000000..f099332
--- /dev/null
+++ b/SOURCES/0030-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch
@@ -0,0 +1,143 @@
+From 4f32364e1a516cdcd311d369142e93d90a48e11c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 20 May 2019 22:42:47 +0200
+Subject: [PATCH 30/48] 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>
+---
+ 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 423071dcd..b8ebaea2f 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 a1e7999c7..877841055 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -536,14 +536,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;
+-    }
+-
+     req = dp_init_send(be_ctx, be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid);
+     if (req == NULL) {
+         ret = ENOMEM;
+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 5d6302dcd..60e3ef297 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -365,7 +365,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 057e173ad..3ce574e28 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/0030-be-use-be_is_offline-for-the-main-domain-when-asking.patch b/SOURCES/0030-be-use-be_is_offline-for-the-main-domain-when-asking.patch
deleted file mode 100644
index 30cb266..0000000
--- a/SOURCES/0030-be-use-be_is_offline-for-the-main-domain-when-asking.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From c9c4b9cbe87e39d3305be2217535d25d1b272af6 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Fri, 14 Sep 2018 12:30:57 +0200
-Subject: [PATCH] be: use be_is_offline for the main domain when asking for
- domain status
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The DOM_ACTIVE/INACTIVE flag is not used with the main domain as it
-is used only for subdomains.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3830
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit dfa7bf1133f002a9fbbd3495a70909913db25b16)
----
- src/providers/data_provider/dp_iface_backend.c | 20 ++++++++++++++------
- 1 file changed, 14 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/data_provider/dp_iface_backend.c b/src/providers/data_provider/dp_iface_backend.c
-index 25a00f327116bdf513a939c3b68dae375a1d0538..85159a71be603ffadaa7bd2bd5f3bcf03c0a3eca 100644
---- a/src/providers/data_provider/dp_iface_backend.c
-+++ b/src/providers/data_provider/dp_iface_backend.c
-@@ -37,15 +37,23 @@ dp_backend_is_online(TALLOC_CTX *mem_ctx,
-     struct sss_domain_info *domain;
- 
-     if (SBUS_REQ_STRING_IS_EMPTY(domname)) {
--        *_is_online = be_is_offline(be_ctx);
--        return EOK;
-+        domain = be_ctx->domain;
-+    } else {
-+        domain = find_domain_by_name(be_ctx->domain, domname, false);
-+        if (domain == NULL) {
-+            return ERR_DOMAIN_NOT_FOUND;
-+        }
-     }
- 
--    domain = find_domain_by_name(be_ctx->domain, domname, false);
--    if (domain == NULL) {
--        return ERR_DOMAIN_NOT_FOUND;
-+    /**
-+     * FIXME: https://pagure.io/SSSD/sssd/issue/3831
-+     * domain->state is set only for subdomains not for the main domain
-+     */
-+    if (be_ctx->domain == domain) {
-+        *_is_online = be_is_offline(be_ctx) == false;
-+    } else {
-+        *_is_online = domain->state == DOM_ACTIVE;
-     }
- 
--    *_is_online = domain->state == DOM_ACTIVE;
-     return EOK;
- }
--- 
-2.14.4
-
diff --git a/SOURCES/0031-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch b/SOURCES/0031-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch
new file mode 100644
index 0000000..61161cd
--- /dev/null
+++ b/SOURCES/0031-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch
@@ -0,0 +1,108 @@
+From 828edc4089ef570245081afb3bf81bbad4c9f91a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 May 2019 12:09:24 +0200
+Subject: [PATCH 31/48] 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>
+---
+ 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/0031-sudo-respect-case-sensitivity-in-sudo-responder.patch b/SOURCES/0031-sudo-respect-case-sensitivity-in-sudo-responder.patch
deleted file mode 100644
index aa983bd..0000000
--- a/SOURCES/0031-sudo-respect-case-sensitivity-in-sudo-responder.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 2b8665e50f601e2b707b0bc77690821211a79e2d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 6 Sep 2018 13:38:56 +0200
-Subject: [PATCH] sudo: respect case sensitivity in sudo responder
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If the domain is not case sensitive and the case of the original user
-or group name differs from the name in the rule we failed to find the
-rule.
-
-Now we filter the rule only with lower cased values in such domain.
-
-Steps to reproduce:
-1. Add user/group with upper case, e.g. USER-1
-2. Add sudo rule with lower cased name, e.g. sudoUser: user-1
-3. Login to system with lower case, e.g. user-1
-4. Run sudo -l
-
-Without the patch, rule is not found.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3820
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit d7f0b58e2896ed2ef9ed5a390815c1e4df6caaee)
----
- src/db/sysdb_sudo.c | 17 ++++++++++++++---
- 1 file changed, 14 insertions(+), 3 deletions(-)
-
-diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c
-index 3ad462d8fd131bfc6bc5aa15bc48346d64241ee6..19ed97b8666c92c491131765398423062791ba0a 100644
---- a/src/db/sysdb_sudo.c
-+++ b/src/db/sysdb_sudo.c
-@@ -418,7 +418,17 @@ sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx,
-         ret = EINVAL;
-         goto done;
-     }
--    DEBUG(SSSDBG_TRACE_FUNC, "original name: %s\n", orig_name);
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Original name: %s\n", orig_name);
-+
-+    orig_name = sss_get_cased_name(tmp_ctx, orig_name, domain->case_sensitive);
-+    if (orig_name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Cased name: %s\n", orig_name);
- 
-     if (_uid != NULL) {
-         uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
-@@ -450,8 +460,9 @@ sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx,
-                     continue;
-                 }
- 
--                sysdb_groupnames[num_groups] = talloc_strdup(sysdb_groupnames,
--                                                             groupname);
-+                sysdb_groupnames[num_groups] = \
-+                    sss_get_cased_name(sysdb_groupnames, groupname,
-+                                       domain->case_sensitive);
-                 if (sysdb_groupnames[num_groups] == NULL) {
-                     DEBUG(SSSDBG_MINOR_FAILURE, "Cannot strdup %s\n", groupname);
-                     continue;
--- 
-2.14.4
-
diff --git a/SOURCES/0032-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch b/SOURCES/0032-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch
new file mode 100644
index 0000000..72be1ee
--- /dev/null
+++ b/SOURCES/0032-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch
@@ -0,0 +1,99 @@
+From 87ae9cf0fd747e39d1769e6b432b7f48d41f9302 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 May 2019 12:07:34 +0200
+Subject: [PATCH 32/48] 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>
+---
+ 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/0032-sbus-fix-typo.patch b/SOURCES/0032-sbus-fix-typo.patch
deleted file mode 100644
index af080fc..0000000
--- a/SOURCES/0032-sbus-fix-typo.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From fd7cb6f2605a60770a7f83e431b16bb888b5df45 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 16 Aug 2018 11:42:44 +0200
-Subject: [PATCH 32/47] sbus: fix typo
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 8c8f74b0dfa29643279d31b12300ced47d5c2ab5)
----
- src/sbus/sbus_message.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/sbus/sbus_message.h b/src/sbus/sbus_message.h
-index 99dd9309b8ced478b4f9bb761db99000440ef105..92d5cea83b3c19ac19701849972a82ce67b09849 100644
---- a/src/sbus/sbus_message.h
-+++ b/src/sbus/sbus_message.h
-@@ -49,7 +49,7 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg);
-  *
-  * DO NOT USE dbus_message_unref() on such message anymore since it would not
-  * release internal data about the bound. The message will be automatically
-- * unreferenced whent the talloc context is freed.
-+ * unreferenced when the talloc context is freed.
-  *
-  * @param mem_ctx Memory context to bound the message with. It can not be NULL.
-  * @param msg     Message to be bound with memory context.
--- 
-2.14.4
-
diff --git a/SOURCES/0033-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch b/SOURCES/0033-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch
new file mode 100644
index 0000000..0523de5
--- /dev/null
+++ b/SOURCES/0033-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch
@@ -0,0 +1,131 @@
+From 003f8647f9dbeec1a54060fb4e376f04865aafea Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 8 May 2019 14:38:44 +0200
+Subject: [PATCH 33/48] 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>
+---
+ 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/0033-sbus-check-for-null-message-in-sbus_message_bound.patch b/SOURCES/0033-sbus-check-for-null-message-in-sbus_message_bound.patch
deleted file mode 100644
index e257239..0000000
--- a/SOURCES/0033-sbus-check-for-null-message-in-sbus_message_bound.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 25ccb26a6c58cf7284e900588bf68ce6eec21b4c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 16 Aug 2018 12:57:47 +0200
-Subject: [PATCH 33/47] sbus: check for null message in sbus_message_bound
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 30f4adf874aff174734ad77902a79fc5727ab495)
----
- src/sbus/request/sbus_message.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/src/sbus/request/sbus_message.c b/src/sbus/request/sbus_message.c
-index 950be9122610f3394d982173a3616f9d9fac23d9..7314fd724dd3daec520ba0d1fdd2974995446e8c 100644
---- a/src/sbus/request/sbus_message.c
-+++ b/src/sbus/request/sbus_message.c
-@@ -83,6 +83,11 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg)
-         return EINVAL;
-     }
- 
-+    if (msg == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Message can not be NULL!\n");
-+        return EINVAL;
-+    }
-+
-     /* Create a talloc context that will unreference this message when
-      * the parent context is freed. */
-     talloc_msg = talloc(mem_ctx, struct sbus_talloc_msg);
-@@ -122,6 +127,11 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg)
- errno_t
- sbus_message_bound_ref(TALLOC_CTX *mem_ctx, DBusMessage *msg)
- {
-+    if (msg == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Message can not be NULL!\n");
-+        return EINVAL;
-+    }
-+
-     dbus_message_ref(msg);
-     return sbus_message_bound(mem_ctx, msg);
- }
--- 
-2.14.4
-
diff --git a/SOURCES/0034-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch b/SOURCES/0034-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch
new file mode 100644
index 0000000..9ac5adf
--- /dev/null
+++ b/SOURCES/0034-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch
@@ -0,0 +1,70 @@
+From 91f0382974ca7ed158ddb3da179b41c96292cc19 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 21 May 2019 12:07:59 +0200
+Subject: [PATCH 34/48] 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>
+---
+ 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/0034-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch b/SOURCES/0034-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch
deleted file mode 100644
index 2fb9d4f..0000000
--- a/SOURCES/0034-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch
+++ /dev/null
@@ -1,337 +0,0 @@
-From 7ece0bc4b566ab0b7b5596924983d3a84c372836 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 16 Aug 2018 13:17:13 +0200
-Subject: [PATCH 34/47] sbus: replace sbus_message_bound_ref with
- sbus_message_bound_steal
-
-The memory context used to new message reference accidentally overwrote
-the one use by the initial sbus_message_bound call. This caused a memory
-leak of message as its reference counter got increased but number of
-talloc contexts bound this this message decreased at the same time.
-
-Fixing this is non-trival and it would require separate data slot for
-each reference. Because we do not have any existing use case for this
-and we use it only as an equivalent of talloc_steal it is better to
-provide a real equivalent for this talloc function.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3810
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit ca50c40511f08c0f7c786598e5793a06789c6cce)
----
- src/responder/ifp/ifp_iface/sbus_ifp_client_sync.c |  4 +-
- src/sbus/codegen/templates/client_async.c.tpl      |  4 +-
- src/sbus/codegen/templates/client_sync.c.tpl       |  4 +-
- src/sbus/interface_dbus/sbus_dbus_client_async.c   |  8 ++--
- src/sbus/interface_dbus/sbus_dbus_client_sync.c    |  8 ++--
- src/sbus/request/sbus_message.c                    | 51 +++++++++++++++++-----
- src/sbus/request/sbus_request.c                    | 10 ++---
- src/sbus/request/sbus_request_call.c               |  5 +--
- src/sbus/sbus_message.h                            |  8 +---
- src/sbus/sync/sbus_sync_call.c                     |  5 +--
- 10 files changed, 65 insertions(+), 42 deletions(-)
-
-diff --git a/src/responder/ifp/ifp_iface/sbus_ifp_client_sync.c b/src/responder/ifp/ifp_iface/sbus_ifp_client_sync.c
-index 4859b93ea8fe793f1cca3712663aedd25de25a86..1f0a8e367905e20e921e9a31714b9c7de53f47cd 100644
---- a/src/responder/ifp/ifp_iface/sbus_ifp_client_sync.c
-+++ b/src/responder/ifp/ifp_iface/sbus_ifp_client_sync.c
-@@ -526,9 +526,9 @@ sbus_method_in_sas_out_raw
-         goto done;
-     }
- 
--    ret = sbus_message_bound_ref(mem_ctx, reply);
-+    ret = sbus_message_bound_steal(mem_ctx, reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         goto done;
-     }
-diff --git a/src/sbus/codegen/templates/client_async.c.tpl b/src/sbus/codegen/templates/client_async.c.tpl
-index 6ffb4f83c77bd33653011bfcf5008ce86a89e099..e16ce42c7f97e3b4b564570fb73faaa9a5c274c8 100644
---- a/src/sbus/codegen/templates/client_async.c.tpl
-+++ b/src/sbus/codegen/templates/client_async.c.tpl
-@@ -193,9 +193,9 @@
-             return EINVAL;
-         }
- 
--        ret = sbus_message_bound_ref(mem_ctx, state->reply);
-+        ret = sbus_message_bound_steal(mem_ctx, state->reply);
-         if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-                   ret, sss_strerror(ret));
-             return ret;
-         }
-diff --git a/src/sbus/codegen/templates/client_sync.c.tpl b/src/sbus/codegen/templates/client_sync.c.tpl
-index 30fa009fe6f010483ff58d369451c272dfdbd3ec..fe9a3a4726014aa2bcb221a1bbcc949f7d900237 100644
---- a/src/sbus/codegen/templates/client_sync.c.tpl
-+++ b/src/sbus/codegen/templates/client_sync.c.tpl
-@@ -110,9 +110,9 @@
-             goto done;
-         }
- 
--        ret = sbus_message_bound_ref(mem_ctx, reply);
-+        ret = sbus_message_bound_steal(mem_ctx, reply);
-         if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-                   ret, sss_strerror(ret));
-             goto done;
-         }
-diff --git a/src/sbus/interface_dbus/sbus_dbus_client_async.c b/src/sbus/interface_dbus/sbus_dbus_client_async.c
-index 9dbd72cedc95e328d6659283e959c554c39797dc..0060e8b91d5d0c2073558818bd529fda9c97b3f8 100644
---- a/src/sbus/interface_dbus/sbus_dbus_client_async.c
-+++ b/src/sbus/interface_dbus/sbus_dbus_client_async.c
-@@ -301,9 +301,9 @@ sbus_method_in_s_out_raw_recv
-         return EINVAL;
-     }
- 
--    ret = sbus_message_bound_ref(mem_ctx, state->reply);
-+    ret = sbus_message_bound_steal(mem_ctx, state->reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         return ret;
-     }
-@@ -513,9 +513,9 @@ sbus_method_in_ss_out_raw_recv
-         return EINVAL;
-     }
- 
--    ret = sbus_message_bound_ref(mem_ctx, state->reply);
-+    ret = sbus_message_bound_steal(mem_ctx, state->reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         return ret;
-     }
-diff --git a/src/sbus/interface_dbus/sbus_dbus_client_sync.c b/src/sbus/interface_dbus/sbus_dbus_client_sync.c
-index a0473cd377e97021acea594b48b52f4aa565bad9..3ab0aab452d6b1acb702d577087b1c9fd50b4340 100644
---- a/src/sbus/interface_dbus/sbus_dbus_client_sync.c
-+++ b/src/sbus/interface_dbus/sbus_dbus_client_sync.c
-@@ -101,9 +101,9 @@ sbus_method_in_s_out_raw
-         goto done;
-     }
- 
--    ret = sbus_message_bound_ref(mem_ctx, reply);
-+    ret = sbus_message_bound_steal(mem_ctx, reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         goto done;
-     }
-@@ -159,9 +159,9 @@ sbus_method_in_ss_out_raw
-         goto done;
-     }
- 
--    ret = sbus_message_bound_ref(mem_ctx, reply);
-+    ret = sbus_message_bound_steal(mem_ctx, reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         goto done;
-     }
-diff --git a/src/sbus/request/sbus_message.c b/src/sbus/request/sbus_message.c
-index 7314fd724dd3daec520ba0d1fdd2974995446e8c..90c6df40c7882e1f7232d718f8b4a9d1626f755d 100644
---- a/src/sbus/request/sbus_message.c
-+++ b/src/sbus/request/sbus_message.c
-@@ -29,8 +29,9 @@
- #include "sbus/interface/sbus_iterator_writers.h"
- 
- /* Data slot that is used for message data. The slot is shared for all
-- * messages. */
--dbus_int32_t data_slot = -1;
-+ * messages, i.e. when a data slot is allocated all messages have the
-+ * slot available. */
-+dbus_int32_t global_data_slot = -1;
- 
- struct sbus_talloc_msg {
-     DBusMessage *msg;
-@@ -48,7 +49,7 @@ static int sbus_talloc_msg_destructor(struct sbus_talloc_msg *talloc_msg)
-     /* There may exist more references to this message but this talloc
-      * context is no longer valid. We remove dbus message data to invoke
-      * dbus destructor now. */
--    dbus_message_set_data(talloc_msg->msg, data_slot, NULL, NULL);
-+    dbus_message_set_data(talloc_msg->msg, global_data_slot, NULL, NULL);
-     dbus_message_unref(talloc_msg->msg);
-     return 0;
- }
-@@ -60,7 +61,7 @@ static void sbus_msg_data_destructor(void *ctx)
-     talloc_msg = talloc_get_type(ctx, struct sbus_talloc_msg);
- 
-     /* Decrement ref counter on data slot. */
--    dbus_message_free_data_slot(&data_slot);
-+    dbus_message_free_data_slot(&global_data_slot);
- 
-     if (!talloc_msg->in_talloc_destructor) {
-         /* References to this message dropped to zero but through
-@@ -100,7 +101,8 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg)
-     /* Allocate a dbus message data slot that will contain pointer to the
-      * talloc context so we can pick up cases when the dbus message is
-      * freed through dbus api. */
--    bret = dbus_message_allocate_data_slot(&data_slot);
-+
-+    bret = dbus_message_allocate_data_slot(&global_data_slot);
-     if (!bret) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to allocate data slot!\n");
-         talloc_free(talloc_msg);
-@@ -108,11 +110,11 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg)
-     }
- 
-     free_fn = sbus_msg_data_destructor;
--    bret = dbus_message_set_data(msg, data_slot, talloc_msg, free_fn);
-+    bret = dbus_message_set_data(msg, global_data_slot, talloc_msg, free_fn);
-     if (!bret) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set message data!\n");
-         talloc_free(talloc_msg);
--        dbus_message_free_data_slot(&data_slot);
-+        dbus_message_free_data_slot(&global_data_slot);
-         return ENOMEM;
-     }
- 
-@@ -125,15 +127,44 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg)
- }
- 
- errno_t
--sbus_message_bound_ref(TALLOC_CTX *mem_ctx, DBusMessage *msg)
-+sbus_message_bound_steal(TALLOC_CTX *mem_ctx, DBusMessage *msg)
- {
-+    struct sbus_talloc_msg *talloc_msg;
-+    void *data;
-+
-+    if (mem_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Warning: bounding to NULL context!\n");
-+        return EINVAL;
-+    }
-+
-     if (msg == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Message can not be NULL!\n");
-         return EINVAL;
-     }
- 
--    dbus_message_ref(msg);
--    return sbus_message_bound(mem_ctx, msg);
-+    if (global_data_slot < 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "This message is not talloc-bound! "
-+              "(data slot < 0)\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    data = dbus_message_get_data(msg, global_data_slot);
-+    if (data == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "This message is not talloc-bound! "
-+              "(returned data is NULL)\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    talloc_msg = talloc_get_type(data, struct sbus_talloc_msg);
-+    if (talloc_msg == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "This message is not talloc-bound! "
-+              "(invalid data)\n");
-+        return ERR_INTERNAL;
-+    }
-+
-+    talloc_steal(mem_ctx, talloc_msg);
-+
-+    return EOK;
- }
- 
- DBusMessage *
-diff --git a/src/sbus/request/sbus_request.c b/src/sbus/request/sbus_request.c
-index 3d0e2f9e5b0283da7f1d778bf86262db997f12cd..1ccd01e7d571df3c8e196ce7923c8e04523a3b04 100644
---- a/src/sbus/request/sbus_request.c
-+++ b/src/sbus/request/sbus_request.c
-@@ -564,10 +564,9 @@ sbus_incoming_request_recv(TALLOC_CTX *mem_ctx,
-         return EOK;
-     }
- 
--    /* Create new reference to the reply and bound it with caller mem_ctx. */
--    ret = sbus_message_bound_ref(mem_ctx, state->reply);
-+    ret = sbus_message_bound_steal(mem_ctx, state->reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         return ret;
-     }
-@@ -709,10 +708,9 @@ sbus_outgoing_request_recv(TALLOC_CTX *mem_ctx,
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
--    /* Create new reference to the reply and bound it with caller mem_ctx. */
--    ret = sbus_message_bound_ref(mem_ctx, state->reply);
-+    ret = sbus_message_bound_steal(mem_ctx, state->reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         return ret;
-     }
-diff --git a/src/sbus/request/sbus_request_call.c b/src/sbus/request/sbus_request_call.c
-index 1cf58bdd0aecc5814c24c8f0b87864d91bafd094..cf2a6e5bfb7d403a413b6fc06225b0e7e4b663f3 100644
---- a/src/sbus/request/sbus_request_call.c
-+++ b/src/sbus/request/sbus_request_call.c
-@@ -126,10 +126,9 @@ sbus_call_method_recv(TALLOC_CTX *mem_ctx,
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
--    /* Create new reference to the reply and bound it with caller mem_ctx. */
--    ret = sbus_message_bound_ref(mem_ctx, state->reply);
-+    ret = sbus_message_bound_steal(mem_ctx, state->reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         return ret;
-     }
-diff --git a/src/sbus/sbus_message.h b/src/sbus/sbus_message.h
-index 92d5cea83b3c19ac19701849972a82ce67b09849..e7b8fe5942d993fb31740465c6cdbf2797ab0db4 100644
---- a/src/sbus/sbus_message.h
-+++ b/src/sbus/sbus_message.h
-@@ -45,11 +45,7 @@ errno_t
- sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg);
- 
- /**
-- * Reference the message and bound it with talloc context.
-- *
-- * DO NOT USE dbus_message_unref() on such message anymore since it would not
-- * release internal data about the bound. The message will be automatically
-- * unreferenced when the talloc context is freed.
-+ * Steal previously bound D-Bus message to a new talloc parent.
-  *
-  * @param mem_ctx Memory context to bound the message with. It can not be NULL.
-  * @param msg     Message to be bound with memory context.
-@@ -57,7 +53,7 @@ sbus_message_bound(TALLOC_CTX *mem_ctx, DBusMessage *msg);
-  * @return EOK on success, other errno code on error.
-  */
- errno_t
--sbus_message_bound_ref(TALLOC_CTX *mem_ctx, DBusMessage *msg);
-+sbus_message_bound_steal(TALLOC_CTX *mem_ctx, DBusMessage *msg);
- 
- /**
-  * Create an empty D-Bus method call.
-diff --git a/src/sbus/sync/sbus_sync_call.c b/src/sbus/sync/sbus_sync_call.c
-index 8549e5831d4320ffc7831ce8a67f382682d891bb..a4f8a5cc40f4b517fba902ff0dc90d4449d5b3ef 100644
---- a/src/sbus/sync/sbus_sync_call.c
-+++ b/src/sbus/sync/sbus_sync_call.c
-@@ -63,10 +63,9 @@ sbus_sync_call_method(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    /* Create new reference to the reply and bound it with caller mem_ctx. */
--    ret = sbus_message_bound_ref(mem_ctx, reply);
-+    ret = sbus_message_bound_steal(mem_ctx, reply);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to bound message [%d]: %s\n",
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
-               ret, sss_strerror(ret));
-         goto done;
-     }
--- 
-2.14.4
-
diff --git a/SOURCES/0035-BE-Send-refresh-requests-in-batches.patch b/SOURCES/0035-BE-Send-refresh-requests-in-batches.patch
new file mode 100644
index 0000000..d15bd97
--- /dev/null
+++ b/SOURCES/0035-BE-Send-refresh-requests-in-batches.patch
@@ -0,0 +1,297 @@
+From bf3f506d14cf89b9d1d1e3504524b231a6cef2b1 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 8 May 2019 23:16:07 +0200
+Subject: [PATCH 35/48] 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>
+---
+ 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 96f0861ac..e5f3f7041 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 c5680d89a..13e434b62 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -67,6 +67,14 @@
+ #define NULL 0
+ #endif
+ 
++#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/0035-sbus-add-unit-tests-for-public-sbus_message-module.patch b/SOURCES/0035-sbus-add-unit-tests-for-public-sbus_message-module.patch
deleted file mode 100644
index 70e2298..0000000
--- a/SOURCES/0035-sbus-add-unit-tests-for-public-sbus_message-module.patch
+++ /dev/null
@@ -1,664 +0,0 @@
-From 57af8c95f5639e3ff61d4b1e9864fee8150cd2ba Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 16 Aug 2018 13:20:55 +0200
-Subject: [PATCH 35/47] sbus: add unit tests for public sbus_message module
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit c895fa2449900f4abd1dce6bb62a45c52bbb12cf)
----
- Makefile.am                               |  14 +
- src/tests/cmocka/sbus/test_sbus_message.c | 610 ++++++++++++++++++++++++++++++
- 2 files changed, 624 insertions(+)
- create mode 100644 src/tests/cmocka/sbus/test_sbus_message.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 1602ec6236799015fa7fd9f1707cb2bcdb20e07b..c05c9312d74d2adab9dfe6d40987a791785da256 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -270,6 +270,7 @@ if HAVE_CMOCKA
-         test_copy_keytab \
-         test_child_common \
-         responder_cache_req-tests \
-+        test_sbus_message \
-         test_sbus_opath \
-         test_fo_srv \
-         pam-srv-tests \
-@@ -2593,6 +2594,19 @@ test_ssh_client_LDADD = \
-     $(SSSD_LIBS) \
-     $(NULL)
- 
-+test_sbus_message_SOURCES = \
-+    src/tests/cmocka/sbus/test_sbus_message.c \
-+    $(NULL)
-+test_sbus_message_CFLAGS = \
-+    $(AM_CFLAGS)
-+test_sbus_message_LDADD = \
-+    $(CMOCKA_LIBS) \
-+    $(POPT_LIBS) \
-+    libsss_debug.la \
-+    libsss_test_common.la \
-+    libsss_sbus.la \
-+    $(NULL)
-+
- test_sbus_opath_SOURCES = \
-     src/tests/cmocka/sbus/test_sbus_opath.c \
-     $(NULL)
-diff --git a/src/tests/cmocka/sbus/test_sbus_message.c b/src/tests/cmocka/sbus/test_sbus_message.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..c01e16823237775f95b772534adb5639e264c057
---- /dev/null
-+++ b/src/tests/cmocka/sbus/test_sbus_message.c
-@@ -0,0 +1,610 @@
-+/*
-+    Authors:
-+        Jakub Hrozek <jhrozek@redhat.com>
-+        Pavel Březina <pbrezina@redhat.com>
-+
-+    Copyright (C) 2014 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include "config.h"
-+
-+#include <talloc.h>
-+#include <errno.h>
-+#include <popt.h>
-+
-+#include "util/util.h"
-+#include "sbus/sbus_message.h"
-+#include "tests/cmocka/common_mock.h"
-+#include "tests/common.h"
-+
-+#define BASE_PATH "/some/path"
-+
-+struct test_ctx {
-+    bool msg_removed;
-+};
-+
-+static void helper_msg_removed(void *state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(state, struct test_ctx);
-+
-+    test_ctx->msg_removed = true;
-+}
-+
-+static void helper_msg_watch(struct test_ctx *test_ctx, DBusMessage *msg)
-+{
-+    DBusFreeFunction free_fn;
-+    dbus_int32_t data_slot = -1;
-+    dbus_bool_t bret;
-+
-+    assert_non_null(msg);
-+
-+    bret = dbus_message_allocate_data_slot(&data_slot);
-+    assert_true(bret);
-+
-+    free_fn = helper_msg_removed;
-+    bret = dbus_message_set_data(msg, data_slot, test_ctx, free_fn);
-+    assert_true(bret);
-+}
-+
-+static int test_setup(void **state)
-+{
-+    struct test_ctx *test_ctx;
-+
-+    assert_true(leak_check_setup());
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct test_ctx);
-+    assert_non_null(test_ctx);
-+    *state = test_ctx;
-+
-+    check_leaks_push(test_ctx);
-+
-+    return 0;
-+}
-+
-+int test_teardown(void **state)
-+{
-+    struct test_ctx *test_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+
-+    assert_true(check_leaks_pop(test_ctx));
-+    talloc_zfree(test_ctx);
-+    assert_true(leak_check_teardown());
-+
-+    return 0;
-+}
-+
-+void test_sbus_message_bound__null(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+
-+    ret = sbus_message_bound(NULL, msg);
-+    assert_int_equal(ret, EINVAL);
-+
-+    ret = sbus_message_bound(test_ctx, NULL);
-+    assert_int_equal(ret, EINVAL);
-+
-+    dbus_message_unref(msg);
-+}
-+
-+void test_sbus_message_bound__unref(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    ret = sbus_message_bound(test_ctx, msg);
-+    assert_int_equal(ret, EOK);
-+
-+    /* no memory leak should be detected in teardown */
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_message_bound__free(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    TALLOC_CTX *tmp_ctx;
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    ret = sbus_message_bound(tmp_ctx, msg);
-+    assert_int_equal(ret, EOK);
-+
-+    talloc_free(tmp_ctx);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_message_bound_steal__null(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    ret = sbus_message_bound_steal(NULL, msg);
-+    assert_int_equal(ret, EINVAL);
-+
-+    ret = sbus_message_bound_steal(test_ctx, NULL);
-+    assert_int_equal(ret, EINVAL);
-+
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_message_bound_steal__invalid(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    ret = sbus_message_bound_steal(test_ctx, msg);
-+    assert_int_equal(ret, ERR_INTERNAL);
-+
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_message_bound_steal__free(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    TALLOC_CTX *tmp_ctx;
-+    TALLOC_CTX *tmp_ctx_steal;
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    tmp_ctx_steal = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx_steal);
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    ret = sbus_message_bound(tmp_ctx, msg);
-+    assert_int_equal(ret, EOK);
-+
-+    /* this will increase ref counter of message and add new talloc bound */
-+    ret = sbus_message_bound_steal(tmp_ctx_steal, msg);
-+    assert_int_equal(ret, EOK);
-+
-+    talloc_free(tmp_ctx);
-+    assert_false(test_ctx->msg_removed);
-+    talloc_free(tmp_ctx_steal);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_method_create_empty__unref(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+
-+    msg = sbus_method_create_empty(NULL, "bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_METHOD_CALL);
-+    assert_string_equal(dbus_message_get_destination(msg), "bus.test");
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_method_create_empty__free(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    TALLOC_CTX *tmp_ctx;
-+    DBusMessage *msg;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    msg = sbus_method_create_empty(tmp_ctx, "bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_METHOD_CALL);
-+    assert_string_equal(dbus_message_get_destination(msg), "bus.test");
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    talloc_free(tmp_ctx);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_method_create__unref(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+    dbus_bool_t dbret;
-+    uint32_t in_value = 32;
-+    uint32_t out_value;
-+
-+    msg = sbus_method_create(NULL, "bus.test", "/", "iface.test", "method",
-+                             DBUS_TYPE_UINT32, &in_value);
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_METHOD_CALL);
-+    assert_string_equal(dbus_message_get_destination(msg), "bus.test");
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    dbret = dbus_message_get_args(msg, NULL,
-+                                  DBUS_TYPE_UINT32, &out_value,
-+                                  DBUS_TYPE_INVALID);
-+    assert_true(dbret);
-+    assert_int_equal(out_value, 32);
-+
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_method_create__free(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    TALLOC_CTX *tmp_ctx;
-+    DBusMessage *msg;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    msg = sbus_method_create_empty(tmp_ctx, "bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_METHOD_CALL);
-+    assert_string_equal(dbus_message_get_destination(msg), "bus.test");
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    talloc_free(tmp_ctx);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_signal_create_empty__unref(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+
-+    msg = sbus_signal_create_empty(NULL, "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_SIGNAL);
-+    assert_null(dbus_message_get_destination(msg));
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_signal_create_empty__free(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    TALLOC_CTX *tmp_ctx;
-+    DBusMessage *msg;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    msg = sbus_signal_create_empty(tmp_ctx, "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_SIGNAL);
-+    assert_null(dbus_message_get_destination(msg));
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    talloc_free(tmp_ctx);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_signal_create__unref(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    DBusMessage *msg;
-+    dbus_bool_t dbret;
-+    uint32_t in_value = 32;
-+    uint32_t out_value;
-+
-+    msg = sbus_signal_create(NULL, "/", "iface.test", "method",
-+                             DBUS_TYPE_UINT32, &in_value);
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_SIGNAL);
-+    assert_null(dbus_message_get_destination(msg));
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    dbret = dbus_message_get_args(msg, NULL,
-+                                  DBUS_TYPE_UINT32, &out_value,
-+                                  DBUS_TYPE_INVALID);
-+    assert_true(dbret);
-+    assert_int_equal(out_value, 32);
-+
-+    dbus_message_unref(msg);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_signal_create__free(void **state)
-+{
-+    struct test_ctx *test_ctx = talloc_get_type_abort(*state, struct test_ctx);
-+    TALLOC_CTX *tmp_ctx;
-+    DBusMessage *msg;
-+    dbus_bool_t dbret;
-+    uint32_t in_value = 32;
-+    uint32_t out_value;
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    msg = sbus_signal_create(tmp_ctx, "/", "iface.test", "method",
-+                             DBUS_TYPE_UINT32, &in_value);
-+    assert_non_null(msg);
-+    helper_msg_watch(test_ctx, msg);
-+
-+    assert_int_equal(dbus_message_get_type(msg), DBUS_MESSAGE_TYPE_SIGNAL);
-+    assert_null(dbus_message_get_destination(msg));
-+    assert_string_equal(dbus_message_get_path(msg), "/");
-+    assert_string_equal(dbus_message_get_interface(msg), "iface.test");
-+    assert_string_equal(dbus_message_get_member(msg), "method");
-+
-+    dbret = dbus_message_get_args(msg, NULL,
-+                                  DBUS_TYPE_UINT32, &out_value,
-+                                  DBUS_TYPE_INVALID);
-+    assert_true(dbret);
-+    assert_int_equal(out_value, 32);
-+
-+    talloc_free(tmp_ctx);
-+    assert_true(test_ctx->msg_removed);
-+}
-+
-+void test_sbus_reply_parse__ok(void **state)
-+{
-+    DBusMessage *msg;
-+    DBusMessage *reply;
-+    dbus_bool_t dbret;
-+    uint32_t in_value1 = 32;
-+    uint32_t in_value2 = 64;
-+    uint32_t out_value1;
-+    uint32_t out_value2;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    dbus_message_set_serial(msg, 1);
-+
-+    reply = dbus_message_new_method_return(msg);
-+    assert_non_null(reply);
-+
-+    dbret = dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_value1,
-+                                            DBUS_TYPE_UINT32, &in_value2,
-+                                            DBUS_TYPE_INVALID);
-+    assert_true(dbret);
-+
-+    ret = sbus_reply_parse(reply, DBUS_TYPE_UINT32, &out_value1,
-+                                  DBUS_TYPE_UINT32, &out_value2);
-+    assert_int_equal(ret, EOK);
-+    assert_int_equal(out_value1, in_value1);
-+    assert_int_equal(out_value2, in_value2);
-+
-+    dbus_message_unref(msg);
-+    dbus_message_unref(reply);
-+}
-+
-+void test_sbus_reply_parse__error(void **state)
-+{
-+    DBusMessage *msg;
-+    DBusMessage *reply;
-+    uint32_t out_value1;
-+    uint32_t out_value2;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    dbus_message_set_serial(msg, 1);
-+
-+    reply = dbus_message_new_error(msg, SBUS_ERROR_KILLED, "Test error!");
-+    assert_non_null(reply);
-+
-+    ret = sbus_reply_parse(reply, DBUS_TYPE_UINT32, &out_value1,
-+                                  DBUS_TYPE_UINT32, &out_value2);
-+    assert_int_equal(ret, ERR_SBUS_KILL_CONNECTION);
-+
-+    dbus_message_unref(msg);
-+    dbus_message_unref(reply);
-+}
-+
-+void test_sbus_reply_parse__wrong_type(void **state)
-+{
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    dbus_message_set_serial(msg, 1);
-+
-+    ret = sbus_reply_parse(msg);
-+    assert_int_not_equal(ret, EOK);
-+
-+    dbus_message_unref(msg);
-+}
-+
-+void test_sbus_reply_check__ok(void **state)
-+{
-+    DBusMessage *msg;
-+    DBusMessage *reply;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    dbus_message_set_serial(msg, 1);
-+
-+    reply = dbus_message_new_method_return(msg);
-+    assert_non_null(reply);
-+
-+    ret = sbus_reply_check(reply);
-+    assert_int_equal(ret, EOK);
-+
-+    dbus_message_unref(msg);
-+    dbus_message_unref(reply);
-+}
-+
-+void test_sbus_reply_check__error(void **state)
-+{
-+    DBusMessage *msg;
-+    DBusMessage *reply;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    dbus_message_set_serial(msg, 1);
-+
-+    reply = dbus_message_new_error(msg, SBUS_ERROR_KILLED, "Test error!");
-+    assert_non_null(reply);
-+
-+    ret = sbus_reply_check(reply);
-+    assert_int_equal(ret, ERR_SBUS_KILL_CONNECTION);
-+
-+    dbus_message_unref(msg);
-+    dbus_message_unref(reply);
-+}
-+
-+void test_sbus_reply_check__wrong_type(void **state)
-+{
-+    DBusMessage *msg;
-+    errno_t ret;
-+
-+    msg = dbus_message_new_method_call("bus.test", "/", "iface.test", "method");
-+    assert_non_null(msg);
-+    dbus_message_set_serial(msg, 1);
-+
-+    ret = sbus_reply_check(msg);
-+    assert_int_not_equal(ret, EOK);
-+
-+    dbus_message_unref(msg);
-+}
-+
-+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_setup_teardown(test_sbus_message_bound__null,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_message_bound__unref,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_message_bound__free,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_message_bound_steal__null,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_message_bound_steal__invalid,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_message_bound_steal__free,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_method_create_empty__unref,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_method_create_empty__free,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_method_create__unref,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_method_create__free,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_signal_create_empty__unref,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_signal_create_empty__free,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_signal_create__unref,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_signal_create__free,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_reply_parse__ok,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_reply_parse__error,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_reply_parse__wrong_type,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_reply_check__ok,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_reply_check__error,
-+                                        test_setup, test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sbus_reply_check__wrong_type,
-+                                        test_setup, test_teardown),
-+    };
-+
-+    /* 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.14.4
-
diff --git a/SOURCES/0036-BE-Extend-be_ptask_create-with-control-when-to-sched.patch b/SOURCES/0036-BE-Extend-be_ptask_create-with-control-when-to-sched.patch
new file mode 100644
index 0000000..dddaf8d
--- /dev/null
+++ b/SOURCES/0036-BE-Extend-be_ptask_create-with-control-when-to-sched.patch
@@ -0,0 +1,496 @@
+From 25b9f34fb2c7ea493c5e0fe83047703ec65fe60c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 18 Jun 2019 20:49:00 +0200
+Subject: [PATCH 36/48] 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>
+---
+ src/providers/ad/ad_dyndns.c             |  3 +-
+ 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_dyndns.c           |  5 +-
+ 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 ++++++++++++++++--------
+ 12 files changed, 95 insertions(+), 35 deletions(-)
+
+diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
+index 52a4e4d53..02ea7f24b 100644
+--- a/src/providers/ad/ad_dyndns.c
++++ b/src/providers/ad/ad_dyndns.c
+@@ -97,8 +97,9 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
+               "dyndns_refresh_interval is 0\n");
+         return EINVAL;
+     }
++
+     ret = be_ptask_create(ad_opts, be_ctx, period, ptask_first_delay, 0, 0, period,
+-                          BE_PTASK_OFFLINE_DISABLE, 0,
++                          BE_PTASK_OFFLINE_DISABLE, BE_PTASK_SCHEDULE_FROM_LAST, 0,
+                           ad_dyndns_update_send, ad_dyndns_update_recv, ad_opts,
+                           "Dyndns update", NULL);
+ 
+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 c4ac23065..2510498da 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -2066,7 +2066,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_dyndns.c b/src/providers/ipa/ipa_dyndns.c
+index a692b0d19..8e8ff5a4f 100644
+--- a/src/providers/ipa/ipa_dyndns.c
++++ b/src/providers/ipa/ipa_dyndns.c
+@@ -72,8 +72,11 @@ errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
+               "dyndns_refresh_interval is 0\n");
+         return EINVAL;
+     }
++
+     ret = be_ptask_create(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_dyndns_update_send, ipa_dyndns_update_recv, ctx,
+                           "Dyndns update", 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 d2f24ed6e..a00d8e6a9 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 356d9f9e2..03b1165bb 100644
+--- a/src/tests/cmocka/test_be_ptask.c
++++ b/src/tests/cmocka/test_be_ptask.c
+@@ -304,7 +304,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);
+@@ -317,7 +318,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);
+@@ -330,7 +332,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);
+@@ -343,7 +346,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);
+@@ -356,7 +360,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);
+@@ -371,7 +376,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);
+@@ -398,7 +404,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);
+@@ -423,7 +430,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);
+@@ -447,7 +455,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);
+@@ -479,7 +488,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);
+@@ -518,7 +528,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);
+@@ -551,7 +562,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);
+@@ -581,7 +594,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);
+@@ -608,7 +623,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);
+@@ -639,7 +655,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);
+@@ -666,7 +683,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);
+@@ -693,7 +711,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);
+@@ -730,7 +749,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);
+@@ -784,7 +804,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);
+@@ -804,7 +825,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/0036-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch b/SOURCES/0036-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch
deleted file mode 100644
index 945601d..0000000
--- a/SOURCES/0036-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch
+++ /dev/null
@@ -1,147 +0,0 @@
-From 8fbdd8b692be1dc63be4dd18c79d9647aeb2d74d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 2 Oct 2018 12:13:29 +0200
-Subject: [PATCH 36/47] p11: handle multiple certs during auth with OpenSSL
-
-This patch adds missing code already available in the NSS version to
-select a certificate for authentication if multiple certificates are
-available on the Smartcard. A unit test to check this feature is added
-as well.
-
-Related to https://pagure.io/SSSD/sssd/issue/3489
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e29b82077a78157a1e4d90e2308c1272d7612f3d)
----
- src/p11_child/p11_child_openssl.c | 46 ++++++++++++++++++++++++++++++++++++++-
- src/tests/cmocka/test_pam_srv.c   | 36 ++++++++++++++++++++++++++++++
- 2 files changed, 81 insertions(+), 1 deletion(-)
-
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index be5872626e248ad8acc042300a2ee2eee526cdaf..bf4418f8603eac4d77d20f464e8b56fb82285f0a 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -572,8 +572,10 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     char *slot_name = NULL;
-     char *token_name = NULL;
-     CK_SESSION_HANDLE session = 0;
-+    struct cert_list *all_cert_list = NULL;
-     struct cert_list *cert_list = NULL;
-     struct cert_list *item = NULL;
-+    struct cert_list *tmp_cert = NULL;
-     char *multi = NULL;
-     bool pkcs11_session = false;
-     bool pkcs11_login = false;
-@@ -691,12 +693,54 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-         DEBUG(SSSDBG_TRACE_ALL, "Login NOT required.\n");
-     }
- 
--    ret = read_certs(mem_ctx, module, session, p11_ctx, &cert_list);
-+    ret = read_certs(mem_ctx, module, session, p11_ctx, &all_cert_list);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "read_certs failed.\n");
-         goto done;
-     }
- 
-+    DLIST_FOR_EACH(item, all_cert_list) {
-+        /* Check if we found the certificates we needed for authentication or
-+         * the requested ones for pre-auth. For authentication all attributes
-+         * must be given and match, for pre-auth only the given ones must
-+         * match. */
-+        DEBUG(SSSDBG_TRACE_ALL, "%s %s %s %s %s %s.\n",
-+              module_name_in, module_file_name, token_name_in, token_name,
-+              key_id_in, item->id);
-+
-+        if ((mode == OP_AUTH
-+                && module_name_in != NULL
-+                && token_name_in != NULL
-+                && key_id_in != NULL
-+                && item->id != NULL
-+                && strcmp(key_id_in, item->id) == 0
-+                && strcmp(token_name_in, token_name) == 0
-+                && strcmp(module_name_in, module_file_name) == 0)
-+            || (mode == OP_PREAUTH
-+                && (module_name_in == NULL
-+                    || (module_name_in != NULL
-+                        && strcmp(module_name_in, module_file_name) == 0))
-+                && (token_name_in == NULL
-+                    || (token_name_in != NULL
-+                        && strcmp(token_name_in, token_name) == 0))
-+                && (key_id_in == NULL
-+                    || (key_id_in != NULL && item->id != NULL
-+                        && strcmp(key_id_in, item->id) == 0)))) {
-+
-+            tmp_cert = talloc_memdup(mem_ctx, item, sizeof(struct cert_list));
-+            if (tmp_cert == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n");
-+                ret = ENOMEM;
-+                goto done;
-+            }
-+            tmp_cert->prev = NULL;
-+            tmp_cert->next = NULL;
-+
-+            DLIST_ADD(cert_list, tmp_cert);
-+
-+        }
-+    }
-+
-     /* TODO: check module_name_in, token_name_in, key_id_in */
- 
-     if (cert_list == NULL) {
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 446985d5d2462f58a28c702fd5eaa5de7b20ed27..2b02ac27b7356c5bce9e11dae785ecdbddd31aa3 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -2443,6 +2443,40 @@ void test_pam_cert_preauth_2certs_two_mappings(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+void test_pam_cert_auth_2certs_one_mapping(void **state)
-+{
-+    int ret;
-+
-+#ifdef HAVE_NSS
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS);
-+#else
-+    set_cert_auth_param(pam_test_ctx->pctx, CA_DB);
-+    putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_two.conf"));
-+#endif
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token",
-+                        TEST_MODULE_NAME,
-+                        "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL,
-+                        test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001,
-+                        true);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    /* Assume backend cannot handle Smartcard credentials */
-+    pam_test_ctx->exp_pam_status = PAM_BAD_ITEM;
-+
-+    set_cmd_cb(test_pam_simple_check_success);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+
- void test_filter_response(void **state)
- {
-     int ret;
-@@ -2875,6 +2909,8 @@ int main(int argc, const char *argv[])
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_two_mappings,
-                                         pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_cert_auth_2certs_one_mapping,
-+                                        pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name,
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id,
--- 
-2.14.4
-
diff --git a/SOURCES/0037-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch b/SOURCES/0037-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch
new file mode 100644
index 0000000..664c6fe
--- /dev/null
+++ b/SOURCES/0037-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch
@@ -0,0 +1,34 @@
+From 6b068dec9ac5b2f22a9c20b5554a6e45af6dc8bb Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 19 Jun 2019 22:03:16 +0200
+Subject: [PATCH 37/48] 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>
+---
+ 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/0037-p11_child-add-wait_for_card-option.patch b/SOURCES/0037-p11_child-add-wait_for_card-option.patch
deleted file mode 100644
index 6cf433d..0000000
--- a/SOURCES/0037-p11_child-add-wait_for_card-option.patch
+++ /dev/null
@@ -1,476 +0,0 @@
-From 8070497ccd404438712711f1317e800df0c774e3 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 14 Sep 2018 12:47:00 +0200
-Subject: [PATCH 37/47] p11_child: add --wait_for_card option
-
-The --wait_for_card option will let the p11_child wait until a
-Smartcard/token is available in a slot with the removable flag.
-
-Related to  https://pagure.io/SSSD/sssd/issue/3650
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 42f69e26e5b858dd03492cc2a148d02c2ccc2161)
----
- src/p11_child/p11_child.h         |   5 +-
- src/p11_child/p11_child_common.c  |  12 +++-
- src/p11_child/p11_child_nss.c     | 105 +++++++++++++++++++--------
- src/p11_child/p11_child_openssl.c | 146 +++++++++++++++++++++++++++++---------
- 4 files changed, 201 insertions(+), 67 deletions(-)
-
-diff --git a/src/p11_child/p11_child.h b/src/p11_child/p11_child.h
-index 1e9fc3d1c9d0a05f50080f1ef37771448deb162f..dd8fdeafbf947aad930e61ae694bc99df6d8212a 100644
---- a/src/p11_child/p11_child.h
-+++ b/src/p11_child/p11_child.h
-@@ -25,6 +25,9 @@
- #ifndef __P11_CHILD_H__
- #define __P11_CHILD_H__
- 
-+/* Time to wait during a C_Finalize C_Initialize cycle to discover
-+ * new slots. */
-+#define PKCS11_FINIALIZE_INITIALIZE_WAIT_TIME 3
- struct p11_ctx;
- 
- enum op_mode {
-@@ -41,7 +44,7 @@ enum pin_mode {
- };
- 
- errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *nss_db,
--                     struct p11_ctx **p11_ctx);
-+                     bool wait_for_card, struct p11_ctx **p11_ctx);
- 
- errno_t init_verification(struct p11_ctx *p11_ctx,
-                           struct cert_verify_opts *cert_verify_opts);
-diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c
-index 125430d13d0807bc30018b49715367cabb028696..bc5f6b09b191f0ea853f45d8a78bc6e4a69c3da7 100644
---- a/src/p11_child/p11_child_common.c
-+++ b/src/p11_child/p11_child_common.c
-@@ -57,6 +57,7 @@ static const char *op_mode_str(enum op_mode mode)
- 
- static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db,
-                    struct cert_verify_opts *cert_verify_opts,
-+                   bool wait_for_card,
-                    const char *cert_b64, const char *pin,
-                    const char *module_name, const char *token_name,
-                    const char *key_id, char **multi)
-@@ -64,7 +65,7 @@ static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db,
-     int ret;
-     struct p11_ctx *p11_ctx;
- 
--    ret = init_p11_ctx(mem_ctx, ca_db, &p11_ctx);
-+    ret = init_p11_ctx(mem_ctx, ca_db, wait_for_card, &p11_ctx);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "init_p11_ctx failed.\n");
-         return ret;
-@@ -157,6 +158,7 @@ int main(int argc, const char *argv[])
-     char *token_name = NULL;
-     char *key_id = NULL;
-     char *cert_b64 = NULL;
-+    bool wait_for_card = false;
- 
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-@@ -174,6 +176,7 @@ int main(int argc, const char *argv[])
-         SSSD_LOGGER_OPTS
-         {"auth", 0, POPT_ARG_NONE, NULL, 'a', _("Run in auth mode"), NULL},
-         {"pre", 0, POPT_ARG_NONE, NULL, 'p', _("Run in pre-auth mode"), NULL},
-+        {"wait_for_card", 0, POPT_ARG_NONE, NULL, 'w', _("Wait until card is available"), NULL},
-         {"verification", 0, POPT_ARG_NONE, NULL, 'v', _("Run in verification mode"),
-          NULL},
-         {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL},
-@@ -258,6 +261,9 @@ int main(int argc, const char *argv[])
-             }
-             pin_mode = PIN_KEYPAD;
-             break;
-+        case 'w':
-+            wait_for_card = true;
-+            break;
-         default:
-             fprintf(stderr, "\nInvalid option %s: %s\n\n",
-                   poptBadOption(pc, 0), poptStrerror(opt));
-@@ -360,8 +366,8 @@ int main(int argc, const char *argv[])
-         }
-     }
- 
--    ret = do_work(main_ctx, mode, nss_db, cert_verify_opts, cert_b64,
--                 pin, module_name, token_name, key_id, &multi);
-+    ret = do_work(main_ctx, mode, nss_db, cert_verify_opts, wait_for_card,
-+                  cert_b64, pin, module_name, token_name, key_id, &multi);
-     if (ret != 0) {
-         DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n");
-         goto fail;
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index d6a0b804a23a02389d1f764488cda6924dc0b41e..b2777d1d245d4942263ebf0610eef5cf6a528bd1 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -51,6 +51,7 @@ struct p11_ctx {
-     CERTCertDBHandle *handle;
-     struct cert_verify_opts *cert_verify_opts;
-     const char *nss_db;
-+    bool wait_for_card;
- };
- 
- #define EXP_USAGES (  certificateUsageSSLClient \
-@@ -141,6 +142,19 @@ static int talloc_free_handle(struct p11_ctx *p11_ctx)
-     return 0;
- }
- 
-+static NSSInitContext *get_nss_ctx(const char *nss_db)
-+{
-+    uint32_t flags = NSS_INIT_READONLY
-+                                   | NSS_INIT_FORCEOPEN
-+                                   | NSS_INIT_NOROOTINIT
-+                                   | NSS_INIT_OPTIMIZESPACE
-+                                   | NSS_INIT_PK11RELOAD;
-+    NSSInitParameters parameters = { 0 };
-+    parameters.length =  sizeof (parameters);
-+
-+    return NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
-+}
-+
- errno_t init_verification(struct p11_ctx *p11_ctx,
-                           struct cert_verify_opts *cert_verify_opts)
- {
-@@ -256,14 +270,15 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     SECItem signed_random_value = {0};
-     SECKEYPublicKey *pub_key;
-     CERTCertificate *found_cert = NULL;
--    PK11SlotList *list = NULL;
--    PK11SlotListElement *le;
-     const char *label;
-     char *key_id_str = NULL;
-     CERTCertList *valid_certs = NULL;
-     char *cert_b64 = NULL;
-     char *multi = NULL;
-     PRCList *node;
-+    CK_SLOT_INFO slInfo;
-+    PK11TokenStatus token_status;
-+    size_t s;
- 
-     PK11_SetPasswordFunc(password_passthrough);
- 
-@@ -297,28 +312,50 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-                                 mod_list_item->module->dllName);
-     }
- 
--    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE,
--                             NULL);
--    if (list == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n");
--        ret = EIO;
--        goto done;
--    }
-+    for (;;)  {
-+        mod_list = SECMOD_GetDefaultModuleList();
-+        for (mod_list_item = mod_list; mod_list_item != NULL;
-+                                       mod_list_item = mod_list_item->next) {
-+            for (s = 0; s < mod_list_item->module->slotCount; s++) {
-+                slInfo.flags = 0;
-+                rv = PK11_GetSlotInfo(mod_list_item->module->slots[s], &slInfo);
-+                DEBUG(SSSDBG_TRACE_ALL,
-+                      "Description [%s] Manufacturer [%s] flags [%lu] "
-+                      "removable [%s] token present [%s].\n",
-+                      slInfo.slotDescription, slInfo.manufacturerID,
-+                      slInfo.flags,
-+                      (slInfo.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
-+                      (slInfo.flags & CKF_TOKEN_PRESENT) ? "true": "false");
- 
--    for (le = list->head; le; le = le->next) {
--        CK_SLOT_INFO slInfo;
-+                if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
-+                    slot = PK11_ReferenceSlot(mod_list_item->module->slots[s]);
-+                    break;
-+                }
-+            }
-+        }
- 
--        slInfo.flags = 0;
--        rv = PK11_GetSlotInfo(le->slot, &slInfo);
--        DEBUG(SSSDBG_TRACE_ALL,
--              "Description [%s] Manufacturer [%s] flags [%lu].\n",
--              slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags);
--        if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
--            slot = PK11_ReferenceSlot(le->slot);
-+        /* When e.g. using Yubikeys the slot isn't present until the device is
-+         * inserted, so we should wait for a slot as well. */
-+        if (p11_ctx->wait_for_card && slot == NULL) {
-+            rv = NSS_ShutdownContext(p11_ctx->nss_ctx);
-+            if (rv != SECSuccess) {
-+                DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d][%s].\n",
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-+            }
-+
-+            sleep(PKCS11_FINIALIZE_INITIALIZE_WAIT_TIME);
-+
-+            p11_ctx->nss_ctx = get_nss_ctx(p11_ctx->nss_db);
-+            if (p11_ctx->nss_ctx == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n",
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-+                return EIO;
-+            }
-+        } else {
-             break;
-         }
-     }
--    PK11_FreeSlotList(list);
-+
-     if (slot == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n");
-         ret = EIO;
-@@ -332,6 +369,22 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     module = PK11_GetModule(slot);
-     module_name = module->dllName == NULL ? "NSS-Internal" : module->dllName;
- 
-+    if (!(slInfo.flags & CKF_TOKEN_PRESENT)) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Token not present.\n");
-+        if (p11_ctx->wait_for_card) {
-+            token_status = PK11_WaitForTokenEvent(slot, PK11TokenPresentEvent,
-+                                                 PR_INTERVAL_NO_TIMEOUT, 0, 0);
-+            if (token_status != PK11TokenPresent) {
-+                DEBUG(SSSDBG_OP_FAILURE, "PK11_WaitForTokenEvent failed.\n");
-+                ret = EIO;
-+                goto done;
-+            }
-+        } else {
-+            ret = EIO;
-+            goto done;
-+        }
-+    }
-+
-     DEBUG(SSSDBG_TRACE_ALL, "Found [%s] in slot [%s][%d] of module [%d][%s].\n",
-           token_name, slot_name, (int) slot_id, (int) module_id, module_name);
- 
-@@ -651,26 +704,18 @@ static int talloc_nss_shutdown(struct p11_ctx *p11_ctx)
- }
- 
- errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *nss_db,
--                     struct p11_ctx **p11_ctx)
-+                     bool wait_for_card, struct p11_ctx **p11_ctx)
- {
-     struct p11_ctx *ctx;
--    uint32_t flags = NSS_INIT_READONLY
--                                   | NSS_INIT_FORCEOPEN
--                                   | NSS_INIT_NOROOTINIT
--                                   | NSS_INIT_OPTIMIZESPACE
--                                   | NSS_INIT_PK11RELOAD;
--    NSSInitParameters parameters = { 0 };
--    parameters.length =  sizeof (parameters);
--
-     ctx = talloc_zero(mem_ctx, struct p11_ctx);
-     if (ctx == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
-         return ENOMEM;
-     }
-     ctx->nss_db = nss_db;
-+    ctx->wait_for_card = wait_for_card;
- 
--    ctx->nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters,
--                                    flags);
-+    ctx->nss_ctx = get_nss_ctx(nss_db);
-     if (ctx->nss_ctx == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n",
-               PR_GetError(), PORT_ErrorToString(PR_GetError()));
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index bf4418f8603eac4d77d20f464e8b56fb82285f0a..d4572d99cd3a3186128b46cc4a9453d716bd7979 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -40,6 +40,7 @@
- struct p11_ctx {
-     X509_STORE *x509_store;
-     const char *ca_db;
-+    bool wait_for_card;
- };
- 
- static int talloc_cleanup_openssl(struct p11_ctx *p11_ctx)
-@@ -48,8 +49,9 @@ static int talloc_cleanup_openssl(struct p11_ctx *p11_ctx)
- 
-     return 0;
- }
-+
- errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *ca_db,
--                     struct p11_ctx **p11_ctx)
-+                     bool wait_for_card, struct p11_ctx **p11_ctx)
- {
-     int ret;
-     struct p11_ctx *ctx;
-@@ -73,6 +75,7 @@ errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *ca_db,
-     }
- 
-     ctx->ca_db = ca_db;
-+    ctx->wait_for_card = wait_for_card;
-     talloc_set_destructor(ctx, talloc_cleanup_openssl);
- 
-     *p11_ctx = ctx;
-@@ -547,6 +550,45 @@ done:
-     return ret;
- }
- 
-+static errno_t wait_for_card(CK_FUNCTION_LIST *module, CK_SLOT_ID *slot_id)
-+{
-+    CK_FLAGS wait_flags = 0;
-+    CK_RV rv;
-+    CK_SLOT_INFO info;
-+
-+    rv = module->C_WaitForSlotEvent(wait_flags, slot_id, NULL);
-+    if (rv != CKR_OK) {
-+        if (rv != CKR_FUNCTION_NOT_SUPPORTED) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "C_WaitForSlotEvent failed [%lu][%s].\n",
-+                  rv, p11_kit_strerror(rv));
-+            return EIO;
-+        }
-+
-+        /* Poor man's wait */
-+        do {
-+            sleep(10);
-+            rv = module->C_GetSlotInfo(*slot_id, &info);
-+            if (rv != CKR_OK) {
-+                DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotInfo failed\n");
-+                return EIO;
-+            }
-+            DEBUG(SSSDBG_TRACE_ALL,
-+                  "Description [%s] Manufacturer [%s] flags [%lu] "
-+                  "removable [%s] token present [%s].\n",
-+                  info.slotDescription, info.manufacturerID, info.flags,
-+                  (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
-+                  (info.flags & CKF_TOKEN_PRESENT) ? "true": "false");
-+            if ((info.flags & CKF_REMOVABLE_DEVICE)
-+                    && (info.flags & CKF_TOKEN_PRESENT)) {
-+                break;
-+            }
-+        } while (true);
-+    }
-+
-+    return EOK;
-+}
-+
- #define MAX_SLOTS 64
- 
- errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-@@ -588,39 +630,62 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-         return EIO;
-     }
- 
--    DEBUG(SSSDBG_TRACE_ALL, "Module List:\n");
--    for (c = 0; modules[c] != NULL; c++) {
--        mod_name = p11_kit_module_get_name(modules[c]);
--        mod_file_name = p11_kit_module_get_filename(modules[c]);
--        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n", mod_name);
--        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n", mod_file_name);
--        free(mod_name);
--        free(mod_file_name);
-+    for (;;) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Module List:\n");
-+        for (c = 0; modules[c] != NULL; c++) {
-+            mod_name = p11_kit_module_get_name(modules[c]);
-+            mod_file_name = p11_kit_module_get_filename(modules[c]);
-+            DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n", mod_name);
-+            DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n", mod_file_name);
-+            free(mod_name);
-+            free(mod_file_name);
- 
--        num_slots = MAX_SLOTS;
--        rv = modules[c]->C_GetSlotList(CK_TRUE, slots, &num_slots);
--        if (rv != CKR_OK) {
--            DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotList failed.\n");
--            ret = EIO;
--            goto done;
--        }
--
--        for (s = 0; s < num_slots; s++) {
--            rv = modules[c]->C_GetSlotInfo(slots[s], &info);
-+            num_slots = MAX_SLOTS;
-+            rv = modules[c]->C_GetSlotList(CK_FALSE, slots, &num_slots);
-             if (rv != CKR_OK) {
--                DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotInfo failed\n");
-+                DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotList failed.\n");
-                 ret = EIO;
-                 goto done;
-             }
--            DEBUG(SSSDBG_TRACE_ALL,
--                  "Description [%s] Manufacturer [%s] flags [%lu] removable [%s].\n",
--                  info.slotDescription, info.manufacturerID, info.flags,
--                  (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false");
--            if ((info.flags & CKF_REMOVABLE_DEVICE)) {
-+
-+            for (s = 0; s < num_slots; s++) {
-+                rv = modules[c]->C_GetSlotInfo(slots[s], &info);
-+                if (rv != CKR_OK) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotInfo failed\n");
-+                    ret = EIO;
-+                    goto done;
-+                }
-+                DEBUG(SSSDBG_TRACE_ALL,
-+                      "Description [%s] Manufacturer [%s] flags [%lu] "
-+                      "removable [%s] token present [%s].\n",
-+                      info.slotDescription, info.manufacturerID, info.flags,
-+                      (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
-+                      (info.flags & CKF_TOKEN_PRESENT) ? "true": "false");
-+                if ((info.flags & CKF_REMOVABLE_DEVICE)) {
-+                    break;
-+                }
-+            }
-+            if (s != num_slots) {
-                 break;
-             }
-         }
--        if (s != num_slots) {
-+
-+        /* When e.g. using Yubikeys the slot isn't present until the device is
-+         * inserted, so we should wait for a slot as well. */
-+        if (p11_ctx->wait_for_card && modules[c] == NULL) {
-+            p11_kit_modules_finalize_and_release(modules);
-+
-+            sleep(PKCS11_FINIALIZE_INITIALIZE_WAIT_TIME);
-+
-+            modules = p11_kit_modules_load_and_initialize(0);
-+            if (modules == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "p11_kit_modules_load_and_initialize failed.\n");
-+                ret = EIO;
-+                goto done;
-+            }
-+
-+        } else {
-             break;
-         }
-     }
-@@ -631,14 +696,29 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-         goto done;
-     }
- 
--    rv = modules[c]->C_GetTokenInfo(slots[s], &token_info);
--    if (rv != CKR_OK) {
--        DEBUG(SSSDBG_OP_FAILURE, "C_GetTokenInfo failed.\n");
--        ret = EIO;
--        goto done;
--    }
--
-     slot_id = slots[s];
-+
-+    if (!(info.flags & CKF_TOKEN_PRESENT)) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Token not present.\n");
-+        if (p11_ctx->wait_for_card) {
-+            ret = wait_for_card(modules[c], &slot_id);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, "wait_for_card failed.\n");
-+                goto done;
-+            }
-+        } else {
-+            ret = EIO;
-+            goto done;
-+        }
-+    }
-+
-+    rv = modules[c]->C_GetTokenInfo(slot_id, &token_info);
-+    if (rv != CKR_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "C_GetTokenInfo failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-     module_id = c;
-     slot_name = p11_kit_space_strdup(info.slotDescription,
-                                      sizeof(info.slotDescription));
--- 
-2.14.4
-
diff --git a/SOURCES/0038-AD-Implement-background-refresh-for-AD-domains.patch b/SOURCES/0038-AD-Implement-background-refresh-for-AD-domains.patch
new file mode 100644
index 0000000..6a80ec6
--- /dev/null
+++ b/SOURCES/0038-AD-Implement-background-refresh-for-AD-domains.patch
@@ -0,0 +1,589 @@
+From 10e3f8bddc8dd4799c0da68aebf09aa3435950f5 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 24 Apr 2019 20:52:11 +0200
+Subject: [PATCH 38/48] 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>
+---
+ 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 043a7ebb4..f9f17904e 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -4502,7 +4502,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 e224254e1..75f11de2e 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -224,4 +224,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 b8ebaea2f..42c17de00 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/0038-PAM-add-p11_wait_for_card_timeout-option.patch b/SOURCES/0038-PAM-add-p11_wait_for_card_timeout-option.patch
deleted file mode 100644
index d3931d1..0000000
--- a/SOURCES/0038-PAM-add-p11_wait_for_card_timeout-option.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-From 8ec8702a9f06f7c4fe2f4bbfed33a0b3b73f1961 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 18 Sep 2018 18:15:02 +0200
-Subject: [PATCH 38/47] PAM: add p11_wait_for_card_timeout option
-
-If the --wait_for_card is used to call p11_child the PAM responder
-should be prepared to wait longer until p11_child can return
-successfully.
-
-Related to https://pagure.io/SSSD/sssd/issue/3650
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2e4ecf5a866b212bef44e262fd90c67a88dc616a)
----
- src/confdb/confdb.h                  |  1 +
- src/config/SSSDConfig/__init__.py.in |  1 +
- src/config/cfg_rules.ini             |  1 +
- src/config/etc/sssd.api.conf         |  1 +
- src/man/sssd.conf.5.xml              | 14 ++++++++++++++
- src/responder/pam/pamsrv_cmd.c       | 15 +++++++++++++++
- src/util/util.h                      |  1 +
- 7 files changed, 34 insertions(+)
-
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 625d156267ebf5f59e3974663256acfbb5f3b027..87904c2146b33b57106ac3799c5a67ee02387e9b 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -130,6 +130,7 @@
- #define CONFDB_PAM_CERT_AUTH "pam_cert_auth"
- #define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path"
- #define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout"
-+#define CONFDB_PAM_WAIT_FOR_CARD_TIMEOUT "p11_wait_for_card_timeout"
- #define CONFDB_PAM_APP_SERVICES "pam_app_services"
- #define CONFDB_PAM_P11_ALLOWED_SERVICES "pam_p11_allowed_services"
- 
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index 81a03adfe91120233afbaed4d2522788b56bea94..4d1dba2d22eae4716fbabe3a3957952f7cd17751 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -104,6 +104,7 @@ option_strings = {
-     'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'),
-     'pam_app_services' : _('Which PAM services are permitted to contact application domains'),
-     'pam_p11_allowed_services' : _('Allowed services for using smartcards'),
-+    'p11_wait_for_card_timeout' : _('Additional timeout to wait for a card if requested'),
- 
-     # [sudo]
-     'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'),
-diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
-index 36e83a932d6b66cae129a03fb137ba5e4e3092b2..717ccfa3f382b92800bf00ed79f68641a5a83d5c 100644
---- a/src/config/cfg_rules.ini
-+++ b/src/config/cfg_rules.ini
-@@ -127,6 +127,7 @@ option = pam_cert_db_path
- option = p11_child_timeout
- option = pam_app_services
- option = pam_p11_allowed_services
-+option = p11_wait_for_card_timeout
- 
- [rule/allowed_sudo_options]
- validator = ini_allowed_options
-diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
-index 52494c0e6d50efc2d31c56c0fe023dc9c07e35ba..bb686c34480be27d0829b57a853fa05921730630 100644
---- a/src/config/etc/sssd.api.conf
-+++ b/src/config/etc/sssd.api.conf
-@@ -76,6 +76,7 @@ pam_cert_db_path = str, None, false
- p11_child_timeout = int, None, false
- pam_app_services = str, None, false
- pam_p11_allowed_services = str, None, false
-+p11_wait_for_card_timeout = int, None, false
- 
- [sudo]
- # sudo service
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index c1e38950f99cb8df4c59fe10866632030d3c6f25..4df0163311fb3845e6a027be7d0b500cb5d2f0b6 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -1464,6 +1464,20 @@ pam_p11_allowed_services = +my_pam_service, -login
-                         </para>
-                     </listitem>
-                 </varlistentry>
-+                <varlistentry>
-+                    <term>p11_wait_for_card_timeout (integer)</term>
-+                    <listitem>
-+                        <para>
-+                            If Smartcard authentication is required how many
-+                            extra seconds in addition to p11_child_timeout
-+                            should the PAM responder wait until a Smartcard is
-+                            inserted.
-+                        </para>
-+                        <para>
-+                            Default: 60
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-             </variablelist>
-         </refsect2>
- 
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index 817f3c5134ba4c7358ffb4fbf3c6008fa23ffe0e..c8df32de9e72e9f5ce33e26f0a13101a99f01d5f 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1297,6 +1297,7 @@ static errno_t check_cert(TALLOC_CTX *mctx,
-                           struct pam_data *pd)
- {
-     int p11_child_timeout;
-+    int wait_for_card_timeout;
-     char *cert_verification_opts;
-     errno_t ret;
-     struct tevent_req *req;
-@@ -1311,6 +1312,20 @@ static errno_t check_cert(TALLOC_CTX *mctx,
-               ret, sss_strerror(ret));
-         return ret;
-     }
-+    if ((pd->cli_flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) && pd->priv == 1) {
-+        ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
-+                             CONFDB_PAM_WAIT_FOR_CARD_TIMEOUT,
-+                             P11_WAIT_FOR_CARD_TIMEOUT_DEFAULT,
-+                             &wait_for_card_timeout);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to read wait_for_card_timeout from confdb: [%d]: %s\n",
-+                  ret, sss_strerror(ret));
-+            return ret;
-+        }
-+
-+        p11_child_timeout += wait_for_card_timeout;
-+    }
- 
-     ret = confdb_get_string(pctx->rctx->cdb, mctx, CONFDB_MONITOR_CONF_ENTRY,
-                             CONFDB_MONITOR_CERT_VERIFICATION, NULL,
-diff --git a/src/util/util.h b/src/util/util.h
-index 59e7a96ba58aa9400166514064922d25fb713deb..e3e91009728cd8a5a92701220c06e8c378f47431 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -724,6 +724,7 @@ errno_t create_preauth_indicator(void);
- #define P11_CHILD_LOG_FILE "p11_child"
- #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
- #define P11_CHILD_TIMEOUT_DEFAULT 10
-+#define P11_WAIT_FOR_CARD_TIMEOUT_DEFAULT 60
- #endif  /* SSSD_LIBEXEC_PATH */
- 
- #endif /* __SSSD_UTIL_H__ */
--- 
-2.14.4
-
diff --git a/SOURCES/0039-IPA-Implement-background-refresh-for-IPA-domains.patch b/SOURCES/0039-IPA-Implement-background-refresh-for-IPA-domains.patch
new file mode 100644
index 0000000..1dfa06b
--- /dev/null
+++ b/SOURCES/0039-IPA-Implement-background-refresh-for-IPA-domains.patch
@@ -0,0 +1,547 @@
+From 3847082fe85520ab86cefcf78d9ffe6c6df0a04f Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 8 May 2019 14:39:23 +0200
+Subject: [PATCH 39/48] 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>
+---
+ 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 f9f17904e..cbd6bbfdb 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -4430,6 +4430,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/0039-pam_sss-make-flags-public.patch b/SOURCES/0039-pam_sss-make-flags-public.patch
deleted file mode 100644
index b690e75..0000000
--- a/SOURCES/0039-pam_sss-make-flags-public.patch
+++ /dev/null
@@ -1,245 +0,0 @@
-From b01e1a5e2c27d6c642c72e79a326d37803827a78 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 18 Sep 2018 10:11:02 +0200
-Subject: [PATCH 39/47] pam_sss: make flags public
-
-To allow the PAM responder to act on the config flags set for pam_sss
-the flags have to be made public first.
-
-Related to https://pagure.io/SSSD/sssd/issue/3650
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit d33a8bed5aad9135426c9ebdf101cf600685ab81)
----
- src/sss_client/pam_sss.c | 71 +++++++++++++++++++++---------------------------
- src/sss_client/sss_cli.h |  9 ++++++
- 2 files changed, 40 insertions(+), 40 deletions(-)
-
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index 59081cc675e5f466de42872ea9ce539c6df7ff79..b336d1f6197b09c062dd4ece836e088e52fe7393 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -52,15 +52,6 @@
- #include <libintl.h>
- #define _(STRING) dgettext (PACKAGE, STRING)
- 
--#define FLAGS_USE_FIRST_PASS (1 << 0)
--#define FLAGS_FORWARD_PASS   (1 << 1)
--#define FLAGS_USE_AUTHTOK    (1 << 2)
--#define FLAGS_IGNORE_UNKNOWN_USER (1 << 3)
--#define FLAGS_IGNORE_AUTHINFO_UNAVAIL (1 << 4)
--#define FLAGS_USE_2FA (1 << 5)
--#define FLAGS_ALLOW_MISSING_NAME (1 << 6)
--#define FLAGS_PROMPT_ALWAYS (1 << 7)
--
- #define PWEXP_FLAG "pam_sss:password_expired_flag"
- #define FD_DESTRUCTOR "pam_sss:fd_destructor"
- #define PAM_SSS_AUTHOK_TYPE "pam_sss:authtok_type"
-@@ -1193,13 +1184,13 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
-     pi->pam_service_size=strlen(pi->pam_service)+1;
- 
-     ret = pam_get_item(pamh, PAM_USER, (const void **) &(pi->pam_user));
--    if (ret == PAM_PERM_DENIED && (flags & FLAGS_ALLOW_MISSING_NAME)) {
-+    if (ret == PAM_PERM_DENIED && (flags & PAM_CLI_FLAGS_ALLOW_MISSING_NAME)) {
-         pi->pam_user = "";
-         ret = PAM_SUCCESS;
-     }
-     if (ret != PAM_SUCCESS) return ret;
-     if (pi->pam_user == NULL) {
--        if (flags & FLAGS_ALLOW_MISSING_NAME) {
-+        if (flags & PAM_CLI_FLAGS_ALLOW_MISSING_NAME) {
-             pi->pam_user = "";
-         } else {
-             D(("No user found, aborting."));
-@@ -1959,11 +1950,11 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
- 
-     for (; argc-- > 0; ++argv) {
-         if (strcmp(*argv, "forward_pass") == 0) {
--            *flags |= FLAGS_FORWARD_PASS;
-+            *flags |= PAM_CLI_FLAGS_FORWARD_PASS;
-         } else if (strcmp(*argv, "use_first_pass") == 0) {
--            *flags |= FLAGS_USE_FIRST_PASS;
-+            *flags |= PAM_CLI_FLAGS_USE_FIRST_PASS;
-         } else if (strcmp(*argv, "use_authtok") == 0) {
--            *flags |= FLAGS_USE_AUTHTOK;
-+            *flags |= PAM_CLI_FLAGS_USE_AUTHTOK;
-         } else if (strncmp(*argv, OPT_DOMAINS_KEY, strlen(OPT_DOMAINS_KEY)) == 0) {
-             if (*(*argv+strlen(OPT_DOMAINS_KEY)) == '\0') {
-                 logger(pamh, LOG_ERR, "Missing argument to option domains.");
-@@ -1997,15 +1988,15 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
-         } else if (strcmp(*argv, "quiet") == 0) {
-             *quiet_mode = true;
-         } else if (strcmp(*argv, "ignore_unknown_user") == 0) {
--            *flags |= FLAGS_IGNORE_UNKNOWN_USER;
-+            *flags |= PAM_CLI_FLAGS_IGNORE_UNKNOWN_USER;
-         } else if (strcmp(*argv, "ignore_authinfo_unavail") == 0) {
--            *flags |= FLAGS_IGNORE_AUTHINFO_UNAVAIL;
-+            *flags |= PAM_CLI_FLAGS_IGNORE_AUTHINFO_UNAVAIL;
-         } else if (strcmp(*argv, "use_2fa") == 0) {
--            *flags |= FLAGS_USE_2FA;
-+            *flags |= PAM_CLI_FLAGS_USE_2FA;
-         } else if (strcmp(*argv, "allow_missing_name") == 0) {
--            *flags |= FLAGS_ALLOW_MISSING_NAME;
-+            *flags |= PAM_CLI_FLAGS_ALLOW_MISSING_NAME;
-         } else if (strcmp(*argv, "prompt_always") == 0) {
--            *flags |= FLAGS_PROMPT_ALWAYS;
-+            *flags |= PAM_CLI_FLAGS_PROMPT_ALWAYS;
-         } else {
-             logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
-         }
-@@ -2020,10 +2011,10 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
- {
-     int ret;
- 
--    if ((flags & FLAGS_USE_FIRST_PASS)
-+    if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
-             || ( pi->pamstack_authtok != NULL
-                     && *(pi->pamstack_authtok) != '\0'
--                    && !(flags & FLAGS_PROMPT_ALWAYS))) {
-+                    && !(flags & PAM_CLI_FLAGS_PROMPT_ALWAYS))) {
-         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
-         pi->pam_authtok = strdup(pi->pamstack_authtok);
-         if (pi->pam_authtok == NULL) {
-@@ -2032,7 +2023,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
-         }
-         pi->pam_authtok_size = strlen(pi->pam_authtok);
-     } else {
--        if (flags & FLAGS_USE_2FA
-+        if (flags & PAM_CLI_FLAGS_USE_2FA
-                 || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
-                         && pi->otp_challenge != NULL)) {
-             if (pi->password_prompting) {
-@@ -2062,7 +2053,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
-             return ret;
-         }
- 
--        if (flags & FLAGS_FORWARD_PASS) {
-+        if (flags & PAM_CLI_FLAGS_FORWARD_PASS) {
-             if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_PASSWORD) {
-                 ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_authtok);
-             } else if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA
-@@ -2193,8 +2184,8 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
-     /* we query for the old password during PAM_PRELIM_CHECK to make
-      * pam_sss work e.g. with pam_cracklib */
-     if (pam_flags & PAM_PRELIM_CHECK) {
--        if ( (getuid() != 0 || exp_data ) && !(flags & FLAGS_USE_FIRST_PASS)) {
--            if (flags & FLAGS_USE_2FA
-+        if ( (getuid() != 0 || exp_data ) && !(flags & PAM_CLI_FLAGS_USE_FIRST_PASS)) {
-+            if (flags & PAM_CLI_FLAGS_USE_2FA
-                     || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
-                             && pi->otp_challenge != NULL)) {
-                 if (pi->password_prompting) {
-@@ -2253,7 +2244,7 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
-         }
-     }
- 
--    if (flags & FLAGS_USE_AUTHTOK) {
-+    if (flags & PAM_CLI_FLAGS_USE_AUTHTOK) {
-         pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
-         pi->pam_newauthtok =  strdup(pi->pamstack_authtok);
-         if (pi->pam_newauthtok == NULL) {
-@@ -2268,7 +2259,7 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
-             return ret;
-         }
- 
--        if (flags & FLAGS_FORWARD_PASS) {
-+        if (flags & PAM_CLI_FLAGS_FORWARD_PASS) {
-             ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_newauthtok);
-             if (ret != PAM_SUCCESS) {
-                 D(("Failed to set PAM_AUTHTOK [%s], "
-@@ -2376,10 +2367,10 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-     ret = get_pam_items(pamh, flags, &pi);
-     if (ret != PAM_SUCCESS) {
-         D(("get items returned error: %s", pam_strerror(pamh,ret)));
--        if (flags & FLAGS_IGNORE_UNKNOWN_USER && ret == PAM_USER_UNKNOWN) {
-+        if (flags & PAM_CLI_FLAGS_IGNORE_UNKNOWN_USER && ret == PAM_USER_UNKNOWN) {
-             ret = PAM_IGNORE;
-         }
--        if (flags & FLAGS_IGNORE_AUTHINFO_UNAVAIL
-+        if (flags & PAM_CLI_FLAGS_IGNORE_AUTHINFO_UNAVAIL
-                 && ret == PAM_AUTHINFO_UNAVAIL) {
-             ret = PAM_IGNORE;
-         }
-@@ -2393,13 +2384,13 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-             case SSS_PAM_AUTHENTICATE:
-                 /*
-                  * Only do preauth if
--                 * - FLAGS_USE_FIRST_PASS is not set
--                 * - no password is on the stack or FLAGS_PROMPT_ALWAYS is set
-+                 * - PAM_CLI_FLAGS_USE_FIRST_PASS is not set
-+                 * - no password is on the stack or PAM_CLI_FLAGS_PROMPT_ALWAYS is set
-                  * - preauth indicator file exists.
-                  */
--                if ( !(flags & FLAGS_USE_FIRST_PASS)
-+                if ( !(flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
-                         && (pi.pam_authtok == NULL
--                                || (flags & FLAGS_PROMPT_ALWAYS))
-+                                || (flags & PAM_CLI_FLAGS_PROMPT_ALWAYS))
-                         && access(PAM_PREAUTH_INDICATOR, F_OK) == 0) {
-                     pam_status = send_and_receive(pamh, &pi, SSS_PAM_PREAUTH,
-                                                   quiet_mode);
-@@ -2443,14 +2434,14 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-                  * The means the preauth step has to be done here as well but
-                  * only if
-                  * - PAM_PRELIM_CHECK is set
--                 * - FLAGS_USE_FIRST_PASS is not set
--                 * - no password is on the stack or FLAGS_PROMPT_ALWAYS is set
-+                 * - PAM_CLI_FLAGS_USE_FIRST_PASS is not set
-+                 * - no password is on the stack or PAM_CLI_FLAGS_PROMPT_ALWAYS is set
-                  * - preauth indicator file exists.
-                  */
-                 if ( (pam_flags & PAM_PRELIM_CHECK)
--                        && !(flags & FLAGS_USE_FIRST_PASS)
-+                        && !(flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
-                         && (pi.pam_authtok == NULL
--                                || (flags & FLAGS_PROMPT_ALWAYS))
-+                                || (flags & PAM_CLI_FLAGS_PROMPT_ALWAYS))
-                         && access(PAM_PREAUTH_INDICATOR, F_OK) == 0) {
-                     pam_status = send_and_receive(pamh, &pi, SSS_PAM_PREAUTH,
-                                                   quiet_mode);
-@@ -2497,11 +2488,11 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
- 
-         pam_status = send_and_receive(pamh, &pi, task, quiet_mode);
- 
--        if (flags & FLAGS_IGNORE_UNKNOWN_USER
-+        if (flags & PAM_CLI_FLAGS_IGNORE_UNKNOWN_USER
-                 && pam_status == PAM_USER_UNKNOWN) {
-             pam_status = PAM_IGNORE;
-         }
--        if (flags & FLAGS_IGNORE_AUTHINFO_UNAVAIL
-+        if (flags & PAM_CLI_FLAGS_IGNORE_AUTHINFO_UNAVAIL
-                 && pam_status == PAM_AUTHINFO_UNAVAIL) {
-             pam_status = PAM_IGNORE;
-         }
-@@ -2581,7 +2572,7 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-             retry = true;
-             retries--;
- 
--            flags &= ~FLAGS_USE_FIRST_PASS;
-+            flags &= ~PAM_CLI_FLAGS_USE_FIRST_PASS;
-             ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
-             if (ret != PAM_SUCCESS) {
-                 D(("Failed to unset PAM_AUTHTOK [%s]",
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index 24d28ed4b0acdd627067250970d91a0cb5cb05a0..3404715d811332e9013f3f88cb733c62147fb502 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -365,6 +365,15 @@ enum pam_item_type {
-     SSS_PAM_ITEM_REQUESTED_DOMAINS,
- };
- 
-+#define PAM_CLI_FLAGS_USE_FIRST_PASS (1 << 0)
-+#define PAM_CLI_FLAGS_FORWARD_PASS   (1 << 1)
-+#define PAM_CLI_FLAGS_USE_AUTHTOK    (1 << 2)
-+#define PAM_CLI_FLAGS_IGNORE_UNKNOWN_USER (1 << 3)
-+#define PAM_CLI_FLAGS_IGNORE_AUTHINFO_UNAVAIL (1 << 4)
-+#define PAM_CLI_FLAGS_USE_2FA (1 << 5)
-+#define PAM_CLI_FLAGS_ALLOW_MISSING_NAME (1 << 6)
-+#define PAM_CLI_FLAGS_PROMPT_ALWAYS (1 << 7)
-+
- #define SSS_NSS_MAX_ENTRIES 256
- #define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4)
- struct sss_cli_req_data {
--- 
-2.14.4
-
diff --git a/SOURCES/0040-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch b/SOURCES/0040-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch
new file mode 100644
index 0000000..7001f09
--- /dev/null
+++ b/SOURCES/0040-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch
@@ -0,0 +1,291 @@
+From 141738f80a615ed57c7b49dc619a899b617dd62a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 25 Jun 2019 14:16:31 +0200
+Subject: [PATCH 40/48] 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>
+---
+ 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/0040-pam_sss-add-try_cert_auth-option.patch b/SOURCES/0040-pam_sss-add-try_cert_auth-option.patch
deleted file mode 100644
index 89129f6..0000000
--- a/SOURCES/0040-pam_sss-add-try_cert_auth-option.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From caf7ff9935ce26fa3aba404d9003b8fbcfeb391b Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 17 Sep 2018 17:54:26 +0200
-Subject: [PATCH 40/47] pam_sss: add try_cert_auth option
-
-With this new option pam_sss can be configured to only do Smartcard
-authentication or return an error if this is not possible.
-
-Related to https://pagure.io/SSSD/sssd/issue/3650
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit d3a18f06162b9585d2db936472b75fdbff37162d)
----
- src/man/pam_sss.8.xml    | 23 +++++++++++++++++++++++
- src/sss_client/pam_sss.c |  9 +++++++++
- src/sss_client/sss_cli.h |  1 +
- 3 files changed, 33 insertions(+)
-
-diff --git a/src/man/pam_sss.8.xml b/src/man/pam_sss.8.xml
-index d8e6a2041a17814b0ad506170645a5983cc05704..ca2e8e20678d102525a9252678dd83459c3338ac 100644
---- a/src/man/pam_sss.8.xml
-+++ b/src/man/pam_sss.8.xml
-@@ -50,6 +50,9 @@
-             <arg choice='opt'>
-                 <replaceable>prompt_always</replaceable>
-             </arg>
-+            <arg choice='opt'>
-+                <replaceable>try_cert_auth</replaceable>
-+            </arg>
-         </cmdsynopsis>
-     </refsynopsisdiv>
- 
-@@ -200,6 +203,26 @@ auth sufficient pam_sss.so allow_missing_name
-                     </para>
-                 </listitem>
-             </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>try_cert_auth</option>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Try to use certificate based authentication, i.e.
-+                        authentication with a Smartcard or similar devices. If a
-+                        Smartcard is available and the service is allowed for
-+                        Smartcard authentication the use will be prompted for a
-+                        PIN and the certificate based authentication will
-+                        continue
-+                    </para>
-+                    <para>
-+                        If no Smartcard is available or certificate based
-+                        authentication is not allowed for the current service
-+                        PAM_AUTHINFO_UNAVAIL is returned.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-         </variablelist>
-     </refsect1>
- 
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index b336d1f6197b09c062dd4ece836e088e52fe7393..96ff15adad867aceae17431cd5256ae52e4b9306 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -1997,6 +1997,8 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
-             *flags |= PAM_CLI_FLAGS_ALLOW_MISSING_NAME;
-         } else if (strcmp(*argv, "prompt_always") == 0) {
-             *flags |= PAM_CLI_FLAGS_PROMPT_ALWAYS;
-+        } else if (strcmp(*argv, "try_cert_auth") == 0) {
-+            *flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
-         } else {
-             logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
-         }
-@@ -2405,6 +2407,13 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-                     }
-                 }
- 
-+                if (flags & PAM_CLI_FLAGS_TRY_CERT_AUTH
-+                        && pi.cert_list == NULL) {
-+                    D(("No certificates for authentication available."));
-+                    overwrite_and_free_pam_items(&pi);
-+                    return PAM_AUTHINFO_UNAVAIL;
-+                }
-+
-                 if (strcmp(pi.pam_service, "gdm-smartcard") == 0) {
-                     ret = check_login_token_name(pamh, &pi, quiet_mode);
-                     if (ret != PAM_SUCCESS) {
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index 3404715d811332e9013f3f88cb733c62147fb502..38e3f999d799556a56ac08f0f3a6b538b8cde9f3 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -373,6 +373,7 @@ enum pam_item_type {
- #define PAM_CLI_FLAGS_USE_2FA (1 << 5)
- #define PAM_CLI_FLAGS_ALLOW_MISSING_NAME (1 << 6)
- #define PAM_CLI_FLAGS_PROMPT_ALWAYS (1 << 7)
-+#define PAM_CLI_FLAGS_TRY_CERT_AUTH (1 << 8)
- 
- #define SSS_NSS_MAX_ENTRIES 256
- #define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4)
--- 
-2.14.4
-
diff --git a/SOURCES/0041-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch b/SOURCES/0041-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch
new file mode 100644
index 0000000..7bb9535
--- /dev/null
+++ b/SOURCES/0041-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch
@@ -0,0 +1,495 @@
+From 330507ab3146e877391ff85d4bf6be9ce069e2bd Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 25 Jun 2019 15:05:59 +0200
+Subject: [PATCH 41/48] 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>
+---
+ 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/0041-pam_sss-add-option-require_cert_auth.patch b/SOURCES/0041-pam_sss-add-option-require_cert_auth.patch
deleted file mode 100644
index 7dc8826..0000000
--- a/SOURCES/0041-pam_sss-add-option-require_cert_auth.patch
+++ /dev/null
@@ -1,372 +0,0 @@
-From f724123e20f8d4a1c85473d917da6c65a10d6d62 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 18 Sep 2018 09:53:37 +0200
-Subject: [PATCH 41/47] pam_sss: add option require_cert_auth
-
-With this new option pam_sss will wait until a Smartcard is available
-and then try to authenticate with the help of the Smartcard.
-
-Related https://pagure.io/SSSD/sssd/issue/3650
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 49be8974b490c368d349752f3196af0c9ed28dd5)
----
- src/man/pam_sss.8.xml          | 25 ++++++++++++
- src/responder/pam/pamsrv_cmd.c | 12 ++++++
- src/responder/pam/pamsrv_p11.c |  5 ++-
- src/sss_client/pam_message.c   |  4 ++
- src/sss_client/pam_message.h   |  1 +
- src/sss_client/pam_sss.c       | 92 ++++++++++++++++++++++++++----------------
- src/sss_client/sss_cli.h       |  2 +
- src/util/sss_pam_data.c        |  1 +
- src/util/sss_pam_data.h        |  1 +
- 9 files changed, 107 insertions(+), 36 deletions(-)
-
-diff --git a/src/man/pam_sss.8.xml b/src/man/pam_sss.8.xml
-index ca2e8e20678d102525a9252678dd83459c3338ac..9998519f16c934e0d578760a57cc0908db760bfb 100644
---- a/src/man/pam_sss.8.xml
-+++ b/src/man/pam_sss.8.xml
-@@ -53,6 +53,9 @@
-             <arg choice='opt'>
-                 <replaceable>try_cert_auth</replaceable>
-             </arg>
-+            <arg choice='opt'>
-+                <replaceable>require_cert_auth</replaceable>
-+            </arg>
-         </cmdsynopsis>
-     </refsynopsisdiv>
- 
-@@ -223,6 +226,28 @@ auth sufficient pam_sss.so allow_missing_name
-                     </para>
-                 </listitem>
-             </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>require_cert_auth</option>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Do certificate based authentication, i.e.
-+                        authentication with a Smartcard or similar devices. If a
-+                        Smartcard is not available the user will be prompted to
-+                        insert one. SSSD will wait for a Smartcard until the
-+                        timeout defined by p11_wait_for_card_timeout passed,
-+                        please see
-+                        <citerefentry><refentrytitle>sssd.conf</refentrytitle>
-+                        <manvolnum>5</manvolnum></citerefentry> for details.
-+                    </para>
-+                    <para>
-+                        If no Smartcard is available after the timeout or
-+                        certificate based authentication is not allowed for the
-+                        current service PAM_AUTHINFO_UNAVAIL is returned.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-         </variablelist>
-     </refsect1>
- 
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index c8df32de9e72e9f5ce33e26f0a13101a99f01d5f..6e37f831602e4c367176cc14126dbbec72c858cd 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -317,6 +317,11 @@ static int pam_parse_in_data_v2(struct pam_data *pd,
-                                              size, body, blen, &c);
-                     if (ret != EOK) return ret;
-                     break;
-+                case SSS_PAM_ITEM_FLAGS:
-+                    ret = extract_uint32_t(&pd->cli_flags, size,
-+                                           body, blen, &c);
-+                    if (ret != EOK) return ret;
-+                    break;
-                 default:
-                     DEBUG(SSSDBG_CRIT_FAILURE,
-                           "Ignoring unknown data type [%d].\n", type);
-@@ -1447,6 +1452,13 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
-                   "No certificate found and no logon name given, " \
-                   "authentication not possible.\n");
-             ret = ENOENT;
-+        } else if (pd->cli_flags & PAM_CLI_FLAGS_TRY_CERT_AUTH) {
-+            DEBUG(SSSDBG_TRACE_ALL,
-+                  "try_cert_auth flag set but no certificate available, "
-+                  "request finished.\n");
-+            preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
-+            pam_reply(preq);
-+            return;
-         } else {
-             if (pd->cmd == SSS_PAM_AUTHENTICATE) {
-                 DEBUG(SSSDBG_CRIT_FAILURE,
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index ffa6787e967488ac408ce0f0a11b96066c29b630..8b8859d9d335aec6d310201256522fa8afdd3694 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -721,7 +721,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-     struct timeval tv;
-     int pipefd_to_child[2] = PIPE_INIT;
-     int pipefd_from_child[2] = PIPE_INIT;
--    const char *extra_args[13] = { NULL };
-+    const char *extra_args[14] = { NULL };
-     uint8_t *write_buf = NULL;
-     size_t write_buf_len = 0;
-     size_t arg_c;
-@@ -748,6 +748,9 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
- 
-     /* extra_args are added in revers order */
-     arg_c = 0;
-+    if ((pd->cli_flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) && pd->priv == 1) {
-+        extra_args[arg_c++] = "--wait_for_card";
-+    }
-     extra_args[arg_c++] = nss_db;
-     extra_args[arg_c++] = "--nssdb";
-     if (verify_opts != NULL) {
-diff --git a/src/sss_client/pam_message.c b/src/sss_client/pam_message.c
-index b239f6f53da54054c52e484bdd076193709cb003..036ae2ad17742c123ba59e39a122ea605b7b95a6 100644
---- a/src/sss_client/pam_message.c
-+++ b/src/sss_client/pam_message.c
-@@ -126,6 +126,7 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
-     len += 3*sizeof(uint32_t); /* cli_pid */
-     len += *pi->requested_domains != '\0' ?
-                 2*sizeof(uint32_t) + pi->requested_domains_size : 0;
-+    len += 3*sizeof(uint32_t); /* flags */
- 
-     buf = malloc(len);
-     if (buf == NULL) {
-@@ -164,6 +165,9 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
-                            pi->pam_newauthtok, pi->pam_newauthtok_size,
-                            &buf[rp]);
- 
-+    rp += add_uint32_t_item(SSS_PAM_ITEM_FLAGS, (uint32_t) pi->flags,
-+                            &buf[rp]);
-+
-     SAFEALIGN_SETMEM_UINT32(buf + rp, SSS_END_OF_PAM_REQUEST, &rp);
- 
-     if (rp != len) {
-diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
-index 11526a80a767ff5602b194d14765ff261e8f9707..50fedcd82d8ace520d0360d85d163f91df0cb100 100644
---- a/src/sss_client/pam_message.h
-+++ b/src/sss_client/pam_message.h
-@@ -51,6 +51,7 @@ struct pam_items {
-     enum sss_authtok_type pam_newauthtok_type;
-     size_t pam_newauthtok_size;
-     pid_t cli_pid;
-+    uint32_t flags;
-     const char *login_name;
-     char *domain_name;
-     const char *requested_domains;
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index 96ff15adad867aceae17431cd5256ae52e4b9306..b4c1036ad68a97821f5d0aee873fa18fe5e72683 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -134,6 +134,7 @@ static void free_cai(struct cert_auth_info *cai)
-         free(cai->cert_user);
-         free(cai->cert);
-         free(cai->token_name);
-+        free(cai->module_name);
-         free(cai->key_id);
-         free(cai->prompt_str);
-         free(cai);
-@@ -1247,6 +1248,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
-     pi->cert_list = NULL;
-     pi->selected_cert = NULL;
- 
-+    pi->flags = flags;
-+
-     return PAM_SUCCESS;
- }
- 
-@@ -1267,6 +1270,7 @@ static void print_pam_items(struct pam_items *pi)
-     D(("Newauthtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_newauthtok)));
-     D(("Cli_PID: %d", pi->cli_pid));
-     D(("Requested domains: %s", pi->requested_domains));
-+    D(("Flags: %d", pi->flags));
- }
- 
- static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
-@@ -1999,6 +2003,8 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
-             *flags |= PAM_CLI_FLAGS_PROMPT_ALWAYS;
-         } else if (strcmp(*argv, "try_cert_auth") == 0) {
-             *flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
-+        } else if (strcmp(*argv, "require_cert_auth") == 0) {
-+            *flags |= PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
-         } else {
-             logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
-         }
-@@ -2274,55 +2280,51 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
-     return PAM_SUCCESS;
- }
- 
--#define SC_ENTER_FMT "Please enter smart card labeled\n %s\nand press enter"
-+#define SC_ENTER_LABEL_FMT "Please enter smart card labeled\n %s"
-+#define SC_ENTER_FMT "Please enter smart card"
- 
- static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
--                                  bool quiet_mode)
-+                                  int retries, bool quiet_mode)
- {
-     int ret;
-     int pam_status;
-     char *login_token_name;
-     char *prompt = NULL;
--    size_t size;
--    char *answer = NULL;
--    /* TODO: check multiple cert case */
--    struct cert_auth_info *cai = pi->cert_list;
--
--    if (cai == NULL) {
--        D(("No certificate information available"));
--        return EINVAL;
--    }
-+    uint32_t orig_flags = pi->flags;
- 
-     login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
-+    if (login_token_name == NULL
-+            && !(pi->flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH)) {
-+        return PAM_SUCCESS;
-+    }
-+
-     if (login_token_name == NULL) {
--        return PAM_SUCCESS;
-+        ret = asprintf(&prompt, SC_ENTER_FMT);
-+    } else {
-+        ret = asprintf(&prompt, SC_ENTER_LABEL_FMT, login_token_name);
-+    }
-+    if (ret == -1) {
-+        return ENOMEM;
-     }
- 
--    while (cai->token_name == NULL
--               || strcmp(login_token_name, cai->token_name) != 0) {
--        size = sizeof(SC_ENTER_FMT) + strlen(login_token_name);
--        prompt = malloc(size);
--        if (prompt == NULL) {
--            D(("malloc failed."));
--            return ENOMEM;
--        }
-+    pi->flags |= PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
-+
-+    /* TODO: check multiple cert case */
-+    while (pi->cert_list == NULL || pi->cert_list->token_name == NULL
-+                || (login_token_name != NULL
-+                        && strcmp(login_token_name,
-+                                  pi->cert_list->token_name) != 0)) {
- 
--        ret = snprintf(prompt, size, SC_ENTER_FMT,
--                       login_token_name);
--        if (ret < 0 || ret >= size) {
--            D(("snprintf failed."));
--            free(prompt);
--            return EFAULT;
-+        if (retries < 0) {
-+            ret = PAM_AUTHINFO_UNAVAIL;
-+            goto done;
-         }
-+        retries--;
- 
--        ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt,
--                                  NULL, &answer);
--        free(prompt);
-+        ret = do_pam_conversation(pamh, PAM_TEXT_INFO, prompt, NULL, NULL);
-         if (ret != PAM_SUCCESS) {
-             D(("do_pam_conversation failed."));
--            return ret;
--        } else {
--            free(answer);
-+            goto done;
-         }
- 
-         pam_status = send_and_receive(pamh, pi, SSS_PAM_PREAUTH, quiet_mode);
-@@ -2335,7 +2337,14 @@ static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
-         }
-     }
- 
--    return PAM_SUCCESS;
-+    ret = PAM_SUCCESS;
-+
-+done:
-+
-+    pi->flags = orig_flags;
-+    free(prompt);
-+
-+    return ret;
- }
- 
- static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-@@ -2394,8 +2403,19 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-                         && (pi.pam_authtok == NULL
-                                 || (flags & PAM_CLI_FLAGS_PROMPT_ALWAYS))
-                         && access(PAM_PREAUTH_INDICATOR, F_OK) == 0) {
-+
-+                    if (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) {
-+                        /* Do not use PAM_CLI_FLAGS_REQUIRE_CERT_AUTH in the first
-+                         * SSS_PAM_PREAUTH run. In case a card is already inserted
-+                         * we do not have to prompt to insert a card. */
-+                        pi.flags &= ~PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
-+                        pi.flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
-+                    }
-+
-                     pam_status = send_and_receive(pamh, &pi, SSS_PAM_PREAUTH,
-                                                   quiet_mode);
-+
-+                    pi.flags = flags;
-                     if (pam_status != PAM_SUCCESS) {
-                         D(("send_and_receive returned [%d] during pre-auth",
-                            pam_status));
-@@ -2414,8 +2434,10 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-                     return PAM_AUTHINFO_UNAVAIL;
-                 }
- 
--                if (strcmp(pi.pam_service, "gdm-smartcard") == 0) {
--                    ret = check_login_token_name(pamh, &pi, quiet_mode);
-+                if (strcmp(pi.pam_service, "gdm-smartcard") == 0
-+                        || (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH)) {
-+                    ret = check_login_token_name(pamh, &pi, retries,
-+                                                 quiet_mode);
-                     if (ret != PAM_SUCCESS) {
-                         D(("check_login_token_name failed.\n"));
-                         return ret;
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index 38e3f999d799556a56ac08f0f3a6b538b8cde9f3..af8a43916d43b631092941fed13c520273a1acc5 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -363,6 +363,7 @@ enum pam_item_type {
-     SSS_PAM_ITEM_CLI_LOCALE,
-     SSS_PAM_ITEM_CLI_PID,
-     SSS_PAM_ITEM_REQUESTED_DOMAINS,
-+    SSS_PAM_ITEM_FLAGS,
- };
- 
- #define PAM_CLI_FLAGS_USE_FIRST_PASS (1 << 0)
-@@ -374,6 +375,7 @@ enum pam_item_type {
- #define PAM_CLI_FLAGS_ALLOW_MISSING_NAME (1 << 6)
- #define PAM_CLI_FLAGS_PROMPT_ALWAYS (1 << 7)
- #define PAM_CLI_FLAGS_TRY_CERT_AUTH (1 << 8)
-+#define PAM_CLI_FLAGS_REQUIRE_CERT_AUTH (1 << 9)
- 
- #define SSS_NSS_MAX_ENTRIES 256
- #define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4)
-diff --git a/src/util/sss_pam_data.c b/src/util/sss_pam_data.c
-index 5e41349b9e98974563bf55c41ce36c26b897ac99..cb8779c1dff04832f623eb518d2b010107d4b045 100644
---- a/src/util/sss_pam_data.c
-+++ b/src/util/sss_pam_data.c
-@@ -176,6 +176,7 @@ void pam_print_data(int l, struct pam_data *pd)
-     DEBUG(l, "priv: %d\n", pd->priv);
-     DEBUG(l, "cli_pid: %d\n", pd->cli_pid);
-     DEBUG(l, "logon name: %s\n", PAM_SAFE_ITEM(pd->logon_name));
-+    DEBUG(l, "flags: %d\n", pd->cli_flags);
- }
- 
- int pam_add_response(struct pam_data *pd, enum response_type type,
-diff --git a/src/util/sss_pam_data.h b/src/util/sss_pam_data.h
-index 7d74fa6a0026d3964f33c8529063b1dceae45688..c9898105418fc76b45d78883a0520f37d0ae1c05 100644
---- a/src/util/sss_pam_data.h
-+++ b/src/util/sss_pam_data.h
-@@ -58,6 +58,7 @@ struct pam_data {
-     struct sss_auth_token *newauthtok;
-     uint32_t cli_pid;
-     char *logon_name;
-+    uint32_t cli_flags;
- 
-     int pam_status;
-     int response_delay;
--- 
-2.14.4
-
diff --git a/SOURCES/0042-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch b/SOURCES/0042-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch
new file mode 100644
index 0000000..4540691
--- /dev/null
+++ b/SOURCES/0042-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch
@@ -0,0 +1,300 @@
+From 01572f3d8c18dcbd4836522ee5e24bd0739e0255 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 25 Jun 2019 15:01:15 +0200
+Subject: [PATCH 42/48] 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>
+---
+ 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/0042-intg-require-SC-tests.patch b/SOURCES/0042-intg-require-SC-tests.patch
deleted file mode 100644
index a8c7e18..0000000
--- a/SOURCES/0042-intg-require-SC-tests.patch
+++ /dev/null
@@ -1,310 +0,0 @@
-From 0c56f4aee8115081cf0ee32cceb8c1dc56945e6f Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 26 Sep 2018 11:48:37 +0200
-Subject: [PATCH 42/47] intg: require SC tests
-
-Integration test for the new try_cert_auth and require_cert_auth option
-for pam_sss.
-
-Related to https://pagure.io/SSSD/sssd/issue/3650
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 5cdb6968f407c7bcaba69f4892f51fd6426dddb2)
----
- src/tests/intg/Makefile.am           |  16 ++-
- src/tests/intg/test_pam_responder.py | 188 +++++++++++++++++++++++++++++++----
- 2 files changed, 182 insertions(+), 22 deletions(-)
-
-diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
-index bb3a7f01ae4f79fa05cd661993e8f9872ecd0450..44fb6353ad031fc9edac291ce70aa7557999509d 100644
---- a/src/tests/intg/Makefile.am
-+++ b/src/tests/intg/Makefile.am
-@@ -113,6 +113,20 @@ pam_sss_service:
- 	echo "password required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- 	echo "session  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- 
-+pam_sss_sc_required:
-+	$(MKDIR_P) $(PAM_SERVICE_DIR)
-+	echo "auth     required       $(DESTDIR)$(pammoddir)/pam_sss.so require_cert_auth retry=1"  > $(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_try_sc:
-+	$(MKDIR_P) $(PAM_SERVICE_DIR)
-+	echo "auth     required       $(DESTDIR)$(pammoddir)/pam_sss.so try_cert_auth"  > $(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:
-@@ -127,7 +141,7 @@ 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
-+intgcheck-installed: config.py passwd group pam_sss_service pam_sss_sc_required pam_sss_try_sc
- 	pipepath="$(DESTDIR)$(pipepath)"; \
- 	if test $${#pipepath} -gt 80; then \
- 	    echo "error: Pipe directory path too long," \
-diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
-index c6d048cd342838fe312287eaffff734e30ba9e1c..06f69a3d82f5502fd5ae1928d81db0287e582e88 100644
---- a/src/tests/intg/test_pam_responder.py
-+++ b/src/tests/intg/test_pam_responder.py
-@@ -41,6 +41,11 @@ USER1 = dict(name='user1', passwd='x', uid=10001, gid=20001,
-              dir='/home/user1',
-              shell='/bin/bash')
- 
-+USER2 = dict(name='user2', passwd='x', uid=10002, gid=20002,
-+             gecos='User with no Smartcard mapping',
-+             dir='/home/user2',
-+             shell='/bin/bash')
-+
- 
- def format_pam_cert_auth_conf(config):
-     """Format a basic SSSD configuration"""
-@@ -55,8 +60,11 @@ def format_pam_cert_auth_conf(config):
- 
-         [pam]
-         pam_cert_auth = True
--        pam_p11_allowed_services = +pam_sss_service
-+        pam_p11_allowed_services = +pam_sss_service, +pam_sss_sc_required, \
-+                                   +pam_sss_try_sc
-         pam_cert_db_path = {config.PAM_CERT_DB_PATH}
-+        p11_child_timeout = 5
-+        p11_wait_for_card_timeout = 5
-         debug_level = 10
- 
-         [domain/auth_only]
-@@ -149,6 +157,15 @@ def create_nssdb():
-     pkcs11_txt.close()
- 
- 
-+def create_nssdb_no_cert():
-+    os.mkdir(config.SYSCONFDIR + "/pki")
-+    os.mkdir(config.SYSCONFDIR + "/pki/nssdb")
-+    if subprocess.call(["certutil", "-N", "-d",
-+                        "sql:" + config.SYSCONFDIR + "/pki/nssdb/",
-+                        "--empty-password"]) != 0:
-+        raise Exception("certutil failed")
-+
-+
- def cleanup_nssdb():
-     shutil.rmtree(config.SYSCONFDIR + "/pki")
- 
-@@ -158,14 +175,42 @@ def create_nssdb_fixture(request):
-     request.addfinalizer(cleanup_nssdb)
- 
- 
-+def create_nssdb_no_cert_fixture(request):
-+    create_nssdb_no_cert()
-+    request.addfinalizer(cleanup_nssdb)
-+
-+
- @pytest.fixture
--def simple_pam_cert_auth(request):
-+def simple_pam_cert_auth(request, passwd_ops_setup):
-     """Setup SSSD with pam_cert_auth=True"""
-     config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
-     conf = format_pam_cert_auth_conf(config)
-     create_conf_fixture(request, conf)
-     create_sssd_fixture(request)
-     create_nssdb_fixture(request)
-+    passwd_ops_setup.useradd(**USER1)
-+    passwd_ops_setup.useradd(**USER2)
-+    return None
-+
-+
-+@pytest.fixture
-+def simple_pam_cert_auth_no_cert(request, passwd_ops_setup):
-+    """Setup SSSD with pam_cert_auth=True"""
-+    config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
-+
-+    old_softhsm2_conf = os.environ['SOFTHSM2_CONF']
-+    del os.environ['SOFTHSM2_CONF']
-+
-+    conf = format_pam_cert_auth_conf(config)
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    create_nssdb_no_cert_fixture(request)
-+
-+    os.environ['SOFTHSM2_CONF'] = old_softhsm2_conf
-+
-+    passwd_ops_setup.useradd(**USER1)
-+    passwd_ops_setup.useradd(**USER2)
-+
-     return None
- 
- 
-@@ -176,26 +221,26 @@ def test_preauth_indicator(simple_pam_cert_auth):
- 
- 
- @pytest.fixture
--def pam_wrapper_setup(request):
-+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']
- 
--def test_sc_auth_wrong_pin(simple_pam_cert_auth, pam_wrapper_setup,
--                           passwd_ops_setup):
-+    return env_for_sssctl
- 
--    passwd_ops_setup.useradd(**USER1)
--    current_env = os.environ.copy()
--    current_env['PAM_WRAPPER'] = "1"
--    current_env['SSSD_INTG_PEER_UID'] = "0"
--    current_env['SSSD_INTG_PEER_GID'] = "0"
--    current_env['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
-+
-+def test_sc_auth_wrong_pin(simple_pam_cert_auth, env_for_sssctl):
- 
-     sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-                                "--action=auth", "--service=pam_sss_service"],
-                               universal_newlines=True,
--                              env=current_env, stdin=subprocess.PIPE,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- 
-     try:
-@@ -214,19 +259,120 @@ def test_sc_auth_wrong_pin(simple_pam_cert_auth, pam_wrapper_setup,
-                     "Authentication failure") != -1
- 
- 
--def test_sc_auth(simple_pam_cert_auth, pam_wrapper_setup, passwd_ops_setup):
--
--    passwd_ops_setup.useradd(**USER1)
--    current_env = os.environ.copy()
--    current_env['PAM_WRAPPER'] = "1"
--    current_env['SSSD_INTG_PEER_UID'] = "0"
--    current_env['SSSD_INTG_PEER_GID'] = "0"
--    current_env['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
-+def test_sc_auth(simple_pam_cert_auth, env_for_sssctl):
- 
-     sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-                                "--action=auth", "--service=pam_sss_service"],
-                               universal_newlines=True,
--                              env=current_env, stdin=subprocess.PIPE,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-+
-+    try:
-+        out, err = sssctl.communicate(input="123456")
-+    except:
-+        sssctl.kill()
-+        out, err = sssctl.communicate()
-+
-+    sssctl.stdin.close()
-+    sssctl.stdout.close()
-+
-+    if sssctl.wait() != 0:
-+        raise Exception("sssctl failed")
-+
-+    assert err.find("pam_authenticate for user [user1]: Success") != -1
-+
-+
-+def test_require_sc_auth(simple_pam_cert_auth, env_for_sssctl):
-+
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-+                               "--action=auth",
-+                               "--service=pam_sss_sc_required"],
-+                              universal_newlines=True,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-+
-+    try:
-+        out, err = sssctl.communicate(input="123456")
-+    except:
-+        sssctl.kill()
-+        out, err = sssctl.communicate()
-+
-+    sssctl.stdin.close()
-+    sssctl.stdout.close()
-+
-+    if sssctl.wait() != 0:
-+        raise Exception("sssctl failed")
-+
-+    assert err.find("pam_authenticate for user [user1]: Success") != -1
-+
-+
-+def test_require_sc_auth_no_cert(simple_pam_cert_auth_no_cert, env_for_sssctl):
-+
-+    # We have to wait about 20s before the command returns because there will
-+    # be 2 run since retry=1 in the PAM configuration and both
-+    # p11_child_timeout and p11_wait_for_card_timeout are 5s in sssd.conf,
-+    # so 2*(5+5)=20. */
-+    start_time = time.time()
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-+                               "--action=auth",
-+                               "--service=pam_sss_sc_required"],
-+                              universal_newlines=True,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-+
-+    try:
-+        out, err = sssctl.communicate(input="123456")
-+    except:
-+        sssctl.kill()
-+        out, err = sssctl.communicate()
-+
-+    sssctl.stdin.close()
-+    sssctl.stdout.close()
-+
-+    if sssctl.wait() != 0:
-+        raise Exception("sssctl failed")
-+
-+    end_time = time.time()
-+    assert end_time > start_time and \
-+        (end_time - start_time) >= 20 and \
-+        (end_time - start_time) < 40
-+    assert out.find("Please enter smart card\nPlease enter smart card") != -1
-+    assert err.find("pam_authenticate for user [user1]: Authentication " +
-+                    "service cannot retrieve authentication info") != -1
-+
-+
-+def test_try_sc_auth_no_map(simple_pam_cert_auth, env_for_sssctl):
-+
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user2",
-+                               "--action=auth",
-+                               "--service=pam_sss_try_sc"],
-+                              universal_newlines=True,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-+
-+    try:
-+        out, err = sssctl.communicate(input="123456")
-+    except:
-+        sssctl.kill()
-+        out, err = sssctl.communicate()
-+
-+    sssctl.stdin.close()
-+    sssctl.stdout.close()
-+
-+    if sssctl.wait() != 0:
-+        raise Exception("sssctl failed")
-+
-+    assert err.find("pam_authenticate for user [user2]: Authentication " +
-+                    "service cannot retrieve authentication info") != -1
-+
-+
-+def test_try_sc_auth(simple_pam_cert_auth, env_for_sssctl):
-+
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
-+                               "--action=auth",
-+                               "--service=pam_sss_try_sc"],
-+                              universal_newlines=True,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- 
-     try:
--- 
-2.14.4
-
diff --git a/SOURCES/0043-MAN-Amend-the-documentation-for-the-background-refre.patch b/SOURCES/0043-MAN-Amend-the-documentation-for-the-background-refre.patch
new file mode 100644
index 0000000..27c03ac
--- /dev/null
+++ b/SOURCES/0043-MAN-Amend-the-documentation-for-the-background-refre.patch
@@ -0,0 +1,36 @@
+From 67ede7a6e6199f39f8c62e3ad56c1702fc0b4298 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 26 Jun 2019 12:43:45 +0200
+Subject: [PATCH 43/48] MAN: Amend the documentation for the background refresh
+
+Related: https://pagure.io/SSSD/sssd/issue/4012
+
+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 337543e56..3b4840793 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2170,7 +2170,15 @@ p11_uri = library-description=OpenSC%20smartcard%20framework;slot-id=2
+                         </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/0043-p11_child-show-PKCS-11-URI-in-debug-output.patch b/SOURCES/0043-p11_child-show-PKCS-11-URI-in-debug-output.patch
deleted file mode 100644
index 1b0cf16..0000000
--- a/SOURCES/0043-p11_child-show-PKCS-11-URI-in-debug-output.patch
+++ /dev/null
@@ -1,408 +0,0 @@
-From d931db919e85fda2bfc195403c81b873ca94c4d4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 8 Oct 2018 10:45:28 +0200
-Subject: [PATCH 43/47] p11_child: show PKCS#11 URI in debug output
-
-Related to https://pagure.io/SSSD/sssd/issue/3814
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 46fd681a73ffef062cd027e7018e1a02d7a0a9df)
----
- src/p11_child/p11_child_nss.c     | 240 ++++++++++++++++++++++++++++++++++++++
- src/p11_child/p11_child_openssl.c |  80 +++++++++++++
- 2 files changed, 320 insertions(+)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index b2777d1d245d4942263ebf0610eef5cf6a528bd1..fff1f2525878b596e518b717476e892d1cf2ddae 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -39,6 +39,7 @@
- #include <pk11pub.h>
- #include <prerror.h>
- #include <ocsp.h>
-+#include <pkcs11uri.h>
- 
- #include "util/child_common.h"
- #include "providers/backend.h"
-@@ -63,6 +64,239 @@ struct p11_ctx {
-                     | certificateUsageStatusResponder \
-                     | certificateUsageSSLCA )
- 
-+
-+static char *get_pkcs11_string(TALLOC_CTX *mem_ctx, const char *in, size_t len)
-+{
-+    size_t c = len;
-+
-+    if (in == NULL || len == 0) {
-+        return NULL;
-+    }
-+
-+    while(c > 0 && in[c - 1] == ' ') {
-+        c--;
-+    }
-+
-+    return talloc_strndup(mem_ctx, in, c);
-+}
-+
-+static char *pct_encode(TALLOC_CTX *mem_ctx, SECItem *data)
-+{
-+    char *pct;
-+    size_t c;
-+    int ret;
-+
-+    pct = talloc_zero_size(mem_ctx, sizeof(char) * (3*data->len + 1));
-+    if (pct == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
-+        return NULL;
-+    }
-+
-+    for (c = 0; c < data->len; c++) {
-+        ret = snprintf(pct + 3*c, 4, "%%%02X", data->data[c]);
-+        if (ret != 3) {
-+            DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
-+            talloc_free(pct);
-+            return NULL;
-+        }
-+    }
-+
-+    return pct;
-+}
-+
-+static char *get_key_id_pct(TALLOC_CTX *mem_ctx, PK11SlotInfo *slot,
-+                            CERTCertificate *cert)
-+{
-+    SECItem *key_id = NULL;
-+    char *key_id_str = NULL;
-+
-+    key_id = PK11_GetLowLevelKeyIDForCert(slot, cert, NULL);
-+    if (key_id == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "PK11_GetLowLevelKeyIDForCert failed [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-+        return NULL;
-+    }
-+
-+    key_id_str = pct_encode(mem_ctx, key_id);
-+    SECITEM_FreeItem(key_id, PR_TRUE);
-+    if (key_id_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "pct_encode failed.\n");
-+        return NULL;
-+    }
-+
-+    return key_id_str;
-+}
-+
-+static char *get_pkcs11_uri(TALLOC_CTX *mem_ctx, SECMODModule *mod,
-+                            PK11SlotInfo *slot,
-+                            const char *label, CERTCertificate *cert)
-+{
-+    CK_INFO module_info;
-+    CK_SLOT_INFO slot_info;
-+    CK_TOKEN_INFO token_info;
-+    char *values[13];
-+    PK11URIAttribute attrs[13];
-+    size_t nattrs = 0;
-+    SECStatus rv;
-+    char *tmp_str;
-+    char *uri_str;
-+    PK11URI *uri;
-+    CK_SLOT_ID slot_id;
-+    char *id_pct;
-+
-+    rv = PK11_GetModInfo(mod, &module_info);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetModInfo failed.\n");
-+        return NULL;
-+    }
-+
-+    rv = PK11_GetSlotInfo(slot, &slot_info);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetSlotInfo failed.\n");
-+        return NULL;
-+    }
-+
-+    rv = PK11_GetTokenInfo(slot, &token_info);
-+    if (rv != SECSuccess) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetTokenInfo failed.\n");
-+        return NULL;
-+    }
-+    values[nattrs] = get_pkcs11_string(mem_ctx,
-+                                       (char *)module_info.libraryDescription,
-+                                       sizeof(module_info.libraryDescription));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_LIBRARY_DESCRIPTION;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx,
-+                                       (char *)module_info.manufacturerID,
-+                                       sizeof(module_info.manufacturerID));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_LIBRARY_MANUFACTURER;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = talloc_asprintf(mem_ctx, "%d.%d",
-+                                     module_info.libraryVersion.major,
-+                                     module_info.libraryVersion.minor);
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_LIBRARY_VERSION;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx,
-+                                       (char *)slot_info.slotDescription,
-+                                       sizeof(slot_info.slotDescription));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_SLOT_DESCRIPTION;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx,
-+                                       (char *)slot_info.manufacturerID,
-+                                       sizeof(slot_info.manufacturerID));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_SLOT_MANUFACTURER;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    slot_id = PK11_GetSlotID(slot);
-+    values[nattrs] = talloc_asprintf(mem_ctx, "%d", (int) slot_id);
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_SLOT_ID;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx, (char *)token_info.model,
-+                                       sizeof(token_info.model));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_MODEL;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx,
-+                                       (char *)token_info.manufacturerID,
-+                                       sizeof(token_info.manufacturerID));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_MANUFACTURER;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx,
-+                                       (char *)token_info.serialNumber,
-+                                       sizeof(token_info.serialNumber));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_SERIAL;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    values[nattrs] = get_pkcs11_string(mem_ctx, (char *)token_info.label,
-+                                       sizeof(token_info.label));
-+    if (values[nattrs] != NULL && *values[nattrs] != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_TOKEN;
-+        attrs[nattrs].value = values[nattrs];
-+        nattrs++;
-+    }
-+
-+    if (label != NULL && *label != '\0') {
-+        attrs[nattrs].name = PK11URI_PATTR_OBJECT;
-+        attrs[nattrs].value = label;
-+        nattrs++;
-+    }
-+
-+    attrs[nattrs].name = PK11URI_PATTR_TYPE;
-+    attrs[nattrs].value = "cert";
-+    nattrs++;
-+
-+    uri = PK11URI_CreateURI(attrs, nattrs, NULL, 0);
-+    if (uri == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11URI_CreateURI failed.\n");
-+        return NULL;
-+    }
-+
-+    tmp_str = PK11URI_FormatURI(NULL, uri);
-+    PK11URI_DestroyURI(uri);
-+    if (tmp_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11URI_FormatURI failed.\n");
-+        return NULL;
-+    }
-+
-+    /* Currently I have no idea how to get the ID properly formatted with the
-+     * NSS  PK11 calls. Since all attribute values are treated as strings zeros
-+     * in the IDs cannot be handled. And the IDs cannot be set percent-encoded
-+     * since all attribute values will be escaped which means the '%' sign
-+     * will be escaped to '%25'. Hence for the time being the ID is added
-+     * manually to the end of the URI. */
-+    id_pct = get_key_id_pct(mem_ctx, slot, cert);
-+    if (id_pct == NULL || *id_pct == '\0') {
-+        DEBUG(SSSDBG_OP_FAILURE, "get_key_id_pct failed.\n");
-+        PORT_Free(tmp_str);
-+        return NULL;
-+    }
-+
-+    uri_str = talloc_asprintf(mem_ctx, "%s;%s=%s", tmp_str,
-+                                                   PK11URI_PATTR_ID, id_pct);
-+    talloc_free(id_pct);
-+    if (uri_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
-+        return NULL;
-+    }
-+
-+    return uri_str;
-+
-+}
-+
- static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg)
- {
-   /* give up if 1) no password was supplied, or 2) the password has already
-@@ -465,6 +699,9 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-               cert_list_node->cert->nickname,
-               cert_list_node->cert->subjectName);
- 
-+        DEBUG(SSSDBG_TRACE_ALL, "module uri: %s.\n", PK11_GetModuleURI(module));
-+        DEBUG(SSSDBG_TRACE_ALL, "token uri: %s.\n", PK11_GetTokenURI(slot));
-+
-         if (p11_ctx->handle != NULL) {
-             if (!do_verification(p11_ctx, cert_list_node->cert)) {
-                 DEBUG(SSSDBG_OP_FAILURE,
-@@ -651,6 +888,9 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
- 
-         DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n",
-               key_id_str);
-+        DEBUG(SSSDBG_TRACE_ALL, "uri: %s.\n", get_pkcs11_uri(mem_ctx, module,
-+                                                             slot, label,
-+                                                             found_cert));
- 
-         multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n%s\n",
-                                        token_name, module_name, key_id_str,
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index d4572d99cd3a3186128b46cc4a9453d716bd7979..09edeefbdf95e151af97cd4b4e5811569386caec 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -29,6 +29,7 @@
- #include <openssl/err.h>
- #include <openssl/rand.h>
- #include <p11-kit/p11-kit.h>
-+#include <p11-kit/uri.h>
- 
- #include <popt.h>
- 
-@@ -43,6 +44,72 @@ struct p11_ctx {
-     bool wait_for_card;
- };
- 
-+
-+static char *get_pkcs11_uri(TALLOC_CTX *mem_ctx, CK_INFO *module_info,
-+                            CK_SLOT_INFO *slot_info, CK_SLOT_ID slot_id,
-+                            CK_TOKEN_INFO *token_info, CK_ATTRIBUTE *label,
-+                            CK_ATTRIBUTE *id)
-+{
-+    P11KitUri *uri;
-+    char *uri_str = NULL;
-+    char *tmp_str = NULL;
-+    int ret;
-+    CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
-+    CK_ATTRIBUTE class_attr = {CKA_CLASS, &cert_class, sizeof(CK_OBJECT_CLASS)};
-+
-+    uri = p11_kit_uri_new();
-+    if (uri == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "p11_kit_uri_new failed.\n");
-+        return NULL;
-+    }
-+
-+    ret = p11_kit_uri_set_attribute(uri, label);
-+    if (ret != P11_KIT_URI_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "p11_kit_uri_set_attribute failed.\n");
-+        goto done;
-+    }
-+
-+    ret = p11_kit_uri_set_attribute(uri, id);
-+    if (ret != P11_KIT_URI_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "p11_kit_uri_set_attribute failed.\n");
-+        goto done;
-+    }
-+
-+    ret = p11_kit_uri_set_attribute(uri, &class_attr);
-+    if (ret != P11_KIT_URI_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "p11_kit_uri_set_attribute failed.\n");
-+        goto done;
-+    }
-+
-+
-+    memcpy(p11_kit_uri_get_token_info(uri), token_info, sizeof(CK_TOKEN_INFO));
-+
-+    memcpy(p11_kit_uri_get_slot_info(uri), slot_info, sizeof(CK_SLOT_INFO));
-+    ret = p11_kit_uri_set_slot_id(uri, slot_id);
-+
-+    memcpy(p11_kit_uri_get_module_info(uri), module_info, sizeof(CK_INFO));
-+
-+    ret = p11_kit_uri_format(uri, P11_KIT_URI_FOR_ANY, &tmp_str);
-+    if (ret != P11_KIT_URI_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "p11_kit_uri_format failed [%s].\n",
-+                                 p11_kit_uri_message(ret));
-+        goto done;
-+    }
-+
-+    if (tmp_str != NULL) {
-+        uri_str = talloc_strdup(mem_ctx, tmp_str);
-+        free(tmp_str);
-+        if (uri_str == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+        }
-+    }
-+
-+done:
-+    p11_kit_uri_free(uri);
-+
-+    return uri_str;
-+}
-+
- static int talloc_cleanup_openssl(struct p11_ctx *p11_ctx)
- {
-     CRYPTO_cleanup_all_ex_data();
-@@ -234,6 +301,7 @@ struct cert_list {
-     X509 *cert;
-     char *subject_dn;
-     char *cert_b64;
-+    char *uri;
-     CK_KEY_TYPE key_type;
-     CK_OBJECT_HANDLE private_key;
- };
-@@ -608,6 +676,7 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     CK_SLOT_ID slot_id;
-     CK_SLOT_INFO info;
-     CK_TOKEN_INFO token_info;
-+    CK_INFO module_info;
-     CK_RV rv;
-     size_t module_id;
-     char *module_file_name = NULL;
-@@ -821,6 +890,17 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-         }
-     }
- 
-+    memset(&module_info, 0, sizeof(CK_INFO));
-+    module->C_GetInfo(&module_info);
-+
-+    DLIST_FOR_EACH(item, cert_list) {
-+        item->uri = get_pkcs11_uri(mem_ctx, &module_info, &info, slot_id,
-+                                   &token_info,
-+                                   &item->attributes[1] /* label */,
-+                                   &item->attributes[0] /* id */);
-+        DEBUG(SSSDBG_TRACE_ALL, "uri: %s.\n", item->uri);
-+    }
-+
-     /* TODO: check module_name_in, token_name_in, key_id_in */
- 
-     if (cert_list == NULL) {
--- 
-2.14.4
-
diff --git a/SOURCES/0044-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch b/SOURCES/0044-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch
new file mode 100644
index 0000000..8a169cd
--- /dev/null
+++ b/SOURCES/0044-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch
@@ -0,0 +1,216 @@
+From 4ba4b2d96b59386f3fd4d8bb0c4ada4798db48b0 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 1 Jul 2019 14:15:29 +0200
+Subject: [PATCH 44/48] 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>
+---
+ 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 28801e030..56fd770e4 100644
+--- a/src/db/sysdb.h
++++ b/src/db/sysdb.h
+@@ -1113,6 +1113,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 55ba62140..c57a13be1 100644
+--- a/src/db/sysdb_ops.c
++++ b/src/db/sysdb_ops.c
+@@ -3277,6 +3277,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 748d88674..d5b3823ac 100644
+--- a/src/providers/data_provider/dp_target_id.c
++++ b/src/providers/data_provider/dp_target_id.c
+@@ -390,69 +390,22 @@ done:
+     return ret;
+ }
+ 
+-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/0044-p11_child-add-PKCS-11-uri-to-restrict-selection.patch b/SOURCES/0044-p11_child-add-PKCS-11-uri-to-restrict-selection.patch
deleted file mode 100644
index bc0eb02..0000000
--- a/SOURCES/0044-p11_child-add-PKCS-11-uri-to-restrict-selection.patch
+++ /dev/null
@@ -1,239 +0,0 @@
-From d0830a4445115ef4cdbc8b524794f276f7954f7a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 8 Oct 2018 12:47:25 +0200
-Subject: [PATCH 44/47] p11_child: add PKCS#11 uri to restrict selection
-
-Related to https://pagure.io/SSSD/sssd/issue/3814
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit f7b2152a4c3c816a5bc4226a0e01791313accef3)
----
- src/p11_child/p11_child.h         |  2 +-
- src/p11_child/p11_child_common.c  |  9 +++--
- src/p11_child/p11_child_nss.c     |  2 +-
- src/p11_child/p11_child_openssl.c | 81 +++++++++++++++++++++++++++++++++++++--
- 4 files changed, 86 insertions(+), 8 deletions(-)
-
-diff --git a/src/p11_child/p11_child.h b/src/p11_child/p11_child.h
-index dd8fdeafbf947aad930e61ae694bc99df6d8212a..92ecf74a891e46f93e8dee69391bec6325fe2249 100644
---- a/src/p11_child/p11_child.h
-+++ b/src/p11_child/p11_child.h
-@@ -54,5 +54,5 @@ bool do_verification_b64(struct p11_ctx *p11_ctx, const char *cert_b64);
- errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-                 enum op_mode mode, const char *pin,
-                 const char *module_name_in, const char *token_name_in,
--                const char *key_id_in, char **_multi);
-+                const char *key_id_in, const char *uri, char **_multi);
- #endif /* __P11_CHILD_H__ */
-diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c
-index bc5f6b09b191f0ea853f45d8a78bc6e4a69c3da7..097e7fa07fb4d90e087250aec9f971b4a2afdb52 100644
---- a/src/p11_child/p11_child_common.c
-+++ b/src/p11_child/p11_child_common.c
-@@ -60,7 +60,7 @@ static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db,
-                    bool wait_for_card,
-                    const char *cert_b64, const char *pin,
-                    const char *module_name, const char *token_name,
--                   const char *key_id, char **multi)
-+                   const char *key_id, const char *uri, char **multi)
- {
-     int ret;
-     struct p11_ctx *p11_ctx;
-@@ -90,7 +90,7 @@ static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db,
-         }
-     } else {
-         ret = do_card(mem_ctx, p11_ctx, mode, pin,
--                      module_name, token_name, key_id, multi);
-+                      module_name, token_name, key_id, uri, multi);
-     }
- 
- done:
-@@ -159,6 +159,7 @@ int main(int argc, const char *argv[])
-     char *key_id = NULL;
-     char *cert_b64 = NULL;
-     bool wait_for_card = false;
-+    char *uri = NULL;
- 
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-@@ -194,6 +195,8 @@ int main(int argc, const char *argv[])
-          _("Key ID for authentication"), NULL},
-         {"certificate", 0, POPT_ARG_STRING, &cert_b64, 0,
-          _("certificate to verify, base64 encoded"), NULL},
-+        {"uri", 0, POPT_ARG_STRING, &uri, 0,
-+         _("PKCS#11 URI to restrict selection"), NULL},
-         POPT_TABLEEND
-     };
- 
-@@ -367,7 +370,7 @@ int main(int argc, const char *argv[])
-     }
- 
-     ret = do_work(main_ctx, mode, nss_db, cert_verify_opts, wait_for_card,
--                  cert_b64, pin, module_name, token_name, key_id, &multi);
-+                  cert_b64, pin, module_name, token_name, key_id, uri, &multi);
-     if (ret != 0) {
-         DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n");
-         goto fail;
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index fff1f2525878b596e518b717476e892d1cf2ddae..f9cbf3f37a26c7fefe2106aa9db4b006faaf4e1a 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -480,7 +480,7 @@ bool do_verification_b64(struct p11_ctx *p11_ctx, const char *cert_b64)
- errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-                 enum op_mode mode, const char *pin,
-                 const char *module_name_in, const char *token_name_in,
--                const char *key_id_in, char **_multi)
-+                const char *key_id_in, const char *uri, char **_multi)
- {
-     int ret;
-     SECStatus rv;
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index 09edeefbdf95e151af97cd4b4e5811569386caec..000e1c94f11edc32abceafb39e98b16ca0664c50 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -85,7 +85,7 @@ static char *get_pkcs11_uri(TALLOC_CTX *mem_ctx, CK_INFO *module_info,
-     memcpy(p11_kit_uri_get_token_info(uri), token_info, sizeof(CK_TOKEN_INFO));
- 
-     memcpy(p11_kit_uri_get_slot_info(uri), slot_info, sizeof(CK_SLOT_INFO));
--    ret = p11_kit_uri_set_slot_id(uri, slot_id);
-+    p11_kit_uri_set_slot_id(uri, slot_id);
- 
-     memcpy(p11_kit_uri_get_module_info(uri), module_info, sizeof(CK_INFO));
- 
-@@ -662,7 +662,7 @@ static errno_t wait_for_card(CK_FUNCTION_LIST *module, CK_SLOT_ID *slot_id)
- errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-                 enum op_mode mode, const char *pin,
-                 const char *module_name_in, const char *token_name_in,
--                const char *key_id_in, char **_multi)
-+                const char *key_id_in, const char *uri_str, char **_multi)
- {
-     int ret;
-     size_t c;
-@@ -674,6 +674,7 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     CK_ULONG num_slots;
-     CK_SLOT_ID slots[MAX_SLOTS];
-     CK_SLOT_ID slot_id;
-+    CK_SLOT_ID uri_slot_id;
-     CK_SLOT_INFO info;
-     CK_TOKEN_INFO token_info;
-     CK_INFO module_info;
-@@ -690,6 +691,19 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     char *multi = NULL;
-     bool pkcs11_session = false;
-     bool pkcs11_login = false;
-+    P11KitUri *uri = NULL;
-+
-+    if (uri_str != NULL) {
-+        uri = p11_kit_uri_new();
-+        ret = p11_kit_uri_parse(uri_str, P11_KIT_URI_FOR_ANY, uri);
-+        if (ret != P11_KIT_URI_OK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "p11_kit_uri_parse failed [%d][%s].\n",
-+                                     ret, p11_kit_uri_message(ret));
-+            ret = EINVAL;
-+            goto done;
-+        }
-+    }
-+
- 
-     /* Maybe use P11_KIT_MODULE_TRUSTED ? */
-     modules = p11_kit_modules_load_and_initialize(0);
-@@ -709,6 +723,23 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-             free(mod_name);
-             free(mod_file_name);
- 
-+            if (uri != NULL) {
-+                memset(&module_info, 0, sizeof(CK_INFO));
-+                rv = modules[c]->C_GetInfo(&module_info);
-+                if (rv != CKR_OK) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "C_GetInfo failed.\n");
-+                    ret = EIO;
-+                    goto done;
-+                }
-+
-+                /* Skip modules which do not match the PKCS#11 URI */
-+                if (p11_kit_uri_match_module_info(uri, &module_info) != 1) {
-+                    DEBUG(SSSDBG_TRACE_ALL,
-+                          "Not matching URI [%s], skipping.\n", uri_str);
-+                    continue;
-+                }
-+            }
-+
-             num_slots = MAX_SLOTS;
-             rv = modules[c]->C_GetSlotList(CK_FALSE, slots, &num_slots);
-             if (rv != CKR_OK) {
-@@ -730,6 +761,37 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-                       info.slotDescription, info.manufacturerID, info.flags,
-                       (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
-                       (info.flags & CKF_TOKEN_PRESENT) ? "true": "false");
-+
-+                /* Skip slots which do not match the PKCS#11 URI */
-+                if (uri != NULL) {
-+                    uri_slot_id = p11_kit_uri_get_slot_id(uri);
-+                    if ((uri_slot_id != (CK_SLOT_ID)-1
-+                                && uri_slot_id != slots[s])
-+                            || p11_kit_uri_match_slot_info(uri, &info) != 1) {
-+                        DEBUG(SSSDBG_TRACE_ALL,
-+                              "Not matching URI [%s], skipping.\n", uri_str);
-+                        continue;
-+                    }
-+                }
-+
-+                if ((info.flags & CKF_TOKEN_PRESENT) && uri != NULL) {
-+                    rv = modules[c]->C_GetTokenInfo(slots[s], &token_info);
-+                    if (rv != CKR_OK) {
-+                        DEBUG(SSSDBG_OP_FAILURE, "C_GetTokenInfo failed.\n");
-+                        ret = EIO;
-+                        goto done;
-+                    }
-+                    DEBUG(SSSDBG_TRACE_ALL, "Token label [%s].\n",
-+                          token_info.label);
-+
-+                    if (p11_kit_uri_match_token_info(uri, &token_info) != 1) {
-+                        DEBUG(SSSDBG_CONF_SETTINGS,
-+                              "No matching uri [%s], skipping.\n", uri_str);
-+                        continue;
-+                    }
-+
-+                }
-+
-                 if ((info.flags & CKF_REMOVABLE_DEVICE)) {
-                     break;
-                 }
-@@ -788,6 +850,13 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-         goto done;
-     }
- 
-+    if (uri != NULL && p11_kit_uri_match_token_info(uri, &token_info) != 1) {
-+        DEBUG(SSSDBG_CONF_SETTINGS, "No token matching uri [%s] found.",
-+                                    uri_str);
-+        ret = ENOENT;
-+        goto done;
-+    }
-+
-     module_id = c;
-     slot_name = p11_kit_space_strdup(info.slotDescription,
-                                      sizeof(info.slotDescription));
-@@ -891,7 +960,12 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-     }
- 
-     memset(&module_info, 0, sizeof(CK_INFO));
--    module->C_GetInfo(&module_info);
-+    rv = module->C_GetInfo(&module_info);
-+    if (rv != CKR_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "C_GetInfo failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
- 
-     DLIST_FOR_EACH(item, cert_list) {
-         item->uri = get_pkcs11_uri(mem_ctx, &module_info, &info, slot_id,
-@@ -970,6 +1044,7 @@ done:
-     free(token_name);
-     free(module_file_name);
-     p11_kit_modules_finalize_and_release(modules);
-+    p11_kit_uri_free(uri);
- 
-     return ret;
- }
--- 
-2.14.4
-
diff --git a/SOURCES/0045-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch b/SOURCES/0045-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch
new file mode 100644
index 0000000..0f181c7
--- /dev/null
+++ b/SOURCES/0045-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch
@@ -0,0 +1,137 @@
+From 073f79ecb75ded427d93c5f8925076646b736b1c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 1 Jul 2019 14:26:38 +0200
+Subject: [PATCH 45/48] 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>
+---
+ 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/0045-PAM-add-p11_uri-option.patch b/SOURCES/0045-PAM-add-p11_uri-option.patch
deleted file mode 100644
index e495f08..0000000
--- a/SOURCES/0045-PAM-add-p11_uri-option.patch
+++ /dev/null
@@ -1,194 +0,0 @@
-From 7e7252616137378731af75a8482d4a4cade33dbd Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 9 Oct 2018 10:47:04 +0200
-Subject: [PATCH 45/47] PAM: add p11_uri option
-
-Related to https://pagure.io/SSSD/sssd/issue/3814
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 725b65081d19da658b16338686c53dcf16d49de0)
----
- src/confdb/confdb.h                  |  1 +
- src/config/SSSDConfig/__init__.py.in |  1 +
- src/config/cfg_rules.ini             |  1 +
- src/config/etc/sssd.api.conf         |  1 +
- src/man/sssd.conf.5.xml              | 33 +++++++++++++++++++++++++++++++++
- src/responder/pam/pamsrv.h           |  1 +
- src/responder/pam/pamsrv_cmd.c       | 12 +++++++++++-
- src/responder/pam/pamsrv_p11.c       |  9 ++++++++-
- 8 files changed, 57 insertions(+), 2 deletions(-)
-
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 87904c2146b33b57106ac3799c5a67ee02387e9b..741d4bc47dc77fe23e2ff0bc683354909f61d88f 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -133,6 +133,7 @@
- #define CONFDB_PAM_WAIT_FOR_CARD_TIMEOUT "p11_wait_for_card_timeout"
- #define CONFDB_PAM_APP_SERVICES "pam_app_services"
- #define CONFDB_PAM_P11_ALLOWED_SERVICES "pam_p11_allowed_services"
-+#define CONFDB_PAM_P11_URI "p11_uri"
- 
- /* SUDO */
- #define CONFDB_SUDO_CONF_ENTRY "config/sudo"
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index 4d1dba2d22eae4716fbabe3a3957952f7cd17751..a20157c719765a847a872fe134afe5e0415296db 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -105,6 +105,7 @@ option_strings = {
-     'pam_app_services' : _('Which PAM services are permitted to contact application domains'),
-     'pam_p11_allowed_services' : _('Allowed services for using smartcards'),
-     'p11_wait_for_card_timeout' : _('Additional timeout to wait for a card if requested'),
-+    'p11_uri' : _('PKCS#11 URI to restrict the selection of devices for Smartcard authentication'),
- 
-     # [sudo]
-     'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'),
-diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
-index 717ccfa3f382b92800bf00ed79f68641a5a83d5c..85366d25dfe508c0faf92d7d0891e287eb66dbe0 100644
---- a/src/config/cfg_rules.ini
-+++ b/src/config/cfg_rules.ini
-@@ -128,6 +128,7 @@ option = p11_child_timeout
- option = pam_app_services
- option = pam_p11_allowed_services
- option = p11_wait_for_card_timeout
-+option = p11_uri
- 
- [rule/allowed_sudo_options]
- validator = ini_allowed_options
-diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
-index bb686c34480be27d0829b57a853fa05921730630..c6d6690fb44cafb19b0a01b286812c74cdb2fc71 100644
---- a/src/config/etc/sssd.api.conf
-+++ b/src/config/etc/sssd.api.conf
-@@ -77,6 +77,7 @@ p11_child_timeout = int, None, false
- pam_app_services = str, None, false
- pam_p11_allowed_services = str, None, false
- p11_wait_for_card_timeout = int, None, false
-+p11_uri = str, None, false
- 
- [sudo]
- # sudo service
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 4df0163311fb3845e6a027be7d0b500cb5d2f0b6..c8d53f01f3eedea1e37f6593d02ce1eeaf11d2de 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -1478,6 +1478,39 @@ pam_p11_allowed_services = +my_pam_service, -login
-                         </para>
-                     </listitem>
-                 </varlistentry>
-+                <varlistentry>
-+                    <term>p11_uri (string)</term>
-+                    <listitem>
-+                        <para>
-+                            PKCS#11 URI (see RFC-7512 for details) which can be
-+                            used to restrict the selection of devices used for
-+                            Smartcard authentication. By default SSSD's
-+                            p11_child will search for a PKCS#11 slot (reader)
-+                            where the 'removable' flags is set and read the
-+                            certificates from the inserted token from the first
-+                            slot found. If multiple readers are connected
-+                            p11_uri can be use to tell p11_child to use a
-+                            specific reader.
-+                        </para>
-+                        <para>
-+                            Example:
-+                            <programlisting>
-+p11_uri = slot-description=My%20Smartcar%20Reader
-+                            </programlisting>
-+                            or
-+                            <programlisting>
-+p11_uri = library-description=OpenSC%20smartcard%20framework;slot-id=2
-+                            </programlisting>
-+                            To find suitable URI please check the debug output
-+                            of p11_child. As an alternative the GnuTLS utility
-+                            'p11tool' with e.g. the '--list-all' will show
-+                            PKCS#11 URIs as well.
-+                        </para>
-+                        <para>
-+                            Default: none
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-             </variablelist>
-         </refsect2>
- 
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index 5d877566fc7bacced4f6385f1eae344a9e6d8bd4..60aa97967456b9b7ab35e64f103c1c9a17bef3a9 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -103,6 +103,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        time_t timeout,
-                                        const char *verify_opts,
-                                        struct sss_certmap_ctx *sss_certmap_ctx,
-+                                       const char *uri,
-                                        struct pam_data *pd);
- errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-                             struct cert_auth_info **cert_list);
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index 6e37f831602e4c367176cc14126dbbec72c858cd..a22afd225894872847a0fb13e202f927fd2ae124 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1306,6 +1306,7 @@ static errno_t check_cert(TALLOC_CTX *mctx,
-     char *cert_verification_opts;
-     errno_t ret;
-     struct tevent_req *req;
-+    char *uri = NULL;
- 
-     ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
-                          CONFDB_PAM_P11_CHILD_TIMEOUT,
-@@ -1342,10 +1343,19 @@ static errno_t check_cert(TALLOC_CTX *mctx,
-         return ret;
-     }
- 
-+    ret = confdb_get_string(pctx->rctx->cdb, mctx, CONFDB_PAM_CONF_ENTRY,
-+                            CONFDB_PAM_P11_URI, NULL, &uri);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to read certificate_verification from confdb: [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        return ret;
-+    }
-+
-     req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd,
-                               pctx->nss_db, p11_child_timeout,
-                               cert_verification_opts, pctx->sss_certmap_ctx,
--                              pd);
-+                              uri, pd);
-     if (req == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
-         return ENOMEM;
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index 8b8859d9d335aec6d310201256522fa8afdd3694..491bd2b01d7bf9137b37c35f9da9eca1eed95a6d 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -711,6 +711,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        time_t timeout,
-                                        const char *verify_opts,
-                                        struct sss_certmap_ctx *sss_certmap_ctx,
-+                                       const char *uri,
-                                        struct pam_data *pd)
- {
-     errno_t ret;
-@@ -721,7 +722,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-     struct timeval tv;
-     int pipefd_to_child[2] = PIPE_INIT;
-     int pipefd_from_child[2] = PIPE_INIT;
--    const char *extra_args[14] = { NULL };
-+    const char *extra_args[16] = { NULL };
-     uint8_t *write_buf = NULL;
-     size_t write_buf_len = 0;
-     size_t arg_c;
-@@ -748,6 +749,12 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
- 
-     /* extra_args are added in revers order */
-     arg_c = 0;
-+    if (uri != NULL) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Adding PKCS#11 URI [%s].\n", uri);
-+        extra_args[arg_c++] = uri;
-+        extra_args[arg_c++] = "--uri";
-+    }
-+
-     if ((pd->cli_flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) && pd->priv == 1) {
-         extra_args[arg_c++] = "--wait_for_card";
-     }
--- 
-2.14.4
-
diff --git a/SOURCES/0046-BE-Introduce-flag-for-be_ptask_create.patch b/SOURCES/0046-BE-Introduce-flag-for-be_ptask_create.patch
new file mode 100644
index 0000000..ae2b940
--- /dev/null
+++ b/SOURCES/0046-BE-Introduce-flag-for-be_ptask_create.patch
@@ -0,0 +1,536 @@
+From c5a0909216c406ce3e23d6f41146daf2bb303226 Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Fri, 19 Jul 2019 13:05:44 +0200
+Subject: [PATCH 46/48] BE: Introduce flag for be_ptask_create
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The be_ptask_create has already too many parameters. Lets have flags
+parameter to avoid future extending.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ad/ad_dyndns.c             |  2 +-
+ src/providers/ad/ad_machine_pw_renewal.c |  2 +-
+ src/providers/ad/ad_subdomains.c         |  2 +-
+ src/providers/be_ptask.c                 | 17 +++++-
+ src/providers/be_ptask.h                 | 10 ++++
+ src/providers/be_ptask_private.h         |  1 +
+ src/providers/be_refresh.c               |  2 +-
+ src/providers/data_provider_be.c         |  2 +-
+ src/providers/ipa/ipa_dyndns.c           |  2 +-
+ src/providers/ipa/ipa_subdomains.c       |  2 +-
+ src/providers/ldap/ldap_id_cleanup.c     |  2 +-
+ src/providers/ldap/ldap_id_enum.c        |  2 +-
+ src/providers/ldap/sdap_sudo_shared.c    |  4 +-
+ src/tests/cmocka/test_be_ptask.c         | 67 +++++++++++++++---------
+ 14 files changed, 80 insertions(+), 37 deletions(-)
+
+diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
+index 02ea7f24b..af765b581 100644
+--- a/src/providers/ad/ad_dyndns.c
++++ b/src/providers/ad/ad_dyndns.c
+@@ -101,7 +101,7 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
+     ret = be_ptask_create(ad_opts, be_ctx, period, ptask_first_delay, 0, 0, period,
+                           BE_PTASK_OFFLINE_DISABLE, BE_PTASK_SCHEDULE_FROM_LAST, 0,
+                           ad_dyndns_update_send, ad_dyndns_update_recv, ad_opts,
+-                          "Dyndns update", NULL);
++                          "Dyndns update", 0, NULL);
+ 
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c
+index 47941dfbf..67802c04a 100644
+--- a/src/providers/ad/ad_machine_pw_renewal.c
++++ b/src/providers/ad/ad_machine_pw_renewal.c
+@@ -388,7 +388,7 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
+                           ad_machine_account_password_renewal_send,
+                           ad_machine_account_password_renewal_recv,
+                           renewal_data,
+-                          "AD machine account password renewal", NULL);
++                          "AD machine account password renewal", 0, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "be_ptask_create failed.\n");
+         goto done;
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 2510498da..0f46b46ad 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -2070,7 +2070,7 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,
+                           ad_subdomains_ptask_send, ad_subdomains_ptask_recv, sd_ctx,
+-                          "Subdomains Refresh", NULL);
++                          "Subdomains Refresh", 0, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c
+index 32d9a03ce..56c9c82fe 100644
+--- a/src/providers/be_ptask.c
++++ b/src/providers/be_ptask.c
+@@ -208,6 +208,12 @@ static void be_ptask_schedule(struct be_ptask *task,
+         delay = task->enabled_delay;
+         break;
+     case BE_PTASK_PERIOD:
++        if (task->flags & BE_PTASK_NO_PERIODIC) {
++            /* Periodic task is disabled, */
++            /* only online/offline change can cause some activity. */
++            return;
++        }
++
+         delay = task->period;
+ 
+         if (backoff_allowed(task) && task->period * 2 <= task->max_backoff) {
+@@ -269,16 +275,21 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         be_ptask_recv_t recv_fn,
+                         void *pvt,
+                         const char *name,
++                        uint32_t flags,
+                         struct be_ptask **_task)
+ {
+     struct be_ptask *task = NULL;
+     errno_t ret;
+ 
+-    if (be_ctx == NULL || period == 0 || send_fn == NULL || recv_fn == NULL
++    if (be_ctx == NULL || send_fn == NULL || recv_fn == NULL
+         || name == NULL) {
+         return EINVAL;
+     }
+ 
++    if (period == 0 && (flags & BE_PTASK_NO_PERIODIC) == 0) {
++        return EINVAL;
++    }
++
+     task = talloc_zero(mem_ctx, struct be_ptask);
+     if (task == NULL) {
+         ret = ENOMEM;
+@@ -306,6 +317,7 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
++    task->flags = flags;
+     task->enabled = true;
+ 
+     talloc_set_destructor((TALLOC_CTX*)task, be_ptask_destructor);
+@@ -451,6 +463,7 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+                              be_ptask_sync_t fn,
+                              void *pvt,
+                              const char *name,
++                             uint32_t flags,
+                              struct be_ptask **_task)
+ {
+     errno_t ret;
+@@ -469,7 +482,7 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+                           enabled_delay, random_offset, timeout, offline,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           max_backoff, be_ptask_sync_send, be_ptask_sync_recv,
+-                          ctx, name, _task);
++                          ctx, name, flags, _task);
+     if (ret != EOK) {
+         goto done;
+     }
+diff --git a/src/providers/be_ptask.h b/src/providers/be_ptask.h
+index c23278e88..a33443965 100644
+--- a/src/providers/be_ptask.h
++++ b/src/providers/be_ptask.h
+@@ -30,6 +30,14 @@ struct be_ctx;
+ 
+ struct be_ptask;
+ 
++/* be_ptask flags */
++
++/**
++ * Do not schedule periodic task. This flag is useful for tasks that
++ * should be performend only when there is offline/online change.
++ */
++#define BE_PTASK_NO_PERIODIC         0x0001
++
+ /**
+  * Defines how should task behave when back end is offline.
+  */
+@@ -127,6 +135,7 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         be_ptask_recv_t recv_fn,
+                         void *pvt,
+                         const char *name,
++                        uint32_t flags,
+                         struct be_ptask **_task);
+ 
+ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+@@ -141,6 +150,7 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+                              be_ptask_sync_t fn,
+                              void *pvt,
+                              const char *name,
++                             uint32_t flags,
+                              struct be_ptask **_task);
+ 
+ void be_ptask_enable(struct be_ptask *task);
+diff --git a/src/providers/be_ptask_private.h b/src/providers/be_ptask_private.h
+index e89105f95..496a2f9ae 100644
+--- a/src/providers/be_ptask_private.h
++++ b/src/providers/be_ptask_private.h
+@@ -43,6 +43,7 @@ struct be_ptask {
+     time_t last_execution;  /* last time when send was called */
+     struct tevent_req *req; /* active tevent request */
+     struct tevent_timer *timer; /* active tevent timer */
++    uint32_t flags;
+     bool enabled;
+ };
+ 
+diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
+index 8f50e231d..687d3f022 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -177,7 +177,7 @@ static errno_t be_refresh_ctx_init(struct be_ctx *be_ctx,
+                               BE_PTASK_SCHEDULE_FROM_NOW,
+                               0,
+                               be_refresh_send, be_refresh_recv,
+-                              ctx, "Refresh Records", NULL);
++                              ctx, "Refresh Records", 0, NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+                   "Unable to initialize refresh periodic task [%d]: %s\n",
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index 877841055..f21669b8c 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -133,7 +133,7 @@ void be_mark_offline(struct be_ctx *ctx)
+                                    BE_PTASK_OFFLINE_EXECUTE,
+                                    3600 /* max_backoff */,
+                                    try_to_go_online,
+-                                   ctx, "Check if online (periodic)",
++                                   ctx, "Check if online (periodic)", 0,
+                                    &ctx->check_if_online_ptask);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
+index 8e8ff5a4f..27852c2e2 100644
+--- a/src/providers/ipa/ipa_dyndns.c
++++ b/src/providers/ipa/ipa_dyndns.c
+@@ -78,7 +78,7 @@ errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,
+                           ipa_dyndns_update_send, ipa_dyndns_update_recv, ctx,
+-                          "Dyndns update", NULL);
++                          "Dyndns update", 0, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 3a17c851d..13e49c5c0 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -3138,7 +3138,7 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,
+                           ipa_subdomains_ptask_send, ipa_subdomains_ptask_recv, sd_ctx,
+-                          "Subdomains Refresh", NULL);
++                          "Subdomains Refresh", 0, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
+index e50fb0f22..df56f4da4 100644
+--- a/src/providers/ldap/ldap_id_cleanup.c
++++ b/src/providers/ldap/ldap_id_cleanup.c
+@@ -88,7 +88,7 @@ errno_t ldap_setup_cleanup(struct sdap_id_ctx *id_ctx,
+     ret = be_ptask_create_sync(sdom, id_ctx->be, period, first_delay,
+                                5 /* enabled delay */, 0 /* random offset */,
+                                period /* timeout */, BE_PTASK_OFFLINE_SKIP, 0,
+-                               ldap_cleanup_task, cleanup_ctx, name,
++                               ldap_cleanup_task, cleanup_ctx, name, 0,
+                                &sdom->cleanup_task);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize cleanup periodic "
+diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
+index 062185c55..2137f6821 100644
+--- a/src/providers/ldap/ldap_id_enum.c
++++ b/src/providers/ldap/ldap_id_enum.c
+@@ -102,7 +102,7 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,                        /* max_backoff */
+                           send_fn, recv_fn,
+-                          ectx, "enumeration", &sdom->enum_task);
++                          ectx, "enumeration", 0, &sdom->enum_task);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "Unable to initialize enumeration periodic task\n");
+diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c
+index a00d8e6a9..59356bd44 100644
+--- a/src/providers/ldap/sdap_sudo_shared.c
++++ b/src/providers/ldap/sdap_sudo_shared.c
+@@ -94,7 +94,7 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx,
+                               BE_PTASK_SCHEDULE_FROM_LAST,
+                               0,
+                               full_send_fn, full_recv_fn, pvt,
+-                              "SUDO Full Refresh", NULL);
++                              "SUDO Full Refresh", 0, NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask "
+                   "[%d]: %s\n", ret, sss_strerror(ret));
+@@ -113,7 +113,7 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx,
+                               BE_PTASK_SCHEDULE_FROM_LAST,
+                               0,
+                               smart_send_fn, smart_recv_fn, pvt,
+-                              "SUDO Smart Refresh", NULL);
++                              "SUDO Smart Refresh", 0, NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask "
+                   "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/tests/cmocka/test_be_ptask.c b/src/tests/cmocka/test_be_ptask.c
+index 03b1165bb..ac8c0767f 100644
+--- a/src/tests/cmocka/test_be_ptask.c
++++ b/src/tests/cmocka/test_be_ptask.c
+@@ -306,7 +306,7 @@ void test_be_ptask_create_einval_be(void **state)
+     ret = be_ptask_create(test_ctx, NULL, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, NULL, "Test ptask", &ptask);
++                          test_be_ptask_recv, NULL, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -320,7 +320,7 @@ void test_be_ptask_create_einval_period(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, 0, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, NULL, "Test ptask", &ptask);
++                          test_be_ptask_recv, NULL, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -334,7 +334,7 @@ void test_be_ptask_create_einval_send(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, NULL,
+-                          test_be_ptask_recv, NULL, "Test ptask", &ptask);
++                          test_be_ptask_recv, NULL, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -348,7 +348,7 @@ void test_be_ptask_create_einval_recv(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          NULL, NULL, "Test ptask", &ptask);
++                          NULL, NULL, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -362,7 +362,7 @@ void test_be_ptask_create_einval_name(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, NULL, NULL, &ptask);
++                          test_be_ptask_recv, NULL, NULL, 0, &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -378,7 +378,7 @@ void test_be_ptask_create_no_delay(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -406,7 +406,7 @@ void test_be_ptask_create_first_delay(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, DELAY, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -432,7 +432,7 @@ void test_be_ptask_disable(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -457,7 +457,7 @@ void test_be_ptask_enable(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -490,7 +490,7 @@ void test_be_ptask_enable_delay(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, DELAY, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -530,7 +530,7 @@ void test_be_ptask_offline_skip(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -565,7 +565,7 @@ void test_be_ptask_offline_disable(void **state)
+                           BE_PTASK_OFFLINE_DISABLE,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -597,7 +597,7 @@ void test_be_ptask_offline_execute(void **state)
+                           BE_PTASK_OFFLINE_EXECUTE,
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -625,7 +625,7 @@ void test_be_ptask_reschedule_ok(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -657,7 +657,7 @@ void test_be_ptask_reschedule_null(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_null_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0,
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -685,7 +685,7 @@ void test_be_ptask_reschedule_error(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_error_recv, test_ctx, "Test ptask",
++                          test_be_ptask_error_recv, test_ctx, "Test ptask", 0,
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -713,7 +713,7 @@ void test_be_ptask_reschedule_timeout(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 1,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_timeout_send,
+-                          test_be_ptask_error_recv, test_ctx, "Test ptask",
++                          test_be_ptask_error_recv, test_ctx, "Test ptask", 0,
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -751,7 +751,7 @@ void test_be_ptask_reschedule_backoff(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           PERIOD*2, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -806,7 +806,7 @@ void test_be_ptask_get_period(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+ 
+@@ -827,7 +827,7 @@ void test_be_ptask_get_timeout(void **state)
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, TIMEOUT,
+                           BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+ 
+@@ -838,6 +838,24 @@ void test_be_ptask_get_timeout(void **state)
+     assert_null(ptask);
+ }
+ 
++void test_be_ptask_no_periodic(void **state)
++{
++    struct test_ctx *test_ctx = (struct test_ctx *)(*state);
++    struct be_ptask *ptask = NULL;
++    errno_t ret;
++
++    ret = be_ptask_create(test_ctx, test_ctx->be_ctx, 0, 0, DELAY, 0, 0,
++                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
++                          0, test_be_ptask_send,
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_NO_PERIODIC, &ptask);
++    assert_int_equal(ret, ERR_OK);
++    assert_non_null(ptask);
++
++    be_ptask_destroy(&ptask);
++    assert_null(ptask);
++}
++
+ void test_be_ptask_create_sync(void **state)
+ {
+     struct test_ctx *test_ctx = (struct test_ctx *)(*state);
+@@ -848,7 +866,7 @@ void test_be_ptask_create_sync(void **state)
+     now = get_current_time();
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                                BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_sync,
+-                               test_ctx, "Test ptask", &ptask);
++                               test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -876,7 +894,7 @@ void test_be_ptask_sync_reschedule_ok(void **state)
+     now = get_current_time();
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                                BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_sync,
+-                               test_ctx, "Test ptask", &ptask);
++                               test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -908,7 +926,7 @@ void test_be_ptask_sync_reschedule_error(void **state)
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                                BE_PTASK_OFFLINE_SKIP, 0,
+                                test_be_ptask_sync_error,
+-                               test_ctx, "Test ptask", &ptask);
++                               test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -938,7 +956,7 @@ void test_be_ptask_sync_reschedule_backoff(void **state)
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+                                BE_PTASK_OFFLINE_SKIP, PERIOD*2,
+                                test_be_ptask_sync_error,
+-                               test_ctx, "Test ptask", &ptask);
++                               test_ctx, "Test ptask", 0, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -1014,6 +1032,7 @@ int main(int argc, const char *argv[])
+         new_test(be_ptask_reschedule_backoff),
+         new_test(be_ptask_get_period),
+         new_test(be_ptask_get_timeout),
++        new_test(be_ptask_no_periodic),
+         new_test(be_ptask_create_sync),
+         new_test(be_ptask_sync_reschedule_ok),
+         new_test(be_ptask_sync_reschedule_error),
+-- 
+2.20.1
+
diff --git a/SOURCES/0046-tests-add-PKCS-11-URI-tests.patch b/SOURCES/0046-tests-add-PKCS-11-URI-tests.patch
deleted file mode 100644
index a63bb54..0000000
--- a/SOURCES/0046-tests-add-PKCS-11-URI-tests.patch
+++ /dev/null
@@ -1,210 +0,0 @@
-From b2a979e5e66f463d9567165fa7a46a39a9e6ae18 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 9 Oct 2018 10:46:43 +0200
-Subject: [PATCH 46/47] tests: add PKCS#11 URI tests
-
-Related to https://pagure.io/SSSD/sssd/issue/3814
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 4a22fb6bba6662ad628f6e17203e8ccf20eb9666)
----
- src/tests/cmocka/test_pam_srv.c | 120 ++++++++++++++++++++++++++++++++++++++++
- src/tests/test_CA/Makefile.am   |  16 +++++-
- 2 files changed, 135 insertions(+), 1 deletion(-)
-
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 2b02ac27b7356c5bce9e11dae785ecdbddd31aa3..7fc9224e152b8c206faf5d0cd9b6778099c6605c 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -65,6 +65,7 @@
- #endif
- 
- #define TEST_TOKEN_NAME "SSSD Test Token"
-+#define TEST_TOKEN2_NAME "SSSD Test Token Number 2"
- #define TEST_KEY_ID "C554C9F82C2A9D58B70921C143304153A8A42F17"
- #ifdef HAVE_NSS
- #define TEST_MODULE_NAME "NSS-Internal"
-@@ -961,6 +962,54 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-     return EOK;
- }
- 
-+static int test_pam_cert2_token2_check_ex(uint32_t status, uint8_t *body,
-+                                          size_t blen, enum response_type type,
-+                                          const char *name)
-+{
-+    size_t rp = 0;
-+    uint32_t val;
-+    size_t check2_len = 0;
-+    char const *check2_strings[] = { NULL,
-+                                     TEST_TOKEN2_NAME,
-+                                     TEST_MODULE_NAME,
-+                                     TEST2_KEY_ID,
-+                                     TEST2_PROMPT,
-+                                     NULL };
-+
-+    assert_int_equal(status, 0);
-+
-+    check2_strings[0] = name;
-+    check2_len = check_string_array_len(check2_strings);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, pam_test_ctx->exp_pam_status);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, 2);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, SSS_PAM_DOMAIN_NAME);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, 9);
-+
-+    assert_int_equal(*(body + rp + val - 1), 0);
-+    assert_string_equal(body + rp, TEST_DOM_NAME);
-+    rp += val;
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, type);
-+
-+    SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+    assert_int_equal(val, check2_len);
-+
-+    check_string_array(check2_strings, body, &rp);
-+
-+    assert_int_equal(rp, blen);
-+
-+    return EOK;
-+}
-+
- static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
- {
-     return test_pam_cert_check_ex(status, body, blen,
-@@ -968,6 +1017,12 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
-                                   NULL);
- }
- 
-+static int test_pam_cert2_check(uint32_t status, uint8_t *body, size_t blen)
-+{
-+    return test_pam_cert2_token2_check_ex(status, body, blen, SSS_PAM_CERT_INFO,
-+                                          "pamuser@"TEST_DOM_NAME);
-+}
-+
- static int test_pam_cert_check_auth_success(uint32_t status, uint8_t *body,
-                                             size_t blen)
- {
-@@ -2476,6 +2531,65 @@ void test_pam_cert_auth_2certs_one_mapping(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+void test_pam_cert_preauth_uri_token1(void **state)
-+{
-+    int ret;
-+
-+    struct sss_test_conf_param pam_params[] = {
-+        { CONFDB_PAM_P11_URI, "pkcs11:token=SSSD%20Test%20Token" },
-+        { NULL, NULL },             /* Sentinel */
-+    };
-+
-+    ret = add_pam_params(pam_params, pam_test_ctx->rctx->cdb);
-+    assert_int_equal(ret, EOK);
-+    set_cert_auth_param(pam_test_ctx->pctx, CA_DB);
-+    putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2tokens.conf"));
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-+                        test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, false);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_pam_cert_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_pam_cert_preauth_uri_token2(void **state)
-+{
-+    int ret;
-+
-+    struct sss_test_conf_param pam_params[] = {
-+        { CONFDB_PAM_P11_URI, "pkcs11:token=SSSD%20Test%20Token%20Number%202" },
-+        { NULL, NULL },             /* Sentinel */
-+    };
-+
-+    ret = add_pam_params(pam_params, pam_test_ctx->rctx->cdb);
-+    assert_int_equal(ret, EOK);
-+    set_cert_auth_param(pam_test_ctx->pctx, CA_DB);
-+    putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2tokens.conf"));
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-+                        test_lookup_by_cert_cb, SSSD_TEST_CERT_0002, false);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_pam_cert2_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
- 
- void test_filter_response(void **state)
- {
-@@ -2915,6 +3029,12 @@ int main(int argc, const char *argv[])
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id,
-                                         pam_test_setup, pam_test_teardown),
-+#ifndef HAVE_NSS
-+        cmocka_unit_test_setup_teardown(test_pam_cert_preauth_uri_token1,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_cert_preauth_uri_token2,
-+                                        pam_test_setup, pam_test_teardown),
-+#endif /* ! HAVE_NSS */
- #endif /* HAVE_TEST_CA */
- 
-         cmocka_unit_test_setup_teardown(test_filter_response,
-diff --git a/src/tests/test_CA/Makefile.am b/src/tests/test_CA/Makefile.am
-index 1bce2c36633b2d1df65c29258f8ee163a4bfce9e..b574c76111560ba3fce453254e74c267fc680681 100644
---- a/src/tests/test_CA/Makefile.am
-+++ b/src/tests/test_CA/Makefile.am
-@@ -24,7 +24,7 @@ pkcs12 = $(addprefix SSSD_test_cert_pkcs12_,$(addsuffix .pem,$(ids)))
- if HAVE_NSS
- extra = p11_nssdb p11_nssdb_2certs
- else
--extra = softhsm2_none softhsm2_one softhsm2_two
-+extra = softhsm2_none softhsm2_one softhsm2_two softhsm2_2tokens
- endif
- 
- # If openssl is run in parallel there might be conflicts with the serial
-@@ -114,6 +114,20 @@ softhsm2_two.conf:
- 	@echo "objectstore.backend = file" >> $@
- 	@echo "slots.removable = true" >> $@
- 
-+softhsm2_2tokens: softhsm2_2tokens.conf
-+	mkdir $@
-+	SOFTHSM2_CONF=./$< $(SOFTHSM2_UTIL) --init-token  --label "SSSD Test Token" --pin 123456 --so-pin 123456 --free
-+	GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --no-mark-private --load-certificate=SSSD_test_cert_x509_0001.pem --login  --label 'SSSD test cert 0001' --id 'C554C9F82C2A9D58B70921C143304153A8A42F17' pkcs11:token=SSSD%20Test%20Token
-+	GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --load-privkey=$(srcdir)/SSSD_test_cert_key_0001.pem --login  --label 'SSSD test cert 0001' --id 'C554C9F82C2A9D58B70921C143304153A8A42F17' pkcs11:token=SSSD%20Test%20Token
-+	SOFTHSM2_CONF=./$< $(SOFTHSM2_UTIL) --init-token  --label "SSSD Test Token Number 2" --pin 654321 --so-pin 654321 --free
-+	GNUTLS_PIN=654321 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --no-mark-private --load-certificate=SSSD_test_cert_x509_0002.pem --login  --label 'SSSD test cert 0002' --id '5405842D56CF31F0BB025A695C5F3E907051C5B9' pkcs11:token=SSSD%20Test%20Token%20Number%202
-+	GNUTLS_PIN=654321 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --load-privkey=$(srcdir)/SSSD_test_cert_key_0002.pem --login  --label 'SSSD test cert 0002' --id '5405842D56CF31F0BB025A695C5F3E907051C5B9' pkcs11:token=SSSD%20Test%20Token%20Number%202
-+
-+softhsm2_2tokens.conf:
-+	@echo "directories.tokendir = "$(abs_top_builddir)"/src/tests/test_CA/softhsm2_2tokens" > $@
-+	@echo "objectstore.backend = file" >> $@
-+	@echo "slots.removable = true" >> $@
-+
- CLEANFILES = \
-     index.txt  index.txt.attr \
-     index.txt.attr.old  index.txt.old \
--- 
-2.14.4
-
diff --git a/SOURCES/0047-BE-Convert-be_ptask-params-to-flags.patch b/SOURCES/0047-BE-Convert-be_ptask-params-to-flags.patch
new file mode 100644
index 0000000..af30e21
--- /dev/null
+++ b/SOURCES/0047-BE-Convert-be_ptask-params-to-flags.patch
@@ -0,0 +1,916 @@
+From f5ef6aa9965fec34c8de9fe2635b0e5c5b8a0ab9 Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Fri, 19 Jul 2019 15:59:32 +0200
+Subject: [PATCH 47/48] BE: Convert be_ptask params to flags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The be_ptask_create call has a lot of parameters.
+Some of them can be converted to flags to simplify
+the declaration.
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ad/ad_dyndns.c             |   9 +-
+ src/providers/ad/ad_machine_pw_renewal.c |  10 +-
+ src/providers/ad/ad_subdomains.c         |  11 +-
+ src/providers/be_ptask.c                 |  74 ++++++---
+ src/providers/be_ptask.h                 |  39 ++---
+ src/providers/be_ptask_private.h         |   2 -
+ src/providers/be_refresh.c               |   9 +-
+ src/providers/data_provider_be.c         |   4 +-
+ src/providers/ipa/ipa_dyndns.c           |   7 +-
+ src/providers/ipa/ipa_subdomains.c       |   7 +-
+ src/providers/ldap/ldap_id_cleanup.c     |   5 +-
+ src/providers/ldap/ldap_id_enum.c        |   6 +-
+ src/providers/ldap/sdap_sudo_shared.c    |  16 +-
+ src/tests/cmocka/test_be_ptask.c         | 194 ++++++++++++++++-------
+ 14 files changed, 251 insertions(+), 142 deletions(-)
+
+diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
+index af765b581..c9763d449 100644
+--- a/src/providers/ad/ad_dyndns.c
++++ b/src/providers/ad/ad_dyndns.c
+@@ -98,10 +98,13 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
+         return EINVAL;
+     }
+ 
+-    ret = be_ptask_create(ad_opts, be_ctx, period, ptask_first_delay, 0, 0, period,
+-                          BE_PTASK_OFFLINE_DISABLE, BE_PTASK_SCHEDULE_FROM_LAST, 0,
++    ret = be_ptask_create(ad_opts, be_ctx, period, ptask_first_delay, 0, 0,
++                          period, 0,
+                           ad_dyndns_update_send, ad_dyndns_update_recv, ad_opts,
+-                          "Dyndns update", 0, NULL);
++                          "Dyndns update",
++                          BE_PTASK_OFFLINE_DISABLE |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          NULL);
+ 
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c
+index 67802c04a..9dc36247a 100644
+--- a/src/providers/ad/ad_machine_pw_renewal.c
++++ b/src/providers/ad/ad_machine_pw_renewal.c
+@@ -381,14 +381,14 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
+         goto done;
+     }
+ 
+-    ret = be_ptask_create(be_ctx, be_ctx, period, initial_delay, 0, 0, 60,
+-                          BE_PTASK_OFFLINE_DISABLE,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
+-                          0,
++    ret = be_ptask_create(be_ctx, be_ctx, period, initial_delay, 0, 0, 60, 0,
+                           ad_machine_account_password_renewal_send,
+                           ad_machine_account_password_renewal_recv,
+                           renewal_data,
+-                          "AD machine account password renewal", 0, NULL);
++                          "AD machine account password renewal",
++                          BE_PTASK_OFFLINE_DISABLE |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "be_ptask_create failed.\n");
+         goto done;
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 0f46b46ad..d934e70d6 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -2065,12 +2065,13 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+                   struct ad_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std);
+ 
+     period = be_ctx->domain->subdomain_refresh_interval;
+-    ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period,
+-                          BE_PTASK_OFFLINE_DISABLE,
++    ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period, 0,
++                          ad_subdomains_ptask_send, ad_subdomains_ptask_recv,
++                          sd_ctx,
++                          "Subdomains Refresh",
++                          BE_PTASK_OFFLINE_DISABLE |
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+-                          0,
+-                          ad_subdomains_ptask_send, ad_subdomains_ptask_recv, sd_ctx,
+-                          "Subdomains Refresh", 0, NULL);
++                          NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c
+index 56c9c82fe..9a432c948 100644
+--- a/src/providers/be_ptask.c
++++ b/src/providers/be_ptask.c
+@@ -38,7 +38,7 @@ enum be_ptask_delay {
+ 
+ static void be_ptask_schedule(struct be_ptask *task,
+                               enum be_ptask_delay delay_type,
+-                              enum be_ptask_schedule from);
++                              uint32_t from);
+ 
+ static int be_ptask_destructor(void *pvt)
+ {
+@@ -107,21 +107,20 @@ static void be_ptask_execute(struct tevent_context *ev,
+ 
+     if (be_is_offline(task->be_ctx)) {
+         DEBUG(SSSDBG_TRACE_FUNC, "Back end is offline\n");
+-        switch (task->offline) {
+-        case BE_PTASK_OFFLINE_SKIP:
++        if (task->flags & BE_PTASK_OFFLINE_SKIP) {
+             be_ptask_schedule(task, BE_PTASK_PERIOD,
+                               BE_PTASK_SCHEDULE_FROM_NOW);
+             return;
+-        case BE_PTASK_OFFLINE_DISABLE:
++        }
++        else if(task->flags & BE_PTASK_OFFLINE_DISABLE) {
+             /* This case is normally handled by offline callback but we
+              * should handle it here as well since we can get here in some
+              * special cases for example unit tests or tevent events order. */
+             be_ptask_disable(task);
+             return;
+-        case BE_PTASK_OFFLINE_EXECUTE:
+-            /* continue */
+-            break;
+         }
++        /* BE_PTASK_OFFLINE_EXECUTE */
++        /* continue */
+     }
+ 
+     DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: executing task, timeout %lu "
+@@ -177,7 +176,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, task->success_schedule_type);
++        be_ptask_schedule(task, BE_PTASK_PERIOD, task->flags);
+         break;
+     default:
+         DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed with [%d]: %s\n",
+@@ -190,7 +189,7 @@ static void be_ptask_done(struct tevent_req *req)
+ 
+ static void be_ptask_schedule(struct be_ptask *task,
+                               enum be_ptask_delay delay_type,
+-                              enum be_ptask_schedule from)
++                              uint32_t from)
+ {
+     struct timeval tv = { 0, };
+     time_t delay = 0;
+@@ -228,20 +227,18 @@ static void be_ptask_schedule(struct be_ptask *task,
+         delay = delay + (rand_r(&task->ro_seed) % task->random_offset);
+     }
+ 
+-    switch (from) {
+-    case BE_PTASK_SCHEDULE_FROM_NOW:
++    if(from | BE_PTASK_SCHEDULE_FROM_NOW) {
+         tv = tevent_timeval_current_ofs(delay, 0);
+ 
+         DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds "
+               "from now [%lu]\n", task->name, delay, tv.tv_sec);
+-        break;
+-    case BE_PTASK_SCHEDULE_FROM_LAST:
++    }
++    else if (from | BE_PTASK_SCHEDULE_FROM_LAST) {
+         tv = tevent_timeval_set(task->last_execution + delay, 0);
+ 
+         DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds "
+                                   "from last execution time [%lu]\n",
+                                   task->name, delay, tv.tv_sec);
+-        break;
+     }
+ 
+     if (task->timer != NULL) {
+@@ -261,6 +258,36 @@ static void be_ptask_schedule(struct be_ptask *task,
+     task->next_execution = tv.tv_sec;
+ }
+ 
++static unsigned int be_ptask_flag_bits(uint32_t flags)
++{
++    unsigned int cnt = 0;
++    while (flags != 0) {
++        cnt += flags & 1;
++        flags >>= 1;
++    }
++    return cnt;
++}
++
++static int be_ptask_flag_check(uint32_t flags)
++{
++    uint32_t tmpflags;
++
++    tmpflags = flags & (BE_PTASK_SCHEDULE_FROM_LAST |
++                        BE_PTASK_SCHEDULE_FROM_NOW);
++    if (be_ptask_flag_bits(tmpflags) != 1) {
++        return EINVAL;
++    }
++
++    tmpflags = flags & (BE_PTASK_OFFLINE_SKIP |
++                        BE_PTASK_OFFLINE_DISABLE |
++                        BE_PTASK_OFFLINE_EXECUTE);
++    if (be_ptask_flag_bits(tmpflags) != 1) {
++        return EINVAL;
++    }
++
++    return EOK;
++}
++
+ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         struct be_ctx *be_ctx,
+                         time_t period,
+@@ -268,8 +295,6 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         time_t enabled_delay,
+                         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,
+@@ -290,6 +315,12 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+         return EINVAL;
+     }
+ 
++    /* check flags, some of them are exclusive, some must be present */
++    ret = be_ptask_flag_check(flags);
++    if (ret != EOK) {
++        return ret;
++    }
++
+     task = talloc_zero(mem_ctx, struct be_ptask);
+     if (task == NULL) {
+         ret = ENOMEM;
+@@ -306,8 +337,6 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+     task->ro_seed = time(NULL) * getpid();
+     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;
+@@ -322,7 +351,7 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+ 
+     talloc_set_destructor((TALLOC_CTX*)task, be_ptask_destructor);
+ 
+-    if (offline == BE_PTASK_OFFLINE_DISABLE) {
++    if (flags & BE_PTASK_OFFLINE_DISABLE) {
+         /* install offline and online callbacks */
+         ret = be_add_online_cb(task, be_ctx, be_ptask_online_cb, task, NULL);
+         if (ret != EOK) {
+@@ -458,7 +487,6 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+                              time_t enabled_delay,
+                              time_t random_offset,
+                              time_t timeout,
+-                             enum be_ptask_offline offline,
+                              time_t max_backoff,
+                              be_ptask_sync_t fn,
+                              void *pvt,
+@@ -479,10 +507,10 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+     ctx->pvt = pvt;
+ 
+     ret = be_ptask_create(mem_ctx, be_ctx, period, first_delay,
+-                          enabled_delay, random_offset, timeout, offline,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          enabled_delay, random_offset, timeout,
+                           max_backoff, be_ptask_sync_send, be_ptask_sync_recv,
+-                          ctx, name, flags, _task);
++                          ctx, name, flags | BE_PTASK_SCHEDULE_FROM_LAST,
++                          _task);
+     if (ret != EOK) {
+         goto done;
+     }
+diff --git a/src/providers/be_ptask.h b/src/providers/be_ptask.h
+index a33443965..640c8570a 100644
+--- a/src/providers/be_ptask.h
++++ b/src/providers/be_ptask.h
+@@ -39,33 +39,23 @@ struct be_ptask;
+ #define BE_PTASK_NO_PERIODIC         0x0001
+ 
+ /**
+- * Defines how should task behave when back end is offline.
++ * Flags defining the starting point for scheduling a task
+  */
+-enum be_ptask_offline {
+-    /* current request will be skipped and rescheduled to 'now + period' */
+-    BE_PTASK_OFFLINE_SKIP,
+-
+-    /* An offline and online callback is registered. The task is disabled
+-     * immediately when back end goes offline and then enabled again
+-     * when back end goes back online */
+-    BE_PTASK_OFFLINE_DISABLE,
+-
+-    /* current request will be executed as planned */
+-    BE_PTASK_OFFLINE_EXECUTE
+-};
++/* Schedule starting from now, typically this is used when scheduling
++ * relative to the finish time */
++#define BE_PTASK_SCHEDULE_FROM_NOW   0x0002
++/* Schedule relative to the start time of the task */
++#define BE_PTASK_SCHEDULE_FROM_LAST  0x0004
+ 
+ /**
+- * Defines the starting point for scheduling a task
++ * Flags defining how should task behave when back end is offline.
+  */
+-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
+-};
++/* current request will be skipped and rescheduled to 'now + period' */
++#define BE_PTASK_OFFLINE_SKIP        0x0008
++/* An offline and online callback is registered. The task is disabled */
++#define BE_PTASK_OFFLINE_DISABLE     0x0010
++/* current request will be executed as planned */
++#define BE_PTASK_OFFLINE_EXECUTE     0x0020
+ 
+ typedef struct tevent_req *
+ (*be_ptask_send_t)(TALLOC_CTX *mem_ctx,
+@@ -128,8 +118,6 @@ errno_t be_ptask_create(TALLOC_CTX *mem_ctx,
+                         time_t enabled_delay,
+                         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,
+@@ -145,7 +133,6 @@ errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx,
+                              time_t enabled_delay,
+                              time_t random_offset,
+                              time_t timeout,
+-                             enum be_ptask_offline offline,
+                              time_t max_backoff,
+                              be_ptask_sync_t fn,
+                              void *pvt,
+diff --git a/src/providers/be_ptask_private.h b/src/providers/be_ptask_private.h
+index 496a2f9ae..f3e5beec7 100644
+--- a/src/providers/be_ptask_private.h
++++ b/src/providers/be_ptask_private.h
+@@ -31,8 +31,6 @@ struct be_ptask {
+     unsigned int ro_seed;
+     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 687d3f022..6cce38390 100644
+--- a/src/providers/be_refresh.c
++++ b/src/providers/be_refresh.c
+@@ -173,11 +173,12 @@ static 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,
+-                              BE_PTASK_SCHEDULE_FROM_NOW,
+-                              0,
++                              refresh_interval, 0,
+                               be_refresh_send, be_refresh_recv,
+-                              ctx, "Refresh Records", 0, NULL);
++                              ctx, "Refresh Records",
++                              BE_PTASK_OFFLINE_SKIP |
++                              BE_PTASK_SCHEDULE_FROM_NOW,
++                              NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+                   "Unable to initialize refresh periodic task [%d]: %s\n",
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index f21669b8c..ce00231ff 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -130,10 +130,10 @@ void be_mark_offline(struct be_ctx *ctx)
+         ret = be_ptask_create_sync(ctx, ctx,
+                                    offline_timeout, offline_timeout,
+                                    offline_timeout, 30, offline_timeout,
+-                                   BE_PTASK_OFFLINE_EXECUTE,
+                                    3600 /* max_backoff */,
+                                    try_to_go_online,
+-                                   ctx, "Check if online (periodic)", 0,
++                                   ctx, "Check if online (periodic)",
++                                   BE_PTASK_OFFLINE_EXECUTE,
+                                    &ctx->check_if_online_ptask);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_FATAL_FAILURE,
+diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
+index 27852c2e2..f8831287a 100644
+--- a/src/providers/ipa/ipa_dyndns.c
++++ b/src/providers/ipa/ipa_dyndns.c
+@@ -74,11 +74,12 @@ errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
+     }
+ 
+     ret = be_ptask_create(ctx, be_ctx, period, ptask_first_delay, 0, 0, period,
+-                          BE_PTASK_OFFLINE_DISABLE,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,
+                           ipa_dyndns_update_send, ipa_dyndns_update_recv, ctx,
+-                          "Dyndns update", 0, NULL);
++                          "Dyndns update",
++                          BE_PTASK_OFFLINE_DISABLE |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index 13e49c5c0..d000f1230 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -3134,11 +3134,12 @@ 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,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,
+                           ipa_subdomains_ptask_send, ipa_subdomains_ptask_recv, sd_ctx,
+-                          "Subdomains Refresh", 0, NULL);
++                          "Subdomains Refresh",
++                          BE_PTASK_OFFLINE_DISABLE |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
+index df56f4da4..a62060337 100644
+--- a/src/providers/ldap/ldap_id_cleanup.c
++++ b/src/providers/ldap/ldap_id_cleanup.c
+@@ -87,8 +87,9 @@ errno_t ldap_setup_cleanup(struct sdap_id_ctx *id_ctx,
+ 
+     ret = be_ptask_create_sync(sdom, id_ctx->be, period, first_delay,
+                                5 /* enabled delay */, 0 /* random offset */,
+-                               period /* timeout */, BE_PTASK_OFFLINE_SKIP, 0,
+-                               ldap_cleanup_task, cleanup_ctx, name, 0,
++                               period /* timeout */, 0,
++                               ldap_cleanup_task, cleanup_ctx, name,
++                               BE_PTASK_OFFLINE_SKIP,
+                                &sdom->cleanup_task);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize cleanup periodic "
+diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
+index 2137f6821..009d9d275 100644
+--- a/src/providers/ldap/ldap_id_enum.c
++++ b/src/providers/ldap/ldap_id_enum.c
+@@ -98,11 +98,11 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
+                           5,                        /* enabled delay */
+                           0,                        /* random offset */
+                           period,                   /* timeout */
+-                          BE_PTASK_OFFLINE_SKIP,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           0,                        /* max_backoff */
+                           send_fn, recv_fn,
+-                          ectx, "enumeration", 0, &sdom->enum_task);
++                          ectx, "enumeration",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &sdom->enum_task);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE,
+               "Unable to initialize enumeration periodic task\n");
+diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c
+index 59356bd44..062a95ab6 100644
+--- a/src/providers/ldap/sdap_sudo_shared.c
++++ b/src/providers/ldap/sdap_sudo_shared.c
+@@ -90,11 +90,12 @@ 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,
+-                              BE_PTASK_SCHEDULE_FROM_LAST,
+                               0,
+                               full_send_fn, full_recv_fn, pvt,
+-                              "SUDO Full Refresh", 0, NULL);
++                              "SUDO Full Refresh",
++                              BE_PTASK_OFFLINE_DISABLE |
++                              BE_PTASK_SCHEDULE_FROM_LAST,
++                              NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask "
+                   "[%d]: %s\n", ret, sss_strerror(ret));
+@@ -109,11 +110,12 @@ 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,
+-                              BE_PTASK_SCHEDULE_FROM_LAST,
+-                              0,
++                              smart,                              0,
+                               smart_send_fn, smart_recv_fn, pvt,
+-                              "SUDO Smart Refresh", 0, NULL);
++                              "SUDO Smart Refresh",
++                              BE_PTASK_OFFLINE_DISABLE |
++                              BE_PTASK_SCHEDULE_FROM_LAST,
++                              NULL);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask "
+                   "[%d]: %s\n", ret, sss_strerror(ret));
+diff --git a/src/tests/cmocka/test_be_ptask.c b/src/tests/cmocka/test_be_ptask.c
+index ac8c0767f..b30775306 100644
+--- a/src/tests/cmocka/test_be_ptask.c
++++ b/src/tests/cmocka/test_be_ptask.c
+@@ -304,9 +304,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, NULL, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -318,9 +319,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, NULL, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -332,9 +334,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, NULL,
+-                          test_be_ptask_recv, NULL, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -346,9 +349,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          NULL, NULL, "Test ptask", 0, &ptask);
++                          NULL, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -360,9 +364,72 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, NULL, NULL, 0, &ptask);
++                          test_be_ptask_recv, NULL, NULL,
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
++    assert_int_equal(ret, EINVAL);
++    assert_null(ptask);
++}
++
++void test_be_ptask_mixed_from_flags_einval(void **state)
++{
++    struct test_ctx *test_ctx = (struct test_ctx *)(*state);
++    struct be_ptask *ptask = NULL;
++    errno_t ret;
++
++    ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
++                          0, test_be_ptask_send,
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP |
++                          BE_PTASK_SCHEDULE_FROM_LAST |
++                          BE_PTASK_SCHEDULE_FROM_NOW,
++                          &ptask);
++    assert_int_equal(ret, EINVAL);
++    assert_null(ptask);
++}
++
++void test_be_ptask_no_from_flags_einval(void **state)
++{
++    struct test_ctx *test_ctx = (struct test_ctx *)(*state);
++    struct be_ptask *ptask = NULL;
++    errno_t ret;
++
++    ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
++                          0, test_be_ptask_send,
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP,
++                          &ptask);
++    assert_int_equal(ret, EINVAL);
++    assert_null(ptask);
++}
++void test_be_ptask_mixed_offline_flags_einval(void **state)
++{
++    struct test_ctx *test_ctx = (struct test_ctx *)(*state);
++    struct be_ptask *ptask = NULL;
++    errno_t ret;
++
++    ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
++                          0, test_be_ptask_send,
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP |
++                          BE_PTASK_OFFLINE_DISABLE |
++                          BE_PTASK_SCHEDULE_FROM_NOW,
++                          &ptask);
++    assert_int_equal(ret, EINVAL);
++    assert_null(ptask);
++}
++void test_be_ptask_no_offline_flags_einval(void **state)
++{
++    struct test_ctx *test_ctx = (struct test_ctx *)(*state);
++    struct be_ptask *ptask = NULL;
++    errno_t ret;
++
++    ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
++                          0, test_be_ptask_send,
++                          test_be_ptask_recv, NULL, "Test ptask",
++                          BE_PTASK_SCHEDULE_FROM_NOW,
++                          &ptask);
+     assert_int_equal(ret, EINVAL);
+     assert_null(ptask);
+ }
+@@ -376,9 +443,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -404,9 +472,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -430,9 +499,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -455,9 +525,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -488,9 +559,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -528,9 +600,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -562,10 +635,11 @@ 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,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_DISABLE |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -594,10 +668,11 @@ 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,
+-                          BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_EXECUTE |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -623,9 +698,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -655,9 +731,9 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_null_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0,
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -683,9 +759,9 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_error_recv, test_ctx, "Test ptask", 0,
++                          test_be_ptask_error_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -711,9 +787,9 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_timeout_send,
+-                          test_be_ptask_error_recv, test_ctx, "Test ptask", 0,
++                          test_be_ptask_error_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
+                           &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+@@ -749,9 +825,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           PERIOD*2, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -804,9 +881,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+ 
+@@ -825,9 +903,10 @@ 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, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+-                          test_be_ptask_recv, test_ctx, "Test ptask", 0, &ptask);
++                          test_be_ptask_recv, test_ctx, "Test ptask",
++                          BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+ 
+@@ -845,10 +924,12 @@ void test_be_ptask_no_periodic(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create(test_ctx, test_ctx->be_ctx, 0, 0, DELAY, 0, 0,
+-                          BE_PTASK_OFFLINE_SKIP, BE_PTASK_SCHEDULE_FROM_LAST,
+                           0, test_be_ptask_send,
+                           test_be_ptask_recv, test_ctx, "Test ptask",
+-                          BE_PTASK_NO_PERIODIC, &ptask);
++                          BE_PTASK_NO_PERIODIC |
++                          BE_PTASK_OFFLINE_SKIP |
++                          BE_PTASK_SCHEDULE_FROM_LAST,
++                          &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+ 
+@@ -865,8 +946,8 @@ void test_be_ptask_create_sync(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                               BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_sync,
+-                               test_ctx, "Test ptask", 0, &ptask);
++                               0, test_be_ptask_sync, test_ctx, "Test ptask",
++                               BE_PTASK_OFFLINE_SKIP, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -893,8 +974,8 @@ void test_be_ptask_sync_reschedule_ok(void **state)
+ 
+     now = get_current_time();
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                               BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_sync,
+-                               test_ctx, "Test ptask", 0, &ptask);
++                               0, test_be_ptask_sync, test_ctx, "Test ptask",
++                               BE_PTASK_OFFLINE_SKIP, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -924,9 +1005,9 @@ void test_be_ptask_sync_reschedule_error(void **state)
+     errno_t ret;
+ 
+     ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                               BE_PTASK_OFFLINE_SKIP, 0,
+-                               test_be_ptask_sync_error,
+-                               test_ctx, "Test ptask", 0, &ptask);
++                               0, test_be_ptask_sync_error,
++                               test_ctx, "Test ptask",
++                               BE_PTASK_OFFLINE_SKIP, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -953,10 +1034,11 @@ void test_be_ptask_sync_reschedule_backoff(void **state)
+     errno_t ret;
+ 
+     now_first = get_current_time();
+-    ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, 0,
+-                               BE_PTASK_OFFLINE_SKIP, PERIOD*2,
++    ret = be_ptask_create_sync(test_ctx, test_ctx->be_ctx, PERIOD,
++                               0, 0, 0, 0, PERIOD*2,
+                                test_be_ptask_sync_error,
+-                               test_ctx, "Test ptask", 0, &ptask);
++                               test_ctx, "Test ptask",
++                               BE_PTASK_OFFLINE_SKIP, &ptask);
+     assert_int_equal(ret, ERR_OK);
+     assert_non_null(ptask);
+     assert_non_null(ptask->timer);
+@@ -1017,6 +1099,10 @@ int main(int argc, const char *argv[])
+         new_test(be_ptask_create_einval_send),
+         new_test(be_ptask_create_einval_recv),
+         new_test(be_ptask_create_einval_name),
++        new_test(be_ptask_mixed_from_flags_einval),
++        new_test(be_ptask_no_from_flags_einval),
++        new_test(be_ptask_mixed_offline_flags_einval),
++        new_test(be_ptask_no_offline_flags_einval),
+         new_test(be_ptask_create_no_delay),
+         new_test(be_ptask_create_first_delay),
+         new_test(be_ptask_disable),
+-- 
+2.20.1
+
diff --git a/SOURCES/0047-PAM-return-short-name-for-files-provider-users.patch b/SOURCES/0047-PAM-return-short-name-for-files-provider-users.patch
deleted file mode 100644
index b3cbed2..0000000
--- a/SOURCES/0047-PAM-return-short-name-for-files-provider-users.patch
+++ /dev/null
@@ -1,148 +0,0 @@
-From f743c82d11ffafa1a48f9b7108eff072ecc9ab1c Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 9 Oct 2018 13:25:35 +0200
-Subject: [PATCH 47/47] PAM: return short name for files provider users
-
-If the 'allow_missing_name' option is used with pam_sss and the user
-name will be determined based on the certificate content and the mapping
-rules the PAM responder will by default return the fully-qualified name
-of the user which is then later used by other PAM modules as well.
-
-For local users which are configured to use SSSD for Smartcard
-authentication this might cause issues in other PAM modules because they
-are not aware of the fully-qualified name and will treat the user as
-unknown.
-
-With this patch the PAM responder will return the short name for all
-users handled by the files provider.
-
-Related to https://pagure.io/SSSD/sssd/issue/3848
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit dbd717fe5b7d8dd640b6ade435b49edb3db5280a)
----
- src/responder/pam/pamsrv.h     |  3 ++-
- src/responder/pam/pamsrv_cmd.c | 13 +++++++++----
- src/responder/pam/pamsrv_p11.c | 32 +++++++++++++++++++++++++++++---
- 3 files changed, 40 insertions(+), 8 deletions(-)
-
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index 60aa97967456b9b7ab35e64f103c1c9a17bef3a9..3a927bb39b1e03735c237cc6b5a33234c2f4e2ef 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -108,7 +108,8 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
- errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-                             struct cert_auth_info **cert_list);
- 
--errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-+errno_t add_pam_cert_response(struct pam_data *pd, struct sss_domain_info *dom,
-+                              const char *sysdb_username,
-                               struct cert_auth_info *cert_info,
-                               enum response_type type);
- 
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index a22afd225894872847a0fb13e202f927fd2ae124..553bf8fbbdb485f4a7b2610b894b1a78b4e47317 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1645,7 +1645,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                      preq->current_cert != NULL;
-                      preq->current_cert = sss_cai_get_next(preq->current_cert)) {
- 
--                    ret = add_pam_cert_response(preq->pd, "",
-+                    ret = add_pam_cert_response(preq->pd,
-+                                       preq->cctx->rctx->domains, "",
-                                        preq->current_cert,
-                                        preq->cctx->rctx->domains->user_name_hint
-                                             ? SSS_PAM_CERT_INFO_WITH_HINT
-@@ -1699,7 +1700,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
- 
-             if (preq->cctx->rctx->domains->user_name_hint
-                     && preq->pd->cmd == SSS_PAM_PREAUTH) {
--                ret = add_pam_cert_response(preq->pd, cert_user,
-+                ret = add_pam_cert_response(preq->pd,
-+                                            preq->cctx->rctx->domains, cert_user,
-                                             preq->cert_list,
-                                             SSS_PAM_CERT_INFO_WITH_HINT);
-                 preq->pd->pam_status = PAM_SUCCESS;
-@@ -1725,7 +1727,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-              * SSS_PAM_CERT_INFO message to send the name to the caller. */
-             if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
-                     && preq->pd->logon_name == NULL) {
--                ret = add_pam_cert_response(preq->pd, cert_user,
-+                ret = add_pam_cert_response(preq->pd,
-+                                            preq->cctx->rctx->domains, cert_user,
-                                             preq->cert_list,
-                                             SSS_PAM_CERT_INFO);
-                 if (ret != EOK) {
-@@ -2117,7 +2120,9 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
-                                   "the backend.\n");
-                         }
- 
--                        ret = add_pam_cert_response(preq->pd, cert_user,
-+                        ret = add_pam_cert_response(preq->pd,
-+                                                    preq->cctx->rctx->domains,
-+                                                    cert_user,
-                                                     preq->current_cert,
-                                                     SSS_PAM_CERT_INFO);
-                         if (ret != EOK) {
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index 491bd2b01d7bf9137b37c35f9da9eca1eed95a6d..785b29c99a65ec7167b31f746fd9a897b038d817 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -1145,7 +1145,8 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-  * used when running gdm-password. */
- #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME"
- 
--errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-+errno_t add_pam_cert_response(struct pam_data *pd, struct sss_domain_info *dom,
-+                              const char *sysdb_username,
-                               struct cert_auth_info *cert_info,
-                               enum response_type type)
- {
-@@ -1153,6 +1154,10 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-     char *env = NULL;
-     size_t msg_len;
-     int ret;
-+    char *short_name = NULL;
-+    char *domain_name = NULL;
-+    const char *cert_info_name = sysdb_username;
-+
- 
-     if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid response type [%d].\n", type);
-@@ -1174,9 +1179,30 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-      * Smartcard. If this type of name is irritating at the PIN prompt or the
-      * re_expression config option was set in a way that user@domain cannot be
-      * handled anymore some more logic has to be added here. But for the time
--     * being I think using sysdb_username is fine. */
-+     * being I think using sysdb_username is fine.
-+     * As special case is the files provider which handles local users which
-+     * by definition only have a short name. To avoid confusion by other
-+     * modules on the PAM stack the short name is returned in this case. */
- 
--    ret = pack_cert_data(pd, sysdb_username, cert_info, &msg, &msg_len);
-+    if (sysdb_username != NULL) {
-+        ret = sss_parse_internal_fqname(pd, sysdb_username,
-+                                        &short_name, &domain_name);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s, "
-+                                       "using full name.\n",
-+                                        sysdb_username, ret, sss_strerror(ret));
-+        } else {
-+            if (domain_name != NULL
-+                    &&  is_files_provider(find_domain_by_name(dom, domain_name,
-+                                                              false))) {
-+                cert_info_name = short_name;
-+            }
-+        }
-+    }
-+
-+    ret = pack_cert_data(pd, cert_info_name, cert_info, &msg, &msg_len);
-+    talloc_free(short_name);
-+    talloc_free(domain_name);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "pack_cert_data failed.\n");
-         return ret;
--- 
-2.14.4
-
diff --git a/SOURCES/0048-DYNDNS-dyndns_update-is-not-enough.patch b/SOURCES/0048-DYNDNS-dyndns_update-is-not-enough.patch
new file mode 100644
index 0000000..aee251f
--- /dev/null
+++ b/SOURCES/0048-DYNDNS-dyndns_update-is-not-enough.patch
@@ -0,0 +1,92 @@
+From 07b5dd9640071cf5ca5cd91acfc84af8d0cf69fe Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Fri, 19 Jul 2019 16:52:43 +0200
+Subject: [PATCH 48/48] DYNDNS: dyndns_update is not enough
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When dyndns_update is set to True and dyndns_refresh_interval is
+not set or set to 0, DNS is not updated at all.
+
+With this patch DNS is updated when sssd changes its state to
+online.
+
+If dyndns_refresh_interval is set, updates are performed as
+before - i. e. when comming online and then every
+dyndns_refresh_interval.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/4047
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/ad/ad_dyndns.c   | 6 ++++--
+ src/providers/ipa/ipa_dyndns.c | 6 ++++--
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
+index c9763d449..00e1d253a 100644
+--- a/src/providers/ad/ad_dyndns.c
++++ b/src/providers/ad/ad_dyndns.c
+@@ -56,6 +56,7 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
+     errno_t ret;
+     const time_t ptask_first_delay = 10;
+     int period;
++    uint32_t extraflags = 0;
+ 
+     /* nsupdate is available. Dynamic updates
+      * are supported
+@@ -93,15 +94,16 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
+ 
+     period = dp_opt_get_int(ad_opts->dyndns_ctx->opts, DP_OPT_DYNDNS_REFRESH_INTERVAL);
+     if (period == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Dyndns update task can't be started, "
++        DEBUG(SSSDBG_TRACE_FUNC, "DNS will not be updated periodically, "
+               "dyndns_refresh_interval is 0\n");
+-        return EINVAL;
++        extraflags |= BE_PTASK_NO_PERIODIC;
+     }
+ 
+     ret = be_ptask_create(ad_opts, be_ctx, period, ptask_first_delay, 0, 0,
+                           period, 0,
+                           ad_dyndns_update_send, ad_dyndns_update_recv, ad_opts,
+                           "Dyndns update",
++                          extraflags |
+                           BE_PTASK_OFFLINE_DISABLE |
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           NULL);
+diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
+index f8831287a..9404ea9cb 100644
+--- a/src/providers/ipa/ipa_dyndns.c
++++ b/src/providers/ipa/ipa_dyndns.c
+@@ -58,6 +58,7 @@ errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
+     errno_t ret;
+     const time_t ptask_first_delay = 10;
+     int period;
++    uint32_t extraflags = 0;
+ 
+     ctx->be_res = be_ctx->be_res;
+     if (ctx->be_res == NULL) {
+@@ -68,15 +69,16 @@ errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
+ 
+     period = dp_opt_get_int(ctx->dyndns_ctx->opts, DP_OPT_DYNDNS_REFRESH_INTERVAL);
+     if (period == 0) {
+-        DEBUG(SSSDBG_OP_FAILURE, "Dyndns task can't be started, "
++        DEBUG(SSSDBG_TRACE_FUNC, "DNS will not be updated periodically, "
+               "dyndns_refresh_interval is 0\n");
+-        return EINVAL;
++        extraflags |= BE_PTASK_NO_PERIODIC;
+     }
+ 
+     ret = be_ptask_create(ctx, be_ctx, period, ptask_first_delay, 0, 0, period,
+                           0,
+                           ipa_dyndns_update_send, ipa_dyndns_update_recv, ctx,
+                           "Dyndns update",
++                          extraflags |
+                           BE_PTASK_OFFLINE_DISABLE |
+                           BE_PTASK_SCHEDULE_FROM_LAST,
+                           NULL);
+-- 
+2.20.1
+
diff --git a/SOURCES/0048-doc-Add-nsswitch.conf-note-to-manpage.patch b/SOURCES/0048-doc-Add-nsswitch.conf-note-to-manpage.patch
deleted file mode 100644
index 7fd3b19..0000000
--- a/SOURCES/0048-doc-Add-nsswitch.conf-note-to-manpage.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From 42b92ad5b26ebbc7c387aa7111f70c74b63cd84f Mon Sep 17 00:00:00 2001
-From: Tomas Halman <thalman@redhat.com>
-Date: Mon, 1 Oct 2018 13:45:52 +0200
-Subject: [PATCH 48/57] doc: Add nsswitch.conf note to manpage
-
-We want to add note about nsswitch.conf configuration
-into sssd-files manpage.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3750
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Justin Stephenson <jstephen@redhat.com>
-(cherry picked from commit 0be037bbedd0aed6a7eccead6aabe0d07258242a)
----
- src/man/sssd-files.5.xml | 34 +++++++++++++++++++++++++++++++++-
- 1 file changed, 33 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd-files.5.xml b/src/man/sssd-files.5.xml
-index 59e1b652328b6548386d9e15938db38197ad2a92..067e21949ffe10d783cc305c57c0ae57c906f899 100644
---- a/src/man/sssd-files.5.xml
-+++ b/src/man/sssd-files.5.xml
-@@ -51,6 +51,27 @@
-                 <manvolnum>5</manvolnum>
-             </citerefentry>.
-         </para>
-+        <para>
-+            Another reason is to provide efficient caching of local users and groups.
-+        </para>
-+        <para>
-+            Please note that some distributions enable the files domain automatically,
-+            prepending the domain before any explicitly configured domains.
-+            See enable_files_domain in
-+            <citerefentry>
-+                <refentrytitle>sssd.conf</refentrytitle>
-+                <manvolnum>5</manvolnum>
-+            </citerefentry>.
-+        </para>
-+        <para>
-+            SSSD never handles resolution of user/group "root". Also resolution of
-+            UID/GID 0 is not handled by SSSD. Such requests are passed to next
-+            NSS module (usually files).
-+        </para>
-+        <para>
-+            When SSSD is not running or responding, nss_sss returns the UNAVAIL code
-+            which causes the request to be passed to the next module.
-+        </para>
-     </refsect1>
- 
-     <refsect1 id='configuration-options'>
-@@ -110,11 +131,22 @@
- <programlisting>
- [domain/files]
- id_provider = files
-+</programlisting>
-+        </para>
-+        <para>
-+            To leverage caching of local users and groups by SSSD
-+            nss_sss module must be listed before nss_files module
-+            in /etc/nsswitch.conf.
-+        </para>
-+        <para>
-+<programlisting>
-+passwd:     sss files
-+group:      sss files
- </programlisting>
-         </para>
-     </refsect1>
- 
--	<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" />
-+        <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" />
- 
- </refentry>
- </reference>
--- 
-2.14.4
-
diff --git a/SOURCES/0049-intg-flush-the-SSSD-caches-to-sync-with-files.patch b/SOURCES/0049-intg-flush-the-SSSD-caches-to-sync-with-files.patch
deleted file mode 100644
index a49ca25..0000000
--- a/SOURCES/0049-intg-flush-the-SSSD-caches-to-sync-with-files.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From b24cc168b6244a9f215e2e235dbbcb3947da9280 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 10 Sep 2018 15:35:45 +0200
-Subject: [PATCH 49/57] intg: flush the SSSD caches to sync with files
-
-To make sure that SSSD has synced with the latest data added to the
-passwd file sss_cache is called in two places where the current sync
-scheme was not reliable. This was mainly observed when running the
-integration tests on Debian.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 1e2398870e8aa512ead3012d46cbe6252429467a)
----
- src/tests/intg/test_files_provider.py | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py
-index 9f30d2bb485cb4ccd14da2fa2317f62a7c347745..ead1cc4c34a8027f74f2a9564863159defce02ef 100644
---- a/src/tests/intg/test_files_provider.py
-+++ b/src/tests/intg/test_files_provider.py
-@@ -644,6 +644,10 @@ def test_enum_users(setup_pw_with_canary, files_domain_only):
-         user = user_generator(i)
-         setup_pw_with_canary.useradd(**user)
- 
-+    # syncing with the help of the canary is not reliable after adding
-+    # multiple users because the canary might still be in some caches so that
-+    # the data is not refreshed properly.
-+    subprocess.call(["sss_cache", "-E"])
-     sssd_getpwnam_sync(CANARY["name"])
-     user_list = call_sssd_enumeration()
-     # +1 because the canary is added
-@@ -1043,6 +1047,10 @@ def test_getgrnam_add_remove_ghosts(setup_pw_with_canary,
- 
-     # Add this user and verify it's been added as a member
-     pwd_ops.useradd(**USER2)
-+    # The negative cache might still have user2 from the previous request,
-+    # flushing the caches might help to prevent a failed lookup after adding
-+    # the user.
-+    subprocess.call(["sss_cache", "-E"])
-     res, groups = sssd_id_sync('user2')
-     assert res == sssd_id.NssReturnCode.SUCCESS
-     assert len(groups) == 2
--- 
-2.14.4
-
diff --git a/SOURCES/0049-tests-Use-idm-DL1-module-to-install-389-ds.patch b/SOURCES/0049-tests-Use-idm-DL1-module-to-install-389-ds.patch
new file mode 100644
index 0000000..f3834ac
--- /dev/null
+++ b/SOURCES/0049-tests-Use-idm-DL1-module-to-install-389-ds.patch
@@ -0,0 +1,31 @@
+From bd14c31c37da420d3a9c478cadded97545e6609a Mon Sep 17 00:00:00 2001
+From: "Niranjan M.R" <mrniranjan@redhat.com>
+Date: Tue, 20 Aug 2019 15:19:14 +0530
+Subject: [PATCH] tests: Use idm:DL1 module to install 389-ds
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Niranjan M.R <mrniranjan@redhat.com>
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/tests/multihost/basic/conftest.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tests/multihost/basic/conftest.py b/src/tests/multihost/basic/conftest.py
+index a9e9cf0a6..87f74031c 100644
+--- a/src/tests/multihost/basic/conftest.py
++++ b/src/tests/multihost/basic/conftest.py
+@@ -42,7 +42,7 @@ def package_install(session_multihost):
+     if 'Fedora' in distro:
+         cmd = 'dnf install -y %s' % (pkg_list)
+     elif '8.' in distro.split()[5]:
+-        cmd = 'dnf module -y install 389-ds:1.4'
++        cmd = 'yum -y module enable idm:DL1'
+     session_multihost.master[0].run_command(cmd)
+ 
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0050-FILES-The-files-provider-should-not-enumerate.patch b/SOURCES/0050-FILES-The-files-provider-should-not-enumerate.patch
deleted file mode 100644
index 654964a..0000000
--- a/SOURCES/0050-FILES-The-files-provider-should-not-enumerate.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From c26e713307339699dd26b17f11a2f3136d334ba8 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 15 Oct 2018 22:26:07 +0200
-Subject: [PATCH 50/57] FILES: The files provider should not enumerate
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3849
-
-For reason I cannot explain now, the files provider always enumerates.
-There is commit a60e6ec which implements this, but it's clearly wrong,
-because then the plain getent passwd output contains duplicates from
-nss_files and nss_sss:
-
-$ getent passwd | sort
-adm:x:3:4:adm:/var/adm:/sbin/nologin
-adm:x:3:4:adm:/var/adm:/sbin/nologin
-bin:x:1:1:bin:/bin:/sbin/nologin
-bin:x:1:1:bin:/bin:/sbin/nologin
-certuser:x:10329:10330::/home/certuser:/bin/bash
-certuser:x:10329:10330::/home/certuser:/bin/bash
-chrony:x:997:994::/var/lib/chrony:/sbin/nologin
-chrony:x:997:994::/var/lib/chrony:/sbin/nologin
-daemon:x:2:2:daemon:/sbin:/sbin/nologin
-daemon:x:2:2:daemon:/sbin:/sbin/nologin
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/confdb/confdb.c                   |  5 +----
- src/tests/intg/test_files_provider.py | 22 ----------------------
- 2 files changed, 1 insertion(+), 26 deletions(-)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index 2f3d90087e640f77835400b11184b684852d7fda..fdc61226fd7d8e078dd7eb7eb532c11be3cc05ec 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -875,7 +875,6 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
-     char *default_domain;
-     bool fqnames_default = false;
-     int memcache_timeout;
--    bool enum_default;
- 
-     tmp_ctx = talloc_new(mem_ctx);
-     if (!tmp_ctx) return ENOMEM;
-@@ -1009,10 +1008,8 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
-                   "Interpreting as true\n", domain->name);
-         domain->enumerate = true;
-     } else { /* assume the new format */
--        enum_default = is_files_provider(domain);
--
-         ret = get_entry_as_bool(res->msgs[0], &domain->enumerate,
--                                CONFDB_DOMAIN_ENUMERATE, enum_default);
-+                                CONFDB_DOMAIN_ENUMERATE, 0);
-         if(ret != EOK) {
-             DEBUG(SSSDBG_FATAL_FAILURE,
-                   "Invalid value for %s\n", CONFDB_DOMAIN_ENUMERATE);
-diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py
-index ead1cc4c34a8027f74f2a9564863159defce02ef..f0155a2f7e26f17e84e93eab2b99ab72f31d297d 100644
---- a/src/tests/intg/test_files_provider.py
-+++ b/src/tests/intg/test_files_provider.py
-@@ -32,7 +32,6 @@ import ent
- import sssd_id
- from sssd_nss import NssReturnCode
- from sssd_passwd import (call_sssd_getpwnam,
--                         call_sssd_enumeration,
-                          call_sssd_getpwuid)
- from sssd_group import call_sssd_getgrnam, call_sssd_getgrgid
- from files_ops import passwd_ops_setup, group_ops_setup, PasswdOps, GroupOps
-@@ -633,27 +632,6 @@ def test_mod_user_shell(add_user_with_canary, files_domain_only):
-     check_user(moduser)
- 
- 
--def test_enum_users(setup_pw_with_canary, files_domain_only):
--    """
--    Test that enumerating all users works with the default configuration. Also
--    test that removing all entries and then enumerating again returns an empty
--    set
--    """
--    num_users = 10
--    for i in range(1, num_users+1):
--        user = user_generator(i)
--        setup_pw_with_canary.useradd(**user)
--
--    # syncing with the help of the canary is not reliable after adding
--    # multiple users because the canary might still be in some caches so that
--    # the data is not refreshed properly.
--    subprocess.call(["sss_cache", "-E"])
--    sssd_getpwnam_sync(CANARY["name"])
--    user_list = call_sssd_enumeration()
--    # +1 because the canary is added
--    assert len(user_list) == num_users+1
--
--
- def incomplete_user_setup(pwd_ops, del_field, exp_field):
-     adduser = dict(USER1)
-     del adduser[del_field]
--- 
-2.14.4
-
diff --git a/SOURCES/0050-pam-keep-pin-on-the-PAM-stack-for-forward_pass.patch b/SOURCES/0050-pam-keep-pin-on-the-PAM-stack-for-forward_pass.patch
new file mode 100644
index 0000000..0bfa18b
--- /dev/null
+++ b/SOURCES/0050-pam-keep-pin-on-the-PAM-stack-for-forward_pass.patch
@@ -0,0 +1,135 @@
+From e989620bd2b4f7094dee3ef740ba92d0cf45d0c8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 19 Aug 2019 17:38:04 +0200
+Subject: [PATCH] pam: keep pin on the PAM stack for forward_pass
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Currently only the password or the long-term part of a two-factor
+authentication was kept on the PM stack if pam_sss.so has the option
+forward_pass. With this patch the Smartcard PIN can be forwarded to
+other PAM modules as well.
+
+Related https://pagure.io/SSSD/sssd/issue/4067
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/sss_client/pam_sss.c        | 11 ++++++++++-
+ src/tests/cmocka/test_authtok.c |  5 +++++
+ src/util/authtok-utils.c        | 33 +++++++++++++++++++++++++++++++++
+ src/util/authtok-utils.h        | 10 ++++++++++
+ 4 files changed, 58 insertions(+), 1 deletion(-)
+
+diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
+index cfd3e3731..e36407b72 100644
+--- a/src/sss_client/pam_sss.c
++++ b/src/sss_client/pam_sss.c
+@@ -2116,6 +2116,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
+                                           uint32_t flags)
+ {
+     int ret;
++    const char *pin = NULL;
+ 
+     if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
+             || ( pi->pamstack_authtok != NULL
+@@ -2166,11 +2167,19 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
+         if (flags & PAM_CLI_FLAGS_FORWARD_PASS) {
+             if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_PASSWORD) {
+                 ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_authtok);
++            } else if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_SC_PIN) {
++                pin = sss_auth_get_pin_from_sc_blob((uint8_t *) pi->pam_authtok,
++                                                    pi->pam_authtok_size);
++                if (pin != NULL) {
++                    ret = pam_set_item(pamh, PAM_AUTHTOK, pin);
++                } else {
++                    ret = PAM_SYSTEM_ERR;
++                }
+             } else if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA
+                            && pi->first_factor != NULL) {
+                 ret = pam_set_item(pamh, PAM_AUTHTOK, pi->first_factor);
+             } else {
+-                ret = EINVAL;
++                ret = PAM_SYSTEM_ERR;
+             }
+             if (ret != PAM_SUCCESS) {
+                 D(("Failed to set PAM_AUTHTOK [%s], "
+diff --git a/src/tests/cmocka/test_authtok.c b/src/tests/cmocka/test_authtok.c
+index 84e209783..a8f5bdee7 100644
+--- a/src/tests/cmocka/test_authtok.c
++++ b/src/tests/cmocka/test_authtok.c
+@@ -473,6 +473,11 @@ void test_sss_authtok_sc_blobs(void **state)
+                         needed_size);
+ #endif
+ 
++    pin = sss_auth_get_pin_from_sc_blob(buf, needed_size);
++    assert_non_null(pin);
++    assert_string_equal(pin, "abc");
++    pin = NULL;
++
+     ret = sss_authtok_set(ts->authtoken, SSS_AUTHTOK_TYPE_SC_PIN, buf,
+                           needed_size);
+     assert_int_equal(ret, EOK);
+diff --git a/src/util/authtok-utils.c b/src/util/authtok-utils.c
+index e7123df34..e50f86741 100644
+--- a/src/util/authtok-utils.c
++++ b/src/util/authtok-utils.c
+@@ -163,3 +163,36 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len,
+ 
+     return 0;
+ }
++
++const char *sss_auth_get_pin_from_sc_blob(uint8_t *blob, size_t blob_len)
++{
++    size_t c = 0;
++    uint32_t pin_len;
++    uint32_t token_name_len;
++    uint32_t module_name_len;
++    uint32_t key_id_len;
++
++    if (blob == NULL || blob_len == 0) {
++        return NULL;
++    }
++
++    SAFEALIGN_COPY_UINT32(&pin_len, blob, &c);
++    if (pin_len == 0) {
++        return NULL;
++    }
++
++    SAFEALIGN_COPY_UINT32(&token_name_len, blob + c, &c);
++    SAFEALIGN_COPY_UINT32(&module_name_len, blob + c, &c);
++    SAFEALIGN_COPY_UINT32(&key_id_len, blob + c, &c);
++
++    if (blob_len != 4 * sizeof(uint32_t) + pin_len + token_name_len
++                                         + module_name_len + key_id_len) {
++        return NULL;
++    }
++
++    if (blob[c + pin_len - 1] != '\0') {
++        return NULL;
++    }
++
++    return (const char *) blob + c;
++}
+diff --git a/src/util/authtok-utils.h b/src/util/authtok-utils.h
+index c5aace39f..714c8187e 100644
+--- a/src/util/authtok-utils.h
++++ b/src/util/authtok-utils.h
+@@ -123,4 +123,14 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx,
+                                  char **token_name, size_t *_token_name_len,
+                                  char **module_name, size_t *_module_name_len,
+                                  char **key_id, size_t *_key_id_len);
++
++/**
++ * @brief Return a pointer to the PIN string in the memory buffer
++ *
++ * @param[in]  blob              Memory buffer containing the 2FA data
++ * @param[in]  blob_len          Size of the memory buffer
++ *
++ * @return     pointer to 0-terminate PIN string in the memory buffer
++ */
++const char *sss_auth_get_pin_from_sc_blob(uint8_t *blob, size_t blob_len);
+ #endif /*  __AUTHTOK_UTILS_H__ */
+-- 
+2.20.1
+
diff --git a/SOURCES/0051-BE-Invalid-oprator-used-in-condition.patch b/SOURCES/0051-BE-Invalid-oprator-used-in-condition.patch
new file mode 100644
index 0000000..2bd6778
--- /dev/null
+++ b/SOURCES/0051-BE-Invalid-oprator-used-in-condition.patch
@@ -0,0 +1,40 @@
+From 7fcd0a70d6dcaab3aa8f2a84ce9dc939ec350415 Mon Sep 17 00:00:00 2001
+From: Tomas Halman <thalman@redhat.com>
+Date: Wed, 21 Aug 2019 17:00:44 +0200
+Subject: [PATCH] BE: Invalid oprator used in condition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is wrong binary or used in condition. We have to use & here
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1744134
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+---
+ src/providers/be_ptask.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c
+index 8d75d51d1..319e44aa8 100644
+--- a/src/providers/be_ptask.c
++++ b/src/providers/be_ptask.c
+@@ -228,13 +228,13 @@ static void be_ptask_schedule(struct be_ptask *task,
+         delay = delay + (sss_rand() % task->random_offset);
+     }
+ 
+-    if(from | BE_PTASK_SCHEDULE_FROM_NOW) {
++    if(from & BE_PTASK_SCHEDULE_FROM_NOW) {
+         tv = tevent_timeval_current_ofs(delay, 0);
+ 
+         DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds "
+               "from now [%lu]\n", task->name, delay, tv.tv_sec);
+     }
+-    else if (from | BE_PTASK_SCHEDULE_FROM_LAST) {
++    else if (from & BE_PTASK_SCHEDULE_FROM_LAST) {
+         tv = tevent_timeval_set(task->last_execution + delay, 0);
+ 
+         DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds "
+-- 
+2.20.1
+
diff --git a/SOURCES/0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch b/SOURCES/0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch
deleted file mode 100644
index e04bad1..0000000
--- a/SOURCES/0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch
+++ /dev/null
@@ -1,490 +0,0 @@
-From 0606a40ed924f4c1793946365076b5d1277395a4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 10 Oct 2018 15:37:16 +0200
-Subject: [PATCH 51/57] p11_child: add OCSP check ot the OpenSSL version
-
-Related to https://pagure.io/SSSD/sssd/issue/3489
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 91c608d0eb48435b5b5d2f3631a4bb2a40b8d519)
----
- src/man/sssd.conf.5.xml           |  26 ++-
- src/p11_child/p11_child_openssl.c | 346 ++++++++++++++++++++++++++++++++++++++
- src/tests/cmocka/test_utils.c     |   3 +
- src/util/util.c                   |   2 +
- 4 files changed, 370 insertions(+), 7 deletions(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index c8d53f01f3eedea1e37f6593d02ce1eeaf11d2de..5e3ae48d04cc38ea54547a63c6c31795e12544c2 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -479,8 +479,8 @@
-                                         be replaced with the URL of the OCSP
-                                         default responder e.g.
-                                         http://example.com:80/ocsp.</para>
--                                        <para>This option must be used together
--                                        with
-+                                        <para>(NSS Version) This option must be
-+                                        used together with
-                                         ocsp_default_responder_signing_cert.
-                                         </para>
-                                     </listitem>
-@@ -489,17 +489,29 @@
-                                     <term>
-                                     ocsp_default_responder_signing_cert=NAME</term>
-                                     <listitem>
--                                        <para>The nickname of the cert to trust
--                                        (expected) to sign the OCSP responses.
--                                        The certificate with the given nickname
--                                        must be available in the systems NSS
--                                        database.</para>
-+                                        <para>(NSS Version) The nickname of the
-+                                        cert to trust (expected) to sign the
-+                                        OCSP responses.  The certificate with
-+                                        the given nickname must be available in
-+                                        the systems NSS database.</para>
-                                         <para>This option must be used together
-                                         with ocsp_default_responder.</para>
-+                                        <para>(OpenSSL version) This option is
-+                                        currently ignored. All needed
-+                                        certificates must be available in the
-+                                        PEM file given by
-+                                        pam_cert_db_path.</para>
-                                     </listitem>
-                                 </varlistentry>
-                                 </variablelist>
-                             </para>
-+                            <para condition="with_nss">
-+                                This man page was generated for the NSS version.
-+                            </para>
-+                            <para condition="with_openssl">
-+                                This man page was generated for the OpenSSL
-+                                version.
-+                            </para>
-                             <para>
-                                 Unknown options are reported but ignored.
-                             </para>
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index 000e1c94f11edc32abceafb39e98b16ca0664c50..d66a2f82becfa24eae867a2f3df3e23263a5273c 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -28,6 +28,7 @@
- #include <openssl/x509.h>
- #include <openssl/err.h>
- #include <openssl/rand.h>
-+#include <openssl/ocsp.h>
- #include <p11-kit/p11-kit.h>
- #include <p11-kit/uri.h>
- 
-@@ -42,8 +43,344 @@ struct p11_ctx {
-     X509_STORE *x509_store;
-     const char *ca_db;
-     bool wait_for_card;
-+    struct cert_verify_opts *cert_verify_opts;
- };
- 
-+static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host,
-+                                      const char *path,
-+                                      OCSP_REQUEST *req, int req_timeout)
-+{
-+    int fd;
-+    int rv;
-+    OCSP_REQ_CTX *ctx = NULL;
-+    OCSP_RESPONSE *rsp = NULL;
-+    fd_set confds;
-+    struct timeval tv;
-+
-+    if (req_timeout != -1) {
-+        BIO_set_nbio(cbio, 1);
-+    }
-+
-+    rv = BIO_do_connect(cbio);
-+
-+    if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Error connecting BIO\n");
-+        return NULL;
-+    }
-+
-+    if (BIO_get_fd(cbio, &fd) < 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Can't get connection fd\n");
-+        goto err;
-+    }
-+
-+    if (req_timeout != -1 && rv <= 0) {
-+        FD_ZERO(&confds);
-+        FD_SET(fd, &confds);
-+        tv.tv_usec = 0;
-+        tv.tv_sec = req_timeout;
-+        rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
-+        if (rv == 0) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Timeout on connect\n");
-+            return NULL;
-+        }
-+    }
-+
-+    ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
-+    if (ctx == NULL) {
-+        return NULL;
-+    }
-+
-+    if (OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0) {
-+        goto err;
-+    }
-+
-+    if (!OCSP_REQ_CTX_set1_req(ctx, req)) {
-+        goto err;
-+    }
-+
-+    for (;;) {
-+        rv = OCSP_sendreq_nbio(&rsp, ctx);
-+        if (rv != -1)
-+            break;
-+        if (req_timeout == -1)
-+            continue;
-+        FD_ZERO(&confds);
-+        FD_SET(fd, &confds);
-+        tv.tv_usec = 0;
-+        tv.tv_sec = req_timeout;
-+        if (BIO_should_read(cbio)) {
-+            rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
-+        } else if (BIO_should_write(cbio)) {
-+            rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
-+        } else {
-+            DEBUG(SSSDBG_OP_FAILURE, "Unexpected retry condition\n");
-+            goto err;
-+        }
-+        if (rv == 0) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Timeout on request\n");
-+            break;
-+        }
-+        if (rv == -1) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Select error\n");
-+            break;
-+        }
-+
-+    }
-+ err:
-+    OCSP_REQ_CTX_free(ctx);
-+
-+    return rsp;
-+}
-+
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
-+#define TLS_client_method SSLv23_client_method
-+#define X509_STORE_get0_objects(store) (store->objs)
-+#define X509_OBJECT_get_type(object) (object->type)
-+#define X509_OBJECT_get0_X509(object) (object->data.x509)
-+#endif
-+
-+OCSP_RESPONSE *process_responder(OCSP_REQUEST *req,
-+                                 const char *host, const char *path,
-+                                 const char *port, int use_ssl,
-+                                 int req_timeout)
-+{
-+    BIO *cbio = NULL;
-+    SSL_CTX *ctx = NULL;
-+    OCSP_RESPONSE *resp = NULL;
-+
-+    cbio = BIO_new_connect(host);
-+    if (cbio == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Error creating connect BIO\n");
-+        goto end;
-+    }
-+    if (port != NULL)
-+        BIO_set_conn_port(cbio, port);
-+    if (use_ssl == 1) {
-+        BIO *sbio;
-+        ctx = SSL_CTX_new(TLS_client_method());
-+        if (ctx == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Error creating SSL context.\n");
-+            goto end;
-+        }
-+        SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
-+        sbio = BIO_new_ssl(ctx, 1);
-+        cbio = BIO_push(sbio, cbio);
-+    }
-+
-+    resp = query_responder(cbio, host, path, req, req_timeout);
-+    if (resp == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Error querying OCSP responder\n");
-+    }
-+
-+ end:
-+    BIO_free_all(cbio);
-+    SSL_CTX_free(ctx);
-+    return resp;
-+}
-+
-+static errno_t do_ocsp(struct p11_ctx *p11_ctx, X509 *cert)
-+{
-+    OCSP_REQUEST *ocsp_req = NULL;
-+    OCSP_RESPONSE *ocsp_resp = NULL;
-+    OCSP_BASICRESP *ocsp_basic = NULL;
-+    OCSP_CERTID *cid = NULL;
-+    STACK_OF(OPENSSL_STRING) *ocsp_urls = NULL;
-+    char *url_str;
-+    X509 *issuer = NULL;
-+    int req_timeout = -1;
-+    int status;
-+    int ret = EIO;
-+    int reason;
-+    ASN1_GENERALIZEDTIME *revtime;
-+    ASN1_GENERALIZEDTIME *thisupd;
-+    ASN1_GENERALIZEDTIME *nextupd;
-+    long grace_time = (5 * 60); /* Allow 5 minutes time difference when
-+                                 * checking the validity of the OCSP response */
-+    char *host = NULL;
-+    char *path = NULL;
-+    char *port = NULL;
-+    int use_ssl;
-+    X509_NAME *issuer_name = NULL;
-+    X509_OBJECT *x509_obj;
-+    STACK_OF(X509_OBJECT) *store_objects;
-+
-+    ocsp_urls = X509_get1_ocsp(cert);
-+    if (ocsp_urls == NULL
-+            && p11_ctx->cert_verify_opts->ocsp_default_responder == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "No OCSP URL in certificate and no default responder defined, "
-+              "skipping OCSP check.\n");
-+        return EOK;
-+    }
-+
-+    if (p11_ctx->cert_verify_opts->ocsp_default_responder != NULL) {
-+        url_str = p11_ctx->cert_verify_opts->ocsp_default_responder;
-+    } else {
-+        if (sk_OPENSSL_STRING_num(ocsp_urls) > 1) {
-+            DEBUG(SSSDBG_CONF_SETTINGS,
-+                  "Found more than 1 OCSP URLs, just using the first.\n");
-+        }
-+
-+        url_str = sk_OPENSSL_STRING_value(ocsp_urls, 0);
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "Using OCSP URL [%s].\n", url_str);
-+
-+    ret = OCSP_parse_url(url_str, &host, &port, &path, &use_ssl);
-+    if (ret != 1) {
-+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_parse_url failed to parse [%s].\n",
-+                                 url_str);
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    issuer_name = X509_get_issuer_name(cert);
-+    if (issuer_name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Certificate has no issuer, "
-+                                   "cannot run OCSP check.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    store_objects = X509_STORE_get0_objects(p11_ctx->x509_store);
-+    if (store_objects == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "No objects found in certificate store, OCSP failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    x509_obj = X509_OBJECT_retrieve_by_subject(store_objects, X509_LU_X509,
-+                                               issuer_name);
-+    if (x509_obj == NULL || X509_OBJECT_get_type(x509_obj) != X509_LU_X509) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Issuer not found.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    issuer = X509_OBJECT_get0_X509(x509_obj);
-+
-+    ocsp_req = OCSP_REQUEST_new();
-+    if (ocsp_req == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_REQUEST_new failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    cid = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
-+    if (cid == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_cert_to_id failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    if (OCSP_request_add0_id(ocsp_req, cid) == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_request_add0_id failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    OCSP_request_add1_nonce(ocsp_req, NULL, -1);
-+
-+    ocsp_resp = process_responder(ocsp_req, host, path, port, use_ssl,
-+                                  req_timeout);
-+    if (ocsp_resp == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "process_responder failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    status = OCSP_response_status(ocsp_resp);
-+    if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP response error: [%d][%s].\n",
-+                                   status, OCSP_response_status_str(status));
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    ocsp_basic = OCSP_response_get1_basic(ocsp_resp);
-+    if (ocsp_resp == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_response_get1_basic failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    switch (OCSP_check_nonce(ocsp_req, ocsp_basic)) {
-+    case -1:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "No nonce in OCSP response. This might "
-+              "indicate a replay attack or an OCSP responder which does not "
-+              "support nonces.  Accepting response.\n");
-+        break;
-+    case 0:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Nonce in OCSP response does not match the "
-+                                   "one used in the request.\n");
-+        ret = EIO;
-+        goto done;
-+        break;
-+    case 1:
-+        DEBUG(SSSDBG_TRACE_ALL, "Nonce in OCSP response is the same as the one "
-+                                "used in the request.\n");
-+        break;
-+    case 2:
-+    case 3:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing nonce in OCSP request, this should"
-+                                   "never happen.\n");
-+        ret = EIO;
-+        goto done;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected result of OCSP_check_nonce.\n");
-+    }
-+
-+    status = OCSP_basic_verify(ocsp_basic, NULL, p11_ctx->x509_store, 0);
-+    if (status != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP_base_verify failed to verify OCSP "
-+                                   "response.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    ret = OCSP_resp_find_status(ocsp_basic, cid, &status, &reason,
-+                                &revtime, &thisupd, &nextupd);
-+    if (ret != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP response does not contain status of "
-+                                   "our certificate.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    if (status != V_OCSP_CERTSTATUS_GOOD) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP check failed with [%d][%s].\n",
-+                                   status, OCSP_cert_status_str(status));
-+        if (status == V_OCSP_CERTSTATUS_REVOKED) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Certificate is revoked [%d][%s].\n",
-+                                       reason, OCSP_crl_reason_str(reason));
-+        }
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    if (OCSP_check_validity(thisupd, nextupd, grace_time, -1) != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP response is not valid anymore.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "OCSP check was successful.\n");
-+    ret = EOK;
-+
-+done:
-+    OCSP_BASICRESP_free(ocsp_basic);
-+    OCSP_RESPONSE_free(ocsp_resp);
-+    OCSP_REQUEST_free(ocsp_req);
-+
-+    OPENSSL_free(host);
-+    OPENSSL_free(port);
-+    OPENSSL_free(path);
-+    X509_email_free(ocsp_urls);
-+
-+    return ret;
-+}
- 
- static char *get_pkcs11_uri(TALLOC_CTX *mem_ctx, CK_INFO *module_info,
-                             CK_SLOT_INFO *slot_info, CK_SLOT_ID slot_id,
-@@ -191,6 +528,7 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
-     }
- 
-     p11_ctx->x509_store = store;
-+    p11_ctx->cert_verify_opts = cert_verify_opts;
-     talloc_set_destructor(p11_ctx, talloc_free_x509_store);
- 
-     ret = EOK;
-@@ -262,6 +600,14 @@ bool do_verification(struct p11_ctx *p11_ctx, X509 *cert)
-         goto done;
-     }
- 
-+    if (p11_ctx->cert_verify_opts->do_ocsp) {
-+        ret = do_ocsp(p11_ctx, cert);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "do_ocsp failed.\n");
-+            goto done;
-+        }
-+    }
-+
-     res = true;
- 
- done:
-diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
-index 1a8699a2a87d57ab43c70ceebf9bc71da4def4d4..c86e526e8299122c1c613c8459d3df0d9e4fc878 100644
---- a/src/tests/cmocka/test_utils.c
-+++ b/src/tests/cmocka/test_utils.c
-@@ -1612,6 +1612,8 @@ static void test_parse_cert_verify_opts(void **state)
-                                  &cv_opts);
-     assert_int_equal(ret, EINVAL);
- 
-+/* Only NSS requires that both are set */
-+#ifdef HAVE_NSS
-     ret = parse_cert_verify_opts(global_talloc_context,
-                                  "ocsp_default_responder=abc", &cv_opts);
-     assert_int_equal(ret, EINVAL);
-@@ -1620,6 +1622,7 @@ static void test_parse_cert_verify_opts(void **state)
-                                  "ocsp_default_responder_signing_cert=def",
-                                  &cv_opts);
-     assert_int_equal(ret, EINVAL);
-+#endif
- 
-     ret = parse_cert_verify_opts(global_talloc_context,
-                                  "ocsp_default_responder=abc,"
-diff --git a/src/util/util.c b/src/util/util.c
-index 53dd9a13ab8597b1fec61f10d641c14bf1cedd29..7f475fa9b5f5ddd69e80d5639380824cef82562c 100644
---- a/src/util/util.c
-+++ b/src/util/util.c
-@@ -1123,6 +1123,7 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
-         }
-     }
- 
-+#ifdef HAVE_NSS
-     if ((cert_verify_opts->ocsp_default_responder == NULL
-             && cert_verify_opts->ocsp_default_responder_signing_cert != NULL)
-         || (cert_verify_opts->ocsp_default_responder != NULL
-@@ -1135,6 +1136,7 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
-         ret = EINVAL;
-         goto done;
-     }
-+#endif
- 
-     ret = EOK;
- 
--- 
-2.14.4
-
diff --git a/SOURCES/0052-TESTS-Sync.-multihost-kcm-tests-with-master.patch b/SOURCES/0052-TESTS-Sync.-multihost-kcm-tests-with-master.patch
new file mode 100644
index 0000000..fd8028d
--- /dev/null
+++ b/SOURCES/0052-TESTS-Sync.-multihost-kcm-tests-with-master.patch
@@ -0,0 +1,192 @@
+From 4c77f1d5172b427aad0124d7970fb6905fb0a14a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Mon, 2 Sep 2019 02:01:54 +0200
+Subject: [PATCH] TESTS: Sync. multihost kcm tests with master
+
+---
+ src/tests/multihost/basic/conftest.py |   8 ++
+ src/tests/multihost/basic/test_kcm.py | 138 ++++++++++++++++++++++++++
+ 2 files changed, 146 insertions(+)
+
+diff --git a/src/tests/multihost/basic/conftest.py b/src/tests/multihost/basic/conftest.py
+index 87f74031c..dd3c6f001 100644
+--- a/src/tests/multihost/basic/conftest.py
++++ b/src/tests/multihost/basic/conftest.py
+@@ -397,6 +397,14 @@ def create_posix_usersgroups(session_multihost):
+         assert ret == 'Success'
+ 
+ 
++@pytest.fixture(scope='session')
++def create_many_user_principals(session_multihost):
++    krb = krb5srv(session_multihost.master[0], 'EXAMPLE.TEST')
++    for i in range(1, 65):
++        username = "user%04d" % i
++        krb.add_principal(username, 'user', 'Secret123')
++
++
+ @pytest.fixture(scope="session", autouse=True)
+ def setup_session(request, session_multihost,
+                   package_install,
+diff --git a/src/tests/multihost/basic/test_kcm.py b/src/tests/multihost/basic/test_kcm.py
+index 54b3f7ecd..f18748af7 100644
+--- a/src/tests/multihost/basic/test_kcm.py
++++ b/src/tests/multihost/basic/test_kcm.py
+@@ -3,6 +3,7 @@ from sssd.testlib.common.utils import SSHClient
+ import paramiko
+ import pytest
+ import os
++import re
+ from utils_config import set_param, remove_section
+ 
+ 
+@@ -38,6 +39,11 @@ class TestSanityKCM(object):
+         os.remove(local_kcm_log_file)
+         return nlines
+ 
++    def _remove_secret_db(self, multihost):
++        multihost.master[0].run_command(
++                'rm -f /var/lib/sss/secrets/secrets.ldb')
++        self._restart_kcm(multihost)
++
+     def test_kinit_kcm(self, multihost, enable_kcm):
+         """
+         @Title: kcm: Run kinit with KRB5CCNAME=KCM
+@@ -175,3 +181,135 @@ class TestSanityKCM(object):
+             if 'KCM:14583109' in line:
+                 has_cache = True
+         assert has_cache is True
++
++    def test_kvno_display(self, multihost, enable_kcm):
++        """
++        @Title: kcm: Test kvno correctly displays vesion numbers of principals
++        #https://pagure.io/SSSD/sssd/issue/3757
++        """
++        ssh = SSHClient(multihost.master[0].sys_hostname,
++                        username='foo4', password='Secret123')
++        host_princ = 'host/%s@%s' % (multihost.master[0].sys_hostname,
++                                     'EXAMPLE.TEST')
++        kvno_cmd = 'kvno %s' % (host_princ)
++        (stdout, _, exit_status) = ssh.execute_cmd(kvno_cmd)
++        for line in stdout.readlines():
++            kvno_check = re.search(r'%s: kvno = (\d+)' % host_princ, line)
++            if kvno_check:
++                print(kvno_check.group())
++            else:
++                pytest.fail("kvno display was improper")
++        ssh.close()
++
++    def test_kcm_peruid_quota(self,
++                              multihost,
++                              enable_kcm,
++                              create_many_user_principals):
++        """
++        @Title: kcm: Make sure the quota limits a client, but only that client
++        """
++        # It is easier to keep these tests stable and independent from others
++        # if they start from a clean slate
++        self._remove_secret_db(multihost)
++
++        ssh_foo2 = SSHClient(multihost.master[0].sys_hostname,
++                             username='foo2', password='Secret123')
++        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
++                             username='foo3', password='Secret123')
++
++        # The loop would request 63 users, plus there is foo3 we authenticated
++        # earlier, so this should exactly deplete the quota, but should succeed
++        for i in range(1, 64):
++            username = "user%04d" % i
++            (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username,
++                                                       stdin='Secret123')
++            assert exit_status == 0
++
++        # this kinit should be exactly one over the peruid limit
++        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
++                                                   stdin='Secret123')
++        assert exit_status != 0
++
++        # Since this is a per-uid limit, another user should be able to kinit
++        # just fine
++        (_, _, exit_status) = ssh_foo2.execute_cmd('kinit user0064',
++                                                   stdin='Secret123')
++        assert exit_status == 0
++
++        # kdestroy as the original user, the quota should allow a subsequent
++        # kinit
++        ssh_foo3.execute_cmd('kdestroy -A')
++        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
++                                                   stdin='Secret123')
++        assert exit_status == 0
++
++        ssh_foo2.execute_cmd('kdestroy -A')
++        ssh_foo2.close()
++        ssh_foo3.execute_cmd('kdestroy -A')
++        ssh_foo3.close()
++
++    def test_kcm_peruid_quota_increase(self,
++                                       multihost,
++                                       enable_kcm,
++                                       create_many_user_principals):
++        """
++        @Title: kcm: Quota increase
++
++        Increasing the peruid quota allows a client to store more
++        data
++        """
++        # It is easier to keep these tests stable and independent from others
++        # if they start from a clean slate
++        self._remove_secret_db(multihost)
++
++        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
++                             username='foo3', password='Secret123')
++
++        # The loop would request 63 users, plus there is foo3 we authenticated
++        # earlier, so this should exactly deplete the quota, but should succeed
++        for i in range(1, 64):
++            username = "user%04d" % i
++            (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username,
++                                                       stdin='Secret123')
++            assert exit_status == 0
++
++        # this kinit should be exactly one over the peruid limit
++        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
++                                                   stdin='Secret123')
++        assert exit_status != 0
++
++        set_param(multihost, 'kcm', 'max_uid_ccaches', '65')
++        self._restart_kcm(multihost)
++
++        # Now the kinit should work as we increased the limit
++        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
++                                                   stdin='Secret123')
++        assert exit_status == 0
++
++        ssh_foo3.execute_cmd('kdestroy -A')
++        ssh_foo3.close()
++
++    def test_kcm_payload_low_quota(self,
++                                   multihost,
++                                   enable_kcm):
++        """
++        @Title: kcm: Quota enforcement
++
++        Set a prohibitive quota for the per-ccache payload limit and
++        make sure it gets enforced
++        """
++        # It is easier to keep these tests stable and independent from others
++        # if they start from a clean slate
++        self._remove_secret_db(multihost)
++
++        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
++                             username='foo3', password='Secret123')
++        ssh_foo3.execute_cmd('kdestroy -A')
++        ssh_foo3.close()
++
++        set_param(multihost, 'kcm', 'max_ccache_size', '1')
++        self._restart_kcm(multihost)
++
++        with pytest.raises(paramiko.ssh_exception.AuthenticationException):
++            ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
++                                 username='foo3', password='Secret123')
+-- 
+2.20.1
+
diff --git a/SOURCES/0052-p11_child-add-crl_file-option-for-the-OpenSSL-build.patch b/SOURCES/0052-p11_child-add-crl_file-option-for-the-OpenSSL-build.patch
deleted file mode 100644
index 31dc808..0000000
--- a/SOURCES/0052-p11_child-add-crl_file-option-for-the-OpenSSL-build.patch
+++ /dev/null
@@ -1,280 +0,0 @@
-From 1a8969bb1b3dbd1d5ef7f29dd0fa2ddc8a50fa8b Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 11 Oct 2018 17:35:24 +0200
-Subject: [PATCH 52/57] p11_child: add crl_file option for the OpenSSL build
-
-In the NSS build a Certificate Revocation List (CRL) can just be added
-to the NSS database. For OpenSSL a separate file is needed.
-
-Related to https://pagure.io/SSSD/sssd/issue/3489
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 3c096c9ad6dad911d035cfdd802b5dda4710fc68)
----
- src/man/sssd.conf.5.xml           | 24 ++++++++++++++++++++++++
- src/p11_child/p11_child_common.c  | 12 ++++++------
- src/p11_child/p11_child_openssl.c | 26 +++++++++++++++++++++++++-
- src/tests/cmocka/test_utils.c     | 16 ++++++++++++++++
- src/util/util.c                   | 13 +++++++++++++
- src/util/util.h                   |  1 +
- 6 files changed, 85 insertions(+), 7 deletions(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 5e3ae48d04cc38ea54547a63c6c31795e12544c2..bea25c62286fa638bec47cb7404341be6190f410 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -503,6 +503,30 @@
-                                         pam_cert_db_path.</para>
-                                     </listitem>
-                                 </varlistentry>
-+                                <varlistentry>
-+                                    <term>crl_file=/PATH/TO/CRL/FILE</term>
-+                                    <listitem>
-+                                        <para>(NSS Version) This option is
-+                                        ignored, please see
-+                                            <citerefentry>
-+                                                <refentrytitle>crlutil</refentrytitle>
-+                                                <manvolnum>1</manvolnum>
-+                                            </citerefentry>
-+                                        how to import a Certificate Revocation
-+                                        List (CRL) into a NSS database.</para>
-+
-+                                        <para>(OpenSSL Version) Use the
-+                                        Certificate Revocation List (CRL) from
-+                                        the given file during the verification
-+                                        of the certificate. The CRL must be
-+                                        given in PEM format, see
-+                                            <citerefentry>
-+                                                <refentrytitle>crl</refentrytitle>
-+                                                <manvolnum>1ssl</manvolnum>
-+                                            </citerefentry>
-+                                        for details.</para>
-+                                    </listitem>
-+                                </varlistentry>
-                                 </variablelist>
-                             </para>
-                             <para condition="with_nss">
-diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c
-index 097e7fa07fb4d90e087250aec9f971b4a2afdb52..b992aeb71ee6c8acc8792265aaa7bdcf0d06770d 100644
---- a/src/p11_child/p11_child_common.c
-+++ b/src/p11_child/p11_child_common.c
-@@ -48,7 +48,7 @@ static const char *op_mode_str(enum op_mode mode)
-         return "pre-auth";
-         break;
-     case OP_VERIFIY:
--        return "verifiy";
-+        return "verify";
-         break;
-     default:
-         return "unknown";
-@@ -219,7 +219,7 @@ int main(int argc, const char *argv[])
-         case 'a':
-             if (mode != OP_NONE) {
-                 fprintf(stderr,
--                        "\n--verifiy, --auth and --pre are mutually " \
-+                        "\n--verify, --auth and --pre are mutually " \
-                         "exclusive and should be only used once.\n\n");
-                 poptPrintUsage(pc, stderr, 0);
-                 _exit(-1);
-@@ -229,7 +229,7 @@ int main(int argc, const char *argv[])
-         case 'p':
-             if (mode != OP_NONE) {
-                 fprintf(stderr,
--                        "\n--verifiy, --auth and --pre are mutually " \
-+                        "\n--verify, --auth and --pre are mutually " \
-                         "exclusive and should be only used once.\n\n");
-                 poptPrintUsage(pc, stderr, 0);
-                 _exit(-1);
-@@ -239,7 +239,7 @@ int main(int argc, const char *argv[])
-         case 'v':
-             if (mode != OP_NONE) {
-                 fprintf(stderr,
--                        "\n--verifiy, --auth and --pre are mutually " \
-+                        "\n--verify, --auth and --pre are mutually " \
-                         "exclusive and should be only used once.\n\n");
-                 poptPrintUsage(pc, stderr, 0);
-                 _exit(-1);
-@@ -283,7 +283,7 @@ int main(int argc, const char *argv[])
- 
-     if (mode == OP_NONE) {
-         fprintf(stderr, "\nMissing operation mode, either " \
--                        "--verifiy, --auth or --pre must be specified.\n\n");
-+                        "--verify, --auth or --pre must be specified.\n\n");
-         poptPrintUsage(pc, stderr, 0);
-         _exit(-1);
-     } else if (mode == OP_AUTH && pin_mode == PIN_NONE) {
-@@ -350,7 +350,7 @@ int main(int argc, const char *argv[])
- 
-     ret = parse_cert_verify_opts(main_ctx, verify_opts, &cert_verify_opts);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verifiy option.\n");
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verify option.\n");
-         goto fail;
-     }
- 
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index d66a2f82becfa24eae867a2f3df3e23263a5273c..9defdfc5a7acc70d0cea06d4919b06b93eb33c7b 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -501,6 +501,7 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
-     X509_STORE *store = NULL;
-     unsigned long err;
-     X509_LOOKUP *lookup = NULL;
-+    X509_VERIFY_PARAM *verify_param = NULL;
- 
-     store = X509_STORE_new();
-     if (store == NULL) {
-@@ -527,6 +528,30 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
-         goto done;
-     }
- 
-+    if (cert_verify_opts->crl_file != NULL) {
-+        verify_param = X509_VERIFY_PARAM_new();
-+        if (verify_param == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "X509_VERIFY_PARAM_new failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        X509_VERIFY_PARAM_set_flags(verify_param, (X509_V_FLAG_CRL_CHECK
-+                                                  | X509_V_FLAG_CRL_CHECK_ALL));
-+
-+        X509_STORE_set1_param(store, verify_param);
-+
-+        ret = X509_load_crl_file(lookup, cert_verify_opts->crl_file,
-+                                 X509_FILETYPE_PEM);
-+        if (ret == 0) {
-+            err = ERR_get_error();
-+            DEBUG(SSSDBG_OP_FAILURE, "X509_load_crl_file failed [%lu][%s].\n",
-+                                     err, ERR_error_string(err, NULL));
-+            ret = EIO;
-+            goto done;
-+        }
-+    }
-+
-     p11_ctx->x509_store = store;
-     p11_ctx->cert_verify_opts = cert_verify_opts;
-     talloc_set_destructor(p11_ctx, talloc_free_x509_store);
-@@ -536,7 +561,6 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
- done:
-     if (ret != EOK) {
-         X509_STORE_free(store);
--        X509_LOOKUP_free(lookup);
-     }
- 
-     return ret;
-diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
-index c86e526e8299122c1c613c8459d3df0d9e4fc878..cf1c2ae6787cd1b011089b57d6bac320dadd60de 100644
---- a/src/tests/cmocka/test_utils.c
-+++ b/src/tests/cmocka/test_utils.c
-@@ -1567,6 +1567,7 @@ static void test_parse_cert_verify_opts(void **state)
-     assert_true(cv_opts->do_ocsp);
-     assert_null(cv_opts->ocsp_default_responder);
-     assert_null(cv_opts->ocsp_default_responder_signing_cert);
-+    assert_null(cv_opts->crl_file);
-     talloc_free(cv_opts);
- 
-     ret = parse_cert_verify_opts(global_talloc_context, "wedfkwefjk", &cv_opts);
-@@ -1575,6 +1576,7 @@ static void test_parse_cert_verify_opts(void **state)
-     assert_true(cv_opts->do_ocsp);
-     assert_null(cv_opts->ocsp_default_responder);
-     assert_null(cv_opts->ocsp_default_responder_signing_cert);
-+    assert_null(cv_opts->crl_file);
-     talloc_free(cv_opts);
- 
-     ret = parse_cert_verify_opts(global_talloc_context, "no_ocsp", &cv_opts);
-@@ -1583,6 +1585,7 @@ static void test_parse_cert_verify_opts(void **state)
-     assert_false(cv_opts->do_ocsp);
-     assert_null(cv_opts->ocsp_default_responder);
-     assert_null(cv_opts->ocsp_default_responder_signing_cert);
-+    assert_null(cv_opts->crl_file);
-     talloc_free(cv_opts);
- 
-     ret = parse_cert_verify_opts(global_talloc_context, "no_verification",
-@@ -1592,6 +1595,7 @@ static void test_parse_cert_verify_opts(void **state)
-     assert_true(cv_opts->do_ocsp);
-     assert_null(cv_opts->ocsp_default_responder);
-     assert_null(cv_opts->ocsp_default_responder_signing_cert);
-+    assert_null(cv_opts->crl_file);
-     talloc_free(cv_opts);
- 
-     ret = parse_cert_verify_opts(global_talloc_context,
-@@ -1601,6 +1605,7 @@ static void test_parse_cert_verify_opts(void **state)
-     assert_false(cv_opts->do_ocsp);
-     assert_null(cv_opts->ocsp_default_responder);
-     assert_null(cv_opts->ocsp_default_responder_signing_cert);
-+    assert_null(cv_opts->crl_file);
-     talloc_free(cv_opts);
- 
-     ret = parse_cert_verify_opts(global_talloc_context,
-@@ -1633,6 +1638,17 @@ static void test_parse_cert_verify_opts(void **state)
-     assert_true(cv_opts->do_ocsp);
-     assert_string_equal(cv_opts->ocsp_default_responder, "abc");
-     assert_string_equal(cv_opts->ocsp_default_responder_signing_cert, "def");
-+    assert_null(cv_opts->crl_file);
-+    talloc_free(cv_opts);
-+
-+    ret = parse_cert_verify_opts(global_talloc_context, "crl_file=hij",
-+                                 &cv_opts);
-+    assert_int_equal(ret, EOK);
-+    assert_true(cv_opts->do_verification);
-+    assert_true(cv_opts->do_ocsp);
-+    assert_null(cv_opts->ocsp_default_responder);
-+    assert_null(cv_opts->ocsp_default_responder_signing_cert);
-+    assert_string_equal(cv_opts->crl_file, "hij");
-     talloc_free(cv_opts);
- }
- 
-diff --git a/src/util/util.c b/src/util/util.c
-index 7f475fa9b5f5ddd69e80d5639380824cef82562c..cbe6a2870c302c51770ef5b526bd5bf8cc8df0e0 100644
---- a/src/util/util.c
-+++ b/src/util/util.c
-@@ -1024,6 +1024,7 @@ static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx)
-     cert_verify_opts->do_verification = true;
-     cert_verify_opts->ocsp_default_responder = NULL;
-     cert_verify_opts->ocsp_default_responder_signing_cert = NULL;
-+    cert_verify_opts->crl_file = NULL;
- 
-     return cert_verify_opts;
- }
-@@ -1035,6 +1036,8 @@ static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx)
-                                           "ocsp_default_responder_signing_cert="
- #define OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN \
-                                 (sizeof(OCSP_DEFAUL_RESPONDER_SIGNING_CERT) - 1)
-+#define CRL_FILE "crl_file="
-+#define CRL_FILE_LEN (sizeof(CRL_FILE) -1)
- 
- errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
-                                struct cert_verify_opts **_cert_verify_opts)
-@@ -1116,6 +1119,16 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
-             DEBUG(SSSDBG_TRACE_ALL,
-                   "Using OCSP default responder signing cert nickname [%s]\n",
-                   cert_verify_opts->ocsp_default_responder_signing_cert);
-+        } else if (strncasecmp(opts[c], CRL_FILE, CRL_FILE_LEN) == 0) {
-+            cert_verify_opts->crl_file = talloc_strdup(cert_verify_opts,
-+                                                       &opts[c][CRL_FILE_LEN]);
-+            if (cert_verify_opts->crl_file == NULL
-+                    || *cert_verify_opts->crl_file == '\0') {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "Failed to parse crl_file option [%s].\n", opts[c]);
-+                ret = EINVAL;
-+                goto done;
-+            }
-         } else {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-                   "Unsupported certificate verification option [%s], " \
-diff --git a/src/util/util.h b/src/util/util.h
-index e3e91009728cd8a5a92701220c06e8c378f47431..7e9b3d6a6fe323606ab9646b9757e725b5a4ef74 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -371,6 +371,7 @@ struct cert_verify_opts {
-     bool do_verification;
-     char *ocsp_default_responder;
-     char *ocsp_default_responder_signing_cert;
-+    char *crl_file;
- };
- 
- errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
--- 
-2.14.4
-
diff --git a/SOURCES/0053-KCM-Add-a-forgotten-return.patch b/SOURCES/0053-KCM-Add-a-forgotten-return.patch
new file mode 100644
index 0000000..6ddf5ba
--- /dev/null
+++ b/SOURCES/0053-KCM-Add-a-forgotten-return.patch
@@ -0,0 +1,28 @@
+From 80cf912405c06254008e3c3766f438b8e0f03af7 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 27 Aug 2019 14:27:21 +0200
+Subject: [PATCH 53/55] KCM: Add a forgotten return
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/responder/kcm/kcmsrv_ops.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
+index 1160c93f9..d8a7b03c5 100644
+--- a/src/responder/kcm/kcmsrv_ops.c
++++ b/src/responder/kcm/kcmsrv_ops.c
+@@ -1685,6 +1685,7 @@ static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq)
+         DEBUG(SSSDBG_TRACE_LIBS,
+               "The ccache does not exist, creating a new one\n");
+         kcm_op_set_default_create_step(req);
++        return;
+     } else if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Cannot get ccache by name [%d]: %s\n",
+-- 
+2.20.1
+
diff --git a/SOURCES/0053-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch b/SOURCES/0053-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch
deleted file mode 100644
index 831330d..0000000
--- a/SOURCES/0053-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From cc285823b8966fc03a511c5aa7332a385d8c47c1 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 12 Oct 2018 09:32:11 +0200
-Subject: [PATCH 53/57] p11: Fix two instances of -Wmaybe-uninitialized in
- p11_child_openssl.c
-
-If uri_str was passed to the p11_child and parsing the URI failed, then
-modules would be uninitialized, but freed in the done handler with
-p11_kit_modules_finalize_and_release()
-
-Also, another warning is suppressed by setting the 's' variable to zero.
-While it cannot happen that the variable will be uninitialized, we
-should help the compiler by setting a value explicitly.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 7794caec36e7142423491d90aaade7e49b9df1c1)
----
- src/p11_child/p11_child_openssl.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index 9defdfc5a7acc70d0cea06d4919b06b93eb33c7b..adfe272e069bd0742caa1584153eb483e737e45b 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -1036,8 +1036,8 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
- {
-     int ret;
-     size_t c;
--    size_t s;
--    CK_FUNCTION_LIST **modules;
-+    size_t s = 0;
-+    CK_FUNCTION_LIST **modules = NULL;
-     CK_FUNCTION_LIST *module = NULL;
-     char *mod_name;
-     char *mod_file_name;
--- 
-2.14.4
-
diff --git a/SOURCES/0054-KCM-Allow-modifications-of-ccache-s-principal.patch b/SOURCES/0054-KCM-Allow-modifications-of-ccache-s-principal.patch
new file mode 100644
index 0000000..c60f90c
--- /dev/null
+++ b/SOURCES/0054-KCM-Allow-modifications-of-ccache-s-principal.patch
@@ -0,0 +1,188 @@
+From 436cf4c15b7659b21205affd6743aa6159c55b5c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 28 Aug 2019 14:22:49 +0200
+Subject: [PATCH 54/55] KCM: Allow modifications of ccache's principal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4017
+
+This patch will be useful to fix credential delegation.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/responder/kcm/kcmsrv_ccache.c         | 37 +++++++++++++++++++++--
+ src/responder/kcm/kcmsrv_ccache.h         |  5 +--
+ src/responder/kcm/kcmsrv_ccache_mem.c     |  8 ++++-
+ src/responder/kcm/kcmsrv_ccache_secdb.c   |  8 ++++-
+ src/responder/kcm/kcmsrv_ccache_secrets.c |  9 +++++-
+ src/responder/kcm/kcmsrv_ops.c            |  4 +--
+ 6 files changed, 60 insertions(+), 11 deletions(-)
+
+diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
+index 085cc4464..e24da9aa2 100644
+--- a/src/responder/kcm/kcmsrv_ccache.c
++++ b/src/responder/kcm/kcmsrv_ccache.c
+@@ -1089,25 +1089,56 @@ errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
+-void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx)
++static void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx)
+ {
+     if (mod_ctx == NULL) {
+         return;
+     }
+ 
+     mod_ctx->kdc_offset = INT32_MAX;
++    if (mod_ctx->client != NULL) {
++        krb5_free_principal(NULL, mod_ctx->client);
++        mod_ctx->client = NULL;
++    }
++
++    return;
++}
++
++struct kcm_mod_ctx *kcm_mod_ctx_new(TALLOC_CTX *mem_ctx)
++{
++    struct kcm_mod_ctx *mod_ctx;
++
++    mod_ctx = talloc_zero(mem_ctx, struct kcm_mod_ctx);
++    if (mod_ctx == NULL) {
++        return NULL;
++    }
++
++    kcm_mod_ctx_clear(mod_ctx);
++    return mod_ctx;
+ }
+ 
+-void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx)
++errno_t kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx)
+ {
+     if (cc == NULL || mod_ctx == NULL) {
+-        return;
++        return EINVAL;
+     }
+ 
+     if (mod_ctx->kdc_offset != INT32_MAX) {
+         cc->kdc_offset = mod_ctx->kdc_offset;
+     }
+ 
++    if (mod_ctx->client != NULL) {
++        krb5_error_code kret;
++
++        kret = krb5_copy_principal(NULL, mod_ctx->client, &cc->client);
++        if (kret != 0) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                "krb5_copy_principal failed: %d\n", kret);
++            return ERR_INTERNAL;
++        }
++    }
++
++    return EOK;
+ }
+ 
+ struct kcm_ccdb_mod_cc_state {
+diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
+index 199b75b16..220220ca9 100644
+--- a/src/responder/kcm/kcmsrv_ccache.h
++++ b/src/responder/kcm/kcmsrv_ccache.h
+@@ -257,13 +257,14 @@ errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req);
+  */
+ struct kcm_mod_ctx {
+     int32_t kdc_offset;
++    krb5_principal client;
+     /* More settable properties (like name, when we support renames
+      * will be added later
+      */
+ };
+ 
+-void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx);
+-void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx);
++struct kcm_mod_ctx *kcm_mod_ctx_new(TALLOC_CTX *mem_ctx);
++errno_t kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx);
+ 
+ struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c
+index 35955b2f4..18c3878ad 100644
+--- a/src/responder/kcm/kcmsrv_ccache_mem.c
++++ b/src/responder/kcm/kcmsrv_ccache_mem.c
+@@ -676,7 +676,13 @@ static struct tevent_req *ccdb_mem_mod_send(TALLOC_CTX *mem_ctx,
+         goto immediate;
+     }
+ 
+-    kcm_mod_cc(ccwrap->cc, mod_cc);
++    ret = kcm_mod_cc(ccwrap->cc, mod_cc);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Cannot modify ccache [%d]: %s\n",
++              ret, sss_strerror(ret));
++        goto immediate;
++    }
+ 
+     ret = EOK;
+ immediate:
+diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
+index 26ee1032d..32137a66e 100644
+--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
++++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
+@@ -1290,7 +1290,13 @@ static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx,
+         goto immediate;
+     }
+ 
+-    kcm_mod_cc(cc, mod_cc);
++    ret = kcm_mod_cc(cc, mod_cc);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Cannot modify ccache [%d]: %s\n",
++              ret, sss_strerror(ret));
++        goto immediate;
++    }
+ 
+     ret = kcm_ccache_to_sec_input(state, cc, client, &payload);
+     if (ret != EOK) {
+diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c
+index 7b019fded..83c16974d 100644
+--- a/src/responder/kcm/kcmsrv_ccache_secrets.c
++++ b/src/responder/kcm/kcmsrv_ccache_secrets.c
+@@ -1846,7 +1846,14 @@ static void ccdb_sec_mod_cred_get_done(struct tevent_req *subreq)
+         return;
+     }
+ 
+-    kcm_mod_cc(cc, state->mod_cc);
++    ret = kcm_mod_cc(cc, state->mod_cc);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Cannot modify ccache [%d]: %s\n",
++              ret, sss_strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
+ 
+     ret = kcm_ccache_to_sec_kv(state, cc, state->client, &url, &payload);
+     if (ret != EOK) {
+diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
+index d8a7b03c5..8bd63165b 100644
+--- a/src/responder/kcm/kcmsrv_ops.c
++++ b/src/responder/kcm/kcmsrv_ops.c
+@@ -1990,13 +1990,11 @@ static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq)
+         return;
+     }
+ 
+-    mod_ctx = talloc(state, struct kcm_mod_ctx);
++    mod_ctx = kcm_mod_ctx_new(state);
+     if (mod_ctx == NULL) {
+         tevent_req_error(req, ENOMEM);
+         return;
+     }
+-
+-    kcm_mod_ctx_clear(mod_ctx);
+     mod_ctx->kdc_offset = be32toh(offset_be);
+ 
+     subreq = kcm_ccdb_mod_cc_send(state,
+-- 
+2.20.1
+
diff --git a/SOURCES/0054-sudo-use-correct-sbus-interface.patch b/SOURCES/0054-sudo-use-correct-sbus-interface.patch
deleted file mode 100644
index 7122888..0000000
--- a/SOURCES/0054-sudo-use-correct-sbus-interface.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 7c4b21ff0b9cf12ff520b4eace848ac83b3b47d2 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Mon, 15 Oct 2018 12:46:35 +0200
-Subject: [PATCH 54/57] sudo: use correct sbus interface
-
-Internal dbus interfaces were renamed to shorter names in sbus2.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3854
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 250e82252b53991e2902b292cfa6029ab28a10fb)
----
- src/responder/sudo/sudosrv_dp.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/sudo/sudosrv_dp.c b/src/responder/sudo/sudosrv_dp.c
-index 2c6b26eae1d5d6a1a16658101c6ef526608513cb..78dd296ecdd8dc8389fcf6bce804926d3522e692 100644
---- a/src/responder/sudo/sudosrv_dp.c
-+++ b/src/responder/sudo/sudosrv_dp.c
-@@ -66,7 +66,7 @@ sss_dp_get_sudoers_msg(TALLOC_CTX *mem_ctx,
- 
-     msg = dbus_message_new_method_call(bus_name,
-                                        SSS_BUS_PATH,
--                                       "org.freedesktop.sssd.dataprovider",
-+                                       "sssd.dataprovider",
-                                        "sudoHandler");
-     if (msg == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
--- 
-2.14.4
-
diff --git a/SOURCES/0055-KCM-Fill-empty-cache-do-not-initialize-a-new-one.patch b/SOURCES/0055-KCM-Fill-empty-cache-do-not-initialize-a-new-one.patch
new file mode 100644
index 0000000..1a7d461
--- /dev/null
+++ b/SOURCES/0055-KCM-Fill-empty-cache-do-not-initialize-a-new-one.patch
@@ -0,0 +1,160 @@
+From dbcd8411643a641316696f221860517ab06879ba Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 28 Aug 2019 14:23:18 +0200
+Subject: [PATCH 55/55] KCM: Fill empty cache, do not initialize a new one
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/4017
+
+openssh uses this sequence of calls:
+    gen_new()
+    switch()
+    initialize()
+
+What happened before was that if there was already some cache, gen_new
+would create a new empty cache, then switch would set it as the default.
+But then, during the initialize call, the cache that used to be the
+default was deleted, another one created and used as the default. This
+meant. Afterwards, KCM would store the credentials in the previous
+cache, which would no longer be the default.
+
+The logic behind was that KCM didn't anticipate the client generating
+the new and setting the default on its own.
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+---
+ src/responder/kcm/kcmsrv_ops.c | 84 +++++++++++++++++++++++++++++++++-
+ 1 file changed, 82 insertions(+), 2 deletions(-)
+
+diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
+index 8bd63165b..2181ec6e6 100644
+--- a/src/responder/kcm/kcmsrv_ops.c
++++ b/src/responder/kcm/kcmsrv_ops.c
+@@ -367,6 +367,8 @@ struct kcm_op_initialize_state {
+ static void kcm_op_initialize_got_byname(struct tevent_req *subreq);
+ static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq);
+ static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq);
++static void kcm_op_initialize_fill_princ_step(struct tevent_req *req);
++static void kcm_op_initialize_fill_princ_done(struct tevent_req *subreq);
+ static void kcm_op_initialize_create_step(struct tevent_req *req);
+ static void kcm_op_initialize_got_default(struct tevent_req *subreq);
+ static void kcm_op_initialize_set_default_done(struct tevent_req *subreq);
+@@ -450,6 +452,15 @@ static void kcm_op_initialize_got_byname(struct tevent_req *subreq)
+     }
+ 
+     if (state->new_cc != NULL) {
++        if (kcm_cc_get_client_principal(state->new_cc) == NULL) {
++            /* This is a cache that was pre-created w/o a principal (sshd does this),
++             * let's fill in the principal and set the cache as default if not
++             * already
++             */
++            kcm_op_initialize_fill_princ_step(req);
++            return;
++        }
++
+         ok = kcm_cc_access(state->new_cc, state->op_ctx->client);
+         if (!ok) {
+             state->op_ret = EACCES;
+@@ -501,6 +512,70 @@ static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq)
+     kcm_op_initialize_create_step(req);
+ }
+ 
++static void kcm_op_initialize_fill_princ_step(struct tevent_req *req)
++{
++    struct tevent_req *subreq;
++    struct kcm_op_initialize_state *state = tevent_req_data(req,
++                                            struct kcm_op_initialize_state);
++    errno_t ret;
++    struct kcm_mod_ctx *mod_ctx;
++    uuid_t uuid;
++
++    mod_ctx = kcm_mod_ctx_new(state);
++    if (mod_ctx == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    mod_ctx->client = state->princ;
++
++    ret = kcm_cc_get_uuid(state->new_cc, uuid);
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    subreq = kcm_ccdb_mod_cc_send(state,
++                                  state->ev,
++                                  state->op_ctx->kcm_data->db,
++                                  state->op_ctx->client,
++                                  uuid,
++                                  mod_ctx);
++    if (subreq == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    tevent_req_set_callback(subreq, kcm_op_initialize_fill_princ_done, req);
++}
++
++static void kcm_op_initialize_fill_princ_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                      struct tevent_req);
++    struct kcm_op_initialize_state *state = tevent_req_data(req,
++                                            struct kcm_op_initialize_state);
++    errno_t ret;
++
++    ret = kcm_ccdb_mod_cc_recv(subreq);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Cannot modify ccache [%d]: %s\n",
++              ret, sss_strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    /* Make sure the cache we just initialized is the default one */
++    subreq = kcm_ccdb_get_default_send(state, state->ev,
++                                       state->op_ctx->kcm_data->db,
++                                       state->op_ctx->client);
++    if (subreq == NULL) {
++        tevent_req_error(req, ret);
++        return;
++    }
++    tevent_req_set_callback(subreq, kcm_op_initialize_got_default, req);
++}
++
+ static void kcm_op_initialize_create_step(struct tevent_req *req)
+ {
+     struct tevent_req *subreq;
+@@ -588,11 +663,14 @@ static void kcm_op_initialize_got_default(struct tevent_req *subreq)
+         ret = kcm_cc_get_uuid(state->new_cc, dfl_uuid);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+-              "Cannot get new ccache UUID [%d]: %s\n",
+-              ret, sss_strerror(ret));
++                  "Cannot get new ccache UUID [%d]: %s\n",
++                  ret, sss_strerror(ret));
+             return;
+         }
+ 
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "The default ccached was not set, switching to the "
++              "initialized\n");
+         subreq = kcm_ccdb_set_default_send(state,
+                                            state->ev,
+                                            state->op_ctx->kcm_data->db,
+@@ -1756,6 +1834,8 @@ static void kcm_op_set_default_create_step_done(struct tevent_req *subreq)
+         return;
+     }
+ 
++    DEBUG(SSSDBG_TRACE_FUNC, "The ccache was created, switching to it");
++
+     ret = kcm_cc_get_uuid(state->new_cc, state->dfl_uuid);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+-- 
+2.20.1
+
diff --git a/SOURCES/0055-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch b/SOURCES/0055-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch
deleted file mode 100644
index c7ca404..0000000
--- a/SOURCES/0055-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 402f63b5a3b42797ec2b3e2ad53e50d198eb98b4 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Mon, 15 Oct 2018 13:01:34 +0200
-Subject: [PATCH 55/57] sudo: fix error handling in sudosrv_refresh_rules_done
-
-If sbus returns non-zero code then the output variables are not set and
-therefore we access uninitialized memory.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3854
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 8fbaf224193b9ca8b82a290bd52265c2f9b40315)
----
- src/responder/sudo/sudosrv_get_sudorules.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
-index 14bd824775fea47fd28ca4880d31cfc67b03d0da..76faef0f566235324999a9a85246dd960119cab3 100644
---- a/src/responder/sudo/sudosrv_get_sudorules.c
-+++ b/src/responder/sudo/sudosrv_get_sudorules.c
-@@ -576,10 +576,15 @@ static void sudosrv_refresh_rules_done(struct tevent_req *subreq)
-     ret = sss_dp_get_sudoers_recv(state, subreq, &err_maj, &err_min, &err_msg);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to refresh rules [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        goto done;
-+    } else if (err_maj != 0 || err_min != 0) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "Unable to get information from Data Provider, "
-               "Error: %u, %u, %s\n",
--              (unsigned int)err_maj, (unsigned int)err_min, err_msg);
-+              (unsigned int)err_maj, (unsigned int)err_min,
-+              (err_msg == NULL ? "(null)" : err_msg));
-         goto done;
-     }
- 
--- 
-2.14.4
-
diff --git a/SOURCES/0056-files-add-session-recording-flag.patch b/SOURCES/0056-files-add-session-recording-flag.patch
deleted file mode 100644
index 440e9b7..0000000
--- a/SOURCES/0056-files-add-session-recording-flag.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-From 21087821ab7942a54168d545ea2f96a6f7582344 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 15 Oct 2018 20:05:09 +0200
-Subject: [PATCH 56/57] files: add session recording flag
-
-If session recording is configured for a group the NSS ans PAM
-responder rely on a attribute in the cache set by the backend to
-determine is session recording is configured for the user or not. This
-flag is typically set during the initgroups request.
-
-Since the files provider does not have a dedicated initgroups request
-the attribute must be set otherwise. This patch sets is for all users
-after the files are reloaded.
-
-Related to https://pagure.io/SSSD/sssd/issue/3855
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/data_provider/dp_iface.h     |  3 ++
- src/providers/data_provider/dp_target_id.c | 62 ++++++++++++++++++++++++++++++
- src/providers/files/files_ops.c            |  7 ++++
- 3 files changed, 72 insertions(+)
-
-diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
-index 0b0855da6c62d01d523486fe65e9920578ba58e5..8f6b2076c1adb8ad046a0d03ae5ae8a0600a5707 100644
---- a/src/providers/data_provider/dp_iface.h
-+++ b/src/providers/data_provider/dp_iface.h
-@@ -188,4 +188,7 @@ errno_t
- dp_access_control_refresh_rules_recv(TALLOC_CTX *mem_ctx,
-                                      struct tevent_req *req);
- 
-+
-+errno_t
-+dp_add_sr_attribute(struct be_ctx *be_ctx);
- #endif /* DP_IFACE_H_ */
-diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
-index 265788be9b032fcdf0f354f9c66a98241aa17916..748d886748f34e6b99c6bfc0f7607e048cbd2425 100644
---- a/src/providers/data_provider/dp_target_id.c
-+++ b/src/providers/data_provider/dp_target_id.c
-@@ -328,6 +328,68 @@ done:
-     talloc_free(tmp_ctx);
- }
- 
-+errno_t dp_add_sr_attribute(struct be_ctx *be_ctx)
-+{
-+    int ret;
-+    struct dp_initgr_ctx *dp_initgr_ctx = NULL;
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    struct dp_id_data *data;
-+    size_t msgs_count;
-+    struct ldb_message **msgs = NULL;
-+    const char *attrs[] = {SYSDB_NAME, NULL};
-+    size_t c;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = sysdb_search_users(tmp_ctx, be_ctx->domain, "("SYSDB_NAME "=*)", attrs,
-+                            &msgs_count, &msgs);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_users failed.\n");
-+        goto done;
-+    }
-+
-+    data = talloc_zero(tmp_ctx, struct dp_id_data);
-+    if (data == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    data->entry_type = BE_REQ_INITGROUPS;
-+    data->filter_type = BE_FILTER_NAME;
-+    data->filter_value = NULL;
-+    data->extra_value = NULL;
-+    data->domain = be_ctx->domain->name;
-+
-+    for (c = 0; c < msgs_count; c++) {
-+        data->filter_value = ldb_msg_find_attr_as_string(msgs[c], SYSDB_NAME,
-+                                                         NULL);
-+        if (data->filter_value == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Cache object [%s] does not have a name, skipping.\n",
-+                  ldb_dn_get_linearized(msgs[c]->dn));
-+            continue;
-+        }
-+
-+        talloc_free(dp_initgr_ctx);
-+        ret = dp_create_initgroups_ctx(tmp_ctx, be_ctx, data, &dp_initgr_ctx);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "dp_create_initgroups_ctx failed.\n");
-+            goto done;
-+        }
-+
-+        dp_req_initgr_pp_sr_overlay(be_ctx->provider, dp_initgr_ctx);
-+    }
-+
-+done:
-+    talloc_free(tmp_ctx);
-+
-+    return ret;
-+}
-+
- static errno_t set_initgroups_expire_attribute(struct sss_domain_info *domain,
-                                                const char *name)
- {
-diff --git a/src/providers/files/files_ops.c b/src/providers/files/files_ops.c
-index f5a40297a7cd1eb4ec66315250556ddaf6cc8cfc..74f77b5395285818d049eaa521b4afd8a9c89dde 100644
---- a/src/providers/files/files_ops.c
-+++ b/src/providers/files/files_ops.c
-@@ -26,6 +26,7 @@
- #include "db/sysdb.h"
- #include "util/inotify.h"
- #include "util/util.h"
-+#include "providers/data_provider/dp_iface.h"
- 
- /* When changing this constant, make sure to also adjust the files integration
-  * test for reallocation branch
-@@ -771,6 +772,12 @@ static errno_t sf_enum_files(struct files_id_ctx *id_ctx,
-         }
-     }
- 
-+    ret = dp_add_sr_attribute(id_ctx->be);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to add session recording attribute, ignored.\n");
-+    }
-+
-     ret = sysdb_transaction_commit(id_ctx->domain->sysdb);
-     if (ret != EOK) {
-         goto done;
--- 
-2.14.4
-
diff --git a/SOURCES/0057-UTIL-Suppress-Coverity-warning.patch b/SOURCES/0057-UTIL-Suppress-Coverity-warning.patch
deleted file mode 100644
index dff7c19..0000000
--- a/SOURCES/0057-UTIL-Suppress-Coverity-warning.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 4a9c9aa6dcfa09ca9ff24b7d22a37f2fdba4ee3f Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 16 Oct 2018 10:42:43 +0200
-Subject: [PATCH 57/57] UTIL: Suppress Coverity warning
-
-We recently added this code:
-         if (domain_name != NULL
-                &&  is_files_provider(find_domain_by_name(dom,
-                                                          domain_name,
-                                                          false)))
-
-find_domain_by_name returns NULL if the domain_name can't be found. This
-of course makes mostly sense for trusted domains that can appear and
-disappear. And is_files_provider() didn't handle the situation where the
-domain pointer was NULL and would directly dereference it.
-
-This commit just adds a NULL check for the domain pointer so that
-is_files_provider() returns 'false' if the domain pointer was NULL.
-
-Another alternative might be to check the return value of
-find_domain_by_name(), but I don't think it's worth the trouble.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/util/domain_info_utils.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
-index 8bef6c9af382ad55e14368b76dd4af7a53ea809b..ffb8cdf102c3ef92b4e8059d846f6b15b835ce69 100644
---- a/src/util/domain_info_utils.c
-+++ b/src/util/domain_info_utils.c
-@@ -931,6 +931,7 @@ bool sss_domain_info_get_output_fqnames(struct sss_domain_info *domain)
- 
- bool is_files_provider(struct sss_domain_info *domain)
- {
--    return domain->provider != NULL &&
-+    return domain != NULL &&
-+           domain->provider != NULL &&
-            strcasecmp(domain->provider, "files") == 0;
- }
--- 
-2.14.4
-
diff --git a/SOURCES/0058-PYSSS-Re-add-the-pysss.getgrouplist-interface.patch b/SOURCES/0058-PYSSS-Re-add-the-pysss.getgrouplist-interface.patch
deleted file mode 100644
index 399c5c7..0000000
--- a/SOURCES/0058-PYSSS-Re-add-the-pysss.getgrouplist-interface.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From f0603645f5ea5f707875807b4f815400f4b79e41 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 24 Oct 2018 09:41:44 +0200
-Subject: [PATCH] PYSSS: Re-add the pysss.getgrouplist() interface
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3493
-
-Commit 0e211b8ba30c3adcdeef21ca1339b194cbfffb04 was supposed to remove
-only the parts of the pysss API that relate to the local domain. But it
-removed also the getgrouplist() method by accident. This method is very
-important to IPA, so we need to add it back.
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
----
- src/python/pysss.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 83 insertions(+)
-
-diff --git a/src/python/pysss.c b/src/python/pysss.c
-index e92653a9e4cb4fdfef14b0ab3e297b1d469ad1dc..78b8de0739f8184bd5411e51d99c2baf5ce48057 100644
---- a/src/python/pysss.c
-+++ b/src/python/pysss.c
-@@ -215,12 +215,95 @@ static PyTypeObject pysss_password_type = {
-     .tp_doc   = sss_py_const_p(char, "SSS password obfuscation"),
- };
- 
-+/*
-+ * Get list of groups user belongs to
-+ */
-+PyDoc_STRVAR(py_sss_getgrouplist__doc__,
-+    "Get list of groups user belongs to.\n\n"
-+    "NOTE: The interface uses the system NSS calls and is not limited to "
-+    "users served by the SSSD!\n"
-+    ":param username: name of user to get list for\n");
-+
-+static PyObject *py_sss_getgrouplist(PyObject *self, PyObject *args)
-+{
-+    char *username = NULL;
-+    gid_t *groups = NULL;
-+    struct passwd *pw;
-+    struct group *gr;
-+    int ngroups;
-+    int ret;
-+    Py_ssize_t i, idx;
-+    PyObject *groups_tuple;
-+
-+    if(!PyArg_ParseTuple(args, discard_const_p(char, "s"), &username)) {
-+        goto fail;
-+    }
-+
-+    pw = getpwnam(username);
-+    if (pw == NULL) {
-+        goto fail;
-+    }
-+
-+    ngroups = 32;
-+    groups = malloc(sizeof(gid_t) * ngroups);
-+    if (groups == NULL) {
-+        goto fail;
-+    }
-+
-+    do {
-+        ret = getgrouplist(username, pw->pw_gid, groups, &ngroups);
-+        if (ret < ngroups) {
-+            gid_t *tmp_groups = realloc(groups, ngroups * sizeof(gid_t));
-+            if (tmp_groups == NULL) {
-+                goto fail;
-+            }
-+            groups = tmp_groups;
-+        }
-+    } while (ret != ngroups);
-+
-+    groups_tuple = PyTuple_New((Py_ssize_t) ngroups);
-+    if (groups_tuple == NULL) {
-+        goto fail;
-+    }
-+
-+    /* Populate a tuple with names of groups
-+     * In unlikely case of group not being able to resolve, skip it
-+     * We also need to resize resulting tuple to avoid empty elements there */
-+    idx = 0;
-+    for (i = 0; i < ngroups; i++) {
-+        gr = getgrgid(groups[i]);
-+        if (gr) {
-+            PyTuple_SetItem(groups_tuple, idx,
-+#ifdef IS_PY3K
-+                    PyUnicode_FromString(gr->gr_name)
-+#else
-+                    PyString_FromString(gr->gr_name)
-+#endif
-+                    );
-+            idx++;
-+        }
-+    }
-+    free(groups);
-+    groups = NULL;
-+
-+    if (i != idx) {
-+        _PyTuple_Resize(&groups_tuple, idx);
-+    }
-+
-+    return groups_tuple;
-+
-+fail:
-+    free(groups);
-+    return NULL;
-+}
-+
- /* ==================== the sss module initialization =======================*/
- 
- /*
-  * Module methods
-  */
- static PyMethodDef module_methods[] = {
-+        {"getgrouplist", py_sss_getgrouplist, METH_VARARGS, py_sss_getgrouplist__doc__},
-         {NULL, NULL, 0, NULL}  /* Sentinel */
- };
- 
--- 
-2.14.4
-
diff --git a/SOURCES/0059-ifp-fix-typo-causing-a-crash-in-FindByNameAndCertifi.patch b/SOURCES/0059-ifp-fix-typo-causing-a-crash-in-FindByNameAndCertifi.patch
deleted file mode 100644
index 7509f03..0000000
--- a/SOURCES/0059-ifp-fix-typo-causing-a-crash-in-FindByNameAndCertifi.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From b4063b2d3f1c700aa074f71d5db501e1bdfd6d2a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 24 Oct 2018 17:27:21 +0200
-Subject: [PATCH] ifp: fix typo causing a crash in FindByNameAndCertificate
-
-Due to a typo in the recent refactoring the InfoPipe crashes in the
-FindByNameAndCertificate request.
-
-Additionally a state variable in set to the expected value.
-
-Related to https://pagure.io/SSSD/sssd/issue/3863
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/responder/ifp/ifp_users.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
-index dd44afcc45df5c29e3a9926bf42cd416e3445d77..5dd34d68808fa0230d77de1fd3805b5971cb9aa6 100644
---- a/src/responder/ifp/ifp_users.c
-+++ b/src/responder/ifp/ifp_users.c
-@@ -584,6 +584,12 @@ ifp_users_find_by_name_and_cert_send(TALLOC_CTX *mem_ctx,
-     }
- 
-     if (!SBUS_REQ_STRING_IS_EMPTY(pem_cert)) {
-+        state->pem_cert = talloc_strdup(state, pem_cert);
-+        if (state->pem_cert == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-         ret = sss_cert_pem_to_derb64(state, pem_cert, &state->derb64);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_derb64 failed.\n");
-@@ -741,7 +747,7 @@ static void ifp_users_find_by_name_and_cert_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    ret = ifp_users_list_by_cert_step(req);
-+    ret = ifp_users_find_by_name_and_cert_step(req);
-     if (ret == EOK) {
-         tevent_req_done(req);
-     } else if (ret != EAGAIN) {
--- 
-2.14.4
-
diff --git a/SOURCES/0060-IFP-Use-subreq-not-req-when-calling-RefreshRules_rec.patch b/SOURCES/0060-IFP-Use-subreq-not-req-when-calling-RefreshRules_rec.patch
deleted file mode 100644
index 0c5e349..0000000
--- a/SOURCES/0060-IFP-Use-subreq-not-req-when-calling-RefreshRules_rec.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 0882793e4ba018073c2db9ab390bcdf16276b65f Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 5 Nov 2018 10:53:24 +0100
-Subject: [PATCH] IFP: Use subreq, not req when calling RefreshRules_recv
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This emits a failure when refreshing access control rules from e.g.
-sssctl access-report.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3874
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/responder/ifp/ifp_domains.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
-index ac09f23c6..2020b7580 100644
---- a/src/responder/ifp/ifp_domains.c
-+++ b/src/responder/ifp/ifp_domains.c
-@@ -1001,7 +1001,7 @@ static void ifp_domains_domain_refresh_access_rules_done(struct tevent_req *subr
- 
-     req = tevent_req_callback_data(subreq, struct tevent_req);
- 
--    ret = sbus_call_dp_access_RefreshRules_recv(req);
-+    ret = sbus_call_dp_access_RefreshRules_recv(subreq);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         tevent_req_error(req, ret);
--- 
-2.19.1
-
diff --git a/SOURCES/0061-INI-Return-errno-not-1-on-failure-from-sss_ini_get_s.patch b/SOURCES/0061-INI-Return-errno-not-1-on-failure-from-sss_ini_get_s.patch
deleted file mode 100644
index 2452780..0000000
--- a/SOURCES/0061-INI-Return-errno-not-1-on-failure-from-sss_ini_get_s.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 8007d6150a37c39881418e7f2b32129a5e4cb9e7 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 23 Oct 2018 23:12:20 +0200
-Subject: [PATCH 61/66] INI: Return errno, not -1 on failure from
- sss_ini_get_stat
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-sss_ini_get_stat() has two branches for two libini versions. The newer
-version directly returns EIO on failure, but the old version would have
-returned the return value from fstat() directly. And fstat() returns -1
-on failure but sets errno. This patch returns errno on failure and EOK
-on success.
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/util/sss_ini.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
-index 175a4cfab..9a059fc00 100644
---- a/src/util/sss_ini.c
-+++ b/src/util/sss_ini.c
-@@ -156,8 +156,13 @@ int sss_ini_get_stat(struct sss_ini_initdata *init_data)
- 
-     return EOK;
- #else
-+    int ret;
- 
--    return fstat(init_data->file, &init_data->cstat);
-+    ret = fstat(init_data->file, &init_data->cstat);
-+    if (ret != 0) {
-+        return errno;
-+    }
-+    return EOK;
- #endif
- }
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0062-MONITOR-Don-t-check-for-pidfile-if-SSSD-is-already-r.patch b/SOURCES/0062-MONITOR-Don-t-check-for-pidfile-if-SSSD-is-already-r.patch
deleted file mode 100644
index 824a2a6..0000000
--- a/SOURCES/0062-MONITOR-Don-t-check-for-pidfile-if-SSSD-is-already-r.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 4b52ed0610e399a0fe27cfab3601419acb6aff3d Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Fri, 5 Oct 2018 13:50:37 +0200
-Subject: [PATCH 62/66] MONITOR: Don't check for pidfile if SSSD is already
- running
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3862
-
-The --genconf option of sssd is meant to be used to reload configuration from a
-systemd socket-activated service. But it would only work if sssd was not
-running, which defies its purpose.
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/monitor/monitor.c | 18 +++++++++++-------
- 1 file changed, 11 insertions(+), 7 deletions(-)
-
-diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
-index 335b2070b..ea689c604 100644
---- a/src/monitor/monitor.c
-+++ b/src/monitor/monitor.c
-@@ -2514,13 +2514,17 @@ int main(int argc, const char *argv[])
-         }
-     }
- 
--    /* Check if the SSSD is already running */
--    ret = check_file(SSSD_PIDFILE, 0, 0, S_IFREG|0600, 0, NULL, false);
--    if (ret == EOK) {
--        DEBUG(SSSDBG_FATAL_FAILURE,
--              "pidfile exists at %s\n", SSSD_PIDFILE);
--        ERROR("SSSD is already running\n");
--        return 2;
-+    /* Check if the SSSD is already running unless we're only interested
-+     * in re-reading the configuration
-+     */
-+    if (opt_genconf == 0) {
-+        ret = check_file(SSSD_PIDFILE, 0, 0, S_IFREG|0600, 0, NULL, false);
-+        if (ret == EOK) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                "pidfile exists at %s\n", SSSD_PIDFILE);
-+            ERROR("SSSD is already running\n");
-+            return 2;
-+        }
-     }
- 
-     /* Parse config file, fail if cannot be done */
--- 
-2.19.1
-
diff --git a/SOURCES/0063-SSSD-Allow-refreshing-only-certain-section-with-genc.patch b/SOURCES/0063-SSSD-Allow-refreshing-only-certain-section-with-genc.patch
deleted file mode 100644
index 6af1af1..0000000
--- a/SOURCES/0063-SSSD-Allow-refreshing-only-certain-section-with-genc.patch
+++ /dev/null
@@ -1,399 +0,0 @@
-From 92b8f8d404bfe72abe8cd324f5569be5ba2c6db1 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 9 Oct 2018 15:32:12 +0200
-Subject: [PATCH 63/66] SSSD: Allow refreshing only certain section with
- --genconf
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3862
-
-Adds a new option --genconf-section for the sssd binary.  If this new
-option --genconf-section is used, then only the section passed as this
-option's value is refreshed.
-
-Conversely, if this section no longer exists in the config file, then it
-is removed from the confdb
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/confdb/confdb_setup.c    | 80 +++++++++++++++++++++++++++---------
- src/confdb/confdb_setup.h    |  1 +
- src/man/sssd.8.xml           | 27 ++++++++++++
- src/monitor/monitor.c        | 17 +++++++-
- src/tools/common/sss_tools.c |  1 +
- src/util/sss_ini.c           | 54 ++++++++++++++++++++++++
- src/util/sss_ini.h           |  1 +
- 7 files changed, 160 insertions(+), 21 deletions(-)
-
-diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
-index c2b7f9f73..7acefbe6b 100644
---- a/src/confdb/confdb_setup.c
-+++ b/src/confdb/confdb_setup.c
-@@ -138,6 +138,7 @@ static int confdb_create_base(struct confdb_ctx *cdb)
- static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
-                                      const char *config_file,
-                                      const char *config_dir,
-+                                     const char *only_section,
-                                      struct sss_ini_initdata *init_data,
-                                      const char **_timestr,
-                                      const char **_ldif)
-@@ -222,7 +223,7 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
-         }
-     }
- 
--    ret = sss_confdb_create_ldif(mem_ctx, init_data, _ldif);
-+    ret = sss_confdb_create_ldif(mem_ctx, init_data, only_section, _ldif);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "Could not create LDIF for confdb\n");
-         return ret;
-@@ -249,7 +250,50 @@ static int confdb_fallback_ldif(TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
--static int confdb_init_db(const char *config_file, const char *config_dir,
-+static int confdb_write_ldif(struct confdb_ctx *cdb,
-+                             const char *config_ldif,
-+                             bool replace_whole_db)
-+{
-+    int ret;
-+    struct ldb_ldif *ldif;
-+
-+    while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) {
-+        if (ldif->changetype == LDB_CHANGETYPE_DELETE) {
-+            /* We should remove this section */
-+            ret = ldb_delete(cdb->ldb, ldif->msg->dn);
-+            if (ret == LDB_ERR_NO_SUCH_OBJECT) {
-+                /* Removing a non-existing section is not an error */
-+                ret = LDB_SUCCESS;
-+            }
-+        } else {
-+            ret = ldb_add(cdb->ldb, ldif->msg);
-+            if (ret != LDB_SUCCESS && replace_whole_db == false) {
-+                /* This section already existed, remove and re-add it. We
-+                * really want to replace the whole thing instead of messing
-+                * around with changetypes and flags on individual elements
-+                */
-+                ret = ldb_delete(cdb->ldb, ldif->msg->dn);
-+                if (ret == LDB_SUCCESS) {
-+                    ret = ldb_add(cdb->ldb, ldif->msg);
-+                }
-+            }
-+        }
-+
-+        if (ret != LDB_SUCCESS) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                "Failed to initialize DB (%d,[%s]), aborting!\n",
-+                ret, ldb_errstring(cdb->ldb));
-+            return EIO;
-+        }
-+        ldb_ldif_read_free(cdb->ldb, ldif);
-+    }
-+
-+    return EOK;
-+}
-+
-+static int confdb_init_db(const char *config_file,
-+                          const char *config_dir,
-+                          const char *only_section,
-                           struct confdb_ctx *cdb)
- {
-     TALLOC_CTX *tmp_ctx;
-@@ -259,7 +303,6 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
-     const char *timestr = NULL;
-     const char *config_ldif;
-     const char *vals[2] = { NULL, NULL };
--    struct ldb_ldif *ldif;
-     struct sss_ini_initdata *init_data;
- 
-     tmp_ctx = talloc_new(cdb);
-@@ -281,6 +324,7 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
-         ret = confdb_ldif_from_ini_file(tmp_ctx,
-                                         config_file,
-                                         config_dir,
-+                                        only_section,
-                                         init_data,
-                                         &timestr,
-                                         &config_ldif);
-@@ -318,24 +362,21 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
-     }
-     in_transaction = true;
- 
--    /* Purge existing database */
--    ret = confdb_purge(cdb);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_FATAL_FAILURE,
--              "Could not purge existing configuration\n");
--        goto done;
--    }
--
--    while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) {
--        ret = ldb_add(cdb->ldb, ldif->msg);
--        if (ret != LDB_SUCCESS) {
-+    /* Purge existing database, if we are reinitializing the confdb completely */
-+    if (only_section == NULL) {
-+        ret = confdb_purge(cdb);
-+        if (ret != EOK) {
-             DEBUG(SSSDBG_FATAL_FAILURE,
--                  "Failed to initialize DB (%d,[%s]), aborting!\n",
--                  ret, ldb_errstring(cdb->ldb));
--            ret = EIO;
-+                "Could not purge existing configuration\n");
-             goto done;
-         }
--        ldb_ldif_read_free(cdb->ldb, ldif);
-+    }
-+
-+    ret = confdb_write_ldif(cdb,
-+                            config_ldif,
-+                            only_section == NULL ? true : false);
-+    if (ret != EOK) {
-+        goto done;
-     }
- 
-     /* now store the lastUpdate time so that we do not re-init if nothing
-@@ -377,6 +418,7 @@ errno_t confdb_setup(TALLOC_CTX *mem_ctx,
-                      const char *cdb_file,
-                      const char *config_file,
-                      const char *config_dir,
-+                     const char *only_section,
-                      struct confdb_ctx **_cdb)
- {
-     TALLOC_CTX *tmp_ctx;
-@@ -432,7 +474,7 @@ errno_t confdb_setup(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = confdb_init_db(config_file, config_dir, cdb);
-+    ret = confdb_init_db(config_file, config_dir, only_section, cdb);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "ConfDB initialization has failed "
-               "[%d]: %s\n", ret, sss_strerror(ret));
-diff --git a/src/confdb/confdb_setup.h b/src/confdb/confdb_setup.h
-index 9f647ec16..c7fe59541 100644
---- a/src/confdb/confdb_setup.h
-+++ b/src/confdb/confdb_setup.h
-@@ -49,6 +49,7 @@ errno_t confdb_setup(TALLOC_CTX *mem_ctx,
-                      const char *cdb_file,
-                      const char *config_file,
-                      const char *config_dir,
-+                     const char *only_section,
-                      struct confdb_ctx **_cdb);
- 
- #endif /* CONFDB_SETUP_H_ */
-diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml
-index f2cbe015b..ff3d8825d 100644
---- a/src/man/sssd.8.xml
-+++ b/src/man/sssd.8.xml
-@@ -164,6 +164,33 @@
-                     </para>
-                 </listitem>
-             </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>-g</option>,<option>--genconf</option>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Do not start the SSSD, but refresh the configuration
-+                        database from the contents of
-+                        <filename>/etc/sssd/sssd.conf</filename> and exit.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-+                    <option>-s</option>,<option>--genconf-section</option>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Similar to <quote>--genconf</quote>, but only refresh
-+                        a single section from the configuration file.  This
-+                        option is useful mainly to be called from systemd
-+                        unit files to allow socket-activated responders
-+                        to refresh their configuration without requiring
-+                        the administrator to restart the whole SSSD.
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-             <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/param_help.xml" />
-             <varlistentry>
-                 <term>
-diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
-index ea689c604..136cf8f27 100644
---- a/src/monitor/monitor.c
-+++ b/src/monitor/monitor.c
-@@ -1579,6 +1579,7 @@ static int monitor_ctx_destructor(void *mem)
- errno_t load_configuration(TALLOC_CTX *mem_ctx,
-                            const char *config_file,
-                            const char *config_dir,
-+                           const char *only_section,
-                            struct mt_ctx **monitor)
- {
-     errno_t ret;
-@@ -1600,7 +1601,8 @@ errno_t load_configuration(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = confdb_setup(ctx, cdb_file, config_file, config_dir, &ctx->cdb);
-+    ret = confdb_setup(ctx, cdb_file, config_file, config_dir, only_section,
-+                       &ctx->cdb);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup ConfDB [%d]: %s\n",
-              ret, sss_strerror(ret));
-@@ -2329,6 +2331,7 @@ int main(int argc, const char *argv[])
-     char *opt_config_file = NULL;
-     char *opt_logger = NULL;
-     char *config_file = NULL;
-+    char *opt_genconf_section = NULL;
-     int flags = 0;
-     struct main_context *main_ctx;
-     TALLOC_CTX *tmp_ctx;
-@@ -2352,6 +2355,9 @@ int main(int argc, const char *argv[])
-         {"genconf", 'g', POPT_ARG_NONE, &opt_genconf, 0, \
-          _("Refresh the configuration database, then exit"), \
-          NULL}, \
-+        {"genconf-section", 's', POPT_ARG_STRING, &opt_genconf_section, 0, \
-+         _("Similar to --genconf, but only refreshes the given section"), \
-+         NULL}, \
-         {"version", '\0', POPT_ARG_NONE, &opt_version, 0, \
-          _("Print version number and exit"), NULL }, \
-         POPT_TABLEEND
-@@ -2378,6 +2384,13 @@ int main(int argc, const char *argv[])
-         return EXIT_SUCCESS;
-     }
- 
-+    if (opt_genconf_section) {
-+        /* --genconf-section implies genconf, just restricted to a single
-+         * section
-+         */
-+        opt_genconf = 1;
-+    }
-+
-     /* If the level or timestamps was passed at the command-line, we want
-      * to save it and pass it to the children later.
-      */
-@@ -2529,7 +2542,7 @@ int main(int argc, const char *argv[])
- 
-     /* Parse config file, fail if cannot be done */
-     ret = load_configuration(tmp_ctx, config_file, CONFDB_DEFAULT_CONFIG_DIR,
--                             &monitor);
-+                             opt_genconf_section, &monitor);
-     if (ret != EOK) {
-         switch (ret) {
-         case EPERM:
-diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
-index 701db2d93..0d918f164 100644
---- a/src/tools/common/sss_tools.c
-+++ b/src/tools/common/sss_tools.c
-@@ -98,6 +98,7 @@ static errno_t sss_tool_confdb_init(TALLOC_CTX *mem_ctx,
- 
-     ret = confdb_setup(mem_ctx, path,
-                        SSSD_CONFIG_FILE, CONFDB_DEFAULT_CONFIG_DIR,
-+                       NULL,
-                        &confdb);
-     talloc_zfree(path);
-     if (ret != EOK) {
-diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
-index 9a059fc00..3c15b2809 100644
---- a/src/util/sss_ini.c
-+++ b/src/util/sss_ini.c
-@@ -414,6 +414,7 @@ void sss_ini_config_destroy(struct sss_ini_initdata *init_data)
- 
- int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-                            struct sss_ini_initdata *init_data,
-+                           const char *only_section,
-                            const char **config_ldif)
- {
-     int ret, i, j;
-@@ -436,6 +437,14 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
- #else
-     struct collection_item *obj = NULL;
- #endif
-+    bool section_handled = true;
-+
-+    if (only_section != NULL) {
-+        /* If the section is specified, we must handle it, either by adding
-+         * its contents or by deleting the section if it doesn't exist
-+         */
-+        section_handled = false;
-+    }
- 
-     ldif_len = strlen(CONFDB_INTERNAL_LDIF);
-     ldif = talloc_array(mem_ctx, char, ldif_len+1);
-@@ -466,6 +475,18 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-             goto error;
-         }
- 
-+        if (only_section != NULL) {
-+            if (strcasecmp(only_section, sections[i])) {
-+                DEBUG(SSSDBG_TRACE_FUNC, "Skipping section %s\n", sections[i]);
-+                continue;
-+            } else {
-+                /* Mark the requested section as handled so that we don't
-+                 * try to re-add it later
-+                 */
-+                section_handled = true;
-+            }
-+        }
-+
-         dn = talloc_asprintf(tmp_ctx,
-                              "dn: %s,cn=config\n"
-                              "cn: %s\n",
-@@ -552,6 +573,39 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-         talloc_free(dn);
-     }
- 
-+
-+    if (only_section != NULL && section_handled == false) {
-+        /* If only a single section was supposed to be
-+         * handled, but it wasn't found in the INI file,
-+         * create an LDIF that would remove the section
-+         */
-+        ret = parse_section(tmp_ctx, only_section, &sec_dn, NULL);
-+        if (ret != EOK) {
-+            goto error;
-+        }
-+
-+        dn = talloc_asprintf(tmp_ctx,
-+                             "dn: %s,cn=config\n"
-+                             "changetype: delete\n\n",
-+                             sec_dn);
-+        if (dn == NULL) {
-+            ret = ENOMEM;
-+            goto error;
-+        }
-+        dn_size = strlen(dn);
-+
-+        tmp_ldif = talloc_realloc(mem_ctx, ldif, char,
-+                                  ldif_len+dn_size+1);
-+        if (!tmp_ldif) {
-+            ret = ENOMEM;
-+            goto error;
-+        }
-+
-+        ldif = tmp_ldif;
-+        memcpy(ldif+ldif_len, dn, dn_size);
-+        ldif_len += dn_size;
-+    }
-+
-     ldif[ldif_len] = '\0';
- 
-     free_section_list(sections);
-diff --git a/src/util/sss_ini.h b/src/util/sss_ini.h
-index 0b173831d..470b88f99 100644
---- a/src/util/sss_ini.h
-+++ b/src/util/sss_ini.h
-@@ -77,6 +77,7 @@ void sss_ini_config_destroy(struct sss_ini_initdata *init_data);
- /* Create LDIF */
- int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-                            struct sss_ini_initdata *init_data,
-+                           const char *only_section,
-                            const char **config_ldif);
- 
- /* Validate sssd.conf if libini_config support it */
--- 
-2.19.1
-
diff --git a/SOURCES/0064-SYSTEMD-Re-read-KCM-configuration-on-systemctl-resta.patch b/SOURCES/0064-SYSTEMD-Re-read-KCM-configuration-on-systemctl-resta.patch
deleted file mode 100644
index e5f66ba..0000000
--- a/SOURCES/0064-SYSTEMD-Re-read-KCM-configuration-on-systemctl-resta.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From c53fc08a70679b181b0eff6422f199a51d527e67 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 9 Oct 2018 15:41:44 +0200
-Subject: [PATCH 64/66] SYSTEMD: Re-read KCM configuration on systemctl restart
- kcm
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3862
-
-Uses the sssd command together with the --genconf-section=kcm option to
-refresh the kcm configuration when the sssd-kcm systemd service is
-restarted.
-
-This allows the administrator to e.g. just drop a snippet to
-/etc/sssd.conf.d/ or create the [kcm] section directly in the main sssd
-config file, then just restart the sssd-kcm service for the changes to
-apply.
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/man/sssd-kcm.8.xml               | 33 ++++++++++++++++++++++++++++
- src/sysv/systemd/sssd-kcm.service.in |  1 +
- 2 files changed, 34 insertions(+)
-
-diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
-index ec27aa57b..fff8b0a16 100644
---- a/src/man/sssd-kcm.8.xml
-+++ b/src/man/sssd-kcm.8.xml
-@@ -127,6 +127,39 @@ systemctl enable sssd-kcm.socket
-         </para>
-     </refsect1>
- 
-+    <refsect1 id='debugging'>
-+        <title>OBTAINING DEBUG LOGS</title>
-+        <para>
-+            The sssd-kcm service is typically socket-activated
-+            <citerefentry>
-+                <refentrytitle>systemd</refentrytitle>
-+                <manvolnum>1</manvolnum>
-+            </citerefentry>. To generate debug logs, add the following
-+            either to the <filename>/etc/sssd/sssd.conf</filename>
-+            file directly or as a configuration snippet to
-+            <filename>/etc/sssd/conf.d/</filename> directory:
-+            <programlisting>
-+[kcm]
-+debug_level = 10
-+            </programlisting>
-+            Then, restart the sssd-kcm service:
-+            <programlisting>
-+systemctl restart sssd-kcm.service
-+            </programlisting>
-+            Finally, run whatever use-case doesn't work for you. The KCM
-+            logs will be generated at
-+            <filename>/var/log/sssd/sssd_kcm.log</filename>. It is
-+            recommended to disable the debug logs when you no longer need
-+            the debugging to be enabled as the sssd-kcm service can generate
-+            quite a large amount of debugging information.
-+        </para>
-+        <para>
-+            Please note that configuration snippets are, at the moment,
-+            only processed if the main configuration file at
-+            <filename>/etc/sssd/sssd.conf</filename> exists at all.
-+        </para>
-+    </refsect1>
-+
-     <refsect1 id='options'>
-         <title>CONFIGURATION OPTIONS</title>
-         <para>
-diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in
-index 8d689bfd7..5c82bee7d 100644
---- a/src/sysv/systemd/sssd-kcm.service.in
-+++ b/src/sysv/systemd/sssd-kcm.service.in
-@@ -9,4 +9,5 @@ Also=sssd-kcm.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+ExecStartPre=-@sbindir@/sssd --genconf-section=kcm
- ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 ${DEBUG_LOGGER}
--- 
-2.19.1
-
diff --git a/SOURCES/0065-pam_sss-return-PAM_AUTHINFO_UNAVAIL-if-sc-options-ar.patch b/SOURCES/0065-pam_sss-return-PAM_AUTHINFO_UNAVAIL-if-sc-options-ar.patch
deleted file mode 100644
index 700b249..0000000
--- a/SOURCES/0065-pam_sss-return-PAM_AUTHINFO_UNAVAIL-if-sc-options-ar.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 55470b17eacdf97696b4736e9eb8bd2618601475 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 7 Nov 2018 11:49:11 +0100
-Subject: [PATCH] pam_sss: return PAM_AUTHINFO_UNAVAIL if sc options are set
-
-If pam_sss is called for PAM_USER root it currently returns
-PAM_USER_UNKNOWN since SSSD does not handle root. To meet the documented
-behavior if one to the sc options is used pam_sss should return
-PAM_AUTHINFO_UNAVAIL in this case as well.
-
-Related to https://pagure.io/SSSD/sssd/issue/3876
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/sss_client/pam_sss.c             |  4 ++++
- src/tests/intg/test_pam_responder.py | 28 ++++++++++++++++++++++++++++
- 2 files changed, 32 insertions(+)
-
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index b4c1036ad..69dc50dfd 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -2378,6 +2378,10 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
-     ret = get_pam_items(pamh, flags, &pi);
-     if (ret != PAM_SUCCESS) {
-         D(("get items returned error: %s", pam_strerror(pamh,ret)));
-+        if ((flags & PAM_CLI_FLAGS_TRY_CERT_AUTH)
-+                || (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) ) {
-+            return PAM_AUTHINFO_UNAVAIL;
-+        }
-         if (flags & PAM_CLI_FLAGS_IGNORE_UNKNOWN_USER && ret == PAM_USER_UNKNOWN) {
-             ret = PAM_IGNORE;
-         }
-diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
-index 06f69a3d8..d1ad9affd 100644
---- a/src/tests/intg/test_pam_responder.py
-+++ b/src/tests/intg/test_pam_responder.py
-@@ -388,3 +388,31 @@ def test_try_sc_auth(simple_pam_cert_auth, env_for_sssctl):
-         raise Exception("sssctl failed")
- 
-     assert err.find("pam_authenticate for user [user1]: Success") != -1
-+
-+
-+def test_try_sc_auth_root(simple_pam_cert_auth, env_for_sssctl):
-+    """
-+    Make sure pam_sss returns PAM_AUTHINFO_UNAVAIL even for root if
-+    try_cert_auth is set.
-+    """
-+    sssctl = subprocess.Popen(["sssctl", "user-checks", "root",
-+                               "--action=auth",
-+                               "--service=pam_sss_try_sc"],
-+                              universal_newlines=True,
-+                              env=env_for_sssctl, stdin=subprocess.PIPE,
-+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-+
-+    try:
-+        out, err = sssctl.communicate(input="123456")
-+    except:
-+        sssctl.kill()
-+        out, err = sssctl.communicate()
-+
-+    sssctl.stdin.close()
-+    sssctl.stdout.close()
-+
-+    if sssctl.wait() != 0:
-+        raise Exception("sssctl failed")
-+
-+    assert err.find("pam_authenticate for user [root]: Authentication " +
-+                    "service cannot retrieve authentication info") != -1
--- 
-2.19.1
-
diff --git a/SOURCES/0066-p11_child-NSS-print-key-type-in-a-debug-message.patch b/SOURCES/0066-p11_child-NSS-print-key-type-in-a-debug-message.patch
deleted file mode 100644
index e9e73dd..0000000
--- a/SOURCES/0066-p11_child-NSS-print-key-type-in-a-debug-message.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 6286f8120ac9986b418f4f08f26d6808cf028a9b Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 9 Nov 2018 13:34:33 +0100
-Subject: [PATCH 66/74] p11_child(NSS): print key type in a debug message
-
-NSS can handle EC keys automatically but a debug message indicating
-which key type is used might be useful.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/p11_child/p11_child_nss.c | 36 +++++++++++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index f9cbf3f37..d3064ff98 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -477,6 +477,40 @@ bool do_verification_b64(struct p11_ctx *p11_ctx, const char *cert_b64)
-     return res;
- }
- 
-+static const char *keytype2str(KeyType keyType) {
-+    switch (keyType) {
-+        case nullKey:
-+            return "nullKey";
-+            break;
-+        case rsaKey:
-+            return "rsaKey";
-+            break;
-+        case dsaKey:
-+            return "dsaKey";
-+            break;
-+        case fortezzaKey:
-+            return "fortezzaKey";
-+            break;
-+        case dhKey:
-+            return "dhKey";
-+            break;
-+        case keaKey:
-+            return "keaKey";
-+            break;
-+        case ecKey:
-+            return "ecKey";
-+            break;
-+        case rsaPssKey:
-+            return "rsaPssKey";
-+            break;
-+        case rsaOaepKey:
-+            return "rsaOaepKey";
-+            break;
-+        default:
-+            return "Unknown key type";
-+    }
-+}
-+
- errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-                 enum op_mode mode, const char *pin,
-                 const char *module_name_in, const char *token_name_in,
-@@ -798,6 +832,8 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
-             goto done;
-         }
- 
-+        DEBUG(SSSDBG_TRACE_ALL, "Private key has type [%s].\n",
-+                                keytype2str(priv_key->keyType));
-         algtag = SEC_GetSignatureAlgorithmOidTag(priv_key->keyType,
-                                                   SEC_OID_SHA1);
-         if (algtag == SEC_OID_UNKNOWN) {
--- 
-2.19.1
-
diff --git a/SOURCES/0067-pam_test_srv-set-default-value-for-SOFTHSM2_CONF.patch b/SOURCES/0067-pam_test_srv-set-default-value-for-SOFTHSM2_CONF.patch
deleted file mode 100644
index 6662610..0000000
--- a/SOURCES/0067-pam_test_srv-set-default-value-for-SOFTHSM2_CONF.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From ef631f9e61e7a0e168cce9071470839a4c04114c Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 9 Nov 2018 14:04:38 +0100
-Subject: [PATCH 67/74] pam_test_srv: set default value for SOFTHSM2_CONF
-
-Currently the SOFTHSM2_CONF is not set by any fixture but some tests
-sets them and other might rely on the setting done by a previous test.
-This means that the tests have to run in a given order and depend on
-each other.
-
-To remove this dependency SOFTHSM2_CONF is set in the fixture to the
-"default" SoftHSM2 configuration with one valid certificate. Any test
-which needs a different setup must now set SOFTHSM2_CONF explicitly.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tests/cmocka/test_pam_srv.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 7fc9224e1..b29961255 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -356,6 +356,10 @@ static void pam_test_setup_common(void)
- {
-     errno_t ret;
- 
-+#ifndef HAVE_NSS
-+    putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_one.conf"));
-+#endif
-+
-     pam_test_ctx->pam_user_fqdn = \
-                     sss_create_internal_fqname(pam_test_ctx,
-                                                "pamuser",
-@@ -1926,6 +1930,7 @@ void test_pam_preauth_cert_nocert(void **state)
-     set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
- #else
-     set_cert_auth_param(pam_test_ctx->pctx, CA_DB);
-+    unsetenv("SOFTHSM2_CONF");
- #endif
- 
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0068-tests-add-ECC-CA.patch b/SOURCES/0068-tests-add-ECC-CA.patch
deleted file mode 100644
index a8f0717..0000000
--- a/SOURCES/0068-tests-add-ECC-CA.patch
+++ /dev/null
@@ -1,276 +0,0 @@
-From a0cdc3bdf0e7f8ef15997f269b6f1ca5cab85825 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 9 Nov 2018 14:06:03 +0100
-Subject: [PATCH 68/74] tests: add ECC CA
-
-To be able to test certificates with elliptic curve (EC) keys a new test
-CA with this kind of keys is added.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- Makefile.am                                   |  6 +-
- configure.ac                                  |  1 +
- src/tests/test_ECC_CA/Makefile.am             | 95 +++++++++++++++++++
- src/tests/test_ECC_CA/SSSD_test_ECC_CA.config | 47 +++++++++
- .../test_ECC_CA/SSSD_test_ECC_CA_key.pem      |  9 ++
- .../SSSD_test_ECC_cert_0001.config            | 20 ++++
- .../SSSD_test_ECC_cert_key_0001.pem           |  9 ++
- 7 files changed, 185 insertions(+), 2 deletions(-)
- create mode 100644 src/tests/test_ECC_CA/Makefile.am
- create mode 100644 src/tests/test_ECC_CA/SSSD_test_ECC_CA.config
- create mode 100644 src/tests/test_ECC_CA/SSSD_test_ECC_CA_key.pem
- create mode 100644 src/tests/test_ECC_CA/SSSD_test_ECC_cert_0001.config
- create mode 100644 src/tests/test_ECC_CA/SSSD_test_ECC_cert_key_0001.pem
-
-diff --git a/Makefile.am b/Makefile.am
-index 3667856c6..430506028 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -21,7 +21,8 @@ if HAVE_MANPAGES
- SUBDIRS += src/man
- endif
- 
--SUBDIRS += . src/tests/cwrap src/tests/intg src/tests/test_CA
-+SUBDIRS += . src/tests/cwrap src/tests/intg src/tests/test_CA \
-+             src/tests/test_ECC_CA
- 
- # Some old versions of automake don't define builddir
- builddir ?= .
-@@ -5394,8 +5395,9 @@ CLEANFILES += *.X */*.X */*/*.X
- 
- test_CA: test_CA.stamp
- 
--test_CA.stamp: $(srcdir)/src/tests/test_CA/*
-+test_CA.stamp: $(srcdir)/src/tests/test_CA/* $(srcdir)/src/tests/test_ECC_CA/*
- 	$(MAKE) -C src/tests/test_CA ca_all
-+	$(MAKE) -C src/tests/test_ECC_CA ca_all
- 	touch $@
- 
- if BUILD_TEST_CA
-diff --git a/configure.ac b/configure.ac
-index 5816b04c6..fb01a7c3b 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -521,6 +521,7 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
-                  src/sysv/sssd src/sysv/gentoo/sssd src/sysv/SUSE/sssd
-                  po/Makefile.in src/man/Makefile src/tests/cwrap/Makefile
-                  src/tests/intg/Makefile src/tests/test_CA/Makefile
-+                 src/tests/test_ECC_CA/Makefile
-                  src/lib/ipa_hbac/ipa_hbac.pc src/lib/ipa_hbac/ipa_hbac.doxy
-                  src/lib/idmap/sss_idmap.pc src/lib/idmap/sss_idmap.doxy
-                  src/lib/certmap/sss_certmap.pc src/lib/certmap/sss_certmap.doxy
-diff --git a/src/tests/test_ECC_CA/Makefile.am b/src/tests/test_ECC_CA/Makefile.am
-new file mode 100644
-index 000000000..47af991c3
---- /dev/null
-+++ b/src/tests/test_ECC_CA/Makefile.am
-@@ -0,0 +1,95 @@
-+dist_noinst_DATA = \
-+    SSSD_test_ECC_CA.config \
-+    SSSD_test_ECC_CA_key.pem \
-+    SSSD_test_ECC_cert_0001.config  \
-+    SSSD_test_ECC_cert_key_0001.pem
-+
-+openssl_ecc_ca_config = $(srcdir)/SSSD_test_ECC_CA.config
-+openssl_ecc_ca_key = $(srcdir)/SSSD_test_ECC_CA_key.pem
-+pwdfile = pwdfile
-+
-+configs := $(notdir $(wildcard $(srcdir)/SSSD_test_ECC_cert_*.config))
-+ids := $(subst SSSD_test_ECC_cert_,,$(basename $(configs)))
-+certs = $(addprefix SSSD_test_ECC_cert_x509_,$(addsuffix .pem,$(ids)))
-+certs_h = $(addprefix SSSD_test_ECC_cert_x509_,$(addsuffix .h,$(ids)))
-+pubkeys = $(addprefix SSSD_test_ECC_cert_pubsshkey_,$(addsuffix .pub,$(ids)))
-+pubkeys_h = $(addprefix SSSD_test_ECC_cert_pubsshkey_,$(addsuffix .h,$(ids)))
-+pkcs12 = $(addprefix SSSD_test_ECC_cert_pkcs12_,$(addsuffix .pem,$(ids)))
-+
-+if HAVE_NSS
-+extra = p11_ecc_nssdb
-+else
-+extra = softhsm2_ecc_one p11_ecc_nssdb
-+endif
-+
-+# If openssl is run in parallel there might be conflicts with the serial
-+.NOTPARALLEL:
-+
-+ca_all: clean serial SSSD_test_ECC_CA.pem $(certs) $(certs_h) $(pubkeys) $(pubkeys_h) $(pkcs12) $(extra)
-+
-+$(pwdfile):
-+	@echo "123456" > $@
-+
-+SSSD_test_ECC_CA.pem: $(openssl_ecc_ca_key) $(openssl_ecc_ca_config) serial
-+	$(OPENSSL) req -batch -config ${openssl_ecc_ca_config} -x509 -new -nodes -key $< -sha384 -days 1024 -set_serial 0 -extensions v3_ca -out $@
-+
-+
-+SSSD_test_ECC_cert_req_%.pem: $(srcdir)/SSSD_test_ECC_cert_key_%.pem $(srcdir)/SSSD_test_ECC_cert_%.config
-+	$(OPENSSL) req -new -nodes -key $< -reqexts req_exts -config $(srcdir)/SSSD_test_ECC_cert_$*.config -out $@
-+
-+SSSD_test_ECC_cert_x509_%.pem: SSSD_test_ECC_cert_req_%.pem $(openssl_ecc_ca_config) SSSD_test_ECC_CA.pem
-+	$(OPENSSL) ca -config ${openssl_ecc_ca_config} -batch -notext -keyfile $(openssl_ecc_ca_key) -in $< -days 200 -extensions usr_cert -out $@
-+
-+SSSD_test_ECC_cert_pkcs12_%.pem: SSSD_test_ECC_cert_x509_%.pem $(srcdir)/SSSD_test_ECC_cert_key_%.pem $(pwdfile)
-+	$(OPENSSL) pkcs12 -export -in SSSD_test_ECC_cert_x509_$*.pem -inkey $(srcdir)/SSSD_test_ECC_cert_key_$*.pem -nodes -passout file:$(pwdfile) -out $@
-+
-+SSSD_test_ECC_cert_pubkey_%.pem: SSSD_test_ECC_cert_x509_%.pem
-+	$(OPENSSL) x509 -in $< -pubkey -noout > $@
-+
-+SSSD_test_ECC_cert_pubsshkey_%.pub: SSSD_test_ECC_cert_pubkey_%.pem
-+	$(SSH_KEYGEN) -i -m PKCS8 -f $< > $@
-+
-+SSSD_test_ECC_cert_x509_%.h: SSSD_test_ECC_cert_x509_%.pem
-+	@echo "#define SSSD_TEST_ECC_CERT_$* \""$(shell cat $< |openssl x509 -outform der | base64 -w 0)"\"" > $@
-+
-+SSSD_test_ECC_cert_pubsshkey_%.h: SSSD_test_ECC_cert_pubsshkey_%.pub
-+	@echo "#define SSSD_TEST_ECC_CERT_SSH_KEY_$* \""$(shell cut -d' ' -f2 $<)"\"" > $@
-+
-+
-+p11_ecc_nssdb: SSSD_test_ECC_cert_pkcs12_0001.pem SSSD_test_ECC_CA.pem $(pwdfile)
-+	mkdir $@
-+	$(CERTUTIL) -d sql:./$@ -N -f $(pwdfile)
-+	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test ECC CA' -t CT,CT,CT -a -i SSSD_test_ECC_CA.pem -f $(pwdfile)
-+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_ECC_cert_pkcs12_0001.pem -w $(pwdfile) -k $(pwdfile)
-+
-+
-+softhsm2_ecc_one: softhsm2_ecc_one.conf
-+	mkdir $@
-+	SOFTHSM2_CONF=./$< $(SOFTHSM2_UTIL) --init-token  --label "SSSD Test ECC Token" --pin 123456 --so-pin 123456 --free
-+	GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --no-mark-private --load-certificate=SSSD_test_ECC_cert_x509_0001.pem --login  --label 'SSSD test ECC cert 0001' --id '190E513C9A3DFAACDE5D2D0592F0FDFF559C10CB'
-+	GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --load-privkey=$(srcdir)/SSSD_test_ECC_cert_key_0001.pem --login  --label 'SSSD test ECC cert 0001' --id '190E513C9A3DFAACDE5D2D0592F0FDFF559C10CB'
-+
-+softhsm2_ecc_one.conf:
-+	@echo "directories.tokendir = "$(abs_top_builddir)"/src/tests/test_ECC_CA/softhsm2_ecc_one" > $@
-+	@echo "objectstore.backend = file" >> $@
-+	@echo "slots.removable = true" >> $@
-+
-+CLEANFILES = \
-+    index.txt  index.txt.attr \
-+    index.txt.attr.old  index.txt.old \
-+    serial  serial.old  \
-+    SSSD_test_ECC_CA.pem $(pwdfile) \
-+    $(certs) $(certs_h) $(pubkeys) $(pubkeys_h) $(pkcs12) \
-+    softhsm2_*.conf \
-+    $(NULL)
-+
-+clean-local:
-+	rm -rf newcerts
-+	rm -rf p11_ecc_nssdb
-+	rm -rf softhsm*
-+
-+serial: clean
-+	touch index.txt
-+	touch index.txt.attr
-+	mkdir newcerts
-+	echo -n 01 > serial
-diff --git a/src/tests/test_ECC_CA/SSSD_test_ECC_CA.config b/src/tests/test_ECC_CA/SSSD_test_ECC_CA.config
-new file mode 100644
-index 000000000..c1e4e22a6
---- /dev/null
-+++ b/src/tests/test_ECC_CA/SSSD_test_ECC_CA.config
-@@ -0,0 +1,47 @@
-+[ ca ]
-+default_ca = ECC_CA_default
-+
-+[ ECC_CA_default ]
-+dir              = .
-+database         = $dir/index.txt
-+new_certs_dir    = $dir/newcerts
-+
-+certificate      = $dir/SSSD_test_ECC_CA.pem
-+serial           = $dir/serial
-+private_key      = $dir/SSSD_test_ECC_CA_key.pem
-+RANDFILE         = $dir/rand
-+
-+default_days     = 365
-+default_crl_days = 30
-+default_md       = sha256
-+
-+policy           = policy_any
-+email_in_dn      = no
-+
-+name_opt         = ca_default
-+cert_opt         = ca_default
-+copy_extensions  = copy
-+
-+[ usr_cert ]
-+authorityKeyIdentifier = keyid, issuer
-+
-+[ v3_ca ]
-+subjectKeyIdentifier   = hash
-+authorityKeyIdentifier = keyid:always,issuer:always
-+basicConstraints       = CA:true
-+keyUsage               = critical, digitalSignature, cRLSign, keyCertSign
-+
-+[ policy_any ]
-+organizationName       = supplied
-+organizationalUnitName = supplied
-+commonName             = supplied
-+emailAddress           = optional
-+
-+[ req ]
-+distinguished_name = req_distinguished_name
-+prompt             = no
-+
-+[ req_distinguished_name ]
-+O  = SSSD
-+OU = SSSD test
-+CN = SSSD test ECC CA
-diff --git a/src/tests/test_ECC_CA/SSSD_test_ECC_CA_key.pem b/src/tests/test_ECC_CA/SSSD_test_ECC_CA_key.pem
-new file mode 100644
-index 000000000..c5cb3ef42
---- /dev/null
-+++ b/src/tests/test_ECC_CA/SSSD_test_ECC_CA_key.pem
-@@ -0,0 +1,9 @@
-+-----BEGIN EC PARAMETERS-----
-+BgUrgQQAIg==
-+-----END EC PARAMETERS-----
-+-----BEGIN EC PRIVATE KEY-----
-+MIGkAgEBBDBKk+ue3IyidXo3+befiqrcKrpVpy/pWz9CMTIALHMBc/a83Q3h9yEB
-+CNpdsF8B2zegBwYFK4EEACKhZANiAAR/mCPIYxyT4tbjgpJT+oKCGfGjfs3FVnRr
-+GLnNnT/L2b9PACMjjugM/1RNOuLdzRFBVWlQ80ISH5w17R2uhbiDJ/Q254Ele4Ak
-+5e2nR/9x0ZIAqc05tkBDhsXfJ3id3/0=
-+-----END EC PRIVATE KEY-----
-diff --git a/src/tests/test_ECC_CA/SSSD_test_ECC_cert_0001.config b/src/tests/test_ECC_CA/SSSD_test_ECC_cert_0001.config
-new file mode 100644
-index 000000000..17c9192d4
---- /dev/null
-+++ b/src/tests/test_ECC_CA/SSSD_test_ECC_cert_0001.config
-@@ -0,0 +1,20 @@
-+# This certificate is used in
-+# - src/tests/cmocka/test_cert_utils.c
-+# - src/tests/cmocka/test_pam_srv.c
-+[ req ]
-+distinguished_name = req_distinguished_name
-+prompt = no
-+
-+[ req_distinguished_name ]
-+O = SSSD
-+OU = SSSD test ECC
-+CN = SSSD test ECC cert 0001
-+
-+[ req_exts ]
-+basicConstraints = CA:FALSE
-+nsCertType = client, email
-+nsComment = "SSSD test Certificate"
-+subjectKeyIdentifier = hash
-+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
-+extendedKeyUsage = clientAuth, emailProtection
-+subjectAltName = email:sssd-devel@lists.fedorahosted.org,URI:https://pagure.io/SSSD/sssd//
-diff --git a/src/tests/test_ECC_CA/SSSD_test_ECC_cert_key_0001.pem b/src/tests/test_ECC_CA/SSSD_test_ECC_cert_key_0001.pem
-new file mode 100644
-index 000000000..8c9321048
---- /dev/null
-+++ b/src/tests/test_ECC_CA/SSSD_test_ECC_cert_key_0001.pem
-@@ -0,0 +1,9 @@
-+-----BEGIN EC PARAMETERS-----
-+BgUrgQQAIg==
-+-----END EC PARAMETERS-----
-+-----BEGIN EC PRIVATE KEY-----
-+MIGkAgEBBDDVZu1S6+U+1Fs1eAn/6O1iX7LH2w4AaToxqutXtkrdEpuTX7SZskTQ
-+UCL0Lf5oQjigBwYFK4EEACKhZANiAAQheZFBntzcARA52Gba7c01BElFRds1F439
-+KotFOoDx4fJf67hmD69bKuTbWLvc7l3Lf2TKdI5GCp/u9SPhGtve0CaYm9Hcoxwp
-+2yYnhq3stoW+far//4h3mQxU/hG9pj0=
-+-----END EC PRIVATE KEY-----
--- 
-2.19.1
-
diff --git a/SOURCES/0069-test_pam_srv-add-test-for-certificate-with-EC-keys.patch b/SOURCES/0069-test_pam_srv-add-test-for-certificate-with-EC-keys.patch
deleted file mode 100644
index f9e9d92..0000000
--- a/SOURCES/0069-test_pam_srv-add-test-for-certificate-with-EC-keys.patch
+++ /dev/null
@@ -1,198 +0,0 @@
-From a7421b5260cd2edd07ec5c0fefd240e76c5a0f03 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 9 Nov 2018 14:01:20 +0100
-Subject: [PATCH 69/74] test_pam_srv: add test for certificate with EC keys
-
-Add an authentication test with a certificate with EC keys.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tests/cmocka/test_pam_srv.c | 114 ++++++++++++++++++++++++++++++++
- 1 file changed, 114 insertions(+)
-
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index b29961255..f55e6222e 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -42,9 +42,13 @@
- #ifdef HAVE_TEST_CA
- #include "tests/test_CA/SSSD_test_cert_x509_0001.h"
- #include "tests/test_CA/SSSD_test_cert_x509_0002.h"
-+
-+#include "tests/test_ECC_CA/SSSD_test_ECC_cert_x509_0001.h"
- #else
- #define SSSD_TEST_CERT_0001 ""
- #define SSSD_TEST_CERT_0002 ""
-+
-+#define SSSD_TEST_ECC_CERT_0001 ""
- #endif
- 
- #define TESTS_PATH "tp_" BASE_FILE_STEM
-@@ -58,10 +62,16 @@
- 
- #define NSS_DB_PATH_2CERTS TESTS_PATH "_2certs"
- #define NSS_DB_2CERTS "sql:"NSS_DB_PATH_2CERTS
-+
-+#define NSS_DB_PATH_ECC TESTS_PATH "_ecc"
-+#define NSS_DB_ECC "sql:"NSS_DB_PATH_ECC
-+
- #ifdef HAVE_NSS
- #define CA_DB NSS_DB
-+#define ECC_CA_DB NSS_DB_ECC
- #else
- #define CA_DB ABS_BUILD_DIR"/src/tests/test_CA/SSSD_test_CA.pem"
-+#define ECC_CA_DB ABS_BUILD_DIR"/src/tests/test_ECC_CA/SSSD_test_ECC_CA.pem"
- #endif
- 
- #define TEST_TOKEN_NAME "SSSD Test Token"
-@@ -122,6 +132,13 @@ static errno_t setup_nss_db(void)
-         return ret;
-     }
- 
-+    ret = mkdir(NSS_DB_PATH_ECC, 0775);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE,
-+              "Failed to create " NSS_DB_PATH_ECC ".\n");
-+        return ret;
-+    }
-+
-     child_pid = fork();
-     if (child_pid == 0) { /* child */
-         ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d",
-@@ -154,6 +171,22 @@ static errno_t setup_nss_db(void)
-         return ret;
-     }
- 
-+    child_pid = fork();
-+    if (child_pid == 0) { /* child */
-+        ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d",
-+                     NSS_DB_ECC, NULL);
-+        if (ret == -1) {
-+            DEBUG(SSSDBG_FATAL_FAILURE, "execl() failed.\n");
-+            exit(-1);
-+        }
-+    } else if (child_pid > 0) {
-+        wait(&status);
-+    } else {
-+        ret = errno;
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fork() failed\n");
-+        return ret;
-+    }
-+
-     fp = fopen(NSS_DB_PATH"/pkcs11.txt", "w");
-     if (fp == NULL) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n");
-@@ -196,6 +229,27 @@ static errno_t setup_nss_db(void)
-         return ret;
-     }
- 
-+    fp = fopen(NSS_DB_PATH_ECC"/pkcs11.txt", "w");
-+    if (fp == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n");
-+        return ret;
-+    }
-+    ret = fprintf(fp, "library=libsoftokn3.so\nname=soft\n");
-+    if (ret < 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
-+        return ret;
-+    }
-+    ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/test_ECC_CA/p11_ecc_nssdb' dbSlotDescription='SSSD Test ECC Slot' dbTokenDescription='SSSD Test ECC Token' secmod='secmod.db' flags=readOnly \n\n", ABS_BUILD_DIR);
-+    if (ret < 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
-+        return ret;
-+    }
-+    ret = fclose(fp);
-+    if (ret != 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fclose() failed.\n");
-+        return ret;
-+    }
-+
-     return EOK;
- }
- 
-@@ -242,6 +296,26 @@ static void cleanup_nss_db(void)
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n");
-     }
-+
-+    ret = unlink(NSS_DB_PATH_ECC"/cert9.db");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove cert9.db.\n");
-+    }
-+
-+    ret = unlink(NSS_DB_PATH_ECC"/key4.db");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove key4.db.\n");
-+    }
-+
-+    ret = unlink(NSS_DB_PATH_ECC"/pkcs11.txt");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove pkcs11.db.\n");
-+    }
-+
-+    ret = rmdir(NSS_DB_PATH_ECC);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n");
-+    }
- }
- 
- struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
-@@ -2347,6 +2421,44 @@ void test_pam_cert_auth(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+void test_pam_ecc_cert_auth(void **state)
-+{
-+    int ret;
-+
-+#ifndef HAVE_NSS
-+    putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_ECC_CA/softhsm2_ecc_one.conf"));
-+#endif
-+    set_cert_auth_param(pam_test_ctx->pctx, ECC_CA_DB);
-+
-+    /* Here the last option must be set to true because the backend is only
-+     * connected once. During authentication the backend is connected first to
-+     * see if it can handle Smartcard authentication, but before that the user
-+     * is looked up. Since the first mocked reply already adds the certificate
-+     * to the user entry the lookup by certificate will already find the user
-+     * in the cache and no second request to the backend is needed. */
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456",
-+                        "SSSD Test ECC Token",
-+                        TEST_MODULE_NAME,
-+                        "190E513C9A3DFAACDE5D2D0592F0FDFF559C10CB", NULL,
-+                        test_lookup_by_cert_cb, SSSD_TEST_ECC_CERT_0001, true);
-+
-+    will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    /* Assume backend cannot handle Smartcard credentials */
-+    pam_test_ctx->exp_pam_status = PAM_BAD_ITEM;
-+
-+
-+    set_cmd_cb(test_pam_simple_check_success);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
- void test_pam_cert_auth_no_logon_name(void **state)
- {
-     int ret;
-@@ -3022,6 +3134,8 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_pam_cert_auth,
-                                         pam_test_setup_no_verification,
-                                         pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_ecc_cert_auth,
-+                                        pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_auth_double_cert,
-                                         pam_test_setup, pam_test_teardown),
-         cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_one_mapping,
--- 
-2.19.1
-
diff --git a/SOURCES/0070-p11_child-openssl-add-support-for-EC-keys.patch b/SOURCES/0070-p11_child-openssl-add-support-for-EC-keys.patch
deleted file mode 100644
index 3b3f29e..0000000
--- a/SOURCES/0070-p11_child-openssl-add-support-for-EC-keys.patch
+++ /dev/null
@@ -1,409 +0,0 @@
-From d64d9cfbe9dc44db04b253aa08c05e645e10708a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 9 Nov 2018 14:01:46 +0100
-Subject: [PATCH 70/74] p11_child(openssl): add support for EC keys
-
-Add support for EC keys to the OpenSSL version of p11_child. Please see
-comments in the code for some technical details.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/p11_child/p11_child_openssl.c | 319 +++++++++++++++++++++++++++++-
- 1 file changed, 309 insertions(+), 10 deletions(-)
-
-diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
-index af55523a7..0f8ba3d3c 100644
---- a/src/p11_child/p11_child_openssl.c
-+++ b/src/p11_child/p11_child_openssl.c
-@@ -137,6 +137,7 @@ static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host,
- #define X509_STORE_get0_objects(store) (store->objs)
- #define X509_OBJECT_get_type(object) (object->type)
- #define X509_OBJECT_get0_X509(object) (object->data.x509)
-+#define EVP_MD_CTX_free EVP_MD_CTX_destroy
- #endif
- 
- OCSP_RESPONSE *process_responder(OCSP_REQUEST *req,
-@@ -860,6 +861,243 @@ done:
-     return ret;
- }
- 
-+/* Currently this funtion is only used the print the curve type in the debug
-+ * messages. */
-+static void get_ec_curve_type(CK_FUNCTION_LIST *module,
-+                              CK_SESSION_HANDLE session,
-+                              CK_OBJECT_HANDLE key_handle)
-+{
-+    CK_ATTRIBUTE attribute;
-+    CK_RV rv;
-+    EC_GROUP *ec_group;
-+    const unsigned char *p;
-+    int len;
-+    char der_buf[128]; /* FIXME: any other size ?? */
-+    char oid_buf[128]; /* FIXME: any other size ?? */
-+
-+    attribute.type = CKA_ECDSA_PARAMS;
-+    attribute.pValue = &der_buf;
-+    attribute.ulValueLen = sizeof(der_buf);
-+
-+    rv = module->C_GetAttributeValue(session, key_handle, &attribute, 1);
-+    if (rv != CKR_OK) {
-+        free(attribute.pValue);
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "C_GetAttributeValue failed [%lu][%s].\n",
-+              rv, p11_kit_strerror(rv));
-+        return;
-+    }
-+
-+    p = (const unsigned char *) attribute.pValue;
-+    ec_group = d2i_ECPKParameters(NULL, &p, attribute.ulValueLen);
-+    len = OBJ_obj2txt(oid_buf, sizeof(oid_buf),
-+                      OBJ_nid2obj(EC_GROUP_get_curve_name(ec_group)), 1);
-+    DEBUG(SSSDBG_TRACE_ALL, "Curve name [%s][%s][%.*s].\n",
-+                            OBJ_nid2sn(EC_GROUP_get_curve_name(ec_group)),
-+                            OBJ_nid2ln(EC_GROUP_get_curve_name(ec_group)),
-+                            len, oid_buf);
-+
-+    return;
-+}
-+
-+static CK_KEY_TYPE get_key_type(CK_FUNCTION_LIST *module,
-+                                CK_SESSION_HANDLE session,
-+                                CK_OBJECT_HANDLE key_handle)
-+{
-+    CK_ATTRIBUTE attribute;
-+    CK_RV rv;
-+    CK_KEY_TYPE type;
-+
-+    attribute.type = CKA_KEY_TYPE;
-+    attribute.pValue = &type;
-+    attribute.ulValueLen = sizeof(CK_KEY_TYPE);
-+
-+    rv = module->C_GetAttributeValue(session, key_handle, &attribute, 1);
-+    if (rv != CKR_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "C_GetAttributeValue failed [%lu][%s].\n",
-+              rv, p11_kit_strerror(rv));
-+        return CK_UNAVAILABLE_INFORMATION;
-+    }
-+
-+    if (attribute.ulValueLen == -1) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Key type attribute cannot be read.\n");
-+        return CK_UNAVAILABLE_INFORMATION;
-+    }
-+
-+    if (type == CKK_EC && DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
-+        get_ec_curve_type(module, session, key_handle);
-+    }
-+
-+    return type;
-+}
-+
-+static int do_hash(TALLOC_CTX *mem_ctx, const EVP_MD *evp_md,
-+                   CK_BYTE *in, size_t in_len,
-+                   CK_BYTE **hash, size_t *hash_len)
-+{
-+    EVP_MD_CTX *md_ctx = NULL;
-+    int ret;
-+    unsigned char md_value[EVP_MAX_MD_SIZE];
-+    unsigned int md_len;
-+    CK_BYTE *out = NULL;
-+
-+    md_ctx = EVP_MD_CTX_create();
-+    if (md_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EVP_MD_CTX_create failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = EVP_DigestInit(md_ctx, evp_md);
-+    if (ret != 1) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EVP_DigestInit failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    ret = EVP_DigestUpdate(md_ctx, in, in_len);
-+    if (ret != 1) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EVP_DigestUpdate failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    ret = EVP_DigestFinal_ex(md_ctx, md_value, &md_len);
-+    if (ret != 1) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EVP_DigestFinal failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    out = talloc_size(mem_ctx, md_len * sizeof(CK_BYTE));
-+    if (out == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    memcpy(out, md_value, md_len);
-+
-+    *hash = out;
-+    *hash_len = md_len;
-+
-+    ret = EOK;
-+
-+done:
-+
-+    if (ret != EOK) {
-+        free(out);
-+        EVP_MD_CTX_free(md_ctx);
-+    }
-+
-+    return ret;
-+}
-+
-+/* A ECDSA signature consists of 2 integer values r and s. According to the
-+ * "PKCS #11 Cryptographic Token Interface Current Mechanisms Specification":
-+ *
-+ * """
-+ * For the purposes of these mechanisms, an ECDSA signature is an octet string
-+ * of even length which is at most two times nLen octets, where nLen is the
-+ * length in octets of the base point order n. The signature octets correspond
-+ * to the concatenation of the ECDSA values r and s, both represented as an
-+ * octet string of equal length of at most nLen with the most significant byte
-+ * first. If r and s have different octet length, the shorter of both must be
-+ * padded with leading zero octets such that both have the same octet length.
-+ * Loosely spoken, the first half of the signature is r and the second half is
-+ * s. For signatures created by a token, the resulting signature is always of
-+ * length 2nLen.
-+ * """
-+ *
-+ * Unfortunately OpenSSL expects the 2 integer values r and s DER encoded as
-+ * specified in X9.62 "Public Key Cryptography For The Financial Services
-+ * Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)":
-+ *
-+ * """
-+ * When a digital signature is identified by the OID ecdsa-with-SHA1 , the
-+ * digital signature shall be ASN.1 encoded using the following syntax:
-+ *   ECDSA-Sig-Value ::= SEQUENCE {
-+ *     r  INTEGER,
-+ *     s  INTEGER
-+ *   }
-+ *  """
-+ *
-+ *  The following function translates from the PKCS#11 to the X9.62 format by
-+ *  manually creating the DER sequence after splitting the PKCS#11 signature.
-+ *  Since r and s are positive values we have to make sure that the leading
-+ *  bit is not set in the DER encoding by prepending a 0-byte if needed.
-+ */
-+static int rs_to_seq(TALLOC_CTX *mem_ctx, CK_BYTE *rs_sig, CK_ULONG rs_sig_len,
-+                     CK_BYTE **seq_sig, CK_ULONG *seq_sig_len)
-+{
-+    CK_BYTE *r;
-+    size_t r_len;
-+    CK_BYTE *s;
-+    size_t s_len;
-+    size_t r_add = 0;
-+    size_t s_add = 0;
-+    CK_BYTE *out;
-+    size_t out_len;
-+
-+    if (rs_sig_len % 2 != 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected signature size [%lu].\n",
-+                                   rs_sig_len);
-+        return EINVAL;
-+    }
-+
-+    r_len = s_len = rs_sig_len / 2;
-+    r = rs_sig;
-+    s = rs_sig + r_len;
-+
-+    /* Remove padding */
-+    while(r_len > 1 && *r == 0x00) {
-+            r++;
-+            r_len--;
-+    }
-+    while(s_len > 1 && *s == 0x00) {
-+            s++;
-+            s_len--;
-+    }
-+
-+    /* r and s are positive, check if the highest bit is set which would
-+     * indicate a negative value. In this case a 0x00 must be added. */
-+    if ( *r & 0x80 ) {
-+        r_add = 1;
-+    }
-+    if ( *s & 0x80 ) {
-+        s_add = 1;
-+    }
-+
-+    out_len = r_len + r_add + s_len + s_add + 6;
-+    out = talloc_size(mem_ctx, out_len * sizeof(CK_BYTE));
-+    if (out == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+        return ENOMEM;
-+    }
-+
-+    out[0] = 0x30;
-+    out[1] = (CK_BYTE) (out_len - 2);
-+    out[2] = 0x02;
-+    out[3] = (CK_BYTE) (r_len + r_add);
-+    if (r_add == 1) {
-+        out[4] = 0x00;
-+    }
-+    memcpy(&out[4 + r_add], r, r_len);
-+    out[4 + r_add + r_len] = 0x02;
-+    out[5 + r_add + r_len] = (CK_BYTE) (s_len + s_add);
-+    if (s_add == 1)  {
-+        out[6 + r_add + r_len] = 0x00;
-+    }
-+    memcpy(&out[6 + r_add + r_len + s_add], s, s_len);
-+
-+    *seq_sig = out;
-+    *seq_sig_len = out_len;
-+
-+    return EOK;
-+}
-+
- static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-                      struct cert_list *cert)
- {
-@@ -870,17 +1108,25 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-       {CKA_SIGN, &key_sign, sizeof(key_sign)},
-       {CKA_ID, NULL, 0}
-     };
--    CK_MECHANISM mechanism = { CKM_SHA1_RSA_PKCS, NULL, 0 };
-+    CK_MECHANISM mechanism = { CK_UNAVAILABLE_INFORMATION, NULL, 0 };
-     CK_OBJECT_HANDLE priv_key_object;
-     CK_ULONG object_count;
-     CK_BYTE random_value[128];
-     CK_BYTE *signature = NULL;
-     CK_ULONG signature_size = 0;
-+    CK_BYTE *seq_sig = NULL;
-+    CK_ULONG seq_sig_size = 0;
-     CK_RV rv;
-     CK_RV rv_f;
-     EVP_PKEY *cert_pub_key = NULL;
-     EVP_MD_CTX *md_ctx;
-     int ret;
-+    const EVP_MD *evp_md = NULL;
-+    CK_BYTE *hash_val = NULL;
-+    size_t hash_len = 0;
-+    CK_BYTE *val_to_sign = NULL;
-+    size_t val_to_sign_len = 0;
-+    bool card_does_hash = false;
- 
-     key_template[2].pValue = cert->attributes[ATTR_ID].pValue;
-     key_template[2].ulValueLen = cert->attributes[ATTR_ID].ulValueLen;
-@@ -910,9 +1156,31 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-         return EINVAL;
-     }
- 
-+    switch (get_key_type(module, session, priv_key_object)) {
-+    case CKK_RSA:
-+        DEBUG(SSSDBG_TRACE_ALL, "Found RSA key using CKM_SHA1_RSA_PKCS.\n");
-+        mechanism.mechanism = CKM_SHA1_RSA_PKCS;
-+        evp_md = EVP_sha1();
-+        card_does_hash = true;
-+        break;
-+    case CKK_EC:
-+        DEBUG(SSSDBG_TRACE_ALL, "Found ECC key using CKM_ECDSA.\n");
-+        mechanism.mechanism = CKM_ECDSA;
-+        evp_md = EVP_sha1();
-+        card_does_hash = false;
-+        break;
-+    case CK_UNAVAILABLE_INFORMATION:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "get_key_type failed.\n");
-+        return EIO;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported key type.\n");
-+        return EIO;
-+    }
-+
-     rv = module->C_SignInit(session, &mechanism, priv_key_object);
-     if (rv != CKR_OK) {
--        DEBUG(SSSDBG_OP_FAILURE, "C_SignInit failed [%lu][%s].",
-+        DEBUG(SSSDBG_OP_FAILURE, "C_SignInit failed [%lu][%s].\n",
-                                  rv, p11_kit_strerror(rv));
-         return EIO;
-     }
-@@ -923,7 +1191,22 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-         return EINVAL;
-     }
- 
--    rv = module->C_Sign(session, random_value, sizeof(random_value), NULL,
-+    if (card_does_hash) {
-+        val_to_sign = random_value;
-+        val_to_sign_len = sizeof(random_value);
-+    } else {
-+        ret = do_hash(cert, evp_md, random_value, sizeof(random_value),
-+                      &hash_val, &hash_len);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "do_hash failed.\n");
-+            return ret;
-+        }
-+
-+        val_to_sign = hash_val;
-+        val_to_sign_len = hash_len;
-+    }
-+
-+    rv = module->C_Sign(session, val_to_sign, val_to_sign_len, NULL,
-                         &signature_size);
-     if (rv != CKR_OK || signature_size == 0) {
-         DEBUG(SSSDBG_OP_FAILURE, "C_Sign failed [%lu][%s].\n",
-@@ -937,7 +1220,7 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-         return ENOMEM;
-     }
- 
--    rv = module->C_Sign(session, random_value, sizeof(random_value), signature,
-+    rv = module->C_Sign(session, val_to_sign, val_to_sign_len, signature,
-                         &signature_size);
-     if (rv != CKR_OK) {
-         DEBUG(SSSDBG_OP_FAILURE, "C_Sign failed [%lu][%s].\n",
-@@ -958,7 +1241,7 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-         ret = ENOMEM;
-         goto done;
-     }
--    ret = EVP_VerifyInit(md_ctx, EVP_sha1());
-+    ret = EVP_VerifyInit(md_ctx, evp_md);
-     if (ret != 1) {
-         DEBUG(SSSDBG_OP_FAILURE, "EVP_VerifyInit failed.\n");
-         ret = EINVAL;
-@@ -972,11 +1255,27 @@ static int sign_data(CK_FUNCTION_LIST *module, CK_SESSION_HANDLE session,
-         goto done;
-     }
- 
--    ret = EVP_VerifyFinal(md_ctx, signature, signature_size, cert_pub_key);
--    if (ret != 1) {
--        DEBUG(SSSDBG_OP_FAILURE, "EVP_VerifyFinal failed.\n");
--        ret = EINVAL;
--        goto done;
-+    if (mechanism.mechanism == CKM_ECDSA) {
-+        ret = rs_to_seq(signature, signature, signature_size,
-+                        &seq_sig, &seq_sig_size);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "rs_to_seq failed.\n");
-+            goto done;
-+        }
-+
-+        ret = EVP_VerifyFinal(md_ctx, seq_sig, seq_sig_size, cert_pub_key);
-+        if (ret != 1) {
-+            DEBUG(SSSDBG_OP_FAILURE, "EVP_VerifyFinal failed.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+    } else {
-+        ret = EVP_VerifyFinal(md_ctx, signature, signature_size, cert_pub_key);
-+        if (ret != 1) {
-+            DEBUG(SSSDBG_OP_FAILURE, "EVP_VerifyFinal failed.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-     }
- 
-     ret = EOK;
--- 
-2.19.1
-
diff --git a/SOURCES/0071-utils-refactor-ssh-key-extraction-OpenSSL.patch b/SOURCES/0071-utils-refactor-ssh-key-extraction-OpenSSL.patch
deleted file mode 100644
index 6d732d7..0000000
--- a/SOURCES/0071-utils-refactor-ssh-key-extraction-OpenSSL.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From ad3356d105835718f57edb7844e1fed911770610 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 14 Nov 2018 15:02:33 +0100
-Subject: [PATCH 71/74] utils: refactor ssh key extraction (OpenSSL)
-
-Prepare the current code to allow adding other key types.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/util/cert/libcrypto/cert.c | 87 +++++++++++++++++++++-------------
- 1 file changed, 53 insertions(+), 34 deletions(-)
-
-diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c
-index c8e07837f..d925c5c5b 100644
---- a/src/util/cert/libcrypto/cert.c
-+++ b/src/util/cert/libcrypto/cert.c
-@@ -171,17 +171,13 @@ done:
- #define SSH_RSA_HEADER "ssh-rsa"
- #define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
- 
--errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
--                              const uint8_t *der_blob, size_t der_size,
--                              uint8_t **key_blob, size_t *key_size)
-+static errno_t rsa_pub_key_to_ssh(TALLOC_CTX *mem_ctx, EVP_PKEY *cert_pub_key,
-+                                  uint8_t **key_blob, size_t *key_size)
- {
-     int ret;
-+    size_t c;
-     size_t size;
--    const unsigned char *d;
-     uint8_t *buf = NULL;
--    size_t c;
--    X509 *cert = NULL;
--    EVP_PKEY *cert_pub_key = NULL;
-     const BIGNUM *n;
-     const BIGNUM *e;
-     int modulus_len;
-@@ -189,33 +185,6 @@ errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
-     int exponent_len;
-     unsigned char exponent[OPENSSL_RSA_MAX_PUBEXP_BITS/8];
- 
--    if (der_blob == NULL || der_size == 0) {
--        return EINVAL;
--    }
--
--    d = (const unsigned char *) der_blob;
--
--    cert = d2i_X509(NULL, &d, (int) der_size);
--    if (cert == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "d2i_X509 failed.\n");
--        return EINVAL;
--    }
--
--    cert_pub_key = X509_get_pubkey(cert);
--    if (cert_pub_key == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "X509_get_pubkey failed.\n");
--        ret = EIO;
--        goto done;
--    }
--
--    if (EVP_PKEY_base_id(cert_pub_key) != EVP_PKEY_RSA) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              "Expected RSA public key, found unsupported [%d].\n",
--              EVP_PKEY_base_id(cert_pub_key));
--        ret = EINVAL;
--        goto done;
--    }
--
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L
-     RSA *rsa_pub_key = NULL;
-     rsa_pub_key = EVP_PKEY_get0_RSA(cert_pub_key);
-@@ -268,6 +237,56 @@ done:
-     if (ret != EOK)  {
-         talloc_free(buf);
-     }
-+
-+    return ret;
-+}
-+
-+errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
-+                              const uint8_t *der_blob, size_t der_size,
-+                              uint8_t **key_blob, size_t *key_size)
-+{
-+    int ret;
-+    const unsigned char *d;
-+    X509 *cert = NULL;
-+    EVP_PKEY *cert_pub_key = NULL;
-+
-+    if (der_blob == NULL || der_size == 0) {
-+        return EINVAL;
-+    }
-+
-+    d = (const unsigned char *) der_blob;
-+
-+    cert = d2i_X509(NULL, &d, (int) der_size);
-+    if (cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "d2i_X509 failed.\n");
-+        return EINVAL;
-+    }
-+
-+    cert_pub_key = X509_get_pubkey(cert);
-+    if (cert_pub_key == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "X509_get_pubkey failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    switch (EVP_PKEY_base_id(cert_pub_key)) {
-+    case EVP_PKEY_RSA:
-+        ret = rsa_pub_key_to_ssh(mem_ctx, cert_pub_key, key_blob, key_size);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "rsa_pub_key_to_ssh failed.\n");
-+            goto done;
-+        }
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Expected RSA public key, found unsupported [%d].\n",
-+              EVP_PKEY_base_id(cert_pub_key));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+done:
-+
-     EVP_PKEY_free(cert_pub_key);
-     X509_free(cert);
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0072-utils-add-ec_pub_key_to_ssh-OpenSSL.patch b/SOURCES/0072-utils-add-ec_pub_key_to_ssh-OpenSSL.patch
deleted file mode 100644
index 2fa32d0..0000000
--- a/SOURCES/0072-utils-add-ec_pub_key_to_ssh-OpenSSL.patch
+++ /dev/null
@@ -1,265 +0,0 @@
-From 41c4661b6fd237b156606bfd0d8ca3edd5a16795 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 14 Nov 2018 21:13:53 +0100
-Subject: [PATCH 72/74] utils: add ec_pub_key_to_ssh() (OpenSSL)
-
-Add EC key support for the OpenSSL version of the ssh key extraction
-code.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/tests/cmocka/test_cert_utils.c |  70 ++++++++++++++++
- src/util/cert/libcrypto/cert.c     | 126 ++++++++++++++++++++++++++++-
- 2 files changed, 195 insertions(+), 1 deletion(-)
-
-diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
-index 26fffb870..9273356eb 100644
---- a/src/tests/cmocka/test_cert_utils.c
-+++ b/src/tests/cmocka/test_cert_utils.c
-@@ -40,11 +40,15 @@
- #include "tests/test_CA/SSSD_test_cert_x509_0001.h"
- #include "tests/test_CA/SSSD_test_cert_pubsshkey_0002.h"
- #include "tests/test_CA/SSSD_test_cert_x509_0002.h"
-+#include "tests/test_ECC_CA/SSSD_test_ECC_cert_pubsshkey_0001.h"
-+#include "tests/test_ECC_CA/SSSD_test_ECC_cert_x509_0001.h"
- #else
- #define SSSD_TEST_CERT_0001 ""
- #define SSSD_TEST_CERT_SSH_KEY_0001 ""
- #define SSSD_TEST_CERT_0002 ""
- #define SSSD_TEST_CERT_SSH_KEY_0002 ""
-+#define SSSD_TEST_ECC_CERT_0001 ""
-+#define SSSD_TEST_ECC_CERT_SSH_KEY_0001 ""
- #endif
- 
- /* When run under valgrind with --trace-children=yes we have to increase the
-@@ -564,6 +568,70 @@ void test_cert_to_ssh_2keys_invalid_send(void **state)
-     talloc_free(ev);
- }
- 
-+void test_ec_cert_to_ssh_key_done(struct tevent_req *req)
-+{
-+    int ret;
-+    struct test_state *ts = tevent_req_callback_data(req, struct test_state);
-+    struct ldb_val *keys;
-+    uint8_t *exp_key;
-+    size_t exp_key_size;
-+    size_t valid_keys;
-+
-+    assert_non_null(ts);
-+    ts->done = true;
-+
-+    ret = cert_to_ssh_key_recv(req, ts, &keys, &valid_keys);
-+    talloc_free(req);
-+    assert_int_equal(ret, 0);
-+    assert_non_null(keys[0].data);
-+    assert_int_equal(valid_keys, 1);
-+
-+    exp_key = sss_base64_decode(ts, SSSD_TEST_ECC_CERT_SSH_KEY_0001,
-+                                &exp_key_size);
-+    assert_non_null(exp_key);
-+    assert_int_equal(keys[0].length, exp_key_size);
-+    assert_memory_equal(keys[0].data, exp_key, exp_key_size);
-+
-+    talloc_free(exp_key);
-+    talloc_free(keys);
-+}
-+
-+void test_ec_cert_to_ssh_key_send(void **state)
-+{
-+    struct tevent_context *ev;
-+    struct tevent_req *req;
-+    struct ldb_val val[1];
-+
-+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
-+    assert_non_null(ts);
-+    ts->done = false;
-+
-+    val[0].data = sss_base64_decode(ts, SSSD_TEST_ECC_CERT_0001,
-+                                    &val[0].length);
-+    assert_non_null(val[0].data);
-+
-+    ev = tevent_context_init(ts);
-+    assert_non_null(ev);
-+
-+    req = cert_to_ssh_key_send(ts, ev, -1, P11_CHILD_TIMEOUT,
-+#ifdef HAVE_NSS
-+                    "sql:" ABS_BUILD_DIR "/src/tests/test_ECC_CA/p11_ecc_nssdb",
-+#else
-+                    ABS_BUILD_DIR "/src/tests/test_ECC_CA/SSSD_test_ECC_CA.pem",
-+#endif
-+                    1, &val[0], NULL);
-+    assert_non_null(req);
-+
-+    tevent_req_set_callback(req, test_ec_cert_to_ssh_key_done, ts);
-+
-+    while (!ts->done) {
-+        tevent_loop_once(ev);
-+    }
-+
-+    talloc_free(val[0].data);
-+    talloc_free(ev);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -595,6 +663,8 @@ int main(int argc, const char *argv[])
-                                         setup, teardown),
-         cmocka_unit_test_setup_teardown(test_cert_to_ssh_2keys_invalid_send,
-                                         setup, teardown),
-+        cmocka_unit_test_setup_teardown(test_ec_cert_to_ssh_key_send,
-+                                        setup, teardown),
- #endif
-     };
- 
-diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c
-index d925c5c5b..acca07dd0 100644
---- a/src/util/cert/libcrypto/cert.c
-+++ b/src/util/cert/libcrypto/cert.c
-@@ -168,6 +168,123 @@ done:
- 
- }
- 
-+/* SSH EC keys are defined in https://tools.ietf.org/html/rfc5656 */
-+#define ECDSA_SHA2_HEADER "ecdsa-sha2-"
-+/* Looks like OpenSSH currently only supports the following 3 required
-+ * curves. */
-+#define IDENTIFIER_NISTP256 "nistp256"
-+#define IDENTIFIER_NISTP384 "nistp384"
-+#define IDENTIFIER_NISTP521 "nistp521"
-+
-+static errno_t ec_pub_key_to_ssh(TALLOC_CTX *mem_ctx, EVP_PKEY *cert_pub_key,
-+                                 uint8_t **key_blob, size_t *key_size)
-+{
-+    int ret;
-+    size_t c;
-+    uint8_t *buf = NULL;
-+    size_t buf_len;
-+    EC_KEY *ec_key = NULL;
-+    const EC_GROUP *ec_group = NULL;
-+    const EC_POINT *ec_public_key = NULL;
-+    BN_CTX *bn_ctx = NULL;
-+    int key_len;
-+    const char *identifier = NULL;
-+    int identifier_len;
-+    const char *header = NULL;
-+    int header_len;
-+
-+    ec_key = EVP_PKEY_get1_EC_KEY(cert_pub_key);
-+    if (ec_key == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ec_group = EC_KEY_get0_group(ec_key);
-+
-+    switch(EC_GROUP_get_curve_name(ec_group)) {
-+    case NID_X9_62_prime256v1:
-+        identifier = IDENTIFIER_NISTP256;
-+        header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP256;
-+        break;
-+    case NID_secp384r1:
-+        identifier = IDENTIFIER_NISTP384;
-+        header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP384;
-+        break;
-+    case NID_secp521r1:
-+        identifier = IDENTIFIER_NISTP521;
-+        header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP521;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported curve [%s]\n",
-+              OBJ_nid2sn(EC_GROUP_get_curve_name(ec_group)));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    header_len = strlen(header);
-+    identifier_len = strlen(identifier);
-+
-+    ec_public_key = EC_KEY_get0_public_key(ec_key);
-+
-+    bn_ctx =  BN_CTX_new();
-+    if (bn_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "BN_CTX_new failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    key_len = EC_POINT_point2oct(ec_group, ec_public_key,
-+                             POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
-+    if (key_len == 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EC_POINT_point2oct failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    buf_len = header_len + identifier_len + key_len + 3 * sizeof(uint32_t);
-+    buf = talloc_size(mem_ctx, buf_len * sizeof(uint8_t));
-+    if (buf == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    c = 0;
-+
-+    SAFEALIGN_SET_UINT32(buf, htobe32(header_len), &c);
-+    safealign_memcpy(&buf[c], header, header_len, &c);
-+
-+    SAFEALIGN_SET_UINT32(&buf[c], htobe32(identifier_len), &c);
-+    safealign_memcpy(&buf[c], identifier , identifier_len, &c);
-+
-+    SAFEALIGN_SET_UINT32(&buf[c], htobe32(key_len), &c);
-+
-+    if (EC_POINT_point2oct(ec_group, ec_public_key,
-+                           POINT_CONVERSION_UNCOMPRESSED, buf + c, key_len,
-+                           bn_ctx)
-+            != key_len) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EC_POINT_point2oct failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    *key_size = buf_len;
-+    *key_blob = buf;
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(buf);
-+    }
-+
-+    BN_CTX_free(bn_ctx);
-+    EC_KEY_free(ec_key);
-+
-+    return ret;
-+}
-+
-+
- #define SSH_RSA_HEADER "ssh-rsa"
- #define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
- 
-@@ -277,9 +394,16 @@ errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
-             goto done;
-         }
-         break;
-+    case EVP_PKEY_EC:
-+        ret = ec_pub_key_to_ssh(mem_ctx, cert_pub_key, key_blob, key_size);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "rsa_pub_key_to_ssh failed.\n");
-+            goto done;
-+        }
-+        break;
-     default:
-         DEBUG(SSSDBG_CRIT_FAILURE,
--              "Expected RSA public key, found unsupported [%d].\n",
-+              "Expected RSA or EC public key, found unsupported [%d].\n",
-               EVP_PKEY_base_id(cert_pub_key));
-         ret = EINVAL;
-         goto done;
--- 
-2.19.1
-
diff --git a/SOURCES/0073-utils-refactor-ssh-key-extraction-NSS.patch b/SOURCES/0073-utils-refactor-ssh-key-extraction-NSS.patch
deleted file mode 100644
index c3e1ec7..0000000
--- a/SOURCES/0073-utils-refactor-ssh-key-extraction-NSS.patch
+++ /dev/null
@@ -1,153 +0,0 @@
-From 4e627add38af409ec6a5023212677956babca1e7 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 16 Nov 2018 17:31:00 +0100
-Subject: [PATCH 73/74] utils: refactor ssh key extraction (NSS)
-
-Prepare the current code to allow adding other key types.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/util/cert/nss/cert.c | 110 +++++++++++++++++++++++----------------
- 1 file changed, 65 insertions(+), 45 deletions(-)
-
-diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c
-index a8efef818..b5c4769a8 100644
---- a/src/util/cert/nss/cert.c
-+++ b/src/util/cert/nss/cert.c
-@@ -223,14 +223,10 @@ done:
- #define SSH_RSA_HEADER "ssh-rsa"
- #define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
- 
--errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
--                              uint8_t *der_blob, size_t der_size,
--                              uint8_t **key_blob, size_t *key_size)
-+static errno_t rsa_pub_key_to_ssh(TALLOC_CTX *mem_ctx,
-+                                  SECKEYPublicKey *cert_pub_key,
-+                                  uint8_t **key_blob, size_t *key_size)
- {
--    CERTCertDBHandle *handle;
--    CERTCertificate *cert = NULL;
--    SECItem der_item;
--    SECKEYPublicKey *cert_pub_key = NULL;
-     int ret;
-     size_t size;
-     uint8_t *buf = NULL;
-@@ -238,44 +234,6 @@ errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
-     size_t exponent_prefix_len;
-     size_t modulus_prefix_len;
- 
--    if (der_blob == NULL || der_size == 0) {
--        return EINVAL;
--    }
--
--    /* initialize NSS if needed */
--    ret = nspr_nss_init();
--    if (ret != EOK) {
--        ret = EIO;
--        goto done;
--    }
--
--    handle = CERT_GetDefaultCertDB();
--
--    der_item.len = der_size;
--    der_item.data = discard_const(der_blob);
--
--    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
--    if (cert == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
--        ret = EINVAL;
--        goto done;
--    }
--
--    cert_pub_key = CERT_ExtractPublicKey(cert);
--    if (cert_pub_key == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_ExtractPublicKey failed.\n");
--        ret = EIO;
--        goto done;
--    }
--
--    if (cert_pub_key->keyType != rsaKey) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              "Expected RSA public key, found unsupported [%d].\n",
--              cert_pub_key->keyType);
--        ret = EINVAL;
--        goto done;
--    }
--
-     /* Looks like nss drops the leading 00 which AFAIK is added to make sure
-      * the bigint is handled as positive number if the leading bit is set. */
-     exponent_prefix_len = 0;
-@@ -330,6 +288,68 @@ done:
-     if (ret != EOK)  {
-         talloc_free(buf);
-     }
-+
-+    return ret;
-+}
-+
-+errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
-+                              uint8_t *der_blob, size_t der_size,
-+                              uint8_t **key_blob, size_t *key_size)
-+{
-+    CERTCertDBHandle *handle;
-+    CERTCertificate *cert = NULL;
-+    SECItem der_item;
-+    SECKEYPublicKey *cert_pub_key = NULL;
-+    int ret;
-+
-+    if (der_blob == NULL || der_size == 0) {
-+        return EINVAL;
-+    }
-+
-+    /* initialize NSS if needed */
-+    ret = nspr_nss_init();
-+    if (ret != EOK) {
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    handle = CERT_GetDefaultCertDB();
-+
-+    der_item.len = der_size;
-+    der_item.data = discard_const(der_blob);
-+
-+    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
-+    if (cert == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    cert_pub_key = CERT_ExtractPublicKey(cert);
-+    if (cert_pub_key == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_ExtractPublicKey failed.\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    switch (cert_pub_key->keyType) {
-+    case rsaKey:
-+        ret = rsa_pub_key_to_ssh(mem_ctx, cert_pub_key, key_blob, key_size);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "rsa_pub_key_to_ssh failed.\n");
-+            goto done;
-+        }
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Expected RSA public key, found unsupported [%d].\n",
-+              cert_pub_key->keyType);
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+done:
-+
-     SECKEY_DestroyPublicKey(cert_pub_key);
-     CERT_DestroyCertificate(cert);
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0074-utils-add-ec_pub_key_to_ssh-NSS.patch b/SOURCES/0074-utils-add-ec_pub_key_to_ssh-NSS.patch
deleted file mode 100644
index 6ad4d92..0000000
--- a/SOURCES/0074-utils-add-ec_pub_key_to_ssh-NSS.patch
+++ /dev/null
@@ -1,158 +0,0 @@
-From 3906e5f41a00063127e07f5ca696a25eea2e8bb7 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 16 Nov 2018 18:15:32 +0100
-Subject: [PATCH 74/74] utils: add ec_pub_key_to_ssh() (NSS)
-
-Add EC key support for the NSS version of the ssh key extraction code.
-
-Related to https://pagure.io/SSSD/sssd/issue/3887
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/util/cert/nss/cert.c | 121 ++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 120 insertions(+), 1 deletion(-)
-
-diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c
-index b5c4769a8..ad90da0da 100644
---- a/src/util/cert/nss/cert.c
-+++ b/src/util/cert/nss/cert.c
-@@ -220,6 +220,118 @@ done:
-     return ret;
- }
- 
-+/* taken from NSS's lib/cryptohi/seckey.c */
-+static SECOidTag
-+sss_SECKEY_GetECCOid(const SECKEYECParams *params)
-+{
-+    SECItem oid = { siBuffer, NULL, 0 };
-+    SECOidData *oidData = NULL;
-+
-+    /*
-+     * params->data needs to contain the ASN encoding of an object ID (OID)
-+     * representing a named curve. Here, we strip away everything
-+     * before the actual OID and use the OID to look up a named curve.
-+     */
-+    if (params->data[0] != SEC_ASN1_OBJECT_ID)
-+        return 0;
-+    oid.len = params->len - 2;
-+    oid.data = params->data + 2;
-+    if ((oidData = SECOID_FindOID(&oid)) == NULL)
-+        return 0;
-+
-+    return oidData->offset;
-+}
-+
-+/* SSH EC keys are defined in https://tools.ietf.org/html/rfc5656 */
-+#define ECDSA_SHA2_HEADER "ecdsa-sha2-"
-+/* Looks like OpenSSH currently only supports the following 3 required
-+ * curves. */
-+#define IDENTIFIER_NISTP256 "nistp256"
-+#define IDENTIFIER_NISTP384 "nistp384"
-+#define IDENTIFIER_NISTP521 "nistp521"
-+
-+static errno_t ec_pub_key_to_ssh(TALLOC_CTX *mem_ctx,
-+                                 SECKEYPublicKey *cert_pub_key,
-+                                 uint8_t **key_blob, size_t *key_size)
-+{
-+    int ret;
-+    size_t c;
-+    uint8_t *buf = NULL;
-+    size_t buf_len;
-+    SECOidTag curve_tag;
-+    int key_len;
-+    const char *identifier = NULL;
-+    int identifier_len;
-+    const char *header = NULL;
-+    int header_len;
-+    SECItem *ec_public_key;
-+
-+    curve_tag = sss_SECKEY_GetECCOid(&cert_pub_key->u.ec.DEREncodedParams);
-+    switch(curve_tag) {
-+    case SEC_OID_ANSIX962_EC_PRIME256V1:
-+        identifier = IDENTIFIER_NISTP256;
-+        header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP256;
-+        break;
-+    case SEC_OID_SECG_EC_SECP384R1:
-+        identifier = IDENTIFIER_NISTP384;
-+        header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP384;
-+        break;
-+    case SEC_OID_SECG_EC_SECP521R1:
-+        identifier = IDENTIFIER_NISTP521;
-+        header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP521;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported curve [%s]\n",
-+              SECOID_FindOIDTagDescription(curve_tag));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    header_len = strlen(header);
-+    identifier_len = strlen(identifier);
-+
-+    ec_public_key = &cert_pub_key->u.ec.publicValue;
-+
-+    key_len = ec_public_key->len;
-+    if (key_len == 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "EC_POINT_point2oct failed.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    buf_len = header_len + identifier_len + key_len + 3 * sizeof(uint32_t);
-+    buf = talloc_size(mem_ctx, buf_len * sizeof(uint8_t));
-+    if (buf == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    c = 0;
-+
-+    SAFEALIGN_SET_UINT32(buf, htobe32(header_len), &c);
-+    safealign_memcpy(&buf[c], header, header_len, &c);
-+
-+    SAFEALIGN_SET_UINT32(&buf[c], htobe32(identifier_len), &c);
-+    safealign_memcpy(&buf[c], identifier , identifier_len, &c);
-+
-+    SAFEALIGN_SET_UINT32(&buf[c], htobe32(key_len), &c);
-+
-+    safealign_memcpy(&buf[c], ec_public_key->data, key_len, &c);
-+
-+    *key_size = buf_len;
-+    *key_blob = buf;
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(buf);
-+    }
-+
-+    return ret;
-+}
-+
- #define SSH_RSA_HEADER "ssh-rsa"
- #define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
- 
-@@ -340,9 +452,16 @@ errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
-             goto done;
-         }
-         break;
-+    case ecKey:
-+        ret = ec_pub_key_to_ssh(mem_ctx, cert_pub_key, key_blob, key_size);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "rsa_pub_key_to_ssh failed.\n");
-+            goto done;
-+        }
-+        break;
-     default:
-         DEBUG(SSSDBG_CRIT_FAILURE,
--              "Expected RSA public key, found unsupported [%d].\n",
-+              "Expected RSA or EC public key, found unsupported [%d].\n",
-               cert_pub_key->keyType);
-         ret = EINVAL;
-         goto done;
--- 
-2.19.1
-
diff --git a/SOURCES/0075-SSSCTL-user-show-says-that-user-is-expired.patch b/SOURCES/0075-SSSCTL-user-show-says-that-user-is-expired.patch
deleted file mode 100644
index b960eea..0000000
--- a/SOURCES/0075-SSSCTL-user-show-says-that-user-is-expired.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 291071cb3c04eda7606d62bbff123a0a125c7d60 Mon Sep 17 00:00:00 2001
-From: Tomas Halman <thalman@redhat.com>
-Date: Tue, 13 Nov 2018 12:21:16 +0100
-Subject: [PATCH] SSSCTL: user-show says that user is expired
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-sssctl user-show says that user is expired if the user comes from files
-provider. This is ok because files user's expiration time is always set
-to 0 but we should print a better, less confusing message.
-
-The same change apply to groups.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3858
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/tools/sssctl/sssctl_cache.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
-index 42a2a60fd..e0d067cfb 100644
---- a/src/tools/sssctl/sssctl_cache.c
-+++ b/src/tools/sssctl/sssctl_cache.c
-@@ -154,6 +154,11 @@ static errno_t get_attr_expire(TALLOC_CTX *mem_ctx,
-         return ret;
-     }
- 
-+    if (is_files_provider(dom)) {
-+        *_value = "Never";
-+        return EOK;
-+    }
-+
-     if (value < time(NULL)) {
-         *_value = "Expired";
-         return EOK;
-@@ -179,6 +184,11 @@ static errno_t attr_initgr(TALLOC_CTX *mem_ctx,
-         return ret;
-     }
- 
-+    if (is_files_provider(dom)) {
-+        *_value = "Never";
-+        return EOK;
-+    }
-+
-     if (value < time(NULL)) {
-         *_value = "Expired";
-         return EOK;
--- 
-2.19.1
-
diff --git a/SOURCES/0076-sss_iface-prevent-from-using-invalid-names-that-star.patch b/SOURCES/0076-sss_iface-prevent-from-using-invalid-names-that-star.patch
deleted file mode 100644
index a444b0c..0000000
--- a/SOURCES/0076-sss_iface-prevent-from-using-invalid-names-that-star.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From f47940356462a3f477fe462e71d7680c959300db Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 14 Nov 2018 11:48:08 +0100
-Subject: [PATCH] sss_iface: prevent from using invalid names that start with
- digits
-
-https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
-
-- Bus names that start with a colon (':') character are unique connection names. Other bus names are called well-known bus names.
-- Bus names are composed of 1 or more elements separated by a period ('.') character. All elements must contain at least one character.
-- Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-", with "-" discouraged in new bus names. Only elements that are part of a unique connection name may begin with a digit, elements in other bus names must not begin with a digit.
-- Bus names must contain at least one '.' (period) character (and thus at least two elements).
-- Bus names must not begin with a '.' (period) character.
-- Bus names must not exceed the maximum name length (255).
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3872
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/sss_iface/sss_iface.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/sss_iface/sss_iface.c b/src/sss_iface/sss_iface.c
-index 644abd71c..e20c14fea 100644
---- a/src/sss_iface/sss_iface.c
-+++ b/src/sss_iface/sss_iface.c
-@@ -56,7 +56,9 @@ sss_iface_domain_bus(TALLOC_CTX *mem_ctx,
-         return NULL;
-     }
- 
--    bus_name = talloc_asprintf(mem_ctx, "sssd.domain.%s", safe_name);
-+    /* Parts of bus names must not start with digit thus we concatenate
-+     * the name with underscore instead of period. */
-+    bus_name = talloc_asprintf(mem_ctx, "sssd.domain_%s", safe_name);
-     talloc_free(safe_name);
- 
-     return bus_name;
-@@ -66,7 +68,9 @@ char *
- sss_iface_proxy_bus(TALLOC_CTX *mem_ctx,
-                     uint32_t id)
- {
--    return talloc_asprintf(mem_ctx, "sssd.proxy.%"PRIu32, id);
-+    /* Parts of bus names must not start with digit thus we concatenate
-+     * the name with underscore instead of period. */
-+    return talloc_asprintf(mem_ctx, "sssd.proxy_%"PRIu32, id);
- }
- 
- errno_t
--- 
-2.19.1
-
diff --git a/SOURCES/0077-nss-use-enumeration-context-as-talloc-parent-for-cac.patch b/SOURCES/0077-nss-use-enumeration-context-as-talloc-parent-for-cac.patch
deleted file mode 100644
index 3e2745e..0000000
--- a/SOURCES/0077-nss-use-enumeration-context-as-talloc-parent-for-cac.patch
+++ /dev/null
@@ -1,145 +0,0 @@
-From 406b731ddfbeb62623640cc37a7adc76af0a4b22 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 30 Oct 2018 13:21:28 +0100
-Subject: [PATCH] nss: use enumeration context as talloc parent for cache req
- result
-
-Otherwise we end up with memory leak since the result is never freed.
-
-We need to convert nctx->*ent structures into talloc pointer so
-we can use enum_ctx as parent.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3870
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/responder/nss/nss_cmd.c     | 12 ++++++------
- src/responder/nss/nss_enum.c    |  2 +-
- src/responder/nss/nss_private.h |  6 +++---
- src/responder/nss/nsssrv.c      | 21 +++++++++++++++++++++
- 4 files changed, 31 insertions(+), 10 deletions(-)
-
-diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
-index 9ee6ca805..25e663ed5 100644
---- a/src/responder/nss/nss_cmd.c
-+++ b/src/responder/nss/nss_cmd.c
-@@ -942,7 +942,7 @@ static errno_t nss_cmd_setpwent(struct cli_ctx *cli_ctx)
- 
-     nss_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct nss_ctx);
- 
--    return nss_setent(cli_ctx, CACHE_REQ_ENUM_USERS, &nss_ctx->pwent);
-+    return nss_setent(cli_ctx, CACHE_REQ_ENUM_USERS, nss_ctx->pwent);
- }
- 
- static errno_t nss_cmd_getpwent(struct cli_ctx *cli_ctx)
-@@ -955,7 +955,7 @@ static errno_t nss_cmd_getpwent(struct cli_ctx *cli_ctx)
- 
-     return nss_getent(cli_ctx, CACHE_REQ_ENUM_USERS,
-                       &state_ctx->pwent, nss_protocol_fill_pwent,
--                      &nss_ctx->pwent);
-+                      nss_ctx->pwent);
- }
- 
- static errno_t nss_cmd_endpwent(struct cli_ctx *cli_ctx)
-@@ -998,7 +998,7 @@ static errno_t nss_cmd_setgrent(struct cli_ctx *cli_ctx)
- 
-     nss_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct nss_ctx);
- 
--    return nss_setent(cli_ctx, CACHE_REQ_ENUM_GROUPS, &nss_ctx->grent);
-+    return nss_setent(cli_ctx, CACHE_REQ_ENUM_GROUPS, nss_ctx->grent);
- }
- 
- static errno_t nss_cmd_getgrent(struct cli_ctx *cli_ctx)
-@@ -1011,7 +1011,7 @@ static errno_t nss_cmd_getgrent(struct cli_ctx *cli_ctx)
- 
-     return nss_getent(cli_ctx, CACHE_REQ_ENUM_GROUPS,
-                       &state_ctx->grent, nss_protocol_fill_grent,
--                      &nss_ctx->grent);
-+                      nss_ctx->grent);
- }
- 
- static errno_t nss_cmd_endgrent(struct cli_ctx *cli_ctx)
-@@ -1093,7 +1093,7 @@ static errno_t nss_cmd_setservent(struct cli_ctx *cli_ctx)
- 
-     nss_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct nss_ctx);
- 
--    return nss_setent(cli_ctx, CACHE_REQ_ENUM_SVC, &nss_ctx->svcent);
-+    return nss_setent(cli_ctx, CACHE_REQ_ENUM_SVC, nss_ctx->svcent);
- }
- 
- static errno_t nss_cmd_getservent(struct cli_ctx *cli_ctx)
-@@ -1106,7 +1106,7 @@ static errno_t nss_cmd_getservent(struct cli_ctx *cli_ctx)
- 
-     return nss_getent(cli_ctx, CACHE_REQ_ENUM_SVC,
-                       &state_ctx->svcent, nss_protocol_fill_svcent,
--                      &nss_ctx->svcent);
-+                      nss_ctx->svcent);
- }
- 
- static errno_t nss_cmd_endservent(struct cli_ctx *cli_ctx)
-diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c
-index a45b65233..9588943c9 100644
---- a/src/responder/nss/nss_enum.c
-+++ b/src/responder/nss/nss_enum.c
-@@ -138,7 +138,7 @@ static void nss_setent_internal_done(struct tevent_req *subreq)
-     switch (ret) {
-     case EOK:
-         talloc_zfree(state->enum_ctx->result);
--        state->enum_ctx->result = talloc_steal(state->nss_ctx, result);
-+        state->enum_ctx->result = talloc_steal(state->enum_ctx, result);
- 
-         if (state->type == CACHE_REQ_NETGROUP_BY_NAME) {
-             /* We need to expand the netgroup into triples and members. */
-diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h
-index aa8d8e9cd..cd0d35517 100644
---- a/src/responder/nss/nss_private.h
-+++ b/src/responder/nss/nss_private.h
-@@ -78,9 +78,9 @@ struct nss_ctx {
-     const char **extra_attributes;
- 
-     /* Enumeration. */
--    struct nss_enum_ctx pwent;
--    struct nss_enum_ctx grent;
--    struct nss_enum_ctx svcent;
-+    struct nss_enum_ctx *pwent;
-+    struct nss_enum_ctx *grent;
-+    struct nss_enum_ctx *svcent;
-     hash_table_t *netgrent;
- 
-     /* Memory cache. */
-diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
-index 3c4edbb53..fb7326a02 100644
---- a/src/responder/nss/nsssrv.c
-+++ b/src/responder/nss/nsssrv.c
-@@ -345,6 +345,27 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
-         goto fail;
-     }
- 
-+    nctx->pwent = talloc_zero(nctx, struct nss_enum_ctx);
-+    if (nctx->pwent == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize pwent context!\n");
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+
-+    nctx->grent = talloc_zero(nctx, struct nss_enum_ctx);
-+    if (nctx->grent == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize grent context!\n");
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+
-+    nctx->svcent = talloc_zero(nctx, struct nss_enum_ctx);
-+    if (nctx->svcent == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize svcent context!\n");
-+        ret = ENOMEM;
-+        goto fail;
-+    }
-+
-     nctx->netgrent = sss_ptr_hash_create(nctx, NULL, NULL);
-     if (nctx->netgrent == NULL) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize netgroups table!\n");
--- 
-2.19.1
-
diff --git a/SOURCES/0078-LDAP-minor-refactoring-in-auth_send-to-conform-to-ou.patch b/SOURCES/0078-LDAP-minor-refactoring-in-auth_send-to-conform-to-ou.patch
deleted file mode 100644
index d24017d..0000000
--- a/SOURCES/0078-LDAP-minor-refactoring-in-auth_send-to-conform-to-ou.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 09091b4b60456a989ecc8c3b6f76661a14c108ba Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 22 Nov 2018 12:51:14 +0100
-Subject: [PATCH 78/80] LDAP: minor refactoring in auth_send() to conform to
- our coding style
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3451
-
-A tevent _send() function should only return NULL on ENOMEM, otherwise
-it should mark the request as failed but return the req pointer. This
-was not much of an issue, before, but the next patch will add another
-function call to the auth_send call which would make error handling
-awkward.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/providers/ldap/ldap_auth.c | 17 +++++++++++------
- 1 file changed, 11 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index d40bc9414..c409353d9 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -636,6 +636,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
- {
-     struct tevent_req *req;
-     struct auth_state *state;
-+    errno_t ret;
- 
-     req = tevent_req_create(memctx, &state, struct auth_state);
-     if (!req) return NULL;
-@@ -645,11 +646,11 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
-         if (sss_authtok_get_type(authtok) == SSS_AUTHTOK_TYPE_SC_PIN
-             || sss_authtok_get_type(authtok) == SSS_AUTHTOK_TYPE_SC_KEYPAD) {
-             /* Tell frontend that we do not support Smartcard authentication */
--            tevent_req_error(req, ERR_SC_AUTH_NOT_SUPPORTED);
-+            ret = ERR_SC_AUTH_NOT_SUPPORTED;
-         } else {
--            tevent_req_error(req, ERR_AUTH_FAILED);
-+            ret = ERR_AUTH_FAILED;
-         }
--        return tevent_req_post(req, ev);
-+        goto fail;
-     }
- 
-     state->ev = ev;
-@@ -663,13 +664,17 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
-         state->sdap_service = ctx->service;
-     }
- 
--    if (!auth_connect_send(req)) goto fail;
-+    if (auth_connect_send(req) == NULL) {
-+        ret = ENOMEM;
-+        goto fail;
-+    }
- 
-     return req;
- 
- fail:
--    talloc_zfree(req);
--    return NULL;
-+    tevent_req_error(req, ret);
-+    tevent_req_post(req, ev);
-+    return req;
- }
- 
- static struct tevent_req *auth_connect_send(struct tevent_req *req)
--- 
-2.19.1
-
diff --git a/SOURCES/0079-LDAP-Only-authenticate-the-auth-connection-if-we-nee.patch b/SOURCES/0079-LDAP-Only-authenticate-the-auth-connection-if-we-nee.patch
deleted file mode 100644
index db77f7c..0000000
--- a/SOURCES/0079-LDAP-Only-authenticate-the-auth-connection-if-we-nee.patch
+++ /dev/null
@@ -1,130 +0,0 @@
-From 57fc60c9dc77698cf824813c36eb0f90d767b315 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 22 Nov 2018 12:17:51 +0100
-Subject: [PATCH 79/80] LDAP: Only authenticate the auth connection if we need
- to look up user information
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3451
-
-Commit add72860c7a7a2c418f4d8b6790b5caeaf7dfb7b initially addressed #3451 by
-using the full sdap_cli_connect() request during LDAP authentication. This
-was a good idea as it addressed the case where the authentication connection
-must also look up some user information (typically with id_provider=proxy
-where you don't know the DN to bind as during authentication), but this
-approach also broke the use-case of id_provider=ldap and auth_provider=ldap
-with ldap_sasl_auth=gssapi.
-
-This is because (for reason I don't know) AD doesn't like if you use
-both GSSAPI and startTLS on the same connection. But the code would
-force TLS during the authentication as a general measure to not transmit
-passwords in the clear, but then, the connection would also see that
-ldap_sasl_auth=gssapi is set and also bind with GSSAPI.
-
-This patch checks if the user DN is already known and if yes, then
-doesn't authenticate the connection as the connection will then only be
-used for the user simple bind.
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
----
- src/providers/ldap/ldap_auth.c | 53 +++++++++++++++++++++++++++-------
- 1 file changed, 42 insertions(+), 11 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index c409353d9..b4d045a65 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -664,6 +664,18 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
-         state->sdap_service = ctx->service;
-     }
- 
-+    ret = get_user_dn(state, state->ctx->be->domain,
-+                      state->ctx->opts, state->username, &state->dn,
-+                      &state->pw_expire_type, &state->pw_expire_data);
-+    if (ret == EAGAIN) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "Need to look up the DN of %s later\n", state->username);
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Cannot get user DN [%d]: %s\n", ret, sss_strerror(ret));
-+        goto fail;
-+    }
-+
-     if (auth_connect_send(req) == NULL) {
-         ret = ENOMEM;
-         goto fail;
-@@ -683,6 +695,8 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
-     struct auth_state *state = tevent_req_data(req,
-                                                struct auth_state);
-     bool use_tls;
-+    bool skip_conn_auth = false;
-+    const char *sasl_mech;
- 
-     /* Check for undocumented debugging feature to disable TLS
-      * for authentication. This should never be used in production
-@@ -695,10 +709,33 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
-                                "for debugging purposes only.");
-     }
- 
-+    if (state->dn != NULL) {
-+        /* In case the user's DN is known, the connection will only be used
-+         * to bind as the user to perform the authentication. In that case,
-+         * 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.
-+         */
-+        skip_conn_auth = true;
-+    }
-+
-+    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 */
-+            use_tls = false;
-+        }
-+    }
-+
-     subreq = sdap_cli_connect_send(state, state->ev, state->ctx->opts,
-                                    state->ctx->be,
-                                    state->sdap_service, false,
--                                   use_tls ? CON_TLS_ON : CON_TLS_OFF, false);
-+                                   use_tls ? CON_TLS_ON : CON_TLS_OFF,
-+                                   skip_conn_auth);
- 
-     if (subreq == NULL) {
-         tevent_req_error(req, ENOMEM);
-@@ -739,15 +776,7 @@ static void auth_connect_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    ret = get_user_dn(state, state->ctx->be->domain,
--                      state->ctx->opts, state->username, &state->dn,
--                      &state->pw_expire_type, &state->pw_expire_data);
--    if (ret == EOK) {
--        /* All required user data was pre-cached during an identity lookup.
--         * We can proceed with the bind */
--        auth_do_bind(req);
--        return;
--    } else if (ret == EAGAIN) {
-+    if (state->dn == NULL) {
-         /* The cached user entry was missing the bind DN. Need to look
-          * it up based on user name in order to perform the bind */
-         subreq = get_user_dn_send(req, state->ev, state->ctx->be->domain,
-@@ -760,7 +789,9 @@ static void auth_connect_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    tevent_req_error(req, ret);
-+    /* All required user data was pre-cached during an identity lookup.
-+     * We can proceed with the bind */
-+    auth_do_bind(req);
-     return;
- }
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0080-LDAP-Log-the-encryption-used-during-LDAP-authenticat.patch b/SOURCES/0080-LDAP-Log-the-encryption-used-during-LDAP-authenticat.patch
deleted file mode 100644
index 435ecae..0000000
--- a/SOURCES/0080-LDAP-Log-the-encryption-used-during-LDAP-authenticat.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 6f113c7ddeaa5c82558e10118b499d22bf7a2b14 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 26 Nov 2018 12:38:40 +0100
-Subject: [PATCH 80/80] LDAP: Log the encryption used during LDAP
- authentication
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/ldap/ldap_auth.c | 27 +++++++++++++++++++++++++++
- 1 file changed, 27 insertions(+)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index b4d045a65..4666dbfbb 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -747,6 +747,31 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
-     return subreq;
- }
- 
-+static void check_encryption(LDAP *ldap)
-+{
-+    ber_len_t sasl_ssf = 0;
-+    int tls_inplace = 0;
-+    int ret;
-+
-+    ret = ldap_get_option(ldap, LDAP_OPT_X_SASL_SSF, &sasl_ssf);
-+    if (ret != LDAP_SUCCESS) {
-+        DEBUG(SSSDBG_TRACE_LIBS, "ldap_get_option failed to get sasl ssf, "
-+                                 "assuming SASL is not used.\n");
-+    }
-+
-+    tls_inplace = ldap_tls_inplace(ldap);
-+
-+    DEBUG(SSSDBG_TRACE_ALL,
-+          "Encryption used: SASL SSF [%lu] tls_inplace [%s].\n", sasl_ssf,
-+          tls_inplace == 1 ? "TLS inplace" : "TLS NOT inplace");
-+
-+    if (sasl_ssf <= 1 && tls_inplace != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+                "No encryption detected on LDAP connection.\n");
-+        sss_log(SSS_LOG_CRIT, "No encryption detected on LDAP connection.\n");
-+    }
-+}
-+
- static void auth_connect_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-@@ -776,6 +801,8 @@ static void auth_connect_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    check_encryption(state->sh->ldap);
-+
-     if (state->dn == NULL) {
-         /* The cached user entry was missing the bind DN. Need to look
-          * it up based on user name in order to perform the bind */
--- 
-2.19.1
-
diff --git a/SOURCES/0081-nss-sssd-returns-for-emtpy-home-directories.patch b/SOURCES/0081-nss-sssd-returns-for-emtpy-home-directories.patch
deleted file mode 100644
index 6560880..0000000
--- a/SOURCES/0081-nss-sssd-returns-for-emtpy-home-directories.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From 90f32399b4100ce39cf665649fde82d215e5eb49 Mon Sep 17 00:00:00 2001
-From: Tomas Halman <thalman@redhat.com>
-Date: Mon, 3 Dec 2018 14:11:31 +0100
-Subject: [PATCH] nss: sssd returns '/' for emtpy home directories
-
-For empty home directory in passwd file sssd returns "/". Sssd
-should respect system behaviour and return the same as nsswitch
-"files" module - return empty string.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3901
-
-Reviewed-by: Simo Sorce <simo@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/confdb/confdb.c                      |  9 +++++++++
- src/man/include/ad_modified_defaults.xml | 19 +++++++++++++++++++
- src/responder/nss/nss_protocol_pwent.c   |  2 +-
- src/tests/intg/test_files_provider.py    |  2 +-
- 4 files changed, 30 insertions(+), 2 deletions(-)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index b0d886c9d..d3fdd3199 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -1301,6 +1301,15 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
-             ret = ENOMEM;
-             goto done;
-         }
-+    } else {
-+        if (strcasecmp(domain->provider, "ad") == 0) {
-+            /* ad provider default */
-+            domain->fallback_homedir = talloc_strdup(domain, "/home/%d/%u");
-+            if (!domain->fallback_homedir) {
-+                ret = ENOMEM;
-+                goto done;
-+            }
-+        }
-     }
- 
-     tmp = ldb_msg_find_attr_as_string(res->msgs[0],
-diff --git a/src/man/include/ad_modified_defaults.xml b/src/man/include/ad_modified_defaults.xml
-index 818a2bf78..425b7e8ee 100644
---- a/src/man/include/ad_modified_defaults.xml
-+++ b/src/man/include/ad_modified_defaults.xml
-@@ -76,4 +76,23 @@
-             </listitem>
-         </itemizedlist>
-     </refsect2>
-+    <refsect2 id='nss_modifications'>
-+        <title>NSS configuration</title>
-+        <itemizedlist>
-+            <listitem>
-+                <para>
-+                    fallback_homedir = /home/%d/%u
-+                </para>
-+                <para>
-+                    The AD provider automatically sets
-+                    "fallback_homedir = /home/%d/%u" to provide personal
-+                    home directories for users without the homeDirectory
-+                    attribute. If your AD Domain is properly
-+                    populated with Posix attributes, and you want to avoid
-+                    this fallback behavior, you can explicitly
-+                    set "fallback_homedir = %o".
-+                </para>
-+            </listitem>
-+        </itemizedlist>
-+    </refsect2>
- </refsect1>
-diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c
-index af9e74fc8..86fa4ec46 100644
---- a/src/responder/nss/nss_protocol_pwent.c
-+++ b/src/responder/nss/nss_protocol_pwent.c
-@@ -118,7 +118,7 @@ nss_get_homedir(TALLOC_CTX *mem_ctx,
- 
-     homedir = nss_get_homedir_override(mem_ctx, msg, nss_ctx, domain, &hd_ctx);
-     if (homedir == NULL) {
--        return "/";
-+        return "";
-     }
- 
-     return homedir;
-diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py
-index f0155a2f7..b5e5c3fd9 100644
---- a/src/tests/intg/test_files_provider.py
-+++ b/src/tests/intg/test_files_provider.py
-@@ -656,7 +656,7 @@ def test_user_no_dir(setup_pw_with_canary, files_domain_only):
-     Test that resolving a user without a homedir defined works and returns
-     a fallback value
-     """
--    check_user(incomplete_user_setup(setup_pw_with_canary, 'dir', '/'))
-+    check_user(incomplete_user_setup(setup_pw_with_canary, 'dir', ''))
- 
- 
- def test_user_no_gecos(setup_pw_with_canary, files_domain_only):
--- 
-2.19.1
-
diff --git a/SOURCES/0082-PROXY-Copy-the-response-to-the-caller.patch b/SOURCES/0082-PROXY-Copy-the-response-to-the-caller.patch
deleted file mode 100644
index e619358..0000000
--- a/SOURCES/0082-PROXY-Copy-the-response-to-the-caller.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 807bbce25ffedb6f0d2d61831b5d5133e11aa84a Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 3 Dec 2018 23:26:46 +0100
-Subject: [PATCH] PROXY: Copy the response to the caller
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3892
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/proxy/proxy_auth.c | 16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c
-index 3c5affeb5..926ce98f4 100644
---- a/src/providers/proxy/proxy_auth.c
-+++ b/src/providers/proxy/proxy_auth.c
-@@ -570,6 +570,7 @@ done:
- static void proxy_pam_conv_done(struct tevent_req *subreq)
- {
-     struct pam_data *response;
-+    struct response_data *resp;
-     struct proxy_conv_ctx *state;
-     struct tevent_req *req;
-     errno_t ret;
-@@ -583,8 +584,6 @@ static void proxy_pam_conv_done(struct tevent_req *subreq)
-     /* Kill the child */
-     kill(state->pid, SIGKILL);
- 
--    // TODO copy response to pd
--
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get reply from child [%d]: %s\n",
-               ret, sss_strerror(ret));
-@@ -593,6 +592,19 @@ static void proxy_pam_conv_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    state->pd->pam_status = response->pam_status;
-+    state->pd->account_locked = response->account_locked;
-+
-+    for (resp = response->resp_list; resp != NULL; resp = resp->next) {
-+        talloc_steal(state->pd, resp);
-+
-+        if (resp->next == NULL) {
-+            resp->next = state->pd->resp_list;
-+            state->pd->resp_list = response->resp_list;
-+            break;
-+        }
-+    }
-+
-     DEBUG(SSSDBG_CONF_SETTINGS, "received: [%d][%s]\n",
-           state->pd->pam_status,
-           state->pd->domain);
--- 
-2.19.1
-
diff --git a/SOURCES/0083-Revert-IPA-use-forest-name-when-looking-up-the-Globa.patch b/SOURCES/0083-Revert-IPA-use-forest-name-when-looking-up-the-Globa.patch
deleted file mode 100644
index 6b167a4..0000000
--- a/SOURCES/0083-Revert-IPA-use-forest-name-when-looking-up-the-Globa.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 9096fc01cca8fcaeb19c36a27f3a9fa09d60772a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 4 Dec 2018 13:08:11 +0100
-Subject: [PATCH 83/84] Revert "IPA: use forest name when looking up the Global
- Catalog"
-
-This reverts commit 149174acae677d1e72a0da431bf0850d55f2ccb4.
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/ipa/ipa_subdomains_server.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index e5ea4bd02..43a3053cb 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -266,7 +266,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
-         DEBUG(SSSDBG_TRACE_ALL, "No extra attrs set.\n");
-     }
- 
--    gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->forest);
-+    gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->name);
-     if (gc_service_name == NULL) {
-         talloc_free(ad_options);
-         return ENOMEM;
--- 
-2.19.1
-
diff --git a/SOURCES/0084-ipa-use-only-the-global-catalog-service-of-the-fores.patch b/SOURCES/0084-ipa-use-only-the-global-catalog-service-of-the-fores.patch
deleted file mode 100644
index 904a923..0000000
--- a/SOURCES/0084-ipa-use-only-the-global-catalog-service-of-the-fores.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-From 62d671b874a66101c0f4bff39fc6d7f49cb8fca6 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 4 Dec 2018 13:06:23 +0100
-Subject: [PATCH 84/84] ipa: use only the global catalog service of the forest
- root
-
-While creating the domains and sub-domains each domain gets a global
-catalog services assigned but only one should be used because the global
-catalog is by definition responsible for the whole forest so it does not
-make sense to use a global catalog service for each domain and in the
-worst case connect to the same GC multiple times.
-
-In the AD provider this is simple because the GC service of the
-configured domain AD_GC_SERVICE_NAME ("AD_GC") can be used. In the IPA
-case all domains from the trusted forest are on the level of sub-domains
-so we have to pick one. Since the forest root is linked from all domain
-of the same forest it will be the most straight forward choice.
-
-Related to https://pagure.io/SSSD/sssd/issue/3902
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/ipa/ipa_subdomains_id.c | 50 +++++++++++++++++++++++++--
- 1 file changed, 47 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index a16eed284..48cf74460 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -713,6 +713,52 @@ int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out)
-     return EOK;
- }
- 
-+static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
-+                                           struct sss_domain_info *dom);
-+
-+static struct sdap_id_conn_ctx **
-+ipa_ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ipa_id_ctx *ipa_ctx,
-+                    struct ad_id_ctx *ad_ctx, struct sss_domain_info *dom)
-+{
-+    struct ad_id_ctx *forest_root_ad_id_ctx;
-+    struct sdap_id_conn_ctx **clist;
-+    int cindex = 0;
-+
-+    /* While creating the domains and sub-domains each domain gets a global
-+     * catalog services assigned but only one should be used because the
-+     * global catalog is by definition responsible for the whole forest so it
-+     * does not make sense to use a global catalog service for each domain and
-+     * in the worst case connect to the same GC multiple times.
-+     *
-+     * In the AD provider this is simple because the GC service of the
-+     * configured domain AD_GC_SERVICE_NAME ("AD_GC") can be used. In the IPA
-+     * case all domains from the trusted forest are on the level of
-+     * sub-domains so we have to pick one. Since the forest root is linked
-+     * from all domain of the same forest it will be the most straight forward
-+     * choice. */
-+    forest_root_ad_id_ctx = ipa_get_ad_id_ctx(ipa_ctx, dom->forest_root);
-+    if (forest_root_ad_id_ctx == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Missing ad_id_ctx for forest root.\n");
-+        return NULL;
-+    }
-+
-+    clist = talloc_zero_array(mem_ctx, struct sdap_id_conn_ctx *, 3);
-+    if (clist == NULL) return NULL;
-+
-+    /* Always try GC first */
-+    if (dp_opt_get_bool(forest_root_ad_id_ctx->ad_options->basic,
-+                        AD_ENABLE_GC)) {
-+        clist[cindex] = forest_root_ad_id_ctx->gc_ctx;
-+        clist[cindex]->ignore_mark_offline = true;
-+        clist[cindex]->no_mpg_user_fallback = true;
-+        cindex++;
-+    }
-+
-+    clist[cindex] = ad_get_dom_ldap_conn(ad_ctx, dom);
-+
-+    return clist;
-+}
-+
- /* IPA lookup for server mode. Directly to AD. */
- struct ipa_get_ad_acct_state {
-     int dp_error;
-@@ -731,8 +777,6 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req);
- static errno_t ipa_get_ad_ipa_membership_step(struct tevent_req *req);
- static void ipa_id_get_groups_overrides_done(struct tevent_req *subreq);
- static void ipa_get_ad_acct_done(struct tevent_req *subreq);
--static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
--                                           struct sss_domain_info *dom);
- 
- static struct tevent_req *
- ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-@@ -785,7 +829,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
-     case BE_REQ_INITGROUPS:
-     case BE_REQ_BY_SECID:
-     case BE_REQ_GROUP:
--        clist = ad_gc_conn_list(req, ad_id_ctx, state->obj_dom);
-+        clist = ipa_ad_gc_conn_list(req, ipa_ctx, ad_id_ctx, state->obj_dom);
-         break;
-     default:
-         clist = ad_ldap_conn_list(req, ad_id_ctx, state->obj_dom);
--- 
-2.19.1
-
diff --git a/SOURCES/0085-krb5_child-fix-permissions-during-SC-auth.patch b/SOURCES/0085-krb5_child-fix-permissions-during-SC-auth.patch
deleted file mode 100644
index 6765540..0000000
--- a/SOURCES/0085-krb5_child-fix-permissions-during-SC-auth.patch
+++ /dev/null
@@ -1,138 +0,0 @@
-From e49e9f727e4960c8a0a2ed50488dac6e51ddf284 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 10 Dec 2018 17:44:13 +0100
-Subject: [PATCH] krb5_child: fix permissions during SC auth
-
-For PKINIT we might need access to the pcscd socket which by default is
-only allowed for authenticated users. Since PKINIT is part of the
-authentication and the user is not authenticated yet, we have to use
-different privileges and can only drop it only after the TGT is
-received. The fast_uid and fast_gid are the IDs the backend is running
-with. This can be either root or the 'sssd' user. Root is allowed by
-default and the 'sssd' user is allowed with the help of the
-sssd-pcsc.rules policy-kit rule. So those IDs are a suitable choice. We
-can only call switch_creds() because after the TGT is returned we have
-to switch to the IDs of the user to store the TGT.
-
-The final change to the IDs of the user is not only important for KCM
-type credential caches but for file based ccache types like FILE or DIR
-as well.
-
-Related to https://pagure.io/SSSD/sssd/issue/3903
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/providers/krb5/krb5_child.c | 64 ++++++++++++++++++++-------------
- 1 file changed, 39 insertions(+), 25 deletions(-)
-
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index a578930a9..7ad411914 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -108,6 +108,7 @@ struct krb5_req {
- 
-     uid_t fast_uid;
-     gid_t fast_gid;
-+    struct sss_creds *pcsc_saved_creds;
- 
-     struct cli_opts *cli_opts;
- };
-@@ -1746,6 +1747,22 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
-         goto done;
-     }
- 
-+    kerr = restore_creds(kr->pcsc_saved_creds);
-+    if (kerr != 0)  {
-+        DEBUG(SSSDBG_OP_FAILURE, "restore_creds failed.\n");
-+    }
-+    /* Make sure ccache is created and written as the user */
-+    if (geteuid() != kr->uid || getegid() != kr->gid) {
-+        kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
-+        if (kerr != 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
-+            goto done;
-+        }
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL,
-+          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
-+
-     /* If kr->ccname is cache collection (DIR:/...), we want to work
-      * directly with file ccache (DIR::/...), but cache collection
-      * should be returned back to back end.
-@@ -2998,20 +3015,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
-     krb5_error_code kerr;
-     int parse_flags;
- 
--    if (offline || (kr->fast_val == K5C_FAST_NEVER && kr->validate == false)) {
--        /* If krb5_child was started as setuid, but we don't need to
--         * perform either validation or FAST, just drop privileges to
--         * the user who is logging in. The same applies to the offline case.
--         */
--        kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
--        if (kerr != 0) {
--            DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
--            return kerr;
--        }
--    }
--    DEBUG(SSSDBG_TRACE_INTERNAL,
--          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
--
-     /* Set the global error context */
-     krb5_error_ctx = kr->ctx;
- 
-@@ -3205,8 +3208,8 @@ int main(int argc, const char *argv[])
-     const char *opt_logger = NULL;
-     errno_t ret;
-     krb5_error_code kerr;
--    uid_t fast_uid;
--    gid_t fast_gid;
-+    uid_t fast_uid = 0;
-+    gid_t fast_gid = 0;
-     struct cli_opts cli_opts = { 0 };
-     int sss_creds_password = 0;
- 
-@@ -3320,20 +3323,31 @@ int main(int argc, const char *argv[])
-         goto done;
-     }
- 
--    /* pkinit needs access to pcscd */
--    if ((sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
--            && sss_authtok_get_type(kr->pd->authtok)
--                                        != SSS_AUTHTOK_TYPE_SC_KEYPAD)) {
-+    /* For PKINIT we might need access to the pcscd socket which by default
-+     * is only allowed for authenticated users. Since PKINIT is part of
-+     * the authentication and the user is not authenticated yet, we have
-+     * to use different privileges and can only drop it only after the TGT is
-+     * received. The fast_uid and fast_gid are the IDs the backend is running
-+     * with. This can be either root or the 'sssd' user. Root is allowed by
-+     * default and the 'sssd' user is allowed with the help of the
-+     * sssd-pcsc.rules policy-kit rule. So those IDs are a suitable choice. We
-+     * can only call switch_creds() because after the TGT is returned we have
-+     * to switch to the IDs of the user to store the TGT. */
-+    if (IS_SC_AUTHTOK(kr->pd->authtok)) {
-+        kerr = switch_creds(kr, kr->fast_uid, kr->fast_gid, 0, NULL,
-+                            &kr->pcsc_saved_creds);
-+    } else {
-         kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
--        if (kerr != 0) {
--            DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
--            ret = EFAULT;
--            goto done;
--        }
-+    }
-+    if (kerr != 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
-+        ret = EFAULT;
-+        goto done;
-     }
- 
-     DEBUG(SSSDBG_TRACE_INTERNAL,
-           "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
-+
-     try_open_krb5_conf();
- 
-     ret = k5c_setup(kr, offline);
--- 
-2.19.1
-
diff --git a/SOURCES/0086-MAN-Explicitly-state-that-not-all-generic-domain-opt.patch b/SOURCES/0086-MAN-Explicitly-state-that-not-all-generic-domain-opt.patch
deleted file mode 100644
index 078fe9f..0000000
--- a/SOURCES/0086-MAN-Explicitly-state-that-not-all-generic-domain-opt.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From f94881d4d34959231fedbaafd5f1fd6f5e9d8924 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 3 Jan 2019 15:32:26 +0100
-Subject: [PATCH] MAN: Explicitly state that not all generic domain options are
- supported for the files provider
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3882
-
-Reviewed-by: Tomas Halman <thalman@redhat.com>
----
- src/man/sssd-files.5.xml | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd-files.5.xml b/src/man/sssd-files.5.xml
-index 067e21949..34b107965 100644
---- a/src/man/sssd-files.5.xml
-+++ b/src/man/sssd-files.5.xml
-@@ -84,7 +84,13 @@
-                 <refentrytitle>sssd.conf</refentrytitle>
-                 <manvolnum>5</manvolnum>
-             </citerefentry> manual page for details on the configuration
--            of an SSSD domain.
-+            of an SSSD domain. But the purpose of the files provider is
-+            to expose the same data as the UNIX files, just through the
-+            SSSD interfaces. Therefore not all generic domain options are
-+            supported. Likewise, some global options, such as overriding
-+            the shell in the <quote>nss</quote> section for all domains
-+            has no effect on the files domain unless explicitly specified
-+            per-domain.
-             <variablelist>
-                 <varlistentry>
-                     <term>passwd_files (string)</term>
--- 
-2.19.1
-
diff --git a/SOURCES/0087-KCM-Deleting-a-non-existent-ccache-should-not-yield-.patch b/SOURCES/0087-KCM-Deleting-a-non-existent-ccache-should-not-yield-.patch
deleted file mode 100644
index dcc0d83..0000000
--- a/SOURCES/0087-KCM-Deleting-a-non-existent-ccache-should-not-yield-.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 02c15d40efe6dd9107528469904f1315fca37416 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 3 Jan 2019 15:07:59 +0100
-Subject: [PATCH 87/88] KCM: Deleting a non-existent ccache should not yield an
- error
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3910
-
-When the KCM destroy operation is called, it receives a name as an input. If
-the name cannot be found, we would currently return KRB5_CC_NOTFOUND. But
-other ccache types return KRB5_FCC_NOFILE in that case and e.g. utilities
-like kdestroy special case KRB5_FCC_NOFILE to be non-fatal.
-
-Reviewed-by: Tomas Halman <thalman@redhat.com>
----
- src/responder/kcm/kcmsrv_ops.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
-index 1e229adc4..9352909f4 100644
---- a/src/responder/kcm/kcmsrv_ops.c
-+++ b/src/responder/kcm/kcmsrv_ops.c
-@@ -698,9 +698,10 @@ static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq)
-     ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE,
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-               "Cannot get matching ccache [%d]: %s\n",
-               ret, sss_strerror(ret));
-+        ret = ERR_NO_MATCHING_CREDS;
-         tevent_req_error(req, ret);
-         return;
-     }
--- 
-2.19.1
-
diff --git a/SOURCES/0088-confdb-Always-read-snippet-files.patch b/SOURCES/0088-confdb-Always-read-snippet-files.patch
deleted file mode 100644
index c6d5ef0..0000000
--- a/SOURCES/0088-confdb-Always-read-snippet-files.patch
+++ /dev/null
@@ -1,220 +0,0 @@
-From 8a3517c5466c107f4d4e0970a1c33b51d6c762f8 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Wed, 9 Jan 2019 14:08:29 +0100
-Subject: [PATCH 88/89] confdb: Always read snippet files
-
-This patch removes the ldif with fallback configuration
-and adds the fallback configuration as in-memory
-INI snippet.
-
-Fixes:
-https://pagure.io/SSSD/sssd/issue/3439
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/confdb/confdb_setup.c | 122 +++++++++++++++++---------------------
- src/util/sss_ini.c        |  13 +++-
- src/util/sss_ini.h        |   5 ++
- 3 files changed, 70 insertions(+), 70 deletions(-)
-
-diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
-index 7acefbe6b..7d039341d 100644
---- a/src/confdb/confdb_setup.c
-+++ b/src/confdb/confdb_setup.c
-@@ -28,16 +28,6 @@
- #include "confdb_setup.h"
- #include "util/sss_ini.h"
- 
--#ifndef SSSD_FALLBACK_CONFIG_LDIF
--#define SSSD_FALLBACK_CONFIG_LDIF \
--"dn: cn=config\n" \
--"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 */
--
- static int confdb_test(struct confdb_ctx *cdb)
- {
-     char **values;
-@@ -146,28 +136,52 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
-     errno_t ret;
-     char timestr[21];
-     int version;
-+    char fallback_cfg[] =
-+        "[sssd]\n"
-+        "enable_files_domain = true\n"
-+        "services = nss\n";
- 
--    ret = sss_ini_config_access_check(init_data);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              "Permission check on config file failed.\n");
--        return EPERM;
--    }
-+    /* Open config file */
-+    ret = sss_ini_config_file_open(init_data, config_file);
-+    if (ret == ENOENT) {
-+        DEBUG(SSSDBG_TRACE_FUNC, "No sssd.conf.\n");
-+        ret = sss_ini_config_file_from_mem(fallback_cfg,
-+                                           strlen(fallback_cfg),
-+                                           init_data);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "sss_ini_config_file_from_mem failed. Error %d: %s\n",
-+                  ret, sss_strerror(ret));
-+            return ret;
-+        }
-+    } else if (ret == EOK) {
-+        ret = sss_ini_config_access_check(init_data);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Permission check on config file failed.\n");
-+            return EPERM;
-+        }
- 
--    ret = sss_ini_get_stat(init_data);
--    if (ret != EOK) {
--        ret = errno;
--        DEBUG(SSSDBG_FATAL_FAILURE,
-+        ret = sss_ini_get_stat(init_data);
-+        if (ret != EOK) {
-+            ret = errno;
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-               "Status check on config file failed.\n");
--        return ret;
--    }
-+            return ret;
-+        }
- 
--    errno = 0;
--    ret = sss_ini_get_mtime(init_data, sizeof(timestr), timestr);
--    if (ret <= 0 || ret >= (int)sizeof(timestr)) {
--        DEBUG(SSSDBG_FATAL_FAILURE,
--              "Failed to convert time_t to string??\n");
--        ret = errno ? errno : EFAULT;
-+        errno = 0;
-+        ret = sss_ini_get_mtime(init_data, sizeof(timestr), timestr);
-+        if (ret <= 0 || ret >= (int)sizeof(timestr)) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "Failed to convert time_t to string??\n");
-+            ret = errno ? errno : EFAULT;
-+            return ret;
-+        }
-+    } else {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "sss_ini_config_file_open failed: %s [%d]\n", sss_strerror(ret),
-+              ret);
-         return ret;
-     }
- 
-@@ -237,19 +251,6 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
--static int confdb_fallback_ldif(TALLOC_CTX *mem_ctx,
--                                const char **_timestr,
--                                const char **_ldif)
--{
--    *_timestr = talloc_strdup(mem_ctx, "1");
--    *_ldif = talloc_strdup(mem_ctx, SSSD_FALLBACK_CONFIG_LDIF);
--    if (*_timestr == NULL || *_ldif == NULL) {
--        return ENOMEM;
--    }
--
--    return EOK;
--}
--
- static int confdb_write_ldif(struct confdb_ctx *cdb,
-                              const char *config_ldif,
-                              bool replace_whole_db)
-@@ -318,34 +319,17 @@ static int confdb_init_db(const char *config_file,
-         goto done;
-     }
- 
--    /* Open config file */
--    ret = sss_ini_config_file_open(init_data, config_file);
--    if (ret == EOK) {
--        ret = confdb_ldif_from_ini_file(tmp_ctx,
--                                        config_file,
--                                        config_dir,
--                                        only_section,
--                                        init_data,
--                                        &timestr,
--                                        &config_ldif);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Cannot convert INI to LDIF [%d]: [%s]\n",
--                  ret, sss_strerror(ret));
--            goto done;
--        }
--    } else if (ret == ENOENT) {
--        ret = confdb_fallback_ldif(tmp_ctx, &timestr, &config_ldif);
--        if (ret != EOK) {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Cannot create a fallback configuration [%d]: [%s]\n",
--                  ret, sss_strerror(ret));
--            goto done;
--        }
--    } else {
--        DEBUG(SSSDBG_CONF_SETTINGS,
--              "sss_ini_config_file_open failed: %s [%d]\n", sss_strerror(ret),
--              ret);
-+    ret = confdb_ldif_from_ini_file(tmp_ctx,
-+                                    config_file,
-+                                    config_dir,
-+                                    only_section,
-+                                    init_data,
-+                                    &timestr,
-+                                    &config_ldif);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Cannot convert INI to LDIF [%d]: [%s]\n",
-+            ret, sss_strerror(ret));
-         goto done;
-     }
- 
-diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
-index 3c15b2809..010b77889 100644
---- a/src/util/sss_ini.c
-+++ b/src/util/sss_ini.c
-@@ -123,7 +123,18 @@ int sss_ini_config_file_open(struct sss_ini_initdata *init_data,
- #endif
- }
- 
--
-+int sss_ini_config_file_from_mem(void *data_buf,
-+                                 uint32_t data_len,
-+                                 struct sss_ini_initdata *init_data)
-+{
-+#ifdef HAVE_LIBINI_CONFIG_V1
-+    return ini_config_file_from_mem(data_buf, strlen(data_buf),
-+                                   &init_data->file);
-+#else
-+    /* FIXME: Remove support for older libini versions */
-+    return EINVAL;
-+#endif
-+}
- 
- /* Check configuration file permissions */
- 
-diff --git a/src/util/sss_ini.h b/src/util/sss_ini.h
-index 470b88f99..0bf9c0ff5 100644
---- a/src/util/sss_ini.h
-+++ b/src/util/sss_ini.h
-@@ -45,6 +45,11 @@ void sss_ini_close_file(struct sss_ini_initdata *init_data);
- int sss_ini_config_file_open(struct sss_ini_initdata *init_data,
-                              const char *config_file);
- 
-+/* Load config from buffer */
-+int sss_ini_config_file_from_mem(void *data_buf,
-+                                 uint32_t data_len,
-+                                 struct sss_ini_initdata *init_data);
-+
- /* Check file permissions */
- int sss_ini_config_access_check(struct sss_ini_initdata *init_data);
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0089-CONFDB-Remove-old-libini-support.patch b/SOURCES/0089-CONFDB-Remove-old-libini-support.patch
deleted file mode 100644
index a148912..0000000
--- a/SOURCES/0089-CONFDB-Remove-old-libini-support.patch
+++ /dev/null
@@ -1,269 +0,0 @@
-From b66f8dc3bd4e89c424bef5953aeb70742f9656dd Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Wed, 9 Jan 2019 14:19:26 +0100
-Subject: [PATCH 89/89] CONFDB: Remove old libini support
-
-Remove code code that uses libini older then v1
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3439
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/util/sss_ini.c | 111 +--------------------------------------------
- 1 file changed, 1 insertion(+), 110 deletions(-)
-
-diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
-index 010b77889..cf61a1722 100644
---- a/src/util/sss_ini.c
-+++ b/src/util/sss_ini.c
-@@ -32,18 +32,9 @@
- #include "confdb/confdb_setup.h"
- #include "confdb/confdb_private.h"
- 
--#ifdef HAVE_LIBINI_CONFIG_V1
- #include "ini_configobj.h"
--#else
--#include "collection.h"
--#include "collection_tools.h"
--#endif
--
- #include "ini_config.h"
- 
--
--#ifdef HAVE_LIBINI_CONFIG_V1
--
- struct sss_ini_initdata {
-     char **error_list;
-     struct ref_array *ra_success_list;
-@@ -59,25 +50,6 @@ struct sss_ini_initdata {
- #define sss_ini_get_const_string_config_value  ini_get_const_string_config_value
- #define sss_ini_get_config_obj                 ini_get_config_valueobj
- 
--#else
--
--struct sss_ini_initdata {
--    struct collection_item *error_list;
--    struct collection_item *sssd_config;
--    struct collection_item *obj;
--    struct stat cstat;
--    int file;
--};
--
--#define sss_ini_get_sec_list                   get_section_list
--#define sss_ini_get_attr_list                  get_attribute_list
--#define sss_ini_get_const_string_config_value  get_const_string_config_value
--#define sss_ini_get_config_obj(secs,attrs,cfg,flag,attr) \
--    get_config_item(secs,attrs,cfg,attr)
--
--#endif
--
--
- /* Initialize data structure */
- 
- struct sss_ini_initdata* sss_ini_initdata_init(TALLOC_CTX *mem_ctx)
-@@ -92,17 +64,10 @@ struct sss_ini_initdata* sss_ini_initdata_init(TALLOC_CTX *mem_ctx)
- void sss_ini_close_file(struct sss_ini_initdata *init_data)
- {
-     if (init_data == NULL) return;
--#ifdef HAVE_LIBINI_CONFIG_V1
-     if (init_data->file != NULL) {
-         ini_config_file_destroy(init_data->file);
-         init_data->file = NULL;
-     }
--#else
--    if (init_data->file != -1) {
--        close(init_data->file);
--        init_data->file = -1;
--    }
--#endif
- }
- 
- 
-@@ -112,35 +77,23 @@ void sss_ini_close_file(struct sss_ini_initdata *init_data)
- int sss_ini_config_file_open(struct sss_ini_initdata *init_data,
-                              const char *config_file)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     return ini_config_file_open(config_file,
-                                 INI_META_STATS,
-                                 &init_data->file);
--#else
--    return check_and_open_readonly(config_file, &init_data->file, 0, 0,
--                                   S_IFREG|S_IRUSR, /* f r**------ */
--                                   S_IFMT|(ALLPERMS & ~(S_IWUSR|S_IXUSR)));
--#endif
- }
- 
- int sss_ini_config_file_from_mem(void *data_buf,
-                                  uint32_t data_len,
-                                  struct sss_ini_initdata *init_data)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     return ini_config_file_from_mem(data_buf, strlen(data_buf),
-                                    &init_data->file);
--#else
--    /* FIXME: Remove support for older libini versions */
--    return EINVAL;
--#endif
- }
- 
- /* Check configuration file permissions */
- 
- int sss_ini_config_access_check(struct sss_ini_initdata *init_data)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     return ini_config_access_check(init_data->file,
-                                    INI_ACCESS_CHECK_MODE |
-                                    INI_ACCESS_CHECK_UID |
-@@ -149,9 +102,6 @@ int sss_ini_config_access_check(struct sss_ini_initdata *init_data)
-                                    0, /* owned by root */
-                                    S_IRUSR, /* r**------ */
-                                    ALLPERMS & ~(S_IWUSR|S_IXUSR));
--#else
--    return EOK;
--#endif
- }
- 
- 
-@@ -160,21 +110,11 @@ int sss_ini_config_access_check(struct sss_ini_initdata *init_data)
- 
- int sss_ini_get_stat(struct sss_ini_initdata *init_data)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     init_data->cstat = ini_config_get_stat(init_data->file);
- 
-     if (!init_data->cstat) return EIO;
- 
-     return EOK;
--#else
--    int ret;
--
--    ret = fstat(init_data->file, &init_data->cstat);
--    if (ret != 0) {
--        return errno;
--    }
--    return EOK;
--#endif
- }
- 
- 
-@@ -185,13 +125,8 @@ int sss_ini_get_mtime(struct sss_ini_initdata *init_data,
-                       size_t timestr_len,
-                       char *timestr)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     return snprintf(timestr, timestr_len, "%llu",
-                     (long long unsigned)init_data->cstat->st_mtime);
--#else
--    return snprintf(timestr, timestr_len, "%llu",
--                    (long long unsigned)init_data->cstat.st_mtime);
--#endif
- }
- 
- 
-@@ -200,7 +135,6 @@ int sss_ini_get_mtime(struct sss_ini_initdata *init_data,
- 
- static void sss_ini_config_print_errors(char **error_list)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     unsigned count = 0;
- 
-     if (!error_list) {
-@@ -211,9 +145,6 @@ static void sss_ini_config_print_errors(char **error_list)
-         DEBUG(SSSDBG_FATAL_FAILURE, "%s\n", error_list[count]);
-         count++;
-     }
--#endif
--
--    return;
- }
- 
- 
-@@ -225,7 +156,6 @@ int sss_ini_get_config(struct sss_ini_initdata *init_data,
-                        const char *config_dir)
- {
-     int ret;
--#ifdef HAVE_LIBINI_CONFIG_V1
- #ifdef HAVE_LIBINI_CONFIG_V1_3
-     const char *patterns[] = { "^[^\\.].*\\.conf$", NULL };
-     const char *sections[] = { ".*", NULL };
-@@ -317,35 +247,7 @@ int sss_ini_get_config(struct sss_ini_initdata *init_data,
-               "Using only main configuration file due to errors in merging\n");
-     }
- #endif
--
-     return ret;
--
--#else
--
--    /* Read the configuration into a collection */
--    ret = config_from_fd("sssd",
--                         init_data->file,
--                         config_file,
--                         &init_data->sssd_config,
--                         INI_STOP_ON_ANY,
--                         &init_data->error_list);
--
--    if (ret != EOK) {
--        DEBUG(SSSDBG_FATAL_FAILURE,
--                "Parse error reading configuration file [%s]\n",
--                 config_file);
--
--        print_file_parsing_errors(stderr, init_data->error_list);
--
--        free_ini_config_errors(init_data->error_list);
--        free_ini_config(init_data->sssd_config);
--
--        return ret;
--    }
--
--    return EOK;
--
--#endif
- }
- 
- struct ref_array *
-@@ -395,11 +297,7 @@ int sss_ini_check_config_obj(struct sss_ini_initdata *init_data)
- int sss_ini_get_int_config_value(struct sss_ini_initdata *init_data,
-                                  int strict, int def, int *error)
- {
--#ifdef HAVE_LIBINI_CONFIG_V1
-     return ini_get_int_config_value(init_data->obj, strict, def, error);
--#else
--    return get_int_config_value(init_data->obj, strict, def, error);
--#endif
- }
- 
- 
-@@ -409,14 +307,11 @@ int sss_ini_get_int_config_value(struct sss_ini_initdata *init_data,
- void sss_ini_config_destroy(struct sss_ini_initdata *init_data)
- {
-     if (init_data == NULL) return;
--#ifdef HAVE_LIBINI_CONFIG_V1
-+
-     if (init_data->sssd_config != NULL) {
-         ini_config_destroy(init_data->sssd_config);
-         init_data->sssd_config = NULL;
-     }
--#else
--    free_ini_config(init_data->sssd_config);
--#endif
- }
- 
- 
-@@ -443,11 +338,7 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-     size_t dn_size;
-     size_t ldif_len;
-     size_t attr_len;
--#ifdef HAVE_LIBINI_CONFIG_V1
-     struct value_obj *obj = NULL;
--#else
--    struct collection_item *obj = NULL;
--#endif
-     bool section_handled = true;
- 
-     if (only_section != NULL) {
--- 
-2.19.1
-
diff --git a/SOURCES/0090-idmap_sss-improve-man-page.patch b/SOURCES/0090-idmap_sss-improve-man-page.patch
deleted file mode 100644
index 3d5d23e..0000000
--- a/SOURCES/0090-idmap_sss-improve-man-page.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From ea7ada6c0629df45348f699e30acc44194550801 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 10 Jan 2019 18:12:35 +0100
-Subject: [PATCH] idmap_sss: improve man page
-
-The misleading in the idmap_sss man page is improved.
-
-Related to https://pagure.io/SSSD/sssd/issue/3912
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/man/idmap_sss.8.xml | 24 ++++++++++++++++++++----
- 1 file changed, 20 insertions(+), 4 deletions(-)
-
-diff --git a/src/man/idmap_sss.8.xml b/src/man/idmap_sss.8.xml
-index b819304fb..a316c32a3 100644
---- a/src/man/idmap_sss.8.xml
-+++ b/src/man/idmap_sss.8.xml
-@@ -48,12 +48,28 @@
- 
-         <programlisting format="linespecific">
- [global]
--security = domain
--workgroup = MAIN
-+security = ads
-+workgroup = &lt;AD-DOMAIN-SHORTNAME&gt;
- 
--idmap config * : backend        = sss
--idmap config * : range          = 200000-2147483647
-+idmap config &lt;AD-DOMAIN-SHORTNAME&gt; : backend        = sss
-+idmap config &lt;AD-DOMAIN-SHORTNAME&gt; : range          = 200000-2147483647
-+
-+idmap config * : backend        = tdb
-+idmap config * : range          = 100000-199999
-         </programlisting>
-+
-+        <para>
-+            Please replace &lt;AD-DOMAIN-SHORTNAME&gt; with the NetBIOS domain
-+            name of the AD domain. If multiple AD domains should be used each
-+            domain needs an <literal>idmap config</literal> line with
-+            <literal>backend = sss</literal> and a line with a suitable
-+            <literal>range</literal>.
-+        </para>
-+        <para>
-+            Since Winbind requires a writeable default backend and idmap_sss is
-+            read-only the example includes <literal>backend = tdb</literal> as
-+            default.
-+        </para>
-     </refsect1>
- 
-     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" />
--- 
-2.19.1
-
diff --git a/SOURCES/0091-sbus-allow-access-for-sssd-user.patch b/SOURCES/0091-sbus-allow-access-for-sssd-user.patch
deleted file mode 100644
index c6e8679..0000000
--- a/SOURCES/0091-sbus-allow-access-for-sssd-user.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 4760eae9b1b3ebb94fc5590cf5ba1a268e3120be Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 31 Oct 2018 13:07:26 +0100
-Subject: [PATCH] sbus: allow access for sssd user
-
-D-Bus allows access for root and euid by default, however when running
-in non-root mode monitor continues to run as root but responsers as sssd
-user. Therefore monitor euid != sssd user and the connection is terminated.
-
-We must explicitly allow the connection for sssd user uid.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3871
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/sbus/server/sbus_server.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
-
-diff --git a/src/sbus/server/sbus_server.c b/src/sbus/server/sbus_server.c
-index 576cff616..5405dae56 100644
---- a/src/sbus/server/sbus_server.c
-+++ b/src/sbus/server/sbus_server.c
-@@ -400,6 +400,22 @@ sbus_server_filter_add(struct sbus_server *server,
-     return true;
- }
- 
-+static dbus_bool_t
-+sbus_server_check_connection_uid(DBusConnection *dbus_conn,
-+                                 unsigned long uid,
-+                                 void *data)
-+{
-+    struct sbus_server *sbus_server;
-+
-+    sbus_server = talloc_get_type(data, struct sbus_server);
-+
-+    if (uid == 0 || uid == sbus_server->uid) {
-+        return true;
-+    }
-+
-+    return false;
-+}
-+
- static void
- sbus_server_new_connection(DBusServer *dbus_server,
-                            DBusConnection *dbus_conn,
-@@ -415,6 +431,11 @@ sbus_server_new_connection(DBusServer *dbus_server,
- 
-     DEBUG(SSSDBG_FUNC_DATA, "Adding connection %p.\n", dbus_conn);
- 
-+    /* Allow access from uid that is associated with this sbus server. */
-+    dbus_connection_set_unix_user_function(dbus_conn,
-+                                           sbus_server_check_connection_uid,
-+                                           sbus_server, NULL);
-+
-     /* First, add a message filter that will take care of routing messages
-      * between connections. */
-     bret = sbus_server_filter_add(sbus_server, dbus_conn);
--- 
-2.19.1
-
diff --git a/SOURCES/0092-sbus-use-120-second-default-timeout.patch b/SOURCES/0092-sbus-use-120-second-default-timeout.patch
deleted file mode 100644
index dd010bf..0000000
--- a/SOURCES/0092-sbus-use-120-second-default-timeout.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From e4469fbdb3d5c53294c6514280ac75b847b3c61c Mon Sep 17 00:00:00 2001
-From: Adam Williamson <awilliam@redhat.com>
-Date: Wed, 12 Dec 2018 22:28:15 -0800
-Subject: [PATCH] sbus: use 120 second default timeout
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-As discussed in #1654537, first login to a system as a FreeIPA
-domain user now usually causes an expensive SELinux operation
-to happen; this can take longer than the default bus message
-timeout of 25 seconds. To deal with this for now, let's use a
-120 second default timeout; this is a big hammer, but unless we
-can refactor things to use a longer timeout just for that one
-call, or make the actual operation take less time, there's not
-much else we can do.
-
-Resolves:
-https://bugzilla.redhat.com/show_bug.cgi?id=1654537
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3909
-
-Signed-off-by: Adam Williamson <awilliam@redhat.com>
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
----
- src/sbus/sbus_message.h | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/src/sbus/sbus_message.h b/src/sbus/sbus_message.h
-index e7b8fe594..7ae634ece 100644
---- a/src/sbus/sbus_message.h
-+++ b/src/sbus/sbus_message.h
-@@ -27,8 +27,10 @@
- #include "util/util.h"
- #include "sbus/sbus_errors.h"
- 
--/* Use reasonable default timeout which is computed in libdbus */
--#define SBUS_MESSAGE_TIMEOUT -1
-+/* Use longer default timeout than libdbus default due to expensive
-+ * selinux operation: see https://bugzilla.redhat.com/show_bug.cgi?id=1654537
-+ */
-+#define SBUS_MESSAGE_TIMEOUT 120000
- 
- /**
-  * Bound message with a talloc context.
--- 
-2.19.1
-
diff --git a/SOURCES/0093-ifp-extraAttributes-is-UnknownProperty.patch b/SOURCES/0093-ifp-extraAttributes-is-UnknownProperty.patch
deleted file mode 100644
index ad00b4c..0000000
--- a/SOURCES/0093-ifp-extraAttributes-is-UnknownProperty.patch
+++ /dev/null
@@ -1,113 +0,0 @@
-From 814889a7f4691a135b617058c3ae876b54d5b226 Mon Sep 17 00:00:00 2001
-From: Tomas Halman <thalman@redhat.com>
-Date: Tue, 18 Dec 2018 16:31:28 +0100
-Subject: [PATCH] ifp: extraAttributes is UnknownProperty
-
-Attempting to get extraAttributes via SSSD's ifp fails.
-
-Here I uncomment interface function for extraAttributes.
-also right for querying this interface is changed to allow
-this request.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3906
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/responder/ifp/ifp_iface/ifp_iface.c |  4 ++--
- src/responder/ifp/ifpsrv_util.c         |  2 +-
- src/tests/cmocka/test_ifp.c             | 15 +++++++++------
- 3 files changed, 12 insertions(+), 9 deletions(-)
-
-diff --git a/src/responder/ifp/ifp_iface/ifp_iface.c b/src/responder/ifp/ifp_iface/ifp_iface.c
-index 4464b7dd4..fa9f9ba53 100644
---- a/src/responder/ifp/ifp_iface/ifp_iface.c
-+++ b/src/responder/ifp/ifp_iface/ifp_iface.c
-@@ -173,8 +173,8 @@ ifp_register_sbus_interface(struct sbus_connection *conn,
-             SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, uniqueID, ifp_users_user_get_unique_id, ctx),
-             SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, groups, ifp_users_user_get_groups, ctx),
-             SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, domain, ifp_users_user_get_domain, ctx),
--            SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, domainname, ifp_users_user_get_domainname, ctx)
--//            SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, extraAttributes, ifp_users_user_get_extra_attributes, ctx)
-+            SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, domainname, ifp_users_user_get_domainname, ctx),
-+            SBUS_SYNC(GETTER, org_freedesktop_sssd_infopipe_Users_User, extraAttributes, ifp_users_user_get_extra_attributes, ctx)
-         )
-     );
- 
-diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
-index 6a625c244..ebc4c2118 100644
---- a/src/responder/ifp/ifpsrv_util.c
-+++ b/src/responder/ifp/ifpsrv_util.c
-@@ -30,7 +30,7 @@
-                                 SYSDB_GIDNUM, SYSDB_GECOS,  \
-                                 SYSDB_HOMEDIR, SYSDB_SHELL, \
-                                 "groups", "domain", "domainname", \
--                                NULL}
-+                                "extraAttributes", NULL}
- 
- errno_t ifp_add_value_to_dict(DBusMessageIter *iter_dict,
-                               const char *key,
-diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c
-index 82ab70d75..fd754e779 100644
---- a/src/tests/cmocka/test_ifp.c
-+++ b/src/tests/cmocka/test_ifp.c
-@@ -172,7 +172,8 @@ void test_attr_acl(void **state)
-     const char *exp_defaults[] = { SYSDB_NAME, SYSDB_UIDNUM,
-                                    SYSDB_GIDNUM, SYSDB_GECOS,
-                                    SYSDB_HOMEDIR, SYSDB_SHELL,
--                                   "groups", "domain", "domainname", NULL };
-+                                   "groups", "domain", "domainname",
-+                                   "extraAttributes", NULL };
-     attr_parse_test(exp_defaults, NULL);
- 
-     /* Test adding some attributes to the defaults */
-@@ -180,7 +181,8 @@ void test_attr_acl(void **state)
-                               SYSDB_NAME, SYSDB_UIDNUM,
-                               SYSDB_GIDNUM, SYSDB_GECOS,
-                               SYSDB_HOMEDIR, SYSDB_SHELL,
--                              "groups", "domain", "domainname", NULL };
-+                              "groups", "domain", "domainname",
-+                              "extraAttributes", NULL };
-     attr_parse_test(exp_add, "+telephoneNumber, +streetAddress");
- 
-     /* Test removing some attributes to the defaults */
-@@ -188,7 +190,7 @@ void test_attr_acl(void **state)
-                              SYSDB_GIDNUM, SYSDB_GECOS,
-                              SYSDB_HOMEDIR, "groups",
-                              "domain", "domainname",
--                             NULL };
-+                             "extraAttributes", NULL };
-     attr_parse_test(exp_rm, "-"SYSDB_SHELL ",-"SYSDB_UIDNUM);
- 
-     /* Test both add and remove */
-@@ -197,7 +199,7 @@ void test_attr_acl(void **state)
-                                  SYSDB_GIDNUM, SYSDB_GECOS,
-                                  SYSDB_HOMEDIR, "groups",
-                                  "domain", "domainname",
--                                 NULL };
-+                                 "extraAttributes", NULL };
-     attr_parse_test(exp_add_rm, "+telephoneNumber, -"SYSDB_SHELL);
- 
-     /* Test rm trumps add */
-@@ -205,7 +207,8 @@ void test_attr_acl(void **state)
-                                           SYSDB_GIDNUM, SYSDB_GECOS,
-                                           SYSDB_HOMEDIR, SYSDB_SHELL,
-                                           "groups", "domain",
--                                          "domainname", NULL };
-+                                          "domainname",
-+                                          "extraAttributes", NULL };
-     attr_parse_test(exp_add_rm_override,
-                     "+telephoneNumber, -telephoneNumber, +telephoneNumber");
- 
-@@ -214,7 +217,7 @@ void test_attr_acl(void **state)
-     attr_parse_test(rm_all,  "-"SYSDB_NAME ", -"SYSDB_UIDNUM
-                              ", -"SYSDB_GIDNUM ", -"SYSDB_GECOS
-                              ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups, "
--                             "-domain, -domainname");
-+                             "-domain, -domainname, -extraAttributes");
- 
-     /* Malformed list */
-     attr_parse_test(NULL,  "missing_plus_or_minus");
--- 
-2.19.1
-
diff --git a/SOURCES/0094-AD-IPA-Reset-subdomain-service-name-not-domain-name.patch b/SOURCES/0094-AD-IPA-Reset-subdomain-service-name-not-domain-name.patch
deleted file mode 100644
index b62c72f..0000000
--- a/SOURCES/0094-AD-IPA-Reset-subdomain-service-name-not-domain-name.patch
+++ /dev/null
@@ -1,140 +0,0 @@
-From b3285f9f8a5eac3e4e70ed3bd6b74c15ad806e9e Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 19 Dec 2018 14:12:25 +0100
-Subject: [PATCH 94/95] AD/IPA: Reset subdomain service name, not domain name
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3911
-
-Since commit 778f241e78241b0d6b8734148175f8dee804f494 the subdomain fail
-over services use the "sd_" prefix. This was done to make it easier,
-until the whole failover design works better with subdomains, to see
-which services belong to the main domain from tools.
-
-However, some parts of the code would still just use the domain name for
-the failover service, which meant the service was not found, notably
-when trying to reset services:
-
-(Thu Dec 13 05:29:31 2018) [sssd[be[testrelm.test]]] [ipa_srv_ad_acct_retried] (0x0400): Subdomain re-set, will retry lookup
-(Thu Dec 13 05:29:31 2018) [sssd[be[testrelm.test]]] [be_fo_reset_svc] (0x1000): Resetting all servers in service ipaad2016.test
-(Thu Dec 13 05:29:31 2018) [sssd[be[testrelm.test]]] [be_fo_reset_svc] (0x0080): Cannot retrieve service [ipaad2016.test]
-
-This patch switches to reading the service names from the ad_options and
-the sdap_service structures that are contained within ad_options.
-
-Reviewed-by: Tomas Halman <thalman@redhat.com>
----
- src/providers/ad/ad_common.c          | 13 +++++++++++++
- src/providers/ad/ad_common.h          |  4 ++++
- src/providers/ipa/ipa_subdomains_id.c | 11 ++++++++++-
- src/providers/ldap/ldap_common.c      | 11 +++++++++++
- src/providers/ldap/ldap_common.h      |  3 +++
- 5 files changed, 41 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index 0d154ca57..cb5912838 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -839,6 +839,19 @@ done:
-     return ret;
- }
- 
-+void
-+ad_failover_reset(struct be_ctx *bectx,
-+                  struct ad_service *adsvc)
-+{
-+    if (adsvc == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "NULL service\n");
-+        return;
-+    }
-+
-+    sdap_service_reset_fo(bectx, adsvc->sdap);
-+    sdap_service_reset_fo(bectx, adsvc->gc);
-+}
-+
- static void
- ad_resolve_callback(void *private_data, struct fo_server *server)
- {
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index cb4dda750..662276cb6 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -148,6 +148,10 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
-                  bool use_kdcinfo,
-                  struct ad_service **_service);
- 
-+void
-+ad_failover_reset(struct be_ctx *bectx,
-+                  struct ad_service *adsvc);
-+
- errno_t
- ad_get_id_options(struct ad_options *ad_opts,
-                    struct confdb_ctx *cdb,
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 48cf74460..b841f0a52 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -1757,6 +1757,7 @@ fail:
- static void ipa_srv_ad_acct_retried(struct tevent_req *subreq)
- {
-     errno_t ret;
-+    struct ad_id_ctx *ad_id_ctx;
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                 struct tevent_req);
-     struct ipa_srv_ad_acct_state *state = tevent_req_data(req,
-@@ -1772,7 +1773,15 @@ static void ipa_srv_ad_acct_retried(struct tevent_req *subreq)
-     }
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "Subdomain re-set, will retry lookup\n");
--    be_fo_reset_svc(state->be_ctx, state->obj_dom->name);
-+    ad_id_ctx = ipa_get_ad_id_ctx(state->ipa_ctx, state->obj_dom);
-+    if (ad_id_ctx == NULL || ad_id_ctx->ad_options == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "No AD ID ctx or no ID CTX options?\n");
-+        state->dp_error = DP_ERR_FATAL;
-+        tevent_req_error(req, EINVAL);
-+        return;
-+    }
-+
-+    ad_failover_reset(state->be_ctx, ad_id_ctx->ad_options->service);
- 
-     ret = ipa_srv_ad_acct_lookup_step(req);
-     if (ret != EOK) {
-diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
-index 9cd8ec09c..237749aae 100644
---- a/src/providers/ldap/ldap_common.c
-+++ b/src/providers/ldap/ldap_common.c
-@@ -520,6 +520,17 @@ static int ldap_user_data_cmp(void *ud1, void *ud2)
-     return strcasecmp((char*) ud1, (char*) ud2);
- }
- 
-+void sdap_service_reset_fo(struct be_ctx *ctx,
-+                           struct sdap_service *service)
-+{
-+    if (service == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "NULL service\n");
-+        return;
-+    }
-+
-+    be_fo_reset_svc(ctx, service->name);
-+}
-+
- 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/ldap_common.h b/src/providers/ldap/ldap_common.h
-index 6c08d789b..89d819fb9 100644
---- a/src/providers/ldap/ldap_common.h
-+++ b/src/providers/ldap/ldap_common.h
-@@ -171,6 +171,9 @@ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
-                       const char *urls, const char *backup_urls,
-                       struct sdap_service **_service);
- 
-+void sdap_service_reset_fo(struct be_ctx *ctx,
-+                           struct sdap_service *service);
-+
- const char *sdap_gssapi_realm(struct dp_option *opts);
- 
- int sdap_gssapi_init(TALLOC_CTX *mem_ctx,
--- 
-2.19.1
-
diff --git a/SOURCES/0095-IPA-Add-explicit-return-after-tevent_req_error.patch b/SOURCES/0095-IPA-Add-explicit-return-after-tevent_req_error.patch
deleted file mode 100644
index e749f70..0000000
--- a/SOURCES/0095-IPA-Add-explicit-return-after-tevent_req_error.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From aaaa9a3e836e7b7af1ff0fc5058ddddfeef120a8 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 20 Dec 2018 15:30:03 +0100
-Subject: [PATCH 95/95] IPA: Add explicit return after tevent_req_error
-
-When working on another patch I realized that we don't use explicit
-return after failing a request. This could be potentially fatal as the
-code would continue, perhaps with data that is not defined.
-
-Reviewed-by: Tomas Halman <thalman@redhat.com>
----
- src/providers/ipa/ipa_subdomains_id.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index b841f0a52..9958d9dfe 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -1770,6 +1770,7 @@ static void ipa_srv_ad_acct_retried(struct tevent_req *subreq)
-               "Failed to re-set subdomain [%d]: %s\n", ret, sss_strerror(ret));
-         state->dp_error = DP_ERR_FATAL;
-         tevent_req_error(req, ret);
-+        return;
-     }
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "Subdomain re-set, will retry lookup\n");
-@@ -1789,6 +1790,7 @@ static void ipa_srv_ad_acct_retried(struct tevent_req *subreq)
-               "Failed to look up AD acct [%d]: %s\n", ret, sss_strerror(ret));
-         state->dp_error = DP_ERR_FATAL;
-         tevent_req_error(req, ret);
-+        return;
-     }
- }
- 
--- 
-2.19.1
-
diff --git a/SOURCES/0096-KCM-Return-a-valid-tevent-error-code-if-a-request-ca.patch b/SOURCES/0096-KCM-Return-a-valid-tevent-error-code-if-a-request-ca.patch
deleted file mode 100644
index 395e1a9..0000000
--- a/SOURCES/0096-KCM-Return-a-valid-tevent-error-code-if-a-request-ca.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 334950e4b352ffa3a672f30f62b478c69690c830 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 16 Jan 2019 13:06:10 +0100
-Subject: [PATCH 96/99] KCM: Return a valid tevent error code if a request
- cannot be created
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Previously we were returning whatever was in 'ret' which is wrong,
-typically it would have been EOK as returned from a previous successfull
-call or even an uninitialized value.
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-Reviewed-by: Simo Sorce <simo@redhat.com>
----
- src/responder/kcm/kcmsrv_ops.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
-index 9352909f4..60b5677e9 100644
---- a/src/responder/kcm/kcmsrv_ops.c
-+++ b/src/responder/kcm/kcmsrv_ops.c
-@@ -527,7 +527,7 @@ static void kcm_op_initialize_create_step(struct tevent_req *req)
-                                      state->op_ctx->client,
-                                      state->new_cc);
-     if (subreq == NULL) {
--        tevent_req_error(req, ret);
-+        tevent_req_error(req, ENOMEM);
-         return;
-     }
-     tevent_req_set_callback(subreq, kcm_op_initialize_cc_create_done, req);
--- 
-2.19.1
-
diff --git a/SOURCES/0097-KCM-Allow-representing-ccaches-with-a-NULL-principal.patch b/SOURCES/0097-KCM-Allow-representing-ccaches-with-a-NULL-principal.patch
deleted file mode 100644
index 564122b..0000000
--- a/SOURCES/0097-KCM-Allow-representing-ccaches-with-a-NULL-principal.patch
+++ /dev/null
@@ -1,281 +0,0 @@
-From 7c441a13215dfd87f9facdaf5f6bcc19a25ec472 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 16 Jan 2019 13:02:01 +0100
-Subject: [PATCH 97/99] KCM: Allow representing ccaches with a NULL principal
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3873
-
-We need to make it possible to create an internal ccache representation
-without passing in a principal. The principal is only assigned to the
-ccache with krb5_cc_initialize(), but some programs like openssh use the
-following sequence of calls:
-    krb5_cc_new_unique
-    krb5_cc_switch
-    krb5_cc_initialize
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-Reviewed-by: Simo Sorce <simo@redhat.com>
----
- src/responder/kcm/kcmsrv_ccache.c            | 18 +++--
- src/responder/kcm/kcmsrv_ccache_json.c       | 79 ++++++++++++++++---
- src/tests/cmocka/test_kcm_json_marshalling.c | 83 ++++++++++++++++++--
- 3 files changed, 153 insertions(+), 27 deletions(-)
-
-diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
-index af2bcf8bb..e7800662a 100644
---- a/src/responder/kcm/kcmsrv_ccache.c
-+++ b/src/responder/kcm/kcmsrv_ccache.c
-@@ -68,14 +68,16 @@ errno_t kcm_cc_new(TALLOC_CTX *mem_ctx,
- 
-     uuid_generate(cc->uuid);
- 
--    kret = krb5_copy_principal(k5c, princ, &cc->client);
--    if (kret != 0) {
--        const char *err_msg = sss_krb5_get_error_message(k5c, kret);
--        DEBUG(SSSDBG_OP_FAILURE,
--              "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg);
--        sss_krb5_free_error_message(k5c, err_msg);
--        ret = ERR_INTERNAL;
--        goto done;
-+    if (princ) {
-+        kret = krb5_copy_principal(k5c, princ, &cc->client);
-+        if (kret != 0) {
-+            const char *err_msg = sss_krb5_get_error_message(k5c, kret);
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg);
-+            sss_krb5_free_error_message(k5c, err_msg);
-+            ret = ERR_INTERNAL;
-+            goto done;
-+        }
-     }
- 
-     cc->owner.uid = cli_creds_get_uid(owner);
-diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
-index 6341530ee..72e24c430 100644
---- a/src/responder/kcm/kcmsrv_ccache_json.c
-+++ b/src/responder/kcm/kcmsrv_ccache_json.c
-@@ -229,6 +229,20 @@ static json_t *princ_to_json(TALLOC_CTX *mem_ctx,
-     json_error_t error;
-     char *str_realm_data;
- 
-+    if (princ == NULL) {
-+        jprinc = json_pack_ex(&error,
-+                              JSON_STRICT,
-+                              "{}");
-+        if (jprinc == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to pack JSON princ structure on line %d: %s\n",
-+                  error.line, error.text);
-+            return NULL;
-+        }
-+
-+        return jprinc;
-+    }
-+
-     components = princ_data_to_json(mem_ctx, princ);
-     if (components == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -587,13 +601,12 @@ static errno_t json_array_to_krb5_data(TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
--static errno_t json_to_princ(TALLOC_CTX *mem_ctx,
--                             json_t *js_princ,
--                             krb5_principal *_princ)
-+static errno_t json_to_nonempty_princ(TALLOC_CTX *mem_ctx,
-+                                      json_t *js_princ,
-+                                      krb5_principal *_princ)
- {
-     errno_t ret;
-     json_t *components = NULL;
--    int ok;
-     krb5_principal princ = NULL;
-     TALLOC_CTX *tmp_ctx = NULL;
-     char *realm_str;
-@@ -601,13 +614,6 @@ static errno_t json_to_princ(TALLOC_CTX *mem_ctx,
-     size_t comp_count;
-     json_error_t error;
- 
--    ok = json_is_object(js_princ);
--    if (!ok) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Json principal is not an object.\n");
--        ret = ERR_JSON_DECODING;
--        goto done;
--    }
--
-     tmp_ctx = talloc_new(mem_ctx);
-     if (tmp_ctx == NULL) {
-         ret = ENOMEM;
-@@ -684,6 +690,57 @@ done:
-     return ret;
- }
- 
-+static bool is_nonempty_principal(json_t *js_princ)
-+{
-+    errno_t ret;
-+    json_error_t error;
-+
-+    ret = json_unpack_ex(js_princ,
-+                         &error,
-+                         JSON_VALIDATE_ONLY,
-+                         "{s:i, s:s, s:o}",
-+                         "type",
-+                         "realm",
-+                         "components");
-+
-+    return ret == 0 ? true : false;
-+}
-+
-+static bool is_empty_principal(json_t *js_princ)
-+{
-+    errno_t ret;
-+    json_error_t error;
-+
-+    ret = json_unpack_ex(js_princ,
-+                         &error,
-+                         JSON_VALIDATE_ONLY,
-+                         "{}");
-+
-+    return ret == 0 ? true : false;
-+}
-+
-+static errno_t json_to_princ(TALLOC_CTX *mem_ctx,
-+                             json_t *js_princ,
-+                             krb5_principal *_princ)
-+{
-+    int ok;
-+
-+    ok = json_is_object(js_princ);
-+    if (!ok) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Json principal is not an object.\n");
-+        return ERR_JSON_DECODING;
-+    }
-+
-+    if (is_nonempty_principal(js_princ)) {
-+        return json_to_nonempty_princ(mem_ctx, js_princ, _princ);
-+    } else if (is_empty_principal(js_princ)) {
-+        *_princ = NULL;
-+        return EOK;
-+    }
-+
-+    return ERR_JSON_DECODING;
-+}
-+
- static errno_t json_elem_to_cred(TALLOC_CTX *mem_ctx,
-                                  json_t *element,
-                                  struct kcm_cred **_crd)
-diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c
-index 05d472499..48ee92bd6 100644
---- a/src/tests/cmocka/test_kcm_json_marshalling.c
-+++ b/src/tests/cmocka/test_kcm_json_marshalling.c
-@@ -116,14 +116,22 @@ static void assert_cc_princ_equal(struct kcm_ccache *cc1,
-     p1 = kcm_cc_get_client_principal(cc1);
-     p2 = kcm_cc_get_client_principal(cc2);
- 
--    kerr = krb5_unparse_name(NULL, p1, &name1);
--    assert_int_equal(kerr, 0);
--    kerr = krb5_unparse_name(NULL, p2, &name2);
--    assert_int_equal(kerr, 0);
--
--    assert_string_equal(name1, name2);
--    krb5_free_unparsed_name(NULL, name1);
--    krb5_free_unparsed_name(NULL, name2);
-+    if (p1 != NULL && p2 != NULL) {
-+        kerr = krb5_unparse_name(NULL, p1, &name1);
-+        assert_int_equal(kerr, 0);
-+        kerr = krb5_unparse_name(NULL, p2, &name2);
-+        assert_int_equal(kerr, 0);
-+
-+        assert_string_equal(name1, name2);
-+        krb5_free_unparsed_name(NULL, name1);
-+        krb5_free_unparsed_name(NULL, name2);
-+    } else {
-+        /* Either both principals must be NULL or both
-+         * non-NULL and represent the same principals
-+         */
-+        assert_null(p1);
-+        assert_null(p2);
-+    }
- }
- 
- static void assert_cc_offset_equal(struct kcm_ccache *cc1,
-@@ -206,6 +214,62 @@ static void test_kcm_ccache_marshall_unmarshall(void **state)
-     assert_int_equal(ret, EINVAL);
- }
- 
-+static void test_kcm_ccache_no_princ(void **state)
-+{
-+    struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state,
-+                                        struct kcm_marshalling_test_ctx);
-+    errno_t ret;
-+    struct cli_creds owner;
-+    const char *name;
-+    struct kcm_ccache *cc;
-+    krb5_principal princ;
-+    struct kcm_ccache *cc2;
-+    struct sss_iobuf *payload;
-+    const char *key;
-+    uint8_t *data;
-+    uuid_t uuid;
-+
-+    owner.ucred.uid = getuid();
-+    owner.ucred.gid = getuid();
-+
-+    name = talloc_asprintf(test_ctx, "%"SPRIuid, getuid());
-+    assert_non_null(name);
-+
-+    ret = kcm_cc_new(test_ctx,
-+                     test_ctx->kctx,
-+                     &owner,
-+                     name,
-+                     NULL,
-+                     &cc);
-+    assert_int_equal(ret, EOK);
-+
-+    princ = kcm_cc_get_client_principal(cc);
-+    assert_null(princ);
-+
-+    ret = kcm_ccache_to_sec_input(test_ctx,
-+                                  cc,
-+                                  &owner,
-+                                  &payload);
-+    assert_int_equal(ret, EOK);
-+
-+    data = sss_iobuf_get_data(payload);
-+    assert_non_null(data);
-+
-+    ret = kcm_cc_get_uuid(cc, uuid);
-+    assert_int_equal(ret, EOK);
-+    key = sec_key_create(test_ctx, name, uuid);
-+    assert_non_null(key);
-+
-+    ret = sec_kv_to_ccache(test_ctx,
-+                           key,
-+                           (const char *) data,
-+                           &owner,
-+                           &cc2);
-+    assert_int_equal(ret, EOK);
-+
-+    assert_cc_equal(cc, cc2);
-+}
-+
- void test_sec_key_get_uuid(void **state)
- {
-     errno_t ret;
-@@ -279,6 +343,9 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall,
-                                         setup_kcm_marshalling,
-                                         teardown_kcm_marshalling),
-+        cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ,
-+                                        setup_kcm_marshalling,
-+                                        teardown_kcm_marshalling),
-         cmocka_unit_test(test_sec_key_get_uuid),
-         cmocka_unit_test(test_sec_key_get_name),
-         cmocka_unit_test(test_sec_key_match_name),
--- 
-2.19.1
-
diff --git a/SOURCES/0098-KCM-Create-an-empty-ccache-on-switch-to-a-non-existi.patch b/SOURCES/0098-KCM-Create-an-empty-ccache-on-switch-to-a-non-existi.patch
deleted file mode 100644
index c98c83c..0000000
--- a/SOURCES/0098-KCM-Create-an-empty-ccache-on-switch-to-a-non-existi.patch
+++ /dev/null
@@ -1,244 +0,0 @@
-From d0eae0598cfb37e1e5aca10a0827b912f707d783 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 16 Jan 2019 13:06:15 +0100
-Subject: [PATCH 98/99] KCM: Create an empty ccache on switch to a non-existing
- one
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3873
-
-We need to make it possible to create an internal ccache representation
-without passing in a principal. The principal is only assigned to the
-ccache with krb5_cc_initialize(), but some programs like openssh use the
-following sequence of calls:
-    cc = krb5_cc_new_unique
-    krb5_cc_switch(cc)
-    krb5_cc_initialize(cc, principal)
-
-Since switch changes the default ccache, we create a 'dummy' ccache with
-krb5_cc_switch() and then the initialize call just fills in the details.
-
-Reviewed-by: Simo Sorce <simo@redhat.com>
-Reviewed-by: Michal Židek <mzidek@redhat.com>
----
- src/responder/kcm/kcmsrv_ops.c | 133 +++++++++++++++++++++++++++++----
- 1 file changed, 118 insertions(+), 15 deletions(-)
-
-diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
-index 60b5677e9..6544c4ed0 100644
---- a/src/responder/kcm/kcmsrv_ops.c
-+++ b/src/responder/kcm/kcmsrv_ops.c
-@@ -1601,8 +1601,21 @@ static errno_t kcm_op_get_default_ccache_recv(struct tevent_req *req,
- 
- /* (name) -> () */
- static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq);
-+static void kcm_op_set_default_create_step(struct tevent_req *req);
-+static void kcm_op_set_default_create_step_done(struct tevent_req *subreq);
-+static void kcm_op_set_default_step(struct tevent_req *req);
- static void kcm_op_set_default_done(struct tevent_req *subreq);
- 
-+struct kcm_op_set_default_ccache_state {
-+    uint32_t op_ret;
-+    struct kcm_op_ctx *op_ctx;
-+    struct tevent_context *ev;
-+
-+    const char *name;
-+    uuid_t dfl_uuid;
-+    struct kcm_ccache *new_cc;
-+};
-+
- static struct tevent_req *
- kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx,
-                                struct tevent_context *ev,
-@@ -1610,30 +1623,31 @@ kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx,
- {
-     struct tevent_req *req = NULL;
-     struct tevent_req *subreq = NULL;
--    struct kcm_op_common_state *state = NULL;
-+    struct kcm_op_set_default_ccache_state *state = NULL;
-     errno_t ret;
--    const char *name;
- 
--    req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
-+    req = tevent_req_create(mem_ctx,
-+                            &state,
-+                            struct kcm_op_set_default_ccache_state);
-     if (req == NULL) {
-         return NULL;
-     }
-     state->op_ctx = op_ctx;
-     state->ev = ev;
- 
--    ret = sss_iobuf_read_stringz(op_ctx->input, &name);
-+    ret = sss_iobuf_read_stringz(op_ctx->input, &state->name);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "Cannot read input name [%d]: %s\n",
-               ret, sss_strerror(ret));
-         goto immediate;
-     }
--    DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", name);
-+    DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", state->name);
- 
-     subreq = kcm_ccdb_uuid_by_name_send(state, ev,
-                                         op_ctx->kcm_data->db,
-                                         op_ctx->client,
--                                        name);
-+                                        state->name);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto immediate;
-@@ -1652,13 +1666,16 @@ static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq)
-     errno_t ret;
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct kcm_op_common_state *state = tevent_req_data(req,
--                                                struct kcm_op_common_state);
--    uuid_t dfl_uuid;
-+    struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
-+                                    struct kcm_op_set_default_ccache_state);
- 
--    ret = kcm_ccdb_uuid_by_name_recv(subreq, state, dfl_uuid);
-+    ret = kcm_ccdb_uuid_by_name_recv(subreq, state, state->dfl_uuid);
-     talloc_zfree(subreq);
--    if (ret != EOK) {
-+    if (ret == ERR_NO_CREDS) {
-+        DEBUG(SSSDBG_TRACE_LIBS,
-+              "The ccache does not exist, creating a new one\n");
-+        kcm_op_set_default_create_step(req);
-+    } else if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE,
-               "Cannot get ccache by name [%d]: %s\n",
-               ret, sss_strerror(ret));
-@@ -1666,11 +1683,91 @@ static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq)
-         return;
-     }
- 
-+    kcm_op_set_default_step(req);
-+}
-+
-+static void kcm_op_set_default_create_step(struct tevent_req *req)
-+{
-+    errno_t ret;
-+    struct tevent_req *subreq;
-+    struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
-+                                    struct kcm_op_set_default_ccache_state);
-+
-+    /* Only allow to create ccaches for 'self' */
-+    ret = kcm_check_name(state->name, state->op_ctx->client);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+            "Name %s is malformed [%d]: %s\n",
-+            state->name, ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    ret = kcm_cc_new(state->op_ctx,
-+                     state->op_ctx->kcm_data->k5c,
-+                     state->op_ctx->client,
-+                     state->name,
-+                     NULL,
-+                     &state->new_cc);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+            "Cannot create new ccache %d: %s\n", ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    subreq = kcm_ccdb_create_cc_send(state,
-+                                     state->ev,
-+                                     state->op_ctx->kcm_data->db,
-+                                     state->op_ctx->client,
-+                                     state->new_cc);
-+    if (subreq == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    }
-+    tevent_req_set_callback(subreq, kcm_op_set_default_create_step_done, req);
-+}
-+
-+static void kcm_op_set_default_create_step_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
-+                                    struct kcm_op_set_default_ccache_state);
-+
-+    ret = kcm_ccdb_create_cc_recv(subreq);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Cannot add ccache to db %d: %s\n", ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    ret = kcm_cc_get_uuid(state->new_cc, state->dfl_uuid);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Cannot get new ccache UUID [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    kcm_op_set_default_step(req);
-+}
-+
-+static void kcm_op_set_default_step(struct tevent_req *req)
-+{
-+    struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
-+                                    struct kcm_op_set_default_ccache_state);
-+    struct tevent_req *subreq;
-+
-     subreq = kcm_ccdb_set_default_send(state,
-                                        state->ev,
-                                        state->op_ctx->kcm_data->db,
-                                        state->op_ctx->client,
--                                       dfl_uuid);
-+                                       state->dfl_uuid);
-     if (subreq == NULL) {
-         tevent_req_error(req, ENOMEM);
-         return;
-@@ -1684,8 +1781,8 @@ static void kcm_op_set_default_done(struct tevent_req *subreq)
-     errno_t ret;
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct kcm_op_common_state *state = tevent_req_data(req,
--                                                struct kcm_op_common_state);
-+    struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
-+                                    struct kcm_op_set_default_ccache_state);
- 
-     ret = kcm_ccdb_set_default_recv(subreq);
-     talloc_zfree(subreq);
-@@ -1700,6 +1797,12 @@ static void kcm_op_set_default_done(struct tevent_req *subreq)
-     tevent_req_done(req);
- }
- 
-+static errno_t kcm_op_set_default_ccache_recv(struct tevent_req *req,
-+                                              uint32_t *_op_ret)
-+{
-+    KCM_OP_RET_FROM_TYPE(req, struct kcm_op_set_default_ccache_state, _op_ret);
-+}
-+
- /* (name) -> (offset) */
- static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq);
- 
-@@ -1948,7 +2051,7 @@ static struct kcm_op kcm_optable[] = {
-     { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list_send, NULL },
-     { "GET_CACHE_BY_UUID",   kcm_op_get_cache_by_uuid_send, NULL },
-     { "GET_DEFAULT_CACHE",   kcm_op_get_default_ccache_send, kcm_op_get_default_ccache_recv },
--    { "SET_DEFAULT_CACHE",   kcm_op_set_default_ccache_send, NULL },
-+    { "SET_DEFAULT_CACHE",   kcm_op_set_default_ccache_send, kcm_op_set_default_ccache_recv },
-     { "GET_KDC_OFFSET",      kcm_op_get_kdc_offset_send, NULL },
-     { "SET_KDC_OFFSET",      kcm_op_set_kdc_offset_send, kcm_op_set_kdc_offset_recv },
-     { "ADD_NTLM_CRED",       NULL, NULL },
--- 
-2.19.1
-
diff --git a/SOURCES/0099-PAM-use-user-name-hint-if-any-domain-has-set-it.patch b/SOURCES/0099-PAM-use-user-name-hint-if-any-domain-has-set-it.patch
deleted file mode 100644
index 7c7551c..0000000
--- a/SOURCES/0099-PAM-use-user-name-hint-if-any-domain-has-set-it.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From 3eb99a171f59454fc2ec130b3e5052b3de5569a2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 7 Feb 2019 16:48:44 +0100
-Subject: [PATCH] PAM: use user name hint if any domain has set it
-
-When using multiple domains the user name hint should be shown even if
-only one domain has set the flag to have a consistent user experience.
-Currently this would only be related to logins with GDM and activated
-GDM Smartcard plugin.
-
-Related to https://pagure.io/SSSD/sssd/issue/3949
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/responder/pam/pamsrv_cmd.c | 22 ++++++++++++++++++----
- 1 file changed, 18 insertions(+), 4 deletions(-)
-
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index 553bf8fbb..3b4869ece 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1578,6 +1578,20 @@ done:
-     return ret;
- }
- 
-+/* Return true if hint is set for at least one domain */
-+static bool get_user_name_hint(struct sss_domain_info *domains)
-+{
-+    struct sss_domain_info *d;
-+
-+    DLIST_FOR_EACH(d, domains) {
-+        if (d->user_name_hint == true) {
-+            return true;
-+        }
-+    }
-+
-+    return false;
-+}
-+
- static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
- {
-     int ret;
-@@ -1646,9 +1660,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                      preq->current_cert = sss_cai_get_next(preq->current_cert)) {
- 
-                     ret = add_pam_cert_response(preq->pd,
--                                       preq->cctx->rctx->domains, "",
--                                       preq->current_cert,
--                                       preq->cctx->rctx->domains->user_name_hint
-+                                   preq->cctx->rctx->domains, "",
-+                                   preq->current_cert,
-+                                   get_user_name_hint(preq->cctx->rctx->domains)
-                                             ? SSS_PAM_CERT_INFO_WITH_HINT
-                                             : SSS_PAM_CERT_INFO);
-                     if (ret != EOK) {
-@@ -1698,7 +1712,7 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                 }
-             }
- 
--            if (preq->cctx->rctx->domains->user_name_hint
-+            if (get_user_name_hint(preq->cctx->rctx->domains)
-                     && preq->pd->cmd == SSS_PAM_PREAUTH) {
-                 ret = add_pam_cert_response(preq->pd,
-                                             preq->cctx->rctx->domains, cert_user,
--- 
-2.19.2
-
diff --git a/SOURCES/0100-pam_sss-PAM_USER_UNKNOWN-if-socket-is-missing.patch b/SOURCES/0100-pam_sss-PAM_USER_UNKNOWN-if-socket-is-missing.patch
deleted file mode 100644
index ece50bc..0000000
--- a/SOURCES/0100-pam_sss-PAM_USER_UNKNOWN-if-socket-is-missing.patch
+++ /dev/null
@@ -1,139 +0,0 @@
-From 0479c6f1598602909487c499266fe410085251a5 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 25 Mar 2019 10:17:17 +0100
-Subject: [PATCH] pam_sss: PAM_USER_UNKNOWN if socket is missing
-
-If SSSD used without explicit configuration in the files-only mode and
-pam_sss is also used in the PAM configuration, as e.g. in recent Fedora
-systems, users handled by other NSS modules might get an 'Access Denied'
-when trying to log in.
-
-The culprit is the line like
-
-    account     [default=bad success=ok user_unknown=ignore] pam_sss.so
-
-in the PAM configuration which can only grant access if pam_sss.so
-returns PAM_SUCCESS or PAM_USER_UNKNOWN. Even PAM_IGNORE causes a
-rejection because of 'default=bad'.
-
-Of the PAM responder is running PAM_USER_UNKNOWN is returned for users
-from other NSS modules. With this patch PAM_USER_UNKNOWN is returned as
-well during the 'account' step if the PAM responder socket is not
-available.
-
-Related to https://pagure.io/SSSD/sssd/issue/3988
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
----
- src/man/pam_sss.8.xml    |  4 ++++
- src/sss_client/common.c  | 18 ++++++++++++++++++
- src/sss_client/pam_sss.c | 16 +++++++++++++---
- src/sss_client/sss_cli.h |  2 ++
- 4 files changed, 37 insertions(+), 3 deletions(-)
-
-diff --git a/src/man/pam_sss.8.xml b/src/man/pam_sss.8.xml
-index 86ed0fefe..834d9d268 100644
---- a/src/man/pam_sss.8.xml
-+++ b/src/man/pam_sss.8.xml
-@@ -256,6 +256,10 @@ auth sufficient pam_sss.so allow_missing_name
-         <para>All module types (<option>account</option>, <option>auth</option>,
-         <option>password</option> and <option>session</option>) are provided.
-         </para>
-+        <para>If SSSD's PAM responder is not running, e.g. if the PAM responder
-+        socket is not available, pam_sss will return PAM_USER_UNKNOWN when
-+        called as <option>account</option> module to avoid issues with users
-+        from other sources during access control.</para>
-     </refsect1>
- 
-     <refsect1 id='files'>
-diff --git a/src/sss_client/common.c b/src/sss_client/common.c
-index 224f33b55..e2d840540 100644
---- a/src/sss_client/common.c
-+++ b/src/sss_client/common.c
-@@ -913,8 +913,14 @@ int sss_pam_make_request(enum sss_cli_command cmd,
-     /* only root shall use the privileged pipe */
-     if (getuid() == 0 && getgid() == 0) {
-         socket_name = SSS_PAM_PRIV_SOCKET_NAME;
-+        errno = 0;
-         statret = stat(socket_name, &stat_buf);
-         if (statret != 0) {
-+            if (errno == ENOENT) {
-+                *errnop = ESSS_NO_SOCKET;
-+            } else {
-+                *errnop = ESSS_SOCKET_STAT_ERROR;
-+            }
-             ret = PAM_SERVICE_ERR;
-             goto out;
-         }
-@@ -928,8 +934,14 @@ int sss_pam_make_request(enum sss_cli_command cmd,
-         }
-     } else {
-         socket_name = SSS_PAM_SOCKET_NAME;
-+        errno = 0;
-         statret = stat(socket_name, &stat_buf);
-         if (statret != 0) {
-+            if (errno == ENOENT) {
-+                *errnop = ESSS_NO_SOCKET;
-+            } else {
-+                *errnop = ESSS_SOCKET_STAT_ERROR;
-+            }
-             ret = PAM_SERVICE_ERR;
-             goto out;
-         }
-@@ -1075,6 +1087,12 @@ const char *ssscli_err2string(int err)
-         case ESSS_SERVER_NOT_TRUSTED:
-             return _("SSSD is not run by root.");
-             break;
-+        case ESSS_NO_SOCKET:
-+            return _("SSSD socket does not exist.");
-+            break;
-+        case ESSS_SOCKET_STAT_ERROR:
-+            return _("Cannot get stat of SSSD socket.");
-+            break;
-         default:
-             m = strerror(err);
-             if (m == NULL) {
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index 69dc50dfd..9d51aefc6 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -1304,10 +1304,20 @@ static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
-     }
- 
-     if (ret != PAM_SUCCESS) {
--        if (errnop != 0) {
--            logger(pamh, LOG_ERR, "Request to sssd failed. %s", ssscli_err2string(errnop));
-+        /* If there is no PAM responder socket during the access control step
-+         * we assume this is on purpose, i.e. PAM responder is not configured.
-+         * PAM_USER_UNKNOWN is returned to the PAM stack to avoid unexpected
-+         * denials. */
-+        if (errnop == ESSS_NO_SOCKET && task == SSS_PAM_ACCT_MGMT) {
-+            pam_status = PAM_USER_UNKNOWN;
-+        } else {
-+            if (errnop != 0 && errnop != ESSS_NO_SOCKET) {
-+                logger(pamh, LOG_ERR, "Request to sssd failed. %s",
-+                                      ssscli_err2string(errnop));
-+            }
-+
-+            pam_status = PAM_AUTHINFO_UNAVAIL;
-         }
--        pam_status = PAM_AUTHINFO_UNAVAIL;
-         goto done;
-     }
- 
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index af8a43916..31b4e50f7 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -584,6 +584,8 @@ enum sss_cli_error_codes {
-     ESSS_BAD_PUB_SOCKET,
-     ESSS_BAD_CRED_MSG,
-     ESSS_SERVER_NOT_TRUSTED,
-+    ESSS_NO_SOCKET,
-+    ESSS_SOCKET_STAT_ERROR,
- 
-     ESS_SSS_CLI_ERROR_MAX
- };
--- 
-2.19.1
-
diff --git a/SOURCES/0101-ipa-ipa_getkeytab-don-t-call-libnss_sss.patch b/SOURCES/0101-ipa-ipa_getkeytab-don-t-call-libnss_sss.patch
deleted file mode 100644
index 31be7f1..0000000
--- a/SOURCES/0101-ipa-ipa_getkeytab-don-t-call-libnss_sss.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From b927dc7c8d5d4f467749958d3e6330ff70fc3ea2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 1 Apr 2019 17:27:45 +0200
-Subject: [PATCH] ipa: ipa_getkeytab don't call libnss_sss
-
-Resolves: https://pagure.io/SSSD/sssd/issue/3992
-
-ipa-getkeytab is a help process which might even get called during
-the startup of SSSD. Hence it should not try to use any SSSD responder
-especially not the NSS responder.
-
-Typically we call helpers with the environment of the calling SSSD
-component where then _SSS_LOOPS environment variable is set to 'NO' to
-skip calls to SSSD in libnss_sss. Since we have to set the KRB5CCNAME
-environment variable to the ccache with the current TGT for the host
-principal when calling ipa-getkeytab execle() is used to call
-ipa_getkeytab which unfortunately replaces the environment of the caller
-with the one provided in the last argument of the call. To make sure
-ipa_getkeytab does not call back into SSSD we have to set _SSS_LOOPS=NO
-here as well.
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
-(cherry picked from commit d409c10d00101734d1af0c9e0256e607ee8b09c7)
----
- src/providers/ipa/ipa_subdomains_server.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index dd0933642..1d480e52b 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -481,7 +481,7 @@ static void ipa_getkeytab_exec(const char *ccache,
- {
-     errno_t ret;
-     int debug_fd;
--    const char *gkt_env[2] = { NULL, NULL };
-+    const char *gkt_env[3] = { NULL, "_SSS_LOOPS=NO", NULL };
- 
-     if (debug_level >= SSSDBG_TRACE_LIBS) {
-         debug_fd = get_fd_from_debug_file();
--- 
-2.19.1
-
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
index 4e50f5d..6903ad2 100644
--- a/SPECS/sssd.spec
+++ b/SPECS/sssd.spec
@@ -23,8 +23,8 @@
 %endif
 
 Name: sssd
-Version: 2.0.0
-Release: 43%{?dist}.3
+Version: 2.2.0
+Release: 19%{?dist}
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
@@ -32,107 +32,61 @@ URL: https://pagure.io/SSSD/sssd/
 Source0: https://releases.pagure.org/SSSD/sssd/%{name}-%{version}.tar.gz
 
 ### Patches ###
-Patch0001: 0001-KCM-Don-t-error-out-if-creating-a-new-ID-as-the-firs.patch
-Patch0002: 0002-sbus-register-filter-on-new-connection.patch
-Patch0003: 0003-sysdb-extract-sysdb_ldb_msg_attr_to_certmap_info-cal.patch
-Patch0004: 0004-sysdb_ldb_msg_attr_to_certmap_info-set-SSS_CERTMAP_M.patch
-Patch0005: 0005-sysdb-add-attr_map-attribute-to-sysdb_ldb_msg_attr_t.patch
-Patch0006: 0006-confdb-add-confdb_certmap_to_sysdb.patch
-Patch0007: 0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch
-Patch0008: 0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch
-Patch0009: 0009-confdb-add-special-handling-for-rules-for-the-files-.patch
-Patch0010: 0010-files-add-support-for-Smartcard-authentication.patch
-Patch0011: 0011-responder-make-sure-SSS_DP_CERT-is-passed-to-files-p.patch
-Patch0012: 0012-PAM-add-certificate-matching-rules-from-all-domains.patch
-Patch0013: 0013-doc-add-certificate-mapping-section-to-man-page.patch
-Patch0014: 0014-intg-user-default-locale.patch
-Patch0015: 0015-PAM-use-better-PAM-error-code-for-failed-Smartcard-a.patch
-Patch0016: 0016-test_ca-test-library-only-for-readable.patch
-Patch0017: 0017-test_ca-set-a-password-PIN-to-nss-databases.patch
-Patch0018: 0018-getsockopt_wrapper-add-support-for-PAM-clients.patch
-Patch0019: 0019-intg-add-Smartcard-authentication-tests.patch
-Patch0020: 0020-sbus-dectect-python-binary-for-sbus_generate.sh.patch
-Patch0021: 0021-CONFDB-Skip-local-domain-if-not-supported.patch
-Patch0022: 0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch
-Patch0023: 0023-proxy-access-provider-directly-not-through-be_ctx.patch
-Patch0024: 0024-dp-set-be_ctx-provider-as-part-of-dp_init-request.patch
-Patch0025: 0025-sbus-read-destination-after-sender-is-set.patch
-Patch0026: 0026-sbus-do-not-try-to-remove-signal-listeners-when-disc.patch
-Patch0027: 0027-sbus-free-watch_fd-fdevent-explicitly.patch
-Patch0028: 0028-doc-remove-local-provider-reference-from-manpages.patch
-Patch0029: 0029-confdb-log-an-error-when-domain-is-misconfigured.patch
-Patch0030: 0030-be-use-be_is_offline-for-the-main-domain-when-asking.patch
-Patch0031: 0031-sudo-respect-case-sensitivity-in-sudo-responder.patch
-Patch0032: 0032-sbus-fix-typo.patch
-Patch0033: 0033-sbus-check-for-null-message-in-sbus_message_bound.patch
-Patch0034: 0034-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch
-Patch0035: 0035-sbus-add-unit-tests-for-public-sbus_message-module.patch
-Patch0036: 0036-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch
-Patch0037: 0037-p11_child-add-wait_for_card-option.patch
-Patch0038: 0038-PAM-add-p11_wait_for_card_timeout-option.patch
-Patch0039: 0039-pam_sss-make-flags-public.patch
-Patch0040: 0040-pam_sss-add-try_cert_auth-option.patch
-Patch0041: 0041-pam_sss-add-option-require_cert_auth.patch
-Patch0042: 0042-intg-require-SC-tests.patch
-Patch0043: 0043-p11_child-show-PKCS-11-URI-in-debug-output.patch
-Patch0044: 0044-p11_child-add-PKCS-11-uri-to-restrict-selection.patch
-Patch0045: 0045-PAM-add-p11_uri-option.patch
-Patch0046: 0046-tests-add-PKCS-11-URI-tests.patch
-Patch0047: 0047-PAM-return-short-name-for-files-provider-users.patch
-Patch0048: 0048-doc-Add-nsswitch.conf-note-to-manpage.patch
-Patch0049: 0049-intg-flush-the-SSSD-caches-to-sync-with-files.patch
-Patch0050: 0050-FILES-The-files-provider-should-not-enumerate.patch
-Patch0051: 0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch
-Patch0052: 0052-p11_child-add-crl_file-option-for-the-OpenSSL-build.patch
-Patch0053: 0053-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch
-Patch0054: 0054-sudo-use-correct-sbus-interface.patch
-Patch0055: 0055-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch
-Patch0056: 0056-files-add-session-recording-flag.patch
-Patch0057: 0057-UTIL-Suppress-Coverity-warning.patch
-Patch0058: 0058-PYSSS-Re-add-the-pysss.getgrouplist-interface.patch
-Patch0059: 0059-ifp-fix-typo-causing-a-crash-in-FindByNameAndCertifi.patch
-Patch0060: 0060-IFP-Use-subreq-not-req-when-calling-RefreshRules_rec.patch
-Patch0061: 0061-INI-Return-errno-not-1-on-failure-from-sss_ini_get_s.patch
-Patch0062: 0062-MONITOR-Don-t-check-for-pidfile-if-SSSD-is-already-r.patch
-Patch0063: 0063-SSSD-Allow-refreshing-only-certain-section-with-genc.patch
-Patch0064: 0064-SYSTEMD-Re-read-KCM-configuration-on-systemctl-resta.patch
-Patch0065: 0065-pam_sss-return-PAM_AUTHINFO_UNAVAIL-if-sc-options-ar.patch
-Patch0066: 0066-p11_child-NSS-print-key-type-in-a-debug-message.patch
-Patch0067: 0067-pam_test_srv-set-default-value-for-SOFTHSM2_CONF.patch
-Patch0068: 0068-tests-add-ECC-CA.patch
-Patch0069: 0069-test_pam_srv-add-test-for-certificate-with-EC-keys.patch
-Patch0070: 0070-p11_child-openssl-add-support-for-EC-keys.patch
-Patch0071: 0071-utils-refactor-ssh-key-extraction-OpenSSL.patch
-Patch0072: 0072-utils-add-ec_pub_key_to_ssh-OpenSSL.patch
-Patch0073: 0073-utils-refactor-ssh-key-extraction-NSS.patch
-Patch0074: 0074-utils-add-ec_pub_key_to_ssh-NSS.patch
-Patch0075: 0075-SSSCTL-user-show-says-that-user-is-expired.patch
-Patch0076: 0076-sss_iface-prevent-from-using-invalid-names-that-star.patch
-Patch0077: 0077-nss-use-enumeration-context-as-talloc-parent-for-cac.patch
-Patch0078: 0078-LDAP-minor-refactoring-in-auth_send-to-conform-to-ou.patch
-Patch0079: 0079-LDAP-Only-authenticate-the-auth-connection-if-we-nee.patch
-Patch0080: 0080-LDAP-Log-the-encryption-used-during-LDAP-authenticat.patch
-Patch0081: 0081-nss-sssd-returns-for-emtpy-home-directories.patch
-Patch0082: 0082-PROXY-Copy-the-response-to-the-caller.patch
-Patch0083: 0083-Revert-IPA-use-forest-name-when-looking-up-the-Globa.patch
-Patch0084: 0084-ipa-use-only-the-global-catalog-service-of-the-fores.patch
-Patch0085: 0085-krb5_child-fix-permissions-during-SC-auth.patch
-Patch0086: 0086-MAN-Explicitly-state-that-not-all-generic-domain-opt.patch
-Patch0087: 0087-KCM-Deleting-a-non-existent-ccache-should-not-yield-.patch
-Patch0088: 0088-confdb-Always-read-snippet-files.patch
-Patch0089: 0089-CONFDB-Remove-old-libini-support.patch
-Patch0090: 0090-idmap_sss-improve-man-page.patch
-Patch0091: 0091-sbus-allow-access-for-sssd-user.patch
-Patch0092: 0092-sbus-use-120-second-default-timeout.patch
-Patch0093: 0093-ifp-extraAttributes-is-UnknownProperty.patch
-Patch0094: 0094-AD-IPA-Reset-subdomain-service-name-not-domain-name.patch
-Patch0095: 0095-IPA-Add-explicit-return-after-tevent_req_error.patch
-Patch0096: 0096-KCM-Return-a-valid-tevent-error-code-if-a-request-ca.patch
-Patch0097: 0097-KCM-Allow-representing-ccaches-with-a-NULL-principal.patch
-Patch0098: 0098-KCM-Create-an-empty-ccache-on-switch-to-a-non-existi.patch
-Patch0099: 0099-PAM-use-user-name-hint-if-any-domain-has-set-it.patch
-Patch0100: 0100-pam_sss-PAM_USER_UNKNOWN-if-socket-is-missing.patch
-Patch0101: 0101-ipa-ipa_getkeytab-don-t-call-libnss_sss.patch
+Patch0001: 0001-MAN-ldap_user_home_directory-default-missing.patch
+Patch0002: 0002-PROXY-Return-data-in-output-parameter-if-everything-.patch
+Patch0003: 0003-LDAP-failover-does-not-work-on-non-responsive-ldaps.patch
+Patch0004: 0004-sudo-use-proper-datetime-for-default-modifyTimestamp.patch
+Patch0005: 0005-negcache-add-fq-usernames-of-know-domains-to-all-UPN.patch
+Patch0006: 0006-p11_child-prefer-better-digest-function-if-card-supp.patch
+Patch0007: 0007-p11_child-fix-a-memory-leak-and-other-memory-mangeme.patch
+Patch0008: 0008-man-fix-description-of-dns_resolver_op_timeout.patch
+Patch0009: 0009-man-fix-description-of-dns_resolver_timeout.patch
+Patch0010: 0010-failover-add-dns_resolver_server_timeout-option.patch
+Patch0011: 0011-failover-change-default-timeouts.patch
+Patch0012: 0012-config-add-dns_resolver_op_timeout-to-option-list.patch
+Patch0013: 0013-pam_sss-Add-missing-colon-to-the-PIN-prompt.patch
+Patch0014: 0014-pam-make-sure-p11_child.log-has-the-right-permission.patch
+Patch0015: 0015-ssh-make-sure-p11_child.log-has-the-right-permission.patch
+Patch0016: 0016-BE-make-sure-child-log-files-have-the-right-permissi.patch
+Patch0017: 0017-MAN-Get-rid-of-sssd-secrets-reference.patch
+Patch0018: 0018-MAN-Document-that-it-is-enough-to-systemctl-restart-.patch
+Patch0019: 0019-SECRETS-Use-different-option-names-from-secrets-and-.patch
+Patch0020: 0020-SECRETS-Don-t-limit-the-global-number-of-ccaches.patch
+Patch0021: 0021-KCM-Pass-confdb-context-to-the-ccache-db-initializat.patch
+Patch0022: 0022-KCM-Configurable-quotas-for-the-secdb-ccache-back-en.patch
+Patch0023: 0023-MAN-Document-that-PAM-stack-contains-the-systemd-use.patch
+Patch0024: 0024-Don-t-qualify-users-from-files-domain-when-default_d.patch
+Patch0025: 0025-pam-fix-loop-in-Smartcard-authentication.patch
+Patch0026: 0026-SYSDB-Add-sysdb_search_with_ts_attr.patch
+Patch0027: 0027-BE-search-with-sysdb_search_with_ts_attr.patch
+Patch0028: 0028-BE-Enable-refresh-for-multiple-domains.patch
+Patch0029: 0029-BE-Make-be_refresh_ctx_init-set-up-the-periodical-ta.patch
+Patch0030: 0030-BE-LDAP-Call-be_refresh_ctx_init-in-the-provider-lib.patch
+Patch0031: 0031-BE-Pass-in-attribute-to-look-up-with-instead-of-hard.patch
+Patch0032: 0032-BE-Change-be_refresh_ctx_init-to-return-errno-and-se.patch
+Patch0033: 0033-BE-LDAP-Split-out-a-helper-function-from-sdap_refres.patch
+Patch0034: 0034-BE-Pass-in-filter_type-when-creating-the-refresh-acc.patch
+Patch0035: 0035-BE-Send-refresh-requests-in-batches.patch
+Patch0036: 0036-BE-Extend-be_ptask_create-with-control-when-to-sched.patch
+Patch0037: 0037-BE-Schedule-the-refresh-interval-from-the-finish-tim.patch
+Patch0038: 0038-AD-Implement-background-refresh-for-AD-domains.patch 
+Patch0039: 0039-IPA-Implement-background-refresh-for-IPA-domains.patch
+Patch0040: 0040-BE-IPA-AD-LDAP-Add-inigroups-refresh-support.patch
+Patch0041: 0041-BE-IPA-AD-LDAP-Initialize-the-refresh-callback-from-.patch
+Patch0042: 0042-IPA-AD-SDAP-BE-Generate-refresh-callbacks-with-a-mac.patch
+Patch0043: 0043-MAN-Amend-the-documentation-for-the-background-refre.patch
+Patch0044: 0044-DP-SYSDB-Move-the-code-to-set-initgrExpireTimestamp-.patch
+Patch0045: 0045-IPA-AD-LDAP-Increase-the-initgrExpireTimestamp-after.patch
+Patch0046: 0046-BE-Introduce-flag-for-be_ptask_create.patch
+Patch0047: 0047-BE-Convert-be_ptask-params-to-flags.patch
+Patch0048: 0048-DYNDNS-dyndns_update-is-not-enough.patch
+Patch0049: 0049-tests-Use-idm-DL1-module-to-install-389-ds.patch
+Patch0050: 0050-pam-keep-pin-on-the-PAM-stack-for-forward_pass.patch
+Patch0051: 0051-BE-Invalid-oprator-used-in-condition.patch
+Patch0052: 0052-TESTS-Sync.-multihost-kcm-tests-with-master.patch
+Patch0053: 0053-KCM-Add-a-forgotten-return.patch
+Patch0054: 0054-KCM-Allow-modifications-of-ccache-s-principal.patch
+Patch0055: 0055-KCM-Fill-empty-cache-do-not-initialize-a-new-one.patch
 
 ### Downstream Patches ###
 
@@ -204,6 +158,7 @@ BuildRequires: selinux-policy-targeted
 BuildRequires: libcmocka-devel >= 1.0.0
 BuildRequires: uid_wrapper
 BuildRequires: nss_wrapper
+BuildRequires: pam_wrapper
 BuildRequires: p11-kit-devel
 BuildRequires: openssl-devel
 BuildRequires: gnutls-utils
@@ -611,7 +566,7 @@ UIDs/GIDs to names and vice versa. It can be also used for mapping principal
 (user) name to IDs(UID or GID) or to obtain groups which user are member of.
 
 %package -n libsss_certmap
-Summary: SSSD Certficate Mapping Library
+Summary: SSSD Certificate Mapping Library
 Group: Development/Libraries
 License: LGPLv3+
 Requires(post): /sbin/ldconfig
@@ -622,7 +577,7 @@ Conflicts: sssd-common < %{version}-%{release}
 Library to map certificates to users based on rules
 
 %package -n libsss_certmap-devel
-Summary: SSSD Certficate Mapping Library
+Summary: SSSD Certificate Mapping Library
 Group: Development/Libraries
 License: LGPLv3+
 Requires: libsss_certmap = %{version}-%{release}
@@ -889,12 +844,12 @@ done
 %dir %{sssdstatedir}
 %dir %{_localstatedir}/cache/krb5rcache
 %attr(700,sssd,sssd) %dir %{dbpath}
-%attr(755,sssd,sssd) %dir %{mcpath}
+%attr(775,sssd,sssd) %dir %{mcpath}
 %attr(700,root,root) %dir %{secdbpath}
 %attr(751,root,root) %dir %{deskprofilepath}
-%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd
-%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
-%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups
+%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}
@@ -903,7 +858,7 @@ done
 %attr(700,sssd,sssd) %dir %{_sysconfdir}/sssd
 %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d
 %attr(711,root,root) %dir %{_sysconfdir}/sssd/pki
-%ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
+%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
@@ -1284,17 +1239,93 @@ fi
                                 %{_libdir}/%{name}/modules/libwbclient.so
 
 %changelog
-* Thu Apr 18 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-43.3
-- Resolves: rhbz#1701135 - Include libsss_nss_idmap-devel in the Builder
+* Wed Sep 4 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-19
+- Resolves: rhbz#1712875 - Old kerberos credentials active instead of valid
+                           new ones (kcm)
+
+* Sun Sep 1 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-18
+- Resolves: rhbz#1744134 - New defect found in sssd-2.2.0-16.el8
+- Also sync. kcm multihost tests with master
+
+* Sun Sep 1 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-17
+- Resolves: rhbz#1676385 - pam_sss with smartcard auth does not create gnome
+                           keyring
+- Also apply a patch to fix gating tests issue
+
+* Sun Aug 18 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-16
+- Resolves: rhbz#1736861 - dyndns_update = True is no longer enough to get
+                           the IP address of the machine updated in IPA upon
+                           sssd.service startup
+
+* Sun Aug 18 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-15
+- Resolves: rhbz#1736265 - Smart Card auth of local user: endless
+                           loop if wrong PIN was provided
+
+* Sun Aug 18 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-14
+- Resolves: rhbz#1736796 - sssd config option "default_domain_suffix"
+                           should not cause files domain entries to be
+                           qualified, this can break sudo access
+
+* Sun Aug 18 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-13
+- Resolves: rhbz#1669407 - MAN: Document that PAM stack contains the
+            systemd-user service in the account phase in RHEL-8 
+
+* Sun Aug 18 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-12
+- Resolves: rhbz#1448094 - sssd-kcm cannot handle big tickets
+
+* Fri Aug 9 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-11
+- Resolves: rhbz#1733372 - permission denied on logs when running sssd as
+                           non-root user
+
+* Fri Aug 9 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-10
+- Resolves: rhbz#1736483 - Sudo prompt for smart card authentication is missing
+                           the trailing colon
+
+* Fri Aug 9 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-9
+- Resolves: rhbz#1382750 - Conflicting default timeout values
+
+* Fri Aug 2 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-8
+- Resolves: rhbz#1699480 - Include libsss_nss_idmap-devel in the Builder
                            repository
+                         - This just required a raise in release number
+                           and changelog for the record.
+
+* Fri Aug 2 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-7
+- Resolves: rhbz#1711318 - p11_child::sign_data() function implementation is
+                           not FIPS140 compliant
+
+* Fri Aug 2 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-6
+- Resolves: rhbz#1726945 - negative cache does not use values from
+                           'filter_users' config option for known domains
+
+* Thu Jul 25 2019 Jakub Hrozek <jhrozek@redhat.com> - 2.2.0-5
+- Resolves: rhbz#1729055 - sssd does not pass correct rules to sudo
+
+* Thu Jul 25 2019 Jakub Hrozek <jhrozek@redhat.com> - 2.2.0-4
+- Resolves: rhbz#1283798 - sssd failover does not work on connecting to
+                           non-responsive ldaps:// server
+
+* Wed Jul  3 2019 Jakub Hrozek <jhrozek@redhat.com> - 2.2.0-3
+- Resolves: rhbz#1725168 - sssd-proxy crashes resolving groups with
+                           no members
+
+* Wed Jul  3 2019 Jakub Hrozek <jhrozek@redhat.com> - 2.2.0-2
+- Resolves: rhbz#1673443 - sssd man pages: The default value of
+                           "ldap_user_home_directory" is not mentioned
+                           with AD server configuration
+
+* Fri Jun 14 2019 Michal Židek <mzidek@redhat.com> - 2.2.0-1
+- Resolves: rhbz#1687281
+  Rebase sssd in RHEL-8.1 to the latest upstream release 
 
-* Fri Apr 05 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-43.2
-- Resolves: rhbz#1696596 - AD user not found after establishing trust and
-                           restarting sssd [ZStream Clone]
+* Wed Jun 12 2019 Michal Židek <mzidek@redhat.com> - 2.1.0-1
+- Resolves: rhbz#1687281
+  Rebase sssd in RHEL-8.1 to the latest upstream release 
 
-* Fri Mar 29 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-43.1
-- Resolves: rhbz#1691750 - pam_sss failing for external users not configured
-                           via sssd
+* Thu May 30 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-45
+- Replace ARRAY_SIZE with N_ELEMENTS to reflect samba changes. This is
+  done here in order to unblock gating changes before rebase.
+- Related: rhbz#1682305
 
 * Sun Feb 10 2019 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-43
 - Resolves: rhbz#1672780 - gdm login not prompting for username when smart