diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b147e6a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/sssd-2.0.0.tar.gz
diff --git a/.sssd.metadata b/.sssd.metadata
new file mode 100644
index 0000000..7f62e35
--- /dev/null
+++ b/.sssd.metadata
@@ -0,0 +1 @@
+700ff5391bea73c19ddcdf99b25615fd4d284d7b SOURCES/sssd-2.0.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
new file mode 100644
index 0000000..c6c7fa1
--- /dev/null
+++ b/SOURCES/0001-KCM-Don-t-error-out-if-creating-a-new-ID-as-the-firs.patch
@@ -0,0 +1,41 @@
+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/0002-sbus-register-filter-on-new-connection.patch b/SOURCES/0002-sbus-register-filter-on-new-connection.patch
new file mode 100644
index 0000000..69e00c2
--- /dev/null
+++ b/SOURCES/0002-sbus-register-filter-on-new-connection.patch
@@ -0,0 +1,48 @@
+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-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
new file mode 100644
index 0000000..4ed5198
--- /dev/null
+++ b/SOURCES/0003-sysdb-extract-sysdb_ldb_msg_attr_to_certmap_info-cal.patch
@@ -0,0 +1,260 @@
+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-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
new file mode 100644
index 0000000..38fc538
--- /dev/null
+++ b/SOURCES/0004-sysdb_ldb_msg_attr_to_certmap_info-set-SSS_CERTMAP_M.patch
@@ -0,0 +1,40 @@
+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-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
new file mode 100644
index 0000000..c67b895
--- /dev/null
+++ b/SOURCES/0005-sysdb-add-attr_map-attribute-to-sysdb_ldb_msg_attr_t.patch
@@ -0,0 +1,141 @@
+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
new file mode 100644
index 0000000..210f90d
--- /dev/null
+++ b/SOURCES/0006-confdb-add-confdb_certmap_to_sysdb.patch
@@ -0,0 +1,168 @@
+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/0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch b/SOURCES/0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch
new file mode 100644
index 0000000..a838fe7
--- /dev/null
+++ b/SOURCES/0007-AD-LDAP-read-certificate-mapping-rules-from-config-f.patch
@@ -0,0 +1,72 @@
+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/0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch b/SOURCES/0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch
new file mode 100644
index 0000000..0ca43a2
--- /dev/null
+++ b/SOURCES/0008-sysdb-sysdb_certmap_add-handle-domains-more-flexible.patch
@@ -0,0 +1,33 @@
+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
new file mode 100644
index 0000000..ad0e621
--- /dev/null
+++ b/SOURCES/0009-confdb-add-special-handling-for-rules-for-the-files-.patch
@@ -0,0 +1,132 @@
+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/0010-files-add-support-for-Smartcard-authentication.patch b/SOURCES/0010-files-add-support-for-Smartcard-authentication.patch
new file mode 100644
index 0000000..41d3d62
--- /dev/null
+++ b/SOURCES/0010-files-add-support-for-Smartcard-authentication.patch
@@ -0,0 +1,415 @@
+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-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
new file mode 100644
index 0000000..be4740f
--- /dev/null
+++ b/SOURCES/0011-responder-make-sure-SSS_DP_CERT-is-passed-to-files-p.patch
@@ -0,0 +1,69 @@
+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
new file mode 100644
index 0000000..2dea1b9
--- /dev/null
+++ b/SOURCES/0012-PAM-add-certificate-matching-rules-from-all-domains.patch
@@ -0,0 +1,167 @@
+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/0013-doc-add-certificate-mapping-section-to-man-page.patch b/SOURCES/0013-doc-add-certificate-mapping-section-to-man-page.patch
new file mode 100644
index 0000000..e6641ce
--- /dev/null
+++ b/SOURCES/0013-doc-add-certificate-mapping-section-to-man-page.patch
@@ -0,0 +1,183 @@
+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/0014-intg-user-default-locale.patch b/SOURCES/0014-intg-user-default-locale.patch
new file mode 100644
index 0000000..1e94700
--- /dev/null
+++ b/SOURCES/0014-intg-user-default-locale.patch
@@ -0,0 +1,31 @@
+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/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
new file mode 100644
index 0000000..39c3c91
--- /dev/null
+++ b/SOURCES/0015-PAM-use-better-PAM-error-code-for-failed-Smartcard-a.patch
@@ -0,0 +1,35 @@
+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/0016-test_ca-test-library-only-for-readable.patch b/SOURCES/0016-test_ca-test-library-only-for-readable.patch
new file mode 100644
index 0000000..6e71fd2
--- /dev/null
+++ b/SOURCES/0016-test_ca-test-library-only-for-readable.patch
@@ -0,0 +1,32 @@
+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-test_ca-set-a-password-PIN-to-nss-databases.patch b/SOURCES/0017-test_ca-set-a-password-PIN-to-nss-databases.patch
new file mode 100644
index 0000000..6df5716
--- /dev/null
+++ b/SOURCES/0017-test_ca-set-a-password-PIN-to-nss-databases.patch
@@ -0,0 +1,58 @@
+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-getsockopt_wrapper-add-support-for-PAM-clients.patch b/SOURCES/0018-getsockopt_wrapper-add-support-for-PAM-clients.patch
new file mode 100644
index 0000000..c520c4d
--- /dev/null
+++ b/SOURCES/0018-getsockopt_wrapper-add-support-for-PAM-clients.patch
@@ -0,0 +1,79 @@
+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-intg-add-Smartcard-authentication-tests.patch b/SOURCES/0019-intg-add-Smartcard-authentication-tests.patch
new file mode 100644
index 0000000..f7912ec
--- /dev/null
+++ b/SOURCES/0019-intg-add-Smartcard-authentication-tests.patch
@@ -0,0 +1,331 @@
+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-sbus-dectect-python-binary-for-sbus_generate.sh.patch b/SOURCES/0020-sbus-dectect-python-binary-for-sbus_generate.sh.patch
new file mode 100644
index 0000000..bd0e5ee
--- /dev/null
+++ b/SOURCES/0020-sbus-dectect-python-binary-for-sbus_generate.sh.patch
@@ -0,0 +1,88 @@
+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
new file mode 100644
index 0000000..1f608ec
--- /dev/null
+++ b/SOURCES/0021-CONFDB-Skip-local-domain-if-not-supported.patch
@@ -0,0 +1,42 @@
+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/0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch b/SOURCES/0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch
new file mode 100644
index 0000000..3b1da28
--- /dev/null
+++ b/SOURCES/0022-SELINUX-Always-add-SELinux-user-to-the-semanage-data.patch
@@ -0,0 +1,145 @@
+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-proxy-access-provider-directly-not-through-be_ctx.patch b/SOURCES/0023-proxy-access-provider-directly-not-through-be_ctx.patch
new file mode 100644
index 0000000..2ac0feb
--- /dev/null
+++ b/SOURCES/0023-proxy-access-provider-directly-not-through-be_ctx.patch
@@ -0,0 +1,49 @@
+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-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
new file mode 100644
index 0000000..cef0070
--- /dev/null
+++ b/SOURCES/0024-dp-set-be_ctx-provider-as-part-of-dp_init-request.patch
@@ -0,0 +1,144 @@
+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-sbus-read-destination-after-sender-is-set.patch b/SOURCES/0025-sbus-read-destination-after-sender-is-set.patch
new file mode 100644
index 0000000..30364d0
--- /dev/null
+++ b/SOURCES/0025-sbus-read-destination-after-sender-is-set.patch
@@ -0,0 +1,42 @@
+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-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
new file mode 100644
index 0000000..ec4f920
--- /dev/null
+++ b/SOURCES/0026-sbus-do-not-try-to-remove-signal-listeners-when-disc.patch
@@ -0,0 +1,34 @@
+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-sbus-free-watch_fd-fdevent-explicitly.patch b/SOURCES/0027-sbus-free-watch_fd-fdevent-explicitly.patch
new file mode 100644
index 0000000..8fd0972
--- /dev/null
+++ b/SOURCES/0027-sbus-free-watch_fd-fdevent-explicitly.patch
@@ -0,0 +1,29 @@
+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-doc-remove-local-provider-reference-from-manpages.patch b/SOURCES/0028-doc-remove-local-provider-reference-from-manpages.patch
new file mode 100644
index 0000000..aa12719
--- /dev/null
+++ b/SOURCES/0028-doc-remove-local-provider-reference-from-manpages.patch
@@ -0,0 +1,139 @@
+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-confdb-log-an-error-when-domain-is-misconfigured.patch b/SOURCES/0029-confdb-log-an-error-when-domain-is-misconfigured.patch
new file mode 100644
index 0000000..f8120b9
--- /dev/null
+++ b/SOURCES/0029-confdb-log-an-error-when-domain-is-misconfigured.patch
@@ -0,0 +1,48 @@
+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-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
new file mode 100644
index 0000000..30cb266
--- /dev/null
+++ b/SOURCES/0030-be-use-be_is_offline-for-the-main-domain-when-asking.patch
@@ -0,0 +1,58 @@
+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-sudo-respect-case-sensitivity-in-sudo-responder.patch b/SOURCES/0031-sudo-respect-case-sensitivity-in-sudo-responder.patch
new file mode 100644
index 0000000..aa983bd
--- /dev/null
+++ b/SOURCES/0031-sudo-respect-case-sensitivity-in-sudo-responder.patch
@@ -0,0 +1,69 @@
+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-sbus-fix-typo.patch b/SOURCES/0032-sbus-fix-typo.patch
new file mode 100644
index 0000000..af080fc
--- /dev/null
+++ b/SOURCES/0032-sbus-fix-typo.patch
@@ -0,0 +1,27 @@
+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-sbus-check-for-null-message-in-sbus_message_bound.patch b/SOURCES/0033-sbus-check-for-null-message-in-sbus_message_bound.patch
new file mode 100644
index 0000000..e257239
--- /dev/null
+++ b/SOURCES/0033-sbus-check-for-null-message-in-sbus_message_bound.patch
@@ -0,0 +1,42 @@
+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-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch b/SOURCES/0034-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch
new file mode 100644
index 0000000..2fb9d4f
--- /dev/null
+++ b/SOURCES/0034-sbus-replace-sbus_message_bound_ref-with-sbus_messag.patch
@@ -0,0 +1,337 @@
+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-sbus-add-unit-tests-for-public-sbus_message-module.patch b/SOURCES/0035-sbus-add-unit-tests-for-public-sbus_message-module.patch
new file mode 100644
index 0000000..70e2298
--- /dev/null
+++ b/SOURCES/0035-sbus-add-unit-tests-for-public-sbus_message-module.patch
@@ -0,0 +1,664 @@
+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-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch b/SOURCES/0036-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch
new file mode 100644
index 0000000..945601d
--- /dev/null
+++ b/SOURCES/0036-p11-handle-multiple-certs-during-auth-with-OpenSSL.patch
@@ -0,0 +1,147 @@
+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-p11_child-add-wait_for_card-option.patch b/SOURCES/0037-p11_child-add-wait_for_card-option.patch
new file mode 100644
index 0000000..6cf433d
--- /dev/null
+++ b/SOURCES/0037-p11_child-add-wait_for_card-option.patch
@@ -0,0 +1,476 @@
+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-PAM-add-p11_wait_for_card_timeout-option.patch b/SOURCES/0038-PAM-add-p11_wait_for_card_timeout-option.patch
new file mode 100644
index 0000000..d3931d1
--- /dev/null
+++ b/SOURCES/0038-PAM-add-p11_wait_for_card_timeout-option.patch
@@ -0,0 +1,144 @@
+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-pam_sss-make-flags-public.patch b/SOURCES/0039-pam_sss-make-flags-public.patch
new file mode 100644
index 0000000..b690e75
--- /dev/null
+++ b/SOURCES/0039-pam_sss-make-flags-public.patch
@@ -0,0 +1,245 @@
+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-pam_sss-add-try_cert_auth-option.patch b/SOURCES/0040-pam_sss-add-try_cert_auth-option.patch
new file mode 100644
index 0000000..89129f6
--- /dev/null
+++ b/SOURCES/0040-pam_sss-add-try_cert_auth-option.patch
@@ -0,0 +1,101 @@
+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-pam_sss-add-option-require_cert_auth.patch b/SOURCES/0041-pam_sss-add-option-require_cert_auth.patch
new file mode 100644
index 0000000..7dc8826
--- /dev/null
+++ b/SOURCES/0041-pam_sss-add-option-require_cert_auth.patch
@@ -0,0 +1,372 @@
+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-intg-require-SC-tests.patch b/SOURCES/0042-intg-require-SC-tests.patch
new file mode 100644
index 0000000..a8c7e18
--- /dev/null
+++ b/SOURCES/0042-intg-require-SC-tests.patch
@@ -0,0 +1,310 @@
+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-p11_child-show-PKCS-11-URI-in-debug-output.patch b/SOURCES/0043-p11_child-show-PKCS-11-URI-in-debug-output.patch
new file mode 100644
index 0000000..1b0cf16
--- /dev/null
+++ b/SOURCES/0043-p11_child-show-PKCS-11-URI-in-debug-output.patch
@@ -0,0 +1,408 @@
+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-p11_child-add-PKCS-11-uri-to-restrict-selection.patch b/SOURCES/0044-p11_child-add-PKCS-11-uri-to-restrict-selection.patch
new file mode 100644
index 0000000..bc0eb02
--- /dev/null
+++ b/SOURCES/0044-p11_child-add-PKCS-11-uri-to-restrict-selection.patch
@@ -0,0 +1,239 @@
+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-PAM-add-p11_uri-option.patch b/SOURCES/0045-PAM-add-p11_uri-option.patch
new file mode 100644
index 0000000..e495f08
--- /dev/null
+++ b/SOURCES/0045-PAM-add-p11_uri-option.patch
@@ -0,0 +1,194 @@
+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-tests-add-PKCS-11-URI-tests.patch b/SOURCES/0046-tests-add-PKCS-11-URI-tests.patch
new file mode 100644
index 0000000..a63bb54
--- /dev/null
+++ b/SOURCES/0046-tests-add-PKCS-11-URI-tests.patch
@@ -0,0 +1,210 @@
+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-PAM-return-short-name-for-files-provider-users.patch b/SOURCES/0047-PAM-return-short-name-for-files-provider-users.patch
new file mode 100644
index 0000000..b3cbed2
--- /dev/null
+++ b/SOURCES/0047-PAM-return-short-name-for-files-provider-users.patch
@@ -0,0 +1,148 @@
+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-doc-Add-nsswitch.conf-note-to-manpage.patch b/SOURCES/0048-doc-Add-nsswitch.conf-note-to-manpage.patch
new file mode 100644
index 0000000..7fd3b19
--- /dev/null
+++ b/SOURCES/0048-doc-Add-nsswitch.conf-note-to-manpage.patch
@@ -0,0 +1,77 @@
+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
new file mode 100644
index 0000000..a49ca25
--- /dev/null
+++ b/SOURCES/0049-intg-flush-the-SSSD-caches-to-sync-with-files.patch
@@ -0,0 +1,45 @@
+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/0050-FILES-The-files-provider-should-not-enumerate.patch b/SOURCES/0050-FILES-The-files-provider-should-not-enumerate.patch
new file mode 100644
index 0000000..654964a
--- /dev/null
+++ b/SOURCES/0050-FILES-The-files-provider-should-not-enumerate.patch
@@ -0,0 +1,101 @@
+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/0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch b/SOURCES/0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch
new file mode 100644
index 0000000..e04bad1
--- /dev/null
+++ b/SOURCES/0051-p11_child-add-OCSP-check-ot-the-OpenSSL-version.patch
@@ -0,0 +1,490 @@
+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-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
new file mode 100644
index 0000000..31dc808
--- /dev/null
+++ b/SOURCES/0052-p11_child-add-crl_file-option-for-the-OpenSSL-build.patch
@@ -0,0 +1,280 @@
+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-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch b/SOURCES/0053-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch
new file mode 100644
index 0000000..831330d
--- /dev/null
+++ b/SOURCES/0053-p11-Fix-two-instances-of-Wmaybe-uninitialized-in-p11.patch
@@ -0,0 +1,38 @@
+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-sudo-use-correct-sbus-interface.patch b/SOURCES/0054-sudo-use-correct-sbus-interface.patch
new file mode 100644
index 0000000..7122888
--- /dev/null
+++ b/SOURCES/0054-sudo-use-correct-sbus-interface.patch
@@ -0,0 +1,32 @@
+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-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch b/SOURCES/0055-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch
new file mode 100644
index 0000000..c7ca404
--- /dev/null
+++ b/SOURCES/0055-sudo-fix-error-handling-in-sudosrv_refresh_rules_don.patch
@@ -0,0 +1,41 @@
+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
new file mode 100644
index 0000000..440e9b7
--- /dev/null
+++ b/SOURCES/0056-files-add-session-recording-flag.patch
@@ -0,0 +1,136 @@
+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
new file mode 100644
index 0000000..dff7c19
--- /dev/null
+++ b/SOURCES/0057-UTIL-Suppress-Coverity-warning.patch
@@ -0,0 +1,43 @@
+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
new file mode 100644
index 0000000..399c5c7
--- /dev/null
+++ b/SOURCES/0058-PYSSS-Re-add-the-pysss.getgrouplist-interface.patch
@@ -0,0 +1,121 @@
+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
new file mode 100644
index 0000000..7509f03
--- /dev/null
+++ b/SOURCES/0059-ifp-fix-typo-causing-a-crash-in-FindByNameAndCertifi.patch
@@ -0,0 +1,46 @@
+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
new file mode 100644
index 0000000..0c5e349
--- /dev/null
+++ b/SOURCES/0060-IFP-Use-subreq-not-req-when-calling-RefreshRules_rec.patch
@@ -0,0 +1,35 @@
+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
new file mode 100644
index 0000000..2452780
--- /dev/null
+++ b/SOURCES/0061-INI-Return-errno-not-1-on-failure-from-sss_ini_get_s.patch
@@ -0,0 +1,42 @@
+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
new file mode 100644
index 0000000..824a2a6
--- /dev/null
+++ b/SOURCES/0062-MONITOR-Don-t-check-for-pidfile-if-SSSD-is-already-r.patch
@@ -0,0 +1,53 @@
+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
new file mode 100644
index 0000000..6af1af1
--- /dev/null
+++ b/SOURCES/0063-SSSD-Allow-refreshing-only-certain-section-with-genc.patch
@@ -0,0 +1,399 @@
+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
new file mode 100644
index 0000000..e5f66ba
--- /dev/null
+++ b/SOURCES/0064-SYSTEMD-Re-read-KCM-configuration-on-systemctl-resta.patch
@@ -0,0 +1,84 @@
+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
new file mode 100644
index 0000000..700b249
--- /dev/null
+++ b/SOURCES/0065-pam_sss-return-PAM_AUTHINFO_UNAVAIL-if-sc-options-ar.patch
@@ -0,0 +1,72 @@
+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
new file mode 100644
index 0000000..e9e73dd
--- /dev/null
+++ b/SOURCES/0066-p11_child-NSS-print-key-type-in-a-debug-message.patch
@@ -0,0 +1,72 @@
+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
new file mode 100644
index 0000000..6662610
--- /dev/null
+++ b/SOURCES/0067-pam_test_srv-set-default-value-for-SOFTHSM2_CONF.patch
@@ -0,0 +1,47 @@
+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
new file mode 100644
index 0000000..a8f0717
--- /dev/null
+++ b/SOURCES/0068-tests-add-ECC-CA.patch
@@ -0,0 +1,276 @@
+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
new file mode 100644
index 0000000..f9e9d92
--- /dev/null
+++ b/SOURCES/0069-test_pam_srv-add-test-for-certificate-with-EC-keys.patch
@@ -0,0 +1,198 @@
+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
new file mode 100644
index 0000000..3b3f29e
--- /dev/null
+++ b/SOURCES/0070-p11_child-openssl-add-support-for-EC-keys.patch
@@ -0,0 +1,409 @@
+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
new file mode 100644
index 0000000..6d732d7
--- /dev/null
+++ b/SOURCES/0071-utils-refactor-ssh-key-extraction-OpenSSL.patch
@@ -0,0 +1,133 @@
+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
new file mode 100644
index 0000000..2fa32d0
--- /dev/null
+++ b/SOURCES/0072-utils-add-ec_pub_key_to_ssh-OpenSSL.patch
@@ -0,0 +1,265 @@
+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
new file mode 100644
index 0000000..c3e1ec7
--- /dev/null
+++ b/SOURCES/0073-utils-refactor-ssh-key-extraction-NSS.patch
@@ -0,0 +1,153 @@
+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
new file mode 100644
index 0000000..6ad4d92
--- /dev/null
+++ b/SOURCES/0074-utils-add-ec_pub_key_to_ssh-NSS.patch
@@ -0,0 +1,158 @@
+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
new file mode 100644
index 0000000..b960eea
--- /dev/null
+++ b/SOURCES/0075-SSSCTL-user-show-says-that-user-is-expired.patch
@@ -0,0 +1,53 @@
+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
new file mode 100644
index 0000000..a444b0c
--- /dev/null
+++ b/SOURCES/0076-sss_iface-prevent-from-using-invalid-names-that-star.patch
@@ -0,0 +1,52 @@
+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
new file mode 100644
index 0000000..3e2745e
--- /dev/null
+++ b/SOURCES/0077-nss-use-enumeration-context-as-talloc-parent-for-cac.patch
@@ -0,0 +1,145 @@
+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
new file mode 100644
index 0000000..d24017d
--- /dev/null
+++ b/SOURCES/0078-LDAP-minor-refactoring-in-auth_send-to-conform-to-ou.patch
@@ -0,0 +1,71 @@
+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
new file mode 100644
index 0000000..db77f7c
--- /dev/null
+++ b/SOURCES/0079-LDAP-Only-authenticate-the-auth-connection-if-we-nee.patch
@@ -0,0 +1,130 @@
+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
new file mode 100644
index 0000000..435ecae
--- /dev/null
+++ b/SOURCES/0080-LDAP-Log-the-encryption-used-during-LDAP-authenticat.patch
@@ -0,0 +1,59 @@
+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
new file mode 100644
index 0000000..6560880
--- /dev/null
+++ b/SOURCES/0081-nss-sssd-returns-for-emtpy-home-directories.patch
@@ -0,0 +1,98 @@
+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
new file mode 100644
index 0000000..e619358
--- /dev/null
+++ b/SOURCES/0082-PROXY-Copy-the-response-to-the-caller.patch
@@ -0,0 +1,57 @@
+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
new file mode 100644
index 0000000..6b167a4
--- /dev/null
+++ b/SOURCES/0083-Revert-IPA-use-forest-name-when-looking-up-the-Globa.patch
@@ -0,0 +1,29 @@
+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
new file mode 100644
index 0000000..904a923
--- /dev/null
+++ b/SOURCES/0084-ipa-use-only-the-global-catalog-service-of-the-fores.patch
@@ -0,0 +1,103 @@
+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
new file mode 100644
index 0000000..6765540
--- /dev/null
+++ b/SOURCES/0085-krb5_child-fix-permissions-during-SC-auth.patch
@@ -0,0 +1,138 @@
+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
new file mode 100644
index 0000000..078fe9f
--- /dev/null
+++ b/SOURCES/0086-MAN-Explicitly-state-that-not-all-generic-domain-opt.patch
@@ -0,0 +1,36 @@
+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
new file mode 100644
index 0000000..dcc0d83
--- /dev/null
+++ b/SOURCES/0087-KCM-Deleting-a-non-existent-ccache-should-not-yield-.patch
@@ -0,0 +1,38 @@
+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
new file mode 100644
index 0000000..c6d5ef0
--- /dev/null
+++ b/SOURCES/0088-confdb-Always-read-snippet-files.patch
@@ -0,0 +1,220 @@
+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
new file mode 100644
index 0000000..a148912
--- /dev/null
+++ b/SOURCES/0089-CONFDB-Remove-old-libini-support.patch
@@ -0,0 +1,269 @@
+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
new file mode 100644
index 0000000..3d5d23e
--- /dev/null
+++ b/SOURCES/0090-idmap_sss-improve-man-page.patch
@@ -0,0 +1,54 @@
+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
new file mode 100644
index 0000000..c6e8679
--- /dev/null
+++ b/SOURCES/0091-sbus-allow-access-for-sssd-user.patch
@@ -0,0 +1,61 @@
+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
new file mode 100644
index 0000000..dd010bf
--- /dev/null
+++ b/SOURCES/0092-sbus-use-120-second-default-timeout.patch
@@ -0,0 +1,50 @@
+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
new file mode 100644
index 0000000..ad00b4c
--- /dev/null
+++ b/SOURCES/0093-ifp-extraAttributes-is-UnknownProperty.patch
@@ -0,0 +1,113 @@
+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
new file mode 100644
index 0000000..b62c72f
--- /dev/null
+++ b/SOURCES/0094-AD-IPA-Reset-subdomain-service-name-not-domain-name.patch
@@ -0,0 +1,140 @@
+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
new file mode 100644
index 0000000..e749f70
--- /dev/null
+++ b/SOURCES/0095-IPA-Add-explicit-return-after-tevent_req_error.patch
@@ -0,0 +1,37 @@
+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
new file mode 100644
index 0000000..395e1a9
--- /dev/null
+++ b/SOURCES/0096-KCM-Return-a-valid-tevent-error-code-if-a-request-ca.patch
@@ -0,0 +1,35 @@
+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
new file mode 100644
index 0000000..564122b
--- /dev/null
+++ b/SOURCES/0097-KCM-Allow-representing-ccaches-with-a-NULL-principal.patch
@@ -0,0 +1,281 @@
+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
new file mode 100644
index 0000000..c98c83c
--- /dev/null
+++ b/SOURCES/0098-KCM-Create-an-empty-ccache-on-switch-to-a-non-existi.patch
@@ -0,0 +1,244 @@
+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
new file mode 100644
index 0000000..7c7551c
--- /dev/null
+++ b/SOURCES/0099-PAM-use-user-name-hint-if-any-domain-has-set-it.patch
@@ -0,0 +1,67 @@
+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/0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec b/SOURCES/0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
new file mode 100644
index 0000000..f24afe3
--- /dev/null
+++ b/SOURCES/0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
@@ -0,0 +1,26 @@
+From 8d38a4b28ab7af15406b244910f369ba1aff02db Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 30 Oct 2014 15:59:17 +0100
+Subject: [PATCH 93/93] NOUPSTREAM: Default to root if sssd user is not
+ specified
+
+---
+ src/monitor/monitor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
+index 0dea327213a1ad04b6f69c0ffb0fb87254420796..20b4aef4ee94fd42de1585d7d7c2e01ea01845ac 100644
+--- a/src/monitor/monitor.c
++++ b/src/monitor/monitor.c
+@@ -925,7 +925,7 @@ static int get_service_user(struct mt_ctx *ctx)
+ 
+     ret = confdb_get_string(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
+                             CONFDB_MONITOR_USER_RUNAS,
+-                            SSSD_USER, &user_str);
++                            "root", &user_str);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get the user to run as\n");
+         return ret;
+-- 
+1.9.3
+
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
new file mode 100644
index 0000000..6ecbcdd
--- /dev/null
+++ b/SPECS/sssd.spec
@@ -0,0 +1,2920 @@
+# we don't want to provide private python extension libs
+%define __provides_exclude_from %{python3_sitearch}/.*\.so$|%{_libdir}/%{name}/modules/libwbclient.so.*$
+
+# SSSD fails to build with -Wl,-z,defs
+%undefine _strict_symbol_defs_build
+
+%define _hardened_build 1
+
+%global install_pcscd_polkit_rule 1
+
+# Determine the location of the LDB modules directory
+%global ldb_modulesdir %(pkg-config --variable=modulesdir ldb)
+%global ldb_version 1.2.0
+
+%global enable_systemtap 1
+    %global enable_systemtap_opt --enable-systemtap
+
+%global libwbc_alternatives_version 0.14
+%global libwbc_lib_version %{libwbc_alternatives_version}.0
+%global libwbc_alternatives_suffix %nil
+%if 0%{?__isa_bits} == 64
+%global libwbc_alternatives_suffix -64
+%endif
+
+Name: sssd
+Version: 2.0.0
+Release: 43%{?dist}
+Group: Applications/System
+Summary: System Security Services Daemon
+License: GPLv3+
+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
+
+### Downstream Patches ###
+
+#This patch should not be removed in RHEL-8
+Patch999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
+
+### Dependencies ###
+
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-ldap = %{version}-%{release}
+Requires: sssd-krb5 = %{version}-%{release}
+Requires: sssd-ipa = %{version}-%{release}
+Requires: sssd-ad = %{version}-%{release}
+Recommends: sssd-proxy = %{version}-%{release}
+Requires: python3-sssdconfig = %{version}-%{release}
+Suggests: sssd-dbus = %{version}-%{release}
+
+%global servicename sssd
+%global sssdstatedir %{_localstatedir}/lib/sss
+%global dbpath %{sssdstatedir}/db
+%global keytabdir %{sssdstatedir}/keytabs
+%global pipepath %{sssdstatedir}/pipes
+%global mcpath %{sssdstatedir}/mc
+%global pubconfpath %{sssdstatedir}/pubconf
+%global gpocachepath %{sssdstatedir}/gpo_cache
+%global secdbpath %{sssdstatedir}/secrets
+%global deskprofilepath %{sssdstatedir}/deskprofile
+
+### Build Dependencies ###
+
+BuildRequires: autoconf
+BuildRequires: automake
+BuildRequires: libtool
+BuildRequires: m4
+BuildRequires: gcc
+BuildRequires: popt-devel
+BuildRequires: libtalloc-devel
+BuildRequires: libtevent-devel
+BuildRequires: libtdb-devel
+BuildRequires: libldb-devel >= %{ldb_version}
+BuildRequires: libdhash-devel >= 0.4.2
+BuildRequires: libcollection-devel
+BuildRequires: libini_config-devel >= 1.1
+BuildRequires: dbus-devel
+BuildRequires: dbus-libs
+BuildRequires: openldap-devel
+BuildRequires: pam-devel
+BuildRequires: nss-devel
+BuildRequires: nspr-devel
+BuildRequires: pcre-devel
+BuildRequires: libxslt
+BuildRequires: libxml2
+BuildRequires: docbook-style-xsl
+BuildRequires: krb5-devel
+BuildRequires: c-ares-devel
+BuildRequires: python3-devel
+BuildRequires: check-devel
+BuildRequires: doxygen
+BuildRequires: libselinux-devel
+BuildRequires: libsemanage-devel
+BuildRequires: bind-utils
+BuildRequires: keyutils-libs-devel
+BuildRequires: gettext-devel
+BuildRequires: pkgconfig
+BuildRequires: diffstat
+BuildRequires: findutils
+BuildRequires: glib2-devel
+BuildRequires: selinux-policy-targeted
+BuildRequires: libcmocka-devel >= 1.0.0
+BuildRequires: uid_wrapper
+BuildRequires: nss_wrapper
+BuildRequires: p11-kit-devel
+BuildRequires: openssl-devel
+BuildRequires: gnutls-utils
+BuildRequires: softhsm >= 2.1.0
+BuildRequires: openssl
+BuildRequires: openssh
+BuildRequires: libnl3-devel
+BuildRequires: systemd-devel
+BuildRequires: systemd
+BuildRequires: cifs-utils-devel
+BuildRequires: libnfsidmap-devel
+BuildRequires: samba4-devel
+BuildRequires: libsmbclient-devel
+BuildRequires: samba-winbind
+BuildRequires: systemtap-sdt-devel
+BuildRequires: libuuid-devel
+BuildRequires: jansson-devel
+BuildRequires: gdm-pam-extensions-devel
+
+%description
+Provides a set of daemons to manage access to remote directories and
+authentication mechanisms. It provides an NSS and PAM interface toward
+the system and a plug-gable back-end system to connect to multiple different
+account sources. It is also the basis to provide client auditing and policy
+services for projects like FreeIPA.
+
+The sssd sub-package is a meta-package that contains the daemon as well as all
+the existing back ends.
+
+%package common
+Summary: Common files for the SSSD
+Group: Applications/System
+License: GPLv3+
+# Conflicts
+Conflicts: selinux-policy < 3.10.0-46
+Conflicts: sssd < 1.10.0-8%{?dist}.beta2
+# Requires
+# Explicitly require RHEL-8.0 versions of the Samba libraries
+# in order to prevent untested combinations of a new SSSD and
+# older libraries. See e.g. rhbz#1593756
+Requires: libtalloc >= 2.1.14-1
+Requires: libtevent >= 0.9.37-1
+Requires: libldb >= 1.4.2-1
+Requires: libtdb >= 1.3.16-1
+# due to ABI changes in 1.1.30/1.2.0
+Requires: libldb >= %{ldb_version}
+Requires: sssd-client%{?_isa} = %{version}-%{release}
+Recommends: libsss_sudo = %{version}-%{release}
+Recommends: libsss_autofs%{?_isa} = %{version}-%{release}
+Recommends: sssd-nfs-idmap = %{version}-%{release}
+Requires: libsss_idmap = %{version}-%{release}
+Requires(pre): shadow-utils
+%{?systemd_requires}
+
+### Provides ###
+Provides: libsss_sudo-devel = %{version}-%{release}
+Obsoletes: libsss_sudo-devel <= 1.10.0-7%{?dist}.beta1
+
+%description common
+Common files for the SSSD. The common package includes all the files needed
+to run a particular back end, however, the back ends are packaged in separate
+sub-packages such as sssd-ldap.
+
+%package client
+Summary: SSSD Client libraries for NSS and PAM
+Group: Applications/System
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Requires(post):  /usr/sbin/alternatives
+Requires(preun): /usr/sbin/alternatives
+
+%description client
+Provides the libraries needed by the PAM and NSS stacks to connect to the SSSD
+service.
+
+%package -n libsss_sudo
+Summary: A library to allow communication between SUDO and SSSD
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Conflicts: sssd-common < %{version}-%{release}
+
+%description -n libsss_sudo
+A utility library to allow communication between SUDO and SSSD
+
+%package -n libsss_autofs
+Summary: A library to allow communication between Autofs and SSSD
+Group: Development/Libraries
+License: LGPLv3+
+Conflicts: sssd-common < %{version}-%{release}
+
+%description -n libsss_autofs
+A utility library to allow communication between Autofs and SSSD
+
+%package tools
+Summary: Userspace tools for use with the SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+# required by sss_obfuscate
+Requires: python3-sss = %{version}-%{release}
+Requires: python3-sssdconfig = %{version}-%{release}
+
+%description tools
+Provides userspace tools for manipulating users, groups, and nested groups in
+SSSD when using id_provider = local in /etc/sssd/sssd.conf.
+
+Also provides several other administrative tools:
+    * sss_debuglevel to change the debug level on the fly
+    * sss_seed which pre-creates a user entry for use in kickstarts
+    * sss_obfuscate for generating an obfuscated LDAP password
+    * sssctl -- an sssd status and control utility
+
+%package -n python3-sssdconfig
+Summary: SSSD and IPA configuration file manipulation classes and functions
+Group: Applications/System
+License: GPLv3+
+BuildArch: noarch
+%{?python_provide:%python_provide python3-sssdconfig}
+
+%description -n python3-sssdconfig
+Provides python3 files for manipulation SSSD and IPA configuration files.
+
+%package -n python3-sss
+Summary: Python3 bindings for sssd
+Group: Development/Libraries
+License: LGPLv3+
+Requires: sssd-common = %{version}-%{release}
+%{?python_provide:%python_provide python3-sss}
+
+%description -n python3-sss
+Provides python3 module for manipulating users, groups, and nested groups in
+SSSD when using id_provider = local in /etc/sssd/sssd.conf.
+
+Also provides several other useful python3 bindings:
+    * function for retrieving list of groups user belongs to.
+    * class for obfuscation of passwords
+
+%package -n python3-sss-murmur
+Summary: Python3 bindings for murmur hash function
+Group: Development/Libraries
+License: LGPLv3+
+%{?python_provide:%python_provide python3-sss-murmur}
+
+%description -n python3-sss-murmur
+Provides python3 module for calculating the murmur hash version 3
+
+%package ldap
+Summary: The LDAP back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+
+%description ldap
+Provides the LDAP back end that the SSSD can utilize to fetch identity data
+from and authenticate against an LDAP server.
+
+%package krb5-common
+Summary: SSSD helpers needed for Kerberos and GSSAPI authentication
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: cyrus-sasl-gssapi%{?_isa}
+Requires: sssd-common = %{version}-%{release}
+Requires(pre): shadow-utils
+
+%description krb5-common
+Provides helper processes that the LDAP and Kerberos back ends can use for
+Kerberos user or host authentication.
+
+%package krb5
+Summary: The Kerberos authentication back end for the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+
+%description krb5
+Provides the Kerberos back end that the SSSD can utilize authenticate
+against a Kerberos server.
+
+%package common-pac
+Summary: Common files needed for supporting PAC processing
+Group: Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+
+%description common-pac
+Provides common files needed by SSSD providers such as IPA and Active Directory
+for handling Kerberos PACs.
+
+%package ipa
+Summary: The IPA back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+Requires: libipa_hbac%{?_isa} = %{version}-%{release}
+Recommends: bind-utils
+Requires: sssd-common-pac = %{version}-%{release}
+Requires(pre): shadow-utils
+
+%description ipa
+Provides the IPA back end that the SSSD can utilize to fetch identity data
+from and authenticate against an IPA server.
+
+%package ad
+Summary: The AD back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires: sssd-krb5-common = %{version}-%{release}
+Requires: sssd-common-pac = %{version}-%{release}
+Recommends: bind-utils
+Recommends: adcli
+Suggests: sssd-libwbclient = %{version}-%{release}
+Suggests: sssd-winbind-idmap = %{version}-%{release}
+
+%description ad
+Provides the Active Directory back end that the SSSD can utilize to fetch
+identity data from and authenticate against an Active Directory server.
+
+%package proxy
+Summary: The proxy back end of the SSSD
+Group: Applications/System
+License: GPLv3+
+Conflicts: sssd < 1.10.0-8.beta2
+Requires: sssd-common = %{version}-%{release}
+Requires(pre): shadow-utils
+
+%description proxy
+Provides the proxy back end which can be used to wrap an existing NSS and/or
+PAM modules to leverage SSSD caching.
+
+%package -n libsss_idmap
+Summary: FreeIPA Idmap library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_idmap
+Utility library to convert SIDs to Unix uids and gids
+
+%package -n libsss_idmap-devel
+Summary: FreeIPA Idmap library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_idmap = %{version}-%{release}
+
+%description -n libsss_idmap-devel
+Utility library to SIDs to Unix uids and gids
+
+%package -n libipa_hbac
+Summary: FreeIPA HBAC Evaluator library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libipa_hbac
+Utility library to validate FreeIPA HBAC rules for authorization requests
+
+%package -n libipa_hbac-devel
+Summary: FreeIPA HBAC Evaluator library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libipa_hbac = %{version}-%{release}
+
+%description -n libipa_hbac-devel
+Utility library to validate FreeIPA HBAC rules for authorization requests
+
+%package -n python3-libipa_hbac
+Summary: Python3 bindings for the FreeIPA HBAC Evaluator library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libipa_hbac = %{version}-%{release}
+%{?python_provide:%python_provide python3-libipa_hbac}
+
+%description -n python3-libipa_hbac
+The python3-libipa_hbac contains the bindings so that libipa_hbac can be
+used by Python applications.
+
+%package -n libsss_nss_idmap
+Summary: Library for SID and certificate based lookups
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_nss_idmap
+Utility library for SID and certificate based lookups
+
+%package -n libsss_nss_idmap-devel
+Summary: Library for SID and certificate based lookups
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_nss_idmap = %{version}-%{release}
+
+%description -n libsss_nss_idmap-devel
+Utility library for SID and certificate based lookups
+
+%package -n python3-libsss_nss_idmap
+Summary: Python3 bindings for libsss_nss_idmap
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_nss_idmap = %{version}-%{release}
+%{?python_provide:%python_provide python3-libsss_nss_idmap}
+
+%description -n python3-libsss_nss_idmap
+The python3-libsss_nss_idmap contains the bindings so that libsss_nss_idmap can
+be used by Python applications.
+
+%package dbus
+Summary: The D-Bus responder of the SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+%{?systemd_requires}
+
+%description dbus
+Provides the D-Bus responder of the SSSD, called the InfoPipe, that allows
+the information from the SSSD to be transmitted over the system bus.
+
+%if (0%{?install_pcscd_polkit_rule} == 1)
+%package polkit-rules
+Summary: Rules for polkit integration for SSSD
+Group: Applications/System
+License: GPLv3+
+Requires: polkit >= 0.106
+Requires: sssd-common = %{version}-%{release}
+
+%description polkit-rules
+Provides rules for polkit integration with SSSD. This is required
+for smartcard support.
+%endif
+
+%package -n libsss_simpleifp
+Summary: The SSSD D-Bus responder helper library
+Group: Development/Libraries
+License: GPLv3+
+Requires: sssd-dbus = %{version}-%{release}
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_simpleifp
+Provides library that simplifies D-Bus API for the SSSD InfoPipe responder.
+
+%package -n libsss_simpleifp-devel
+Summary: The SSSD D-Bus responder helper library
+Group: Development/Libraries
+License: GPLv3+
+Requires: dbus-devel
+Requires: libsss_simpleifp = %{version}-%{release}
+
+%description -n libsss_simpleifp-devel
+Provides library that simplifies D-Bus API for the SSSD InfoPipe responder.
+
+%package libwbclient
+Summary: The SSSD libwbclient implementation
+Group: Applications/System
+License: GPLv3+ and LGPLv3+
+Conflicts: libwbclient < 4.2.0-0.2.rc2
+Conflicts: sssd-common < %{version}-%{release}
+
+%description libwbclient
+The SSSD libwbclient implementation.
+
+%package libwbclient-devel
+Summary: Development libraries for the SSSD libwbclient implementation
+Group:  Development/Libraries
+License: GPLv3+ and LGPLv3+
+Requires: sssd-libwbclient = %{version}-%{release}
+Conflicts: libwbclient-devel < 4.2.0-0.2.rc2
+
+%description libwbclient-devel
+Development libraries for the SSSD libwbclient implementation.
+
+%package winbind-idmap
+Summary: SSSD's idmap_sss Backend for Winbind
+Group:  Applications/System
+License: GPLv3+ and LGPLv3+
+Conflicts: sssd-common < %{version}-%{release}
+
+%description winbind-idmap
+The idmap_sss module provides a way for Winbind to call SSSD to map UIDs/GIDs
+and SIDs.
+
+%package nfs-idmap
+Summary: SSSD plug-in for NFSv4 rpc.idmapd
+Group:  Applications/System
+License: GPLv3+
+Conflicts: sssd-common < %{version}-%{release}
+
+%description nfs-idmap
+The libnfsidmap sssd module provides a way for rpc.idmapd to call SSSD to map
+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
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Conflicts: sssd-common < %{version}-%{release}
+
+%description -n libsss_certmap
+Library to map certificates to users based on rules
+
+%package -n libsss_certmap-devel
+Summary: SSSD Certficate Mapping Library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_certmap = %{version}-%{release}
+
+%description -n libsss_certmap-devel
+Library to map certificates to users based on rules
+
+%package kcm
+Summary: An implementation of a Kerberos KCM server
+Group:  Applications/System
+License: GPLv3+
+Requires: sssd-common = %{version}-%{release}
+%{?systemd_requires}
+
+%description kcm
+An implementation of a Kerberos KCM server. Use this package if you want to
+use the KCM: Kerberos credentials cache.
+
+%prep
+# Update timestamps on the files touched by a patch, to avoid non-equal
+# .pyc/.pyo files across the multilib peers within a build, where "Level"
+# is the patch prefix option (e.g. -p1)
+# Taken from specfile for python-simplejson
+UpdateTimestamps() {
+  Level=$1
+  PatchFile=$2
+
+  # Locate the affected files:
+  for f in $(diffstat $Level -l $PatchFile); do
+    # Set the files to have the same timestamp as that of the patch:
+    touch -r $PatchFile $f
+  done
+}
+
+%setup -q
+
+for p in %patches ; do
+    %__patch -p1 -i $p
+    UpdateTimestamps -p1 $p
+done
+
+%build
+autoreconf -ivf
+
+%configure \
+    --with-test-dir=/dev/shm \
+    --with-db-path=%{dbpath} \
+    --with-mcache-path=%{mcpath} \
+    --with-pipe-path=%{pipepath} \
+    --with-pubconf-path=%{pubconfpath} \
+    --with-gpo-cache-path=%{gpocachepath} \
+    --with-init-dir=%{_initrddir} \
+    --with-krb5-rcache-dir=%{_localstatedir}/cache/krb5rcache \
+    --enable-nsslibdir=%{_libdir} \
+    --enable-pammoddir=%{_libdir}/security \
+    --enable-nfsidmaplibdir=%{_libdir}/libnfsidmap \
+    --disable-static \
+    --with-crypto=libcrypto \
+    --disable-rpath \
+    --with-initscript=systemd \
+    --with-syslog=journald \
+    --enable-sss-default-nss-plugin \
+    --enable-files-domain \
+    --without-python2-bindings \
+    --with-sssd-user=sssd \
+    %{?with_cifs_utils_plugin_option} \
+    %{?enable_systemtap_opt} \
+
+
+make %{?_smp_mflags} all docs
+
+%check
+export CK_TIMEOUT_MULTIPLIER=10
+make %{?_smp_mflags} check VERBOSE=yes
+unset CK_TIMEOUT_MULTIPLIER
+
+%install
+
+sed -i -e 's:/usr/bin/python:%{__python3}:' src/tools/sss_obfuscate
+
+make install DESTDIR=$RPM_BUILD_ROOT
+
+if [ ! -f $RPM_BUILD_ROOT/%{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version} ]
+then
+    echo "Expected libwbclient version not found, please check if version has changed."
+    exit -1
+fi
+
+# Prepare language files
+/usr/lib/rpm/find-lang.sh $RPM_BUILD_ROOT sssd
+
+# Copy default logrotate file
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d
+install -m644 src/examples/logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/sssd
+
+# Make sure SSSD is able to run on read-only root
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rwtab.d
+install -m644 src/examples/rwtab $RPM_BUILD_ROOT%{_sysconfdir}/rwtab.d/sssd
+
+# Kerberos KCM credential cache by default
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/krb5.conf.d
+cp $RPM_BUILD_ROOT/%{_datadir}/sssd-kcm/kcm_default_ccache \
+   $RPM_BUILD_ROOT/%{_sysconfdir}/krb5.conf.d/kcm_default_ccache
+
+# Create directory for cifs-idmap alternative
+# Otherwise this directory could not be owned by sssd-client
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/cifs-utils
+
+# Remove .la files created by libtool
+find $RPM_BUILD_ROOT -name "*.la" -exec rm -f {} \;
+
+# Suppress developer-only documentation
+rm -Rf ${RPM_BUILD_ROOT}/%{_docdir}/%{name}
+
+# Older versions of rpmbuild can only handle one -f option
+# So we need to append to the sssd*.lang file
+for file in `ls $RPM_BUILD_ROOT/%{python3_sitelib}/*.egg-info 2> /dev/null`
+do
+    echo %{python3_sitelib}/`basename $file` >> python3_sssdconfig.lang
+done
+
+touch sssd.lang
+for subpackage in sssd_ldap sssd_krb5 sssd_ipa sssd_ad sssd_proxy sssd_tools \
+                  sssd_client sssd_dbus sssd_nfs_idmap sssd_winbind_idmap \
+                  libsss_certmap sssd_kcm
+do
+    touch $subpackage.lang
+done
+
+for man in `find $RPM_BUILD_ROOT/%{_mandir}/??/man?/ -type f | sed -e "s#$RPM_BUILD_ROOT/%{_mandir}/##"`
+do
+    lang=`echo $man | cut -c 1-2`
+    case `basename $man` in
+        sss_cache*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang
+            ;;
+        sss_ssh*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang
+            ;;
+        sss_rpcidmapd*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_nfs_idmap.lang
+            ;;
+        sss_*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang
+            ;;
+        sssctl*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang
+            ;;
+        sssd_krb5_*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang
+            ;;
+        pam_sss*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang
+            ;;
+        sssd-ldap*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_ldap.lang
+            ;;
+        sssd-krb5*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_krb5.lang
+            ;;
+        sssd-ipa*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_ipa.lang
+            ;;
+        sssd-ad*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_ad.lang
+            ;;
+        sssd-proxy*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_proxy.lang
+            ;;
+        sssd-ifp*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_dbus.lang
+            ;;
+        sssd-kcm*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_kcm.lang
+            ;;
+        idmap_sss*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_winbind_idmap.lang
+            ;;
+        sss-certmap*)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> libsss_certmap.lang
+            ;;
+        *)
+            echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang
+            ;;
+    esac
+done
+
+# Print these to the rpmbuild log
+echo "sssd.lang:"
+cat sssd.lang
+
+echo "python3_sssdconfig.lang:"
+cat python3_sssdconfig.lang
+
+for subpackage in sssd_ldap sssd_krb5 sssd_ipa sssd_ad sssd_proxy sssd_tools \
+                  sssd_client sssd_dbus sssd_nfs_idmap sssd_winbind_idmap \
+                  libsss_certmap sssd_kcm
+do
+    echo "$subpackage.lang:"
+    cat $subpackage.lang
+done
+
+%files
+%defattr(-,root,root,-)
+%license COPYING
+
+%files common -f sssd.lang
+%defattr(-,root,root,-)
+%license COPYING
+%doc src/examples/sssd-example.conf
+%{_sbindir}/sssd
+%{_unitdir}/sssd.service
+%{_unitdir}/sssd-autofs.socket
+%{_unitdir}/sssd-autofs.service
+%{_unitdir}/sssd-nss.socket
+%{_unitdir}/sssd-nss.service
+%{_unitdir}/sssd-pac.socket
+%{_unitdir}/sssd-pac.service
+%{_unitdir}/sssd-pam.socket
+%{_unitdir}/sssd-pam-priv.socket
+%{_unitdir}/sssd-pam.service
+%{_unitdir}/sssd-ssh.socket
+%{_unitdir}/sssd-ssh.service
+%{_unitdir}/sssd-sudo.socket
+%{_unitdir}/sssd-sudo.service
+
+%dir %{_libexecdir}/%{servicename}
+%{_libexecdir}/%{servicename}/sssd_be
+%{_libexecdir}/%{servicename}/sssd_nss
+%{_libexecdir}/%{servicename}/sssd_pam
+%{_libexecdir}/%{servicename}/sssd_autofs
+%{_libexecdir}/%{servicename}/sssd_ssh
+%{_libexecdir}/%{servicename}/sssd_sudo
+%{_libexecdir}/%{servicename}/p11_child
+%{_libexecdir}/%{servicename}/sssd_check_socket_activated_responders
+
+%dir %{_libdir}/%{name}
+# The files provider is intentionally packaged in -common
+%{_libdir}/%{name}/libsss_files.so
+%{_libdir}/%{name}/libsss_simple.so
+
+#Internal shared libraries
+%{_libdir}/%{name}/libsss_child.so
+%{_libdir}/%{name}/libsss_crypt.so
+%{_libdir}/%{name}/libsss_cert.so
+%{_libdir}/%{name}/libsss_debug.so
+%{_libdir}/%{name}/libsss_krb5_common.so
+%{_libdir}/%{name}/libsss_ldap_common.so
+%{_libdir}/%{name}/libsss_util.so
+%{_libdir}/%{name}/libsss_semanage.so
+%{_libdir}/%{name}/libifp_iface.so
+%{_libdir}/%{name}/libifp_iface_sync.so
+%{_libdir}/%{name}/libsss_iface.so
+%{_libdir}/%{name}/libsss_iface_sync.so
+%{_libdir}/%{name}/libsss_sbus.so
+%{_libdir}/%{name}/libsss_sbus_sync.so
+
+%{ldb_modulesdir}/memberof.so
+%{_bindir}/sss_ssh_authorizedkeys
+%{_bindir}/sss_ssh_knownhostsproxy
+%{_sbindir}/sss_cache
+%{_libexecdir}/%{servicename}/sss_signal
+
+%dir %{sssdstatedir}
+%dir %{_localstatedir}/cache/krb5rcache
+%attr(700,sssd,sssd) %dir %{dbpath}
+%attr(755,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
+%attr(755,sssd,sssd) %dir %{pipepath}
+%attr(750,sssd,root) %dir %{pipepath}/private
+%attr(755,sssd,sssd) %dir %{pubconfpath}
+%attr(755,sssd,sssd) %dir %{gpocachepath}
+%attr(750,sssd,sssd) %dir %{_var}/log/%{name}
+%attr(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
+%dir %{_sysconfdir}/logrotate.d
+%config(noreplace) %{_sysconfdir}/logrotate.d/sssd
+%dir %{_sysconfdir}/rwtab.d
+%config(noreplace) %{_sysconfdir}/rwtab.d/sssd
+%dir %{_datadir}/sssd
+%{_sysconfdir}/pam.d/sssd-shadowutils
+%dir %{_libdir}/%{name}/conf
+%{_libdir}/%{name}/conf/sssd.conf
+
+%{_datadir}/sssd/cfg_rules.ini
+%{_datadir}/sssd/sssd.api.conf
+%{_datadir}/sssd/sssd.api.d
+%{_mandir}/man1/sss_ssh_authorizedkeys.1*
+%{_mandir}/man1/sss_ssh_knownhostsproxy.1*
+%{_mandir}/man5/sssd.conf.5*
+%{_mandir}/man5/sssd-files.5*
+%{_mandir}/man5/sssd-simple.5*
+%{_mandir}/man5/sssd-sudo.5*
+%{_mandir}/man5/sssd-session-recording.5*
+%{_mandir}/man8/sssd.8*
+%{_mandir}/man8/sss_cache.8*
+%dir %{_datadir}/sssd/systemtap
+%{_datadir}/sssd/systemtap/id_perf.stp
+%{_datadir}/sssd/systemtap/nested_group_perf.stp
+%{_datadir}/sssd/systemtap/dp_request.stp
+%dir %{_datadir}/systemtap
+%dir %{_datadir}/systemtap/tapset
+%{_datadir}/systemtap/tapset/sssd.stp
+%{_datadir}/systemtap/tapset/sssd_functions.stp
+%{_mandir}/man5/sssd-systemtap.5*
+
+%if (0%{?install_pcscd_polkit_rule} == 1)
+%files polkit-rules
+%{_datadir}/polkit-1/rules.d/*
+%endif
+
+%files ldap -f sssd_ldap.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libdir}/%{name}/libsss_ldap.so
+%{_mandir}/man5/sssd-ldap.5*
+
+%files krb5-common
+%defattr(-,root,root,-)
+%license COPYING
+%attr(755,sssd,sssd) %dir %{pubconfpath}/krb5.include.d
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child
+
+%files krb5 -f sssd_krb5.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libdir}/%{name}/libsss_krb5.so
+%{_mandir}/man5/sssd-krb5.5*
+
+%files common-pac
+%defattr(-,root,root,-)
+%license COPYING
+%{_libexecdir}/%{servicename}/sssd_pac
+
+%files ipa -f sssd_ipa.lang
+%defattr(-,root,root,-)
+%license COPYING
+%attr(700,sssd,sssd) %dir %{keytabdir}
+%{_libdir}/%{name}/libsss_ipa.so
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child
+%{_mandir}/man5/sssd-ipa.5*
+
+%files ad -f sssd_ad.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libdir}/%{name}/libsss_ad.so
+%{_libexecdir}/%{servicename}/gpo_child
+%{_mandir}/man5/sssd-ad.5*
+
+%files proxy
+%defattr(-,root,root,-)
+%license COPYING
+%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/proxy_child
+%{_libdir}/%{name}/libsss_proxy.so
+
+%files dbus -f sssd_dbus.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_libexecdir}/%{servicename}/sssd_ifp
+%{_mandir}/man5/sssd-ifp.5*
+%{_unitdir}/sssd-ifp.service
+# InfoPipe DBus plumbing
+%{_sysconfdir}/dbus-1/system.d/org.freedesktop.sssd.infopipe.conf
+%{_datadir}/dbus-1/system-services/org.freedesktop.sssd.infopipe.service
+
+%files -n libsss_simpleifp
+%defattr(-,root,root,-)
+%{_libdir}/libsss_simpleifp.so.*
+
+%files -n libsss_simpleifp-devel
+%defattr(-,root,root,-)
+%doc sss_simpleifp_doc/html
+%{_includedir}/sss_sifp.h
+%{_includedir}/sss_sifp_dbus.h
+%{_libdir}/libsss_simpleifp.so
+%{_libdir}/pkgconfig/sss_simpleifp.pc
+
+%files client -f sssd_client.lang
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libnss_sss.so.2
+%{_libdir}/security/pam_sss.so
+%{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
+%{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
+%dir %{_libdir}/cifs-utils
+%{_libdir}/cifs-utils/cifs_idmap_sss.so
+%dir %{_sysconfdir}/cifs-utils
+%ghost %{_sysconfdir}/cifs-utils/idmap-plugin
+%dir %{_libdir}/%{name}
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/sssd_krb5_localauth_plugin.so
+%{_mandir}/man8/pam_sss.8*
+%{_mandir}/man8/sssd_krb5_locator_plugin.8*
+
+%files -n libsss_sudo
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING
+%{_libdir}/libsss_sudo.so*
+
+%files -n libsss_autofs
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/libsss_autofs.so
+
+%files tools -f sssd_tools.lang
+%defattr(-,root,root,-)
+%license COPYING
+%{_sbindir}/sss_obfuscate
+%{_sbindir}/sss_override
+%{_sbindir}/sss_debuglevel
+%{_sbindir}/sss_seed
+%{_sbindir}/sssctl
+%{_mandir}/man8/sss_obfuscate.8*
+%{_mandir}/man8/sss_override.8*
+%{_mandir}/man8/sss_debuglevel.8*
+%{_mandir}/man8/sss_seed.8*
+%{_mandir}/man8/sssctl.8*
+
+%files -n python3-sssdconfig -f python3_sssdconfig.lang
+%defattr(-,root,root,-)
+%dir %{python3_sitelib}/SSSDConfig
+%{python3_sitelib}/SSSDConfig/*.py*
+%dir %{python3_sitelib}/SSSDConfig/__pycache__
+%{python3_sitelib}/SSSDConfig/__pycache__/*.py*
+
+%files -n python3-sss
+%defattr(-,root,root,-)
+%{python3_sitearch}/pysss.so
+
+%files -n python3-sss-murmur
+%defattr(-,root,root,-)
+%{python3_sitearch}/pysss_murmur.so
+
+%files -n libsss_idmap
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_idmap.so.*
+
+%files -n libsss_idmap-devel
+%defattr(-,root,root,-)
+%doc idmap_doc/html
+%{_includedir}/sss_idmap.h
+%{_libdir}/libsss_idmap.so
+%{_libdir}/pkgconfig/sss_idmap.pc
+
+%files -n libipa_hbac
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libipa_hbac.so.*
+
+%files -n libipa_hbac-devel
+%defattr(-,root,root,-)
+%doc hbac_doc/html
+%{_includedir}/ipa_hbac.h
+%{_libdir}/libipa_hbac.so
+%{_libdir}/pkgconfig/ipa_hbac.pc
+
+%files -n libsss_nss_idmap
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_nss_idmap.so.*
+
+%files -n libsss_nss_idmap-devel
+%defattr(-,root,root,-)
+%doc nss_idmap_doc/html
+%{_includedir}/sss_nss_idmap.h
+%{_libdir}/libsss_nss_idmap.so
+%{_libdir}/pkgconfig/sss_nss_idmap.pc
+
+%files -n python3-libsss_nss_idmap
+%defattr(-,root,root,-)
+%{python3_sitearch}/pysss_nss_idmap.so
+
+%files -n python3-libipa_hbac
+%defattr(-,root,root,-)
+%{python3_sitearch}/pyhbac.so
+
+%files libwbclient
+%defattr(-,root,root,-)
+%dir %{_libdir}/%{name}
+%dir %{_libdir}/%{name}/modules
+%{_libdir}/%{name}/modules/libwbclient.so.*
+
+%files libwbclient-devel
+%defattr(-,root,root,-)
+%{_includedir}/wbclient_sssd.h
+%{_libdir}/%{name}/modules/libwbclient.so
+%{_libdir}/pkgconfig/wbclient_sssd.pc
+
+%files winbind-idmap -f sssd_winbind_idmap.lang
+%dir %{_libdir}/samba/idmap
+%{_libdir}/samba/idmap/sss.so
+%{_mandir}/man8/idmap_sss.8*
+
+%files nfs-idmap -f sssd_nfs_idmap.lang
+%{_mandir}/man5/sss_rpcidmapd.5*
+%{_libdir}/libnfsidmap/sss.so
+
+%files -n libsss_certmap -f libsss_certmap.lang
+%defattr(-,root,root,-)
+%license src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_certmap.so.*
+%{_mandir}/man5/sss-certmap.5*
+
+%files -n libsss_certmap-devel
+%defattr(-,root,root,-)
+%doc certmap_doc/html
+%{_includedir}/sss_certmap.h
+%{_libdir}/libsss_certmap.so
+%{_libdir}/pkgconfig/sss_certmap.pc
+
+%files kcm -f sssd_kcm.lang
+%{_libexecdir}/%{servicename}/sssd_kcm
+%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache
+%dir %{_datadir}/sssd-kcm
+%{_datadir}/sssd-kcm/kcm_default_ccache
+%{_unitdir}/sssd-kcm.socket
+%{_unitdir}/sssd-kcm.service
+%{_mandir}/man8/sssd-kcm.8*
+%{_libdir}/%{name}/libsss_secrets.so
+
+%pre ipa
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%pre krb5-common
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%pre common
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%pre proxy
+getent group sssd >/dev/null || groupadd -r sssd
+getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
+
+%post common
+%systemd_post sssd.service
+%systemd_post sssd-autofs.socket
+%systemd_post sssd-nss.socket
+%systemd_post sssd-pac.socket
+%systemd_post sssd-pam.socket
+%systemd_post sssd-pam-priv.socket
+%systemd_post sssd-ssh.socket
+%systemd_post sssd-sudo.socket
+
+%preun common
+%systemd_preun sssd.service
+%systemd_preun sssd-autofs.socket
+%systemd_preun sssd-nss.socket
+%systemd_preun sssd-pac.socket
+%systemd_preun sssd-pam.socket
+%systemd_preun sssd-pam-priv.socket
+%systemd_preun sssd-ssh.socket
+%systemd_preun sssd-sudo.socket
+
+%postun common
+%systemd_postun_with_restart sssd-autofs.socket
+%systemd_postun_with_restart sssd-autofs.service
+%systemd_postun_with_restart sssd-nss.socket
+%systemd_postun_with_restart sssd-nss.service
+%systemd_postun_with_restart sssd-pac.socket
+%systemd_postun_with_restart sssd-pac.service
+%systemd_postun_with_restart sssd-pam.socket
+%systemd_postun_with_restart sssd-pam-priv.socket
+%systemd_postun_with_restart sssd-pam.service
+%systemd_postun_with_restart sssd-ssh.socket
+%systemd_postun_with_restart sssd-ssh.service
+%systemd_postun_with_restart sssd-sudo.socket
+%systemd_postun_with_restart sssd-sudo.service
+
+%post dbus
+%systemd_post sssd-ifp.service
+
+%preun dbus
+%systemd_preun sssd-ifp.service
+
+%postun dbus
+%systemd_postun_with_restart sssd-ifp.service
+
+%post kcm
+%systemd_post sssd-kcm.socket
+
+%preun kcm
+%systemd_preun sssd-kcm.socket
+
+%postun kcm
+%systemd_postun_with_restart sssd-kcm.socket
+%systemd_postun_with_restart sssd-kcm.service
+
+%post client
+/sbin/ldconfig
+/usr/sbin/alternatives --install /etc/cifs-utils/idmap-plugin cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so 20
+
+%preun client
+if [ $1 -eq 0 ] ; then
+        /usr/sbin/alternatives --remove cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so
+fi
+
+%postun client -p /sbin/ldconfig
+
+%post -n libsss_sudo -p /sbin/ldconfig
+
+%postun -n libsss_sudo -p /sbin/ldconfig
+
+%post -n libipa_hbac -p /sbin/ldconfig
+
+%postun -n libipa_hbac -p /sbin/ldconfig
+
+%post -n libsss_idmap -p /sbin/ldconfig
+
+%postun -n libsss_idmap -p /sbin/ldconfig
+
+%post -n libsss_nss_idmap -p /sbin/ldconfig
+
+%postun -n libsss_nss_idmap -p /sbin/ldconfig
+
+%post -n libsss_simpleifp -p /sbin/ldconfig
+
+%postun -n libsss_simpleifp -p /sbin/ldconfig
+
+%post -n libsss_certmap -p /sbin/ldconfig
+
+%postun -n libsss_certmap -p /sbin/ldconfig
+
+%posttrans common
+%systemd_postun_with_restart sssd.service
+
+%posttrans libwbclient
+%{_sbindir}/update-alternatives \
+    --install %{_libdir}/libwbclient.so.%{libwbc_alternatives_version} \
+              libwbclient.so.%{libwbc_alternatives_version}%{libwbc_alternatives_suffix} \
+              %{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version} 5
+/sbin/ldconfig
+
+%preun libwbclient
+%{_sbindir}/update-alternatives \
+    --remove libwbclient.so.%{libwbc_alternatives_version}%{libwbc_alternatives_suffix} \
+             %{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version}
+/sbin/ldconfig
+
+%posttrans libwbclient-devel
+%{_sbindir}/update-alternatives --install %{_libdir}/libwbclient.so \
+                                libwbclient.so%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so 5
+
+%preun libwbclient-devel
+%{_sbindir}/update-alternatives --remove \
+                                libwbclient.so%{libwbc_alternatives_suffix} \
+                                %{_libdir}/%{name}/modules/libwbclient.so
+
+%changelog
+* Sun Feb 10 2019 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-43
+- Resolves: rhbz#1672780 - gdm login not prompting for username when smart
+                           card maps to multiple users
+
+* Fri Feb 08 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-42
+- Resolves: rhbz#1645291 - Perform some basic ccache initialization as part
+                           of gen_new to avoid a subsequent switch call
+                           failure
+
+* Thu Feb 07 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-41
+-Resolves: rhbz#1659498 - Re-setting the trusted AD domain fails due to wrong
+                          subdomain service name being used
+
+* Thu Feb 07 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-40
+-Resolves: rhbz#1660083 - extraAttributes is org.freedesktop.DBus.Error.
+                          UnknownProperty: Unknown property
+
+* Thu Feb 07 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-39
+- Resolves: rhbz#1661183 - SSSD 2.0 has drastically lower sbus timeout than
+                           1.x, this can result in time outs
+
+* Mon Jan 14 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-38
+- Resolves: rhbz#1578014 - sssd does not work under non-root user
+- Note: Actually the patches were in the 2.0.0-37, this one just adds this
+        changelog because it was missing.
+
+* Fri Jan 11 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-36
+- Resolves: rhbz#1652563 - incorrect example in the man page of idmap_sss
+                           suggests using * for backend sss
+
+* Fri Jan 11 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-35
+- Resolves: rhbz#1466503 - Snippets are not used when sssd.conf does not exist
+
+* Thu Jan 10 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-34
+- Resolves: rhbz#1622008 - Error message when IPA server uninstall calls
+                           kdestroy caused by KCM returning a wrong error
+                           code during the delete operation
+
+* Wed Jan 09 2019 Michal Židek <mzidek@redhat.com> - 2.0.0-33
+- Resolves: rhbz#1646113 - Missing concise documentation about valid options
+                           for sssd-files-provider
+
+* Mon Dec 17 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-32
+- Resolves: rhbz#1625670 - sssd needs to require a newer version of libtalloc
+            and libtevent to avoid an issue in GPO processing 
+
+* Sun Dec 16 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-31
+- Resolves: 1658813 - PKINIT with KCM does not work
+
+* Sun Dec 16 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-30
+- Resolves: 1657898 - SSSD must be cleared/restarted periodically in order to
+                      retrieve AD users through IPA Trust 
+
+* Sun Dec 16 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-29
+- Resolves: rhbz#1655459 - [abrt] [faf] sssd: raise():
+                           /usr/libexec/sssd/proxy_child killed by 6
+
+* Sun Dec 16 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-28
+- Resolves: rhbz#1652719 - [SECURITY] sssd returns '/' for emtpy home directories
+
+* Tue Dec 11 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-27
+- Resolves: rhbz#1657979 - SSSD's LDAP authentication provider does not work
+                           if ID provider is authenticated with GSSAPI
+
+* Tue Dec 11 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-26
+- Resolves: rhbz#1657980 - sssd_nss memory leak
+
+* Tue Dec 11 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-25
+- Resolves: rhbz#1645566 - SSSD 2.x does not sanitize domain name properly
+                           for D-bus, resulting in a crash
+
+* Tue Dec 04 2018 Michal Židek <mzidek@redhat.com> - 2.0.0-24
+- Resolves: rhbz#1646168 - sssctl access-report always prints an error message
+- Resolves: rhbz#1643053 - Restarting the sssd-kcm service should reload the
+                           configuration without having to restart the whole
+                           sssd
+- Resolves: rhbz#1640576 - sssctl reports incorrect information about local
+                           user's cache entry expiration time
+- Resolves: rhbz#1645238 - Unable to su to root when logged in as a local user
+- Resolves: rhbz#1639411 - sssd support for for smartcards using ECC keys
+
+* Thu Oct 25 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-23
+- Resolves: rhbz#1642508 - sssd ifp crash when trying to access ipa webui
+                           with smart card
+
+* Wed Oct 24 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-22
+- Resolves: rhbz#1642372 - SSSD Python getgrouplist API was removed but required for IPA
+
+* Tue Oct 16 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-21
+- Related: rhbz#1638150 - session not recording for local user when groups defined
+- Also add silence a Coverity warning, which is related to rhbz#1637131
+
+* Mon Oct 15 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-20
+- Related: rhbz#1637513 - sssd crashes when refreshing expired sudo rules
+
+* Mon Oct 15 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-19
+- Add OSCP checks for p11_child
+- Related: rhbz#1615417 - [RFE] Add Smart Card authentication for local
+                          users
+
+* Mon Oct 15 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-18
+- Related: rhbz#1638006 - Files: The files provider always enumerates
+                          which causes duplicate when running getent passwd
+
+* Thu Oct 11 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-17
+- Related: rhbz#1637131 - pam_unix unable to match fully qualified username
+                          provided by sssd during smartcard auth using gdm
+
+* Thu Oct 11 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-16
+- Related: rhbz#1620123 - [RFE] Add option to specify a Smartcard with a
+                          PKCS#11 URI
+
+* Thu Oct 11 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-15
+- Related: rhbz#1611011 - Support for "require smartcard for login option"
+
+* Thu Oct 11 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-14
+- Related: rhbz#1635595 - Cant login with smartcard with multiple certs
+
+* Thu Oct 11 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-13
+- Backport more sbus2 fixes
+- Related: rhbz#1623878 - crash related to sbus_router_destructor()
+
+* Wed Oct 10 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-12
+- Resolves: rhbz#1636397 - SSSD not fetching all sudo rules from AD
+
+* Wed Oct  3 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-11
+- Resolves: rhbz#1628122 - Printing incorrect information about domain
+                           with sssctl utility
+
+* Wed Oct  3 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-10
+- Resolves: rhbz#1626001 - SSSD should log to syslog if a domain is not
+                           started due to a misconfiguration
+
+* Wed Oct  3 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-9
+- Resolves: rhbz#1624785 - Remove references of sss_user/group/add/del
+                           commands in man pages since local provider
+                           is deprecated
+
+* Wed Oct  3 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-8
+- Resolves: rhbz#1628126 - [abrt] [faf] sssd: unknown function():
+                            /usr/libexec/sssd/sssd_be killed by 11 crash
+                            func _dbus_list_unlink
+
+* Wed Oct  3 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-7
+- Resolves: rhbz#1628503 - sssd only sets the SELinux login context if it
+                           differs from the default
+
+* Wed Sep 26 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-6
+- Resolves: rhbz#1625842 id_provider= local causes SSSD to abort startup
+
+* Tue Sep 25 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-5
+- Resolves: rhbz#1615590 - Do not rely on "python" for el8
+
+* Tue Sep 25 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-4
+- Resolves: rhbz#1615417 - [RFE] Add Smart Card authentication for local
+                           users
+
+* Tue Sep 11 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-3
+- Resolves: rhbz#1623878 - crash related to sbus_router_destructor()
+
+* Thu Aug 30 2018 Jakub Hrozek <jhrozek@redhat.com> - 2.0.0-2
+- Resolves: rhbz#1622026 - sssd 2.0 regression: Kerberos authentication
+                           fails with the KCM ccache
+
+* Mon Aug 13 2018 Fabiano Fidêncio <fidencio@redhat.com> - 2.0.0-1
+- Resolves: rhbz#1615460 - Rebase SSSD to the latest released version
+
+* Tue Jul 03 2018 Tomas Orsava <torsava@redhat.com> - 1.16.2-2
+- Switch hardcoded python3 shebangs into the %%{__python3} macro
+
+* Thu Jun 14 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-1
+- Update to 1.16.2 release
+- Cleanup unused global definitions
+- Remove python2 references from the spec file
+- Resolves: rhbz#1585313 - Kerberos with sssd-kcm is not working on s390x
+
+* Fri Apr 27 2018 Fabiano Fidêncio <fidencio@fedoraproject.org> - 1.16.1-3
+- Resolves: upstream#3684 - A group is not updated if its member is removed
+                            with the cleanup task, but the group does not
+                            change
+- Resolves: upstream#3558 - sudo: report error when two rules share cn
+- Tone down shutdown messages for socket activated responders
+- IPA: Qualify the externalUser sudo attribute
+- Resolves: upstream#3550 - refresh_expired_interval does not work with
+                            netgrous in 1.15
+- Resolves: upstream#3402 - Support alternative sources for the files provider
+- Resolves: upstream#3646 - SSSD's GPO code ignores ad_site option
+- Resolves: upstream#3679 - Make nss netgroup requests more robust
+- Resolves: upstream#3634 - sssctl COMMAND --help fails if sssd is not
+                            configured
+- Resolves: upstream#3469 - extend sss-certmap man page regarding priority
+                            processing
+- Improve docs/debug message about GC detection
+- Resolves: upstream#3715 - ipa 389-ds-base crash in krb5-libs - k5_copy_etypes
+                            list out of bound?
+- Resolves: upstream#2653 - Group renaming issue when "id_provider = ldap" is
+                            set.
+- Document which principal does the AD provider use
+- Resolves: upstream#3680 - GPO: SSSD fails to process GPOs If a rule is
+                            defined, but contains no SIDs
+- Resolves: upstream#3520 - Files provider supports only BE_FILTER_ENUM
+- Resolves: rhbz#1540703 - FreeIPA/SSSD implicit_file sssd_nss error: The Data
+                           Provider returned an error
+                           [org.freedesktop.sssd.Error.DataProvider.Fatal]
+
+* Fri Mar 30 2018 Fabiano Fidêncio <fidencio@fedoraproject.org> - 1.16.1-2
+- Resolves: upstream#3573 - sssd won't show netgroups with blank domain
+- Resolves: upstream#3660 - confdb_expand_app_domains() always fails
+- Resolves: upstream#3658 - Application domain is not interpreted correctly
+- Resolves: upstream#3687 - KCM: Don't pass a non null terminated string to
+                            json_loads()
+- Resolves: upstream#3386 - KCM: Payload buffer is too small
+- Resolves: upstream#3666 - Fix usage of str.decode() in our tests
+- A few KCM misc fixes
+
+* Fri Mar  9 2018 Fabiano Fidêncio <fidencio@fedoraproject.org> - 1.16.1-1
+- New upstream release 1.16.1
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_16_1.html
+
+* Tue Feb 20 2018 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-13
+- Resolves: upstream#3621 - backport bug found by static analyzers
+
+* Wed Feb 14 2018 Fabiano Fidêncio <fidencio@fedoraproject.org> - 1.16.0-12
+- Resolves: rhbz#1538643 - SSSD crashes when retrieving a Desktop Profile
+                           with no specific host/hostgroup set
+- Resolves: upstream#3621 - FleetCommander integration must not require
+                            capability DAC_OVERRIDE
+
+* Wed Feb 07 2018 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-11
+- Resolves: upstream#3618 - selinux_child segfaults in a docker container
+
+* Tue Feb 06 2018 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-10
+- Resolves: rhbz#1431153 - sssd: libsss_proxy.so needs to be linked with -ldl
+
+* Thu Jan 25 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 1.16.0-9
+- Fix systemd executions/requirements
+
+* Thu Jan 25 2018 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-8
+- Fix building on rawhide. Remove -Wl,-z,defs from LDFLAGS
+
+* Thu Jan 11 2018 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-7
+- Fix building of sssd-nfs-idmap with libnfsidmap.so.1
+
+* Thu Jan 11 2018 Björn Esser <besser82@fedoraproject.org> - 1.16.0-6
+- Rebuilt for libnfsidmap.so.1
+
+* Mon Dec 04 2017 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-5
+- Resolves: upstream#3523 - ABRT crash - /usr/libexec/sssd/sssd_nss in
+                            setnetgrent_result_timeout
+- Resolves: upstream#3588 - sssd_nss consumes more memory until restarted
+                            or machine swaps
+- Resolves: failure in glibc tests
+            https://sourceware.org/bugzilla/show_bug.cgi?id=22530
+- Resolves: upstream#3451 - When sssd is configured with id_provider proxy and
+                            auth_provider ldap, login fails if the LDAP server
+                            is not allowing anonymous binds
+- Resolves: upstream#3285 - SSSD needs restart after incorrect clock is
+                            corrected with AD
+- Resolves: upstream#3586 - Give a more detailed debug and system-log message
+                            if krb5_init_context() failed
+- Resolves: rhbz#1431153 - SSSD ships a drop-in configuration snippet
+                           in /etc/systemd/system
+- Backport few upstream features from 1.16.1
+
+* Tue Nov 21 2017 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-4
+- Resolves: rhbz#1494002 - sssd_nss crashed in cache_req_search_domains_next
+
+* Fri Nov 17 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.16.0-3
+- Backport extended NSS API from upstream master branch
+
+* Fri Nov 03 2017 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-2
+- Resolves: upstream#3529 - sssd-kcm Fix restart during/after upgrade
+
+* Fri Oct 20 2017 Lukas Slebodnik <lslebodn@fedoraproject.org> - 1.16.0-1
+- New upstream release 1.16.0
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_16_0.html
+
+* Wed Oct 11 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-5
+- Resolves: rhbz#1499354 - CVE-2017-12173 sssd: unsanitized input when
+                           searching in local cache database access on
+                           the sock_file system_bus_socket
+
+* Mon Sep 11 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-4
+- Resolves: rhbz#1488327 - SELinux is preventing selinux_child from write
+                           access on the sock_file system_bus_socket
+- Resolves: rhbz#1490402 - SSSD does not create /var/lib/sss/deskprofile and
+                           fails to download desktop profile data
+- Resolves: upstream#3485 - getsidbyid does not work with 1.15.3
+- Resolves: upstream#3488 - SUDO doesn't work for IPA users on IPA clients
+                            after applying ID Views for them in IPA server
+- Resolves: upstream#3501 - Accessing IdM kerberos ticket fails while id
+                            mapping is applied
+
+* Fri Sep 01 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-3
+- Backport few upstream patches/fixes
+
+* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Tue Jul 25 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-1
+- New upstream release 1.15.3
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_3.html
+
+* Tue Jun 27 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-0.beta.5
+- Rebuild with libldb-1.2.0
+
+* Tue Jun 27 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-0.beta.4
+- Fix build issues: Update expided certificate in unit tests
+
+* Sat Apr 29 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-0.beta.3
+- Resolves: rhbz#1445680 - Properly fall back to local Smartcard authentication
+- Resolves: rhbz#1437199 - sssd-nfs-idmap-1.15.2-1.fc25.x86_64 conflicts with
+                           file from package sssd-common-1.15.1-1.fc25.x86_64
+- Resolves: rhbz#1063278 - sss_ssh_knownhostsproxy doesn't fall back to ipv4
+
+* Thu Apr 06 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-0.beta.2
+- Fix issue with IPA + SELinux in containers
+- Resolves: upstream https://fedorahosted.org/sssd/ticket/3297
+
+* Tue Apr 04 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.3-0.beta.1
+- Backport upstream patches for 1.15.3 pre-release
+- required for building freeipa-4.5.x in rawhide
+
+* Thu Mar 16 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.2-1
+- New upstream release 1.15.2
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_2.html
+
+* Mon Mar 06 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.1-1
+- New upstream release 1.15.1
+- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_1.html
+
+* Wed Feb 22 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.15.0-4
+- Cherry-pick patches from upstream that enable the files provider
+- Enable the files domain
+- Retire patch 0501-Partially-revert-CONFIG-Use-default-config-when-none.patch
+  which is superseded by the files domain autoconfiguration
+- Related: rhbz#1357418 - SSSD fast cache for local users
+
+* Tue Feb 14 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.0-3
+- Add missing %%license macro
+
+* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Fri Jan 27 2017 Lukas Slebodnik <lslebodn@redhat.com> - 1.15.0-1
+- New upstream release 1.15.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.15.0
+
+* Mon Dec 19 2016 Miro Hrončok <mhroncok@redhat.com> - 1.14.2-3
+- Rebuild for Python 3.6
+
+* Tue Dec 13 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.2-2
+- Resolves: rhbz#1369130 - nss_sss should not link against libpthread
+- Resolves: rhbz#1392916 - sssd failes to start after update
+- Resolves: rhbz#1398789 - SELinux is preventing sssd from 'write' accesses
+                           on the directory /etc/sssd
+
+* Thu Oct 20 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.2-1
+- New upstream release 1.14.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.14.2
+
+* Fri Oct 14 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.1-4
+- libwbclient-sssd: update interface to version 0.13
+
+* Thu Sep 22 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.1-3
+- Fix regression with krb5_map_user
+- Resolves: rhbz#1375552 - krb5_map_user doesn't seem effective anymore
+- Resolves: rhbz#1349286 - authconfig fails with SSSDConfig.NoDomainError:
+                           default if nonexistent domain is mentioned
+
+* Thu Sep 01 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.1-2
+- Backport important patches from upstream 1.14.2 prerelease
+- Resolves: upstream #3154 - sssd exits if clock is adjusted backwards after
+                             boot
+- Resolves: upstream #3163 - resolving IPA nested user group is broken in 1.14
+
+* Fri Aug 19 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.1-1
+- New upstream release 1.14.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.14.1
+
+* Mon Aug 15 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.14.0-5
+- Add workaround patch for RHBZ #1366403
+
+* Tue Jul 19 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.14.0-4
+- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
+
+* Fri Jul 08 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.0-3
+- New upstream release 1.14.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.14.0
+
+* Fri Jul 01 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.0-2.beta
+- New upstream release 1.14 beta
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.14.0beta
+
+* Tue Jun 21 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.14.0-1.alpha
+- New upstream release 1.14 alpha
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.14.0alpha
+
+* Fri May 13 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.4-3
+- Resolves: rhbz#1335639 - [abrt] sssd-dbus: ldb_msg_find_element():
+                           sssd_ifp killed by SIGSEGV
+
+* Fri Apr 22 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.4-2
+- Resolves: rhbz#1328108 - Protocol error with FreeIPA on CentOS 6
+
+* Thu Apr 14 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.4-1
+- New upstream release 1.13.4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.4
+
+* Tue Mar 22 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.3-6
+- Resolves: rhbz#1276868 - Sudo PAM Login should support multiple password
+                           prompts (e.g. Password + Token)
+- Resolves: rhbz#1313041 - ssh with sssd proxy fails with "Connection closed
+                           by remote host" if locale not available
+
+* Thu Feb 25 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.3-5
+- Resolves: rhbz#1310664 - [RFE] IPA: resolve external group memberships of IPA
+                           groups during getgrnam and getgrgid
+- Resolves: rhbz#1301303 - sss_obfuscate: SyntaxError: Missing parentheses
+                           in call to 'print'
+
+* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 1.13.3-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Wed Jan 20 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.3-3
+- Additional upstream fixes
+
+* Tue Jan 19 2016 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.3-2
+- Resolves: rhbz#1256849 - SUDO: Support the IPA schema
+
+* Wed Dec 16 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.3-1
+- New upstream release 1.13.3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.3
+
+* Fri Nov 20 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.2-1
+- New upstream release 1.13.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.2
+
+* Fri Nov 06 2015 Robert Kuska <rkuska@redhat.com> - 1.13.1-5
+- Rebuilt for Python3.5 rebuild
+
+* Tue Oct 27 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.1-4
+- Fix building pac responder with the krb5-1.14
+
+* Mon Oct 19 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.1-3
+- python-sssdconfig: Fix parssing sssd.conf without config_file_version
+- Resolves: upstream #2837 - REGRESSION: ipa-client-automout failed
+
+* Wed Oct 07 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.1-2
+- Fix few segfaults
+- Resolves: upstream #2811 - PAM responder crashed if user was not set
+- Resolves: upstream #2810 - sssd_be crashed in ipa_srv_ad_acct_lookup_step
+
+* Thu Oct 01 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.1-1
+- New upstream release 1.13.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.1
+
+* Thu Sep 10 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-6
+- Fix OTP bug
+- Resolves: upstream #2729 - Do not send SSS_OTP if both factors were
+                             entered separately
+
+* Mon Sep 07 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-5
+- Backport upstream patches required by FreeIPA 4.2.1
+
+* Tue Jul 21 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-4
+- Fix ipa-migration bug
+- Resolves: upstream #2719 - IPA: returned unknown dp error code with disabled
+                             migration mode
+
+* Wed Jul 08 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-3
+- New upstream release 1.13.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.0
+
+* Tue Jun 30 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-2.alpha
+- Unify return type of list_active_domains for python{2,3}
+
+* Mon Jun 22 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-1.alpha
+- New upstream release 1.13 alpha
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.0alpha
+
+* Fri Jun 19 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.12.5-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Fri Jun 12 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.5-3
+- Fix libwbclient alternatives
+
+* Fri Jun 12 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.5-2
+- Backport important patches from upstream 1.13 prerelease
+
+* Fri Jun 12 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.5-1
+- New upstream release 1.12.5
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.5
+
+* Fri May 08 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-8
+- Backport important patches from upstream 1.13 prerelease
+- Resolves: rhbz#1060325 - Does sssd-ad use the most suitable
+                           attribute for group name
+- Resolves: upstream #2335 - Investigate using the krb5 responder
+                             for driving the PAM conversation with OTPs
+- Enable cmocka tests for secondary architectures
+
+* Fri May 08 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-7
+- Backport patches from upstream 1.12.5 prerelease - contains many fixes
+
+* Wed Apr 15 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-6
+- Fix slow login with ipa and SELinux
+- Resolves: upstream #2624 - Only set the selinux context if the context
+                             differs from the local one
+
+* Mon Mar 23 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-5
+- Fix regressions with ipa and SELinux
+- Resolves: upstream #2587 - With empty ipaselinuxusermapdefault security
+                             context on client is staff_u
+
+* Fri Mar  6 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.4-4
+- Also relax libldb Requires
+- Remove --enable-ldb-version-check
+
+* Fri Mar  6 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.4-3
+- Relax libldb BuildRequires to be greater-or-equal
+
+* Wed Feb 25 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-2
+- Add support for python3 bindings
+- Add requirement to python3 or python3 bindings
+- Resolves: rhbz#1014594 - sssd: Support Python 3
+
+* Wed Feb 18 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-1
+- New upstream release 1.12.4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.4
+
+* Sat Feb 14 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.3-7
+- Backport patches with Python3 support from upstream
+
+* Thu Feb 12 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.3-6
+- Fix double free in monitor
+- Resolves: rhbz#1186887 [abrt] sssd-common: talloc_abort():
+                        sssd killed by SIGABRT
+
+* Wed Jan 28 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.12.3-5
+- Rebuild for new libldb
+
+* Thu Jan 22 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.3-4
+- Decrease priority of sssd-libwbclient 20 -> 5
+- It should be lower than priority of samba veriosn of libwbclient.
+- https://bugzilla.redhat.com/show_bug.cgi?id=1175511#c18
+
+* Mon Jan 19 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.3-3
+- Apply a number of patches from upstream to fix issues found 1.12.3
+- Resolves: rhbz#1176373 - dyndns_iface does not accept multiple
+                           interfaces, or isn't documented to be able to
+- Resolves: rhbz#988068 - getpwnam_r fails for non-existing users when sssd is
+                          not running
+- Resolves: upstream #2557  authentication failure with user from AD
+
+* Fri Jan 09 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.3-2
+- Resolves: rhbz#1164156 - libsss_simpleifp should pull sssd-dbus
+- Resolves: rhbz#1179379 - gzip: stdin: file size changed while
+                           zipping when rotating logfile
+
+* Thu Jan 08 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.3-1
+- New upstream release 1.12.3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.3
+- Fix spelling errors in description (fedpkg lint)
+
+* Tue Jan  6 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.2-8
+- Rebuild for libldb 1.1.19
+
+* Fri Dec 19 2014 Sumit Bose <sbose@redhat.com> - 1.12.2-7
+- Resolves: rhbz#1175511 - sssd-libwbclient conflicts with Samba's and causes
+                           crash in wbinfo
+                           - in addition to the patch libwbclient.so is
+                             filtered out of the Provides list of the package
+
+* Wed Dec 17 2014 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.2-6
+- Fix regressions and bugs in sssd upstream 1.12.2
+- https://fedorahosted.org/sssd/ticket/{id}
+- Regressions: #2471, #2475, #2483, #2487, #2529, #2535
+- Bugs: #2287, #2445
+
+* Sun Dec  7 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-5
+- Rebuild for libldb 1.1.18
+
+* Wed Nov 26 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-4
+- Fix typo in libwbclient-devel %%preun
+
+* Tue Nov 25 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-3
+- Use alternatives for libwbclient
+
+* Wed Oct 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-2
+- Backport several patches from upstream.
+- Fix a potential crash against old (pre-4.0) IPA servers
+
+* Mon Oct 20 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.2-1
+- New upstream release 1.12.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.2
+
+* Mon Sep 15 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-2
+- Resolves: rhbz#1139962 - Fedora 21, FreeIPA 4.0.2: sssd does not find user
+                           private group from server
+
+* Mon Sep  8 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.1-1
+- New upstream release 1.12.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.1
+
+* Fri Aug 22 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-7
+- Do not crash on resolving a group SID in IPA server mode
+
+* Mon Aug 18 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.12.0-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Thu Jul 10 2014 Stephen Gallagher <sgallagh@redhat.com> 1.12.0-5
+- Fix release version for upgrades
+
+* Wed Jul 09 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-1
+- New upstream release 1.12.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.0
+
+* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.12.0-4.beta2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Wed Jun 04 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-1.beta2
+- New upstream release 1.12 beta2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.0beta2
+
+* Mon Jun 02 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-2.beta1
+- Fix tests on big-endian
+- Fix previous changelog entry
+
+* Fri May 30 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.12.0-1.beta1
+- New upstream release 1.12 beta1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.12.0beta1
+
+* Thu May 29 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.5.1-4
+- Rebuild against new ding-libs
+
+* Thu May 08 2014 Stephen Gallagher <sgallagh@redhat.com> - 1.11.5.1-3
+- Make LDB dependency a strict equivalency
+
+* Thu May 08 2014 Stephen Gallagher <sgallagh@redhat.com> - 1.11.5.1-2
+- Rebuild against new libldb
+
+* Fri Apr 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.5.1-1
+- New upstream release 1.11.5.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.5.1
+
+* Thu Apr 10 2014 Stephen Gallagher <sgallagh@redhat.com> 1.11.5-2
+- Fix bug in generation of systemd unit file
+
+* Tue Apr 08 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.5-1
+- New upstream release 1.11.5
+- Remove upstreamed patch
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.5
+
+* Thu Mar 13 2014 Sumit Bose <sbose@redhat.com> - 1.11.4-3
+- Handle new error code for IPA password migration
+
+* Tue Mar 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.4-2
+- Include couple of patches from upstream 1.11 branch
+
+* Mon Feb 17 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.4-1
+- New upstream release 1.11.4
+- Remove upstreamed patch
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.4
+
+* Tue Feb 11 2014 Jakub Hrozek <jhrozek@redhat.com> - 1.11.3-2
+- Handle OTP response from FreeIPA server gracefully
+
+* Wed Oct 30 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.3-1
+- New upstream release 1.11.3
+- Remove upstreamed patches
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.3
+
+* Wed Oct 30 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.2-1
+- New upstream release 1.11.2
+- Remove upstreamed patches
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.2
+
+* Wed Oct 16 2013 Sumit Bose <sbose@redhat.com> - 1.11.1-5
+- Fix potential crash with external groups in trusted IPA-AD setup
+
+* Mon Oct 14 2013 Sumit Bose <sbose@redhat.com> - 1.11.1-4
+- Add plugin for cifs-utils
+- Resolves: rhbz#998544
+
+* Tue Oct 08 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.1-3
+- Fix failover from Global Catalog to LDAP in case GC is not available
+
+* Fri Oct 04 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.1-2
+- Remove the ability to create public ccachedir (#1015089)
+
+* Fri Sep 27 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.1-1
+- New upstream release 1.11.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.1
+
+* Thu Sep 26 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0-3
+- Fix multicast checks in the SSSD
+- Resolves: rhbz#1007475 - The multicast check is wrong in the sudo source
+                           code getting the host info
+
+* Wed Aug 28 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0-2
+- Backport simplification of ccache management from 1.11.1
+- Resolves: rhbz#1010553 - sssd setting KRB5CCNAME=(null) on login
+
+* Wed Aug 28 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0-1
+- New upstream release 1.11.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.0
+
+* Fri Aug 23 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0-0.4.beta2
+- Resolves: #967012 - [abrt] sssd-1.9.5-1.fc18: sss_mmap_cache_gr_invalidate_gid:
+                      Process /usr/libexec/sssd/sssd_nss was killed by
+                      signal 11 (SIGSEGV)
+- Resolves: #996214 - sssd proxy_child segfault
+
+* Sun Aug 04 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.11.0-0.3.beta2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Wed Jul 31 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0.2beta2
+- Resolves: #906427 - Do not use %%{_lib} in specfile for the nss and
+                      pam libraries
+
+* Wed Jul 24 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.11.0.1beta2
+- New upstream release 1.11 beta 2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.0beta2
+
+* Thu Jul 18 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.1-1
+- New upstream release 1.10.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.1
+
+* Mon Jul 08 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-17
+- sssd-tools should require sssd-common, not sssd
+
+* Tue Jul 02 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.10.0-16
+- Move sssd_pac to the sssd-ipa and sssd-ad subpackages
+- Trim out RHEL5-specific macros since we don't build on RHEL 5
+- Trim out macros for Fedora older than F18
+- Update libldb requirement to 1.1.16
+- Trim RPM changelog down to the last year
+
+* Tue Jul 02 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.10.0-15
+- Move sssd_pac to the sssd-krb5 subpackage
+
+* Mon Jul 01 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.10.0-14
+- Fix Obsoletes: to account for dist tag
+- Convert post and pre scripts to run on the sssd-common subpackage
+- Remove old conversion from SYSV
+
+* Thu Jun 27 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-13
+- New upstream release 1.10
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0
+
+* Mon Jun 17 2013 Dan Horák <dan[at]danny.cz> - 1.10.0-12.beta2
+- the cmocka toolkit exists only on selected arches
+
+* Sun Jun 16 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-11.beta2
+- Apply a number of patches from upstream to fix issues found post-beta,
+  in particular:
+  -- segfault with a high DEBUG level
+  -- Fix IPA password migration (upstream #1873)
+  -- Fix fail over when retrying SRV resolution (upstream #1886)
+
+* Thu Jun 13 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-10.beta2
+- Only BuildRequire libcmocka on Fedora
+
+* Thu Jun 13 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-9.beta2
+- Fix typo in Requires that prevented an upgrade (#973916)
+- Use a hardcoded version in Conflicts, not less-than-current
+
+* Wed Jun 12 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-8.beta1
+- Enable hardened build for RHEL7
+
+* Wed Jun 12 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-8.beta2
+- New upstream release 1.10 beta2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0beta2
+- BuildRequire libcmocka-devel in order to run all upstream tests during build
+- BuildRequire libnl3 instead of libnl1
+- No longer BuildRequire initscripts, we no longer use /sbin/service
+- Remove explicit krb5-libs >= 1.10 requires; this platform doensn't carry any
+  older krb5-libs version
+
+* Fri May 24 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-7.beta1
+- Apply a couple of patches from upstream git that resolve crashes when
+  ID mapping object was not initialized properly but needed later
+
+* Tue May 14 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-6.beta1
+- Resolves: rhbz#961357 - Missing dyndns_update entry in sssd.conf during
+                          realm join
+- Resolves: rhbz#961278 - Login failure: Enterprise Principal enabled by
+                          default for AD Provider
+- Resolves: rhbz#961251 - sssd does not create user's krb5 ccache dir/file
+                          parent directory when logging in
+
+* Tue May  7 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-5.beta1
+- BuildRequire recent libini_config to ensure consistent behaviour
+
+* Tue May  7 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-4.beta1
+- Explicitly Require libini_config >= 1.0.0.1 to work around a SONAME bug
+  in ding-libs
+- Fix SSH integration with fully-qualified domains
+- Add the ability to dynamically discover the NetBIOS name
+
+* Fri May  3 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-3.beta1
+- New upstream release 1.10 beta1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0beta1
+
+* Wed Apr 17 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-2.alpha1
+- Add a patch to fix krb5 ccache creation issue with krb5 1.11
+
+* Tue Apr  2 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.10.0-1.alpha1
+- New upstream release 1.10 alpha1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0alpha1
+
+* Fri Mar 29 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.5-10
+- Add a patch to fix krb5 unit tests
+
+* Fri Mar 01 2013 Stephen Gallagher <sgallagh@redhat.com> - 1.9.4-9
+- Split internal helper libraries into a shared object
+- Significantly reduce disk-space usage
+
+* Thu Feb 14 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-8
+- Fix the Kerberos password expiration warning (#912223)
+
+* Thu Feb 14 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-7
+- Do not write out dots in the domain-realm mapping file (#905650)
+
+* Mon Feb 11 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-6
+- Include upstream patch to build with krb5-1.11
+
+* Thu Feb 07 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-5
+- Rebuild against new libldb
+
+* Mon Feb 04 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-4
+- Fix build with new automake versions
+
+* Wed Jan 30 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-3
+- Recreate Kerberos ccache directory if it's missing
+- Resolves: rhbz#853558 - [sssd[krb5_child[PID]]]: Credential cache
+                          directory /run/user/UID/ccdir does not exist
+
+* Tue Jan 29 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-2
+- Fix changelog dates to make F19 rpmbuild happy
+
+* Mon Jan 28 2013 Jakub Hrozek <jhrozek@redhat.com> - 1.9.4-1
+- New upstream release 1.9.4
+
+* Thu Dec 06 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.3-1
+- New upstream release 1.9.3
+
+* Tue Oct 30 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-5
+- Resolve groups from AD correctly
+
+* Tue Oct 30 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-4
+- Check the validity of naming context
+
+* Thu Oct 18 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-3
+- Move the sss_cache tool to the main package
+
+* Sun Oct 14 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-2
+- Include the 1.9.2 tarball
+
+* Sun Oct 14 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.2-1
+- New upstream release 1.9.2
+
+* Sun Oct 07 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.1-1
+- New upstream release 1.9.1
+
+* Wed Oct 03 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-24
+- require the latest libldb
+
+* Tue Sep 25 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-24
+- Use mcpath insted of mcachepath macro to be consistent with
+  upsteam spec file
+
+* Tue Sep 25 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-23
+- New upstream release 1.9.0
+
+* Fri Sep 14 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-22.rc1
+- New upstream release 1.9.0 rc1
+
+* Thu Sep 06 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-21.beta7
+- New upstream release 1.9.0 beta7
+- obsoletes patches #1-#3
+
+* Mon Sep 03 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-20.beta6
+- Rebuild against libldb 1.12
+
+* Tue Aug 28 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-19.beta6
+- Rebuild against libldb 1.11
+
+* Fri Aug 24 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-18.beta6
+- Change the default ccache location to DIR:/run/user/${UID}/krb5cc
+  and patch man page accordingly
+- Resolves: rhbz#851304
+
+* Mon Aug 20 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-17.beta6
+- Rebuild against libldb 1.10
+
+* Fri Aug 17 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-16.beta6
+- Only create the SELinux login file if there are SELinux mappings on
+  the IPA server
+
+* Fri Aug 10 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-14.beta6
+- Don't discard HBAC rule processing result if SELinux is on
+  Resolves: rhbz#846792 (CVE-2012-3462)
+
+* Thu Aug 02 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-13.beta6
+- New upstream release 1.9.0 beta 6
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta6
+- A new option, override_shell was added. If this option is set, all users
+  managed by SSSD will have their shell set to its value.
+- Fixes for the support for setting default SELinux user context from FreeIPA.
+- Fixed a regression introduced in beta 5 that broke LDAP SASL binds
+- The SSSD supports the concept of a Primary Server and a Back Up Server in
+  failover
+- A new command-line tool sss_seed is available to help prime the cache with
+  a user record when deploying a new machine
+- SSSD is now able to discover and save the domain-realm mappings
+  between an IPA server and a trusted Active Directory server.
+- Packaging changes to fix ldconfig usage in subpackages (#843995)
+- Rebuild against libldb 1.1.9
+
+* Fri Jul 27 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.9.0-13.beta5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Thu Jul 19 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-12.beta5
+- New upstream release 1.9.0 beta 5
+- Obsoletes the patch for missing DP_OPTION_TERMINATOR in AD provider options
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta5
+- Many fixes for the support for setting default SELinux user context from
+  FreeIPA, most notably fixed the specificity evaluation
+- Fixed an incorrect default in the krb5_canonicalize option of the AD
+  provider which was preventing password change operation
+- The shadowLastChange attribute value is now correctly updated with the
+  number of days since the Epoch, not seconds
+
+* Mon Jul 16 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-11.beta4
+- Fix broken ARM build
+- Add missing DP_OPTION_TERMINATOR in AD provider options
+
+* Wed Jul 11 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-10.beta4
+- Own several directories create during make install (#839782)
+
+* Wed Jul 11 2012 Jakub Hrozek <jhrozek@redhat.com> - 1.9.0-9.beta4
+- New upstream release 1.9.0 beta 4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta4
+- Add a new AD provider to improve integration with Active Directory 2008 R2
+  or later servers
+- SUDO integration was completely rewritten. The new implementation works
+  with multiple domains and uses an improved refresh mechanism to download
+  only the necessary rules
+- The IPA authentication provider now supports subdomains
+- Fixed regression for setups that were setting default_tkt_enctypes
+  manually by reverting a previous workaround.
+
+* Mon Jun 25 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-8.beta3
+- New upstream release 1.9.0 beta 3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta3
+- Add a new PAC responder for dealing with cross-realm Kerberos trusts
+- Terminate idle connections to the NSS and PAM responders
+
+* Wed Jun 20 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-7.beta2
+- Switch unicode library from libunistring to Glib
+- Drop unnecessary explicit Requires on keyutils
+- Guarantee that versioned Requires include the correct architecture
+
+* Mon Jun 18 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-6.beta2
+- Fix accidental disabling of the DIR cache support
+
+* Fri Jun 15 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-5.beta2
+- New upstream release 1.9.0 beta 2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta2
+- Add support for the Kerberos DIR cache for storing multiple TGTs
+  automatically
+- Major performance enhancement when storing large groups in the cache
+- Major performance enhancement when performing initgroups() against Active
+  Directory
+- SSSDConfig data file default locations can now be set during configure for
+  easier packaging
+
+* Tue May 29 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-4.beta1
+- Fix regression in endianness patch
+
+* Tue May 29 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-3.beta1
+- Rebuild SSSD against ding-libs 0.3.0beta1
+- Fix endianness bug in service map protocol
+
+* Thu May 24 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-2.beta1
+- Fix several regressions since 1.5.x
+- Ensure that the RPM creates the /var/lib/sss/mc directory
+- Add support for Netscape password warning expiration control
+- Rebuild against libldb 1.1.6
+
+* Fri May 11 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.9.0-1.beta1
+- New upstream release 1.9.0 beta 1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.0beta1
+- Add native support for autofs to the IPA provider
+- Support for ID-mapping when connecting to Active Directory
+- Support for handling very large (> 1500 users) groups in Active Directory
+- Support for sub-domains (will be used for dealing with trust relationships)
+- Add a new fast in-memory cache to speed up lookups of cached data on
+  repeated requests
+
+* Thu May 03 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.3-11
+- New upstream release 1.8.3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.3
+- Numerous manpage and translation updates
+- LDAP: Handle situations where the RootDSE isn't available anonymously
+- LDAP: Fix regression for users using non-standard LDAP attributes for user
+  information
+
+* Mon Apr 09 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.2-10
+- New upstream release 1.8.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.2
+- Several fixes to case-insensitive domain functions
+- Fix for GSSAPI binds when the keytab contains unrelated principals
+- Fixed several segfaults
+- Workarounds added for LDAP servers with unreadable RootDSE
+- SSH knownhostproxy will no longer enter an infinite loop preventing login
+- The provided SYSV init script now starts SSSD earlier at startup and stops
+  it later during shutdown
+- Assorted minor fixes for issues discovered by static analysis tools
+
+* Mon Mar 26 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.1-9
+- Don't duplicate libsss_autofs.so in two packages
+- Set explicit package contents instead of globbing
+
+* Wed Mar 21 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.1-8
+- Fix uninitialized value bug causing crashes throughout the code
+- Resolves: rhbz#804783 - [abrt] Segfault during LDAP 'services' lookup
+
+* Mon Mar 12 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.1-7
+- New upstream release 1.8.1
+- Resolve issue where we could enter an infinite loop trying to connect to an
+  auth server
+- Fix serious issue with complex (3+ levels) nested groups
+- Fix netgroup support for case-insensitivity and aliases
+- Fix serious issue with lookup bundling resulting in requests never
+  completing
+- IPA provider will now check the value of nsAccountLock during pam_acct_mgmt
+  in addition to pam_authenticate
+- Fix several regressions in the proxy provider
+- Resolves: rhbz#743133 - Performance regression with Kerberos authentication
+                          against AD
+- Resolves: rhbz#799031 - --debug option for sss_debuglevel doesn't work
+
+* Tue Feb 28 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-6
+- New upstream release 1.8.0
+- Support for the service map in NSS
+- Support for setting default SELinux user context from FreeIPA
+- Support for retrieving SSH user and host keys from LDAP (Experimental)
+- Support for caching autofs LDAP requests (Experimental)
+- Support for caching SUDO rules (Experimental)
+- Include the IPA AutoFS provider
+- Fixed several memory-corruption bugs
+- Fixed a regression in group enumeration since 1.7.0
+- Fixed a regression in the proxy provider
+- Resolves: rhbz#741981 - Separate Cache Timeouts for SSSD
+- Resolves: rhbz#797968 - sssd_be: The requested tar get is not configured is
+                          logged at each login
+- Resolves: rhbz#754114 - [abrt] sssd-1.6.3-1.fc16: ping_check: Process
+                          /usr/sbin/sssd was killed by signal 11 (SIGSEGV)
+- Resolves: rhbz#743133 - Performance regression with Kerberos authentication
+                          against AD
+- Resolves: rhbz#773706 - SSSD fails during autodetection of search bases for
+                          new LDAP features
+- Resolves: rhbz#786957 - sssd and kerberos should change the default location for create the Credential Cashes to /run/usr/USERNAME/krb5cc
+
+* Wed Feb 22 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-5.beta3
+- Change default kerberos credential cache location to /run/user/<username>
+
+* Wed Feb 15 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-4.beta3
+- New upstream release 1.8.0 beta 3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.0beta3
+- Fixed a regression in group enumeration since 1.7.0
+- Fixed several memory-corruption bugs
+- Finalized the ABI for the autofs support
+- Fixed a regression in the proxy provider
+
+* Fri Feb 10 2012 Petr Pisar <ppisar@redhat.com> - 1.8.0-3.beta2
+- Rebuild against PCRE 8.30
+
+* Mon Feb 06 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-1.beta2
+- New upstream release
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.0beta2
+- Fix two minor manpage bugs
+- Include the IPA AutoFS provider
+
+* Mon Feb 06 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.8.0-1.beta1
+- New upstream release
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.0beta1
+- Support for the service map in NSS
+- Support for setting default SELinux user context from FreeIPA
+- Support for retrieving SSH user and host keys from LDAP (Experimental)
+- Support for caching autofs LDAP requests (Experimental)
+- Support for caching SUDO rules (Experimental)
+
+* Wed Feb 01 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-5
+- Resolves: rhbz#773706 - SSSD fails during autodetection of search bases for
+                          new LDAP features - fix netgroups and sudo as well
+
+* Wed Feb 01 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-4
+- Fixes a serious memory hierarchy bug causing unpredictable behavior in the
+  LDAP provider.
+
+* Wed Feb 01 2012 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-3
+- Resolves: rhbz#773706 - SSSD fails during autodetection of search bases for
+                          new LDAP features
+
+* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Thu Dec 22 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.7.0-1
+- New upstream release 1.7.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.7.0
+- Support for case-insensitive domains
+- Support for multiple search bases in the LDAP provider
+- Support for the native FreeIPA netgroup implementation
+- Reliability improvements to the process monitor
+- New DEBUG facility with more consistent log levels
+- New tool to change debug log levels without restarting SSSD
+- SSSD will now disconnect from LDAP server when idle
+- FreeIPA HBAC rules can choose to ignore srchost options for significant
+  performance gains
+- Assorted performance improvements in the LDAP provider
+
+* Mon Dec 19 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.4-1
+- New upstream release 1.6.4
+- Rolls up previous patches applied to the 1.6.3 tarball
+- Fixes a rare issue causing crashes in the failover logic
+- Fixes an issue where SSSD would return the wrong PAM error code for users
+  that it does not recognize.
+
+* Wed Dec 07 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-5
+- Rebuild against libldb 1.1.4
+
+* Tue Nov 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-4
+- Resolves: rhbz#753639 - sssd_nss crashes when passed invalid UTF-8 for the
+                          username in getpwnam()
+- Resolves: rhbz#758425 - LDAP failover not working if server refuses
+                          connections
+
+* Thu Nov 24 2011 Jakub Hrozek <jhrozek@redhat.com> - 1.6.3-3
+- Rebuild for libldb 1.1.3
+
+* Thu Nov 10 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-2
+- Resolves: rhbz#752495 - Crash when apply settings
+
+* Fri Nov 04 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.3-1
+- New upstream release 1.6.3
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.6.3
+- Fixes a major cache performance issue introduced in 1.6.2
+- Fixes a potential infinite-loop with certain LDAP layouts
+
+* Wed Oct 26 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.6.2-5
+- Rebuilt for glibc bug#747377
+
+* Sun Oct 23 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-4
+- Change selinux policy requirement to Conflicts: with the old version,
+  rather than Requires: the supported version.
+
+* Fri Oct 21 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-3
+- Add explicit requirement on selinux-policy version to address new SBUS
+  symlinks.
+
+* Wed Oct 19 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-2
+- Remove %%files reference to sss_debuglevel copied from wrong upstreeam
+  spec file.
+
+* Tue Oct 18 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.2-1
+- Improved handling of users and groups with multi-valued name attributes
+  (aliases)
+- Performance enhancements
+    Initgroups on RFC2307bis/FreeIPA
+    HBAC rule processing
+- Improved process-hang detection and restarting
+- Enabled the midpoint cache refresh by default (fewer cache misses on
+  commonly-used entries)
+- Cleaned up the example configuration
+- New tool to change debug level on the fly
+
+* Mon Aug 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.1-1
+- New upstream release 1.6.1
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.6.1
+- Fixes a serious issue with LDAP connections when the communication is
+  dropped (e.g. VPN disconnection, waking from sleep)
+- SSSD is now less strict when dealing with users/groups with multiple names
+  when a definitive primary name cannot be determined
+- The LDAP provider will no longer attempt to canonicalize by default when
+  using SASL. An option to re-enable this has been provided.
+- Fixes for non-standard LDAP attribute names (e.g. those used by Active
+  Directory)
+- Three HBAC regressions have been fixed.
+- Fix for an infinite loop in the deref code
+
+* Wed Aug 03 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.0-2
+- Build with _hardened_build macro
+
+* Wed Aug 03 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.6.0-1
+- New upstream release 1.6.0
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.6.0
+- Add host access control support for LDAP (similar to pam_host_attr)
+- Finer-grained control on principals used with Kerberos (such as for FAST or
+- validation)
+- Added a new tool sss_cache to allow selective expiring of cached entries
+- Added support for LDAP DEREF and ASQ controls
+- Added access control features for Novell Directory Server
+- FreeIPA dynamic DNS update now checks first to see if an update is needed
+- Complete rewrite of the HBAC library
+- New libraries: libipa_hbac and libipa_hbac-python
+
+* Tue Jul 05 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.11-2
+- New upstream release 1.5.11
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.11
+- Fix a serious regression that prevented SSSD from working with ldaps:// URIs
+- IPA Provider: Fix a bug with dynamic DNS that resulted in the wrong IPv6
+- address being saved to the AAAA record
+
+* Fri Jul 01 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.10-1
+- New upstream release 1.5.10
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.10
+- Fixed a regression introduced in 1.5.9 that could result in blocking calls
+- to LDAP
+
+* Thu Jun 30 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.9-1
+- New upstream release 1.5.9
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.9
+- Support for overriding home directory, shell and primary GID locally
+- Properly honor TTL values from SRV record lookups
+- Support non-POSIX groups in nested group chains (for RFC2307bis LDAP
+- servers)
+- Properly escape IPv6 addresses in the failover code
+- Do not crash if inotify fails (e.g. resource exhaustion)
+- Don't add multiple TGT renewal callbacks (too many log messages)
+
+* Fri May 27 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.8-1
+- New upstream release 1.5.8
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.8
+- Support for the LDAP paging control
+- Support for multiple DNS servers for name resolution
+- Fixes for several group membership bugs
+- Fixes for rare crash bugs
+
+* Mon May 23 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.7-3
+- Resolves: rhbz#706740 - Orphaned links on rc0.d-rc6.d
+- Make sure to properly convert to systemd if upgrading from newer
+- updates for Fedora 14
+
+* Mon May 02 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.7-2
+- Fix segfault in TGT renewal
+
+* Fri Apr 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.7-1
+- Resolves: rhbz#700891 - CVE-2011-1758 sssd: automatic TGT renewal overwrites
+-                         cached password with predicatable filename
+
+* Wed Apr 20 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.6.1-1
+- Re-add manpage translations
+
+* Wed Apr 20 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.6-1
+- New upstream release 1.5.6
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.6
+- Fixed a serious memory leak in the memberOf plugin
+- Fixed a regression with the negative cache that caused it to be essentially
+- nonfunctional
+- Fixed an issue where the user's full name would sometimes be removed from
+- the cache
+- Fixed an issue with password changes in the kerberos provider not working
+- with kpasswd
+
+* Wed Apr 20 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-5
+- Resolves: rhbz#697057 - kpasswd fails when using sssd and
+-                         kadmin server != kdc server
+- Upgrades from SysV should now maintain enabled/disabled status
+
+* Mon Apr 18 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-4
+- Fix %%postun
+
+* Thu Apr 14 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-3
+- Fix systemd conversion. Upgrades from SysV to systemd weren't properly
+- enabling the systemd service.
+- Fix a serious memory leak in the memberOf plugin
+- Fix an issue where the user's full name would sometimes be removed
+- from the cache
+
+* Tue Apr 12 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-2
+- Install systemd unit file instead of sysv init script
+
+* Tue Apr 12 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.5-1
+- New upstream release 1.5.5
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.5
+- Fixes for several crash bugs
+- LDAP group lookups will no longer abort if there is a zero-length member
+- attribute
+- Add automatic fallback to 'cn' if the 'gecos' attribute does not exist
+
+* Thu Mar 24 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.4-1
+- New upstream release 1.5.4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.4
+- Fixes for Active Directory when not all users and groups have POSIX attributes
+- Fixes for handling users and groups that have name aliases (aliases are ignored)
+- Fix group memberships after initgroups in the IPA provider
+
+* Thu Mar 17 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.3-2
+- Resolves: rhbz#683267 - sssd 1.5.1-9 breaks AD authentication
+
+* Fri Mar 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.3-1
+- New upstream release 1.5.3
+- Support for libldb >= 1.0.0
+
+* Thu Mar 10 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.2-1
+- New upstream release 1.5.2
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.5.2
+- Fixes for support of FreeIPA v2
+- Fixes for failover if DNS entries change
+- Improved sss_obfuscate tool with better interactive mode
+- Fix several crash bugs
+- Don't attempt to use START_TLS over SSL. Some LDAP servers can't handle this
+- Delete users from the local cache if initgroups calls return 'no such user'
+- (previously only worked for getpwnam/getpwuid)
+- Use new Transifex.net translations
+- Better support for automatic TGT renewal (now survives restart)
+- Netgroup fixes
+
+* Sun Feb 27 2011 Simo Sorce <ssorce@redhat.com> - 1.5.1-9
+- Rebuild sssd against libldb 1.0.2 so the memberof module loads again.
+- Related: rhbz#677425
+
+* Mon Feb 21 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-8
+- Resolves: rhbz#677768 - name service caches names, so id command shows
+-                         recently deleted users
+
+* Fri Feb 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-7
+- Ensure that SSSD builds against libldb-1.0.0 on F15 and later
+- Remove .la for memberOf
+
+* Fri Feb 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-6
+- Fix memberOf install path
+
+* Fri Feb 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-5
+- Add support for libldb 1.0.0
+
+* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.5.1-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Tue Feb 01 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-3
+- Fix nested group member filter sanitization for RFC2307bis
+- Put translated tool manpages into the sssd-tools subpackage
+
+* Thu Jan 27 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-2
+- Restore Requires: cyrus-sasl-gssapi as it is not auto-detected during
+- rpmbuild
+
+* Thu Jan 27 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.1-1
+- New upstream release 1.5.1
+- Addresses CVE-2010-4341 - DoS in sssd PAM responder can prevent logins
+- Vast performance improvements when enumerate = true
+- All PAM actions will now perform a forced initgroups lookup instead of just
+- a user information lookup
+-   This guarantees that all group information is available to other
+-   providers, such as the simple provider.
+- For backwards-compatibility, DNS lookups will also fall back to trying the
+- SSSD domain name as a DNS discovery domain.
+- Support for more password expiration policies in LDAP
+-    389 Directory Server
+-    FreeIPA
+-    ActiveDirectory
+- Support for ldap_tls_{cert,key,cipher_suite} config options
+-Assorted bugfixes
+
+* Tue Jan 11 2011 Stephen Gallagher <sgallagh@redhat.com> - 1.5.0-2
+- CVE-2010-4341 - DoS in sssd PAM responder can prevent logins
+
+* Wed Dec 22 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.5.0-1
+- New upstream release 1.5.0
+- Fixed issues with LDAP search filters that needed to be escaped
+- Add Kerberos FAST support on platforms that support it
+- Reduced verbosity of PAM_TEXT_INFO messages for cached credentials
+- Added a Kerberos access provider to honor .k5login
+- Addressed several thread-safety issues in the sss_client code
+- Improved support for delayed online Kerberos auth
+- Significantly reduced time between connecting to the network/VPN and
+- acquiring a TGT
+- Added feature for automatic Kerberos ticket renewal
+- Provides the kerberos ticket for long-lived processes or cron jobs
+- even when the user logs out
+- Added several new features to the LDAP access provider
+- Support for 'shadow' access control
+- Support for authorizedService access control
+- Ability to mix-and-match LDAP access control features
+- Added an option for a separate password-change LDAP server for those
+- platforms where LDAP referrals are not supported
+- Added support for manpage translations
+
+
+* Thu Nov 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.1-3
+- Solve a shutdown race-condition that sometimes left processes running
+- Resolves: rhbz#606887 - SSSD stops on upgrade
+
+* Tue Nov 16 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.1-2
+- Log startup errors to the syslog
+- Allow cache cleanup to be disabled in sssd.conf
+
+* Mon Nov 01 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.1-1
+- New upstream release 1.4.1
+- Add support for netgroups to the proxy provider
+- Fixes a minor bug with UIDs/GIDs >= 2^31
+- Fixes a segfault in the kerberos provider
+- Fixes a segfault in the NSS responder if a data provider crashes
+- Correctly use sdap_netgroup_search_base
+
+* Mon Oct 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.0-2
+- Fix incorrect tarball URL
+
+* Mon Oct 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.4.0-1
+- New upstream release 1.4.0
+- Added support for netgroups to the LDAP provider
+- Performance improvements made to group processing of RFC2307 LDAP servers
+- Fixed nested group issues with RFC2307bis LDAP servers without a memberOf plugin
+- Build-system improvements to support Gentoo
+- Split out several libraries into the ding-libs tarball
+- Manpage reviewed and updated
+
+* Mon Oct 04 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-35
+- Fix pre and post script requirements
+
+* Mon Oct 04 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-34
+- Resolves: rhbz#606887 - sssd stops on upgrade
+
+* Fri Oct 01 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-33
+- Resolves: rhbz#626205 - Unable to unlock screen
+
+* Tue Sep 28 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-32
+- Resolves: rhbz#637955 - libini_config-devel needs libcollection-devel but
+-                         doesn't require it
+
+* Thu Sep 16 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-31
+- Resolves: rhbz#632615 - the krb5 locator plugin isn't packaged for multilib
+
+* Tue Aug 24 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.3.0-30
+- Resolves: CVE-2010-2940 - sssd allows null password entry to authenticate
+-                           against LDAP
+
+* Thu Jul 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.2.91-21
+- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild
+
+* Fri Jul 09 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.2.91-20
+- New upstream version 1.2.91 (1.3.0rc1)
+- Improved LDAP failover
+- Synchronous sysdb API (provides performance enhancements)
+- Better online reconnection detection
+
+* Mon Jun 21 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.2.1-15
+- New stable upstream version 1.2.1
+- Resolves: rhbz#595529 - spec file should eschew %%define in favor of
+-                         %%global
+- Resolves: rhbz#593644 - Empty list of simple_allow_users causes sssd service
+-                         to fail while restart.
+- Resolves: rhbz#599026 - Makefile typo causes SSSD not to use the kernel
+-                         keyring
+- Resolves: rhbz#599724 - sssd is broken on Rawhide
+
+* Mon May 24 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.2.0-12
+- New stable upstream version 1.2.0
+- Support ServiceGroups for FreeIPA v2 HBAC rules
+- Fix long-standing issue with auth_provider = proxy
+- Better logging for TLS issues in LDAP
+
+* Tue May 18 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.92-11
+- New LDAP access provider allows for filtering user access by LDAP attribute
+- Reduced default timeout for detecting offline status with LDAP
+- GSSAPI ticket lifetime made configurable
+- Better offline->online transition support in Kerberos
+
+* Fri May 07 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.91-10
+- Release new upstream version 1.1.91
+- Enhancements when using SSSD with FreeIPA v2
+- Support for deferred kinit
+- Support for DNS SRV records for failover
+
+* Fri Apr 02 2010 Simo Sorce <ssorce@redhat.com> - 1.1.1-3
+- Bump up release number to avoid library sub-packages version issues with
+  previous releases.
+
+* Thu Apr 01 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.1-1
+- New upstream release 1.1.1
+- Fixed the IPA provider (which was segfaulting at start)
+- Fixed a bug in the SSSDConfig API causing some options to revert to
+- their defaults
+- This impacted the Authconfig UI
+- Ensure that SASL binds to LDAP auto-retry when interrupted by a signal
+
+* Tue Mar 23 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-2
+- Release SSSD 1.1.0 final
+- Fix two potential segfaults
+- Fix memory leak in monitor
+- Better error message for unusable confdb
+
+* Wed Mar 17 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-1.pre20100317git0ea7f19
+- Release candidate for SSSD 1.1
+- Add simple access provider
+- Create subpackages for libcollection, libini_config, libdhash and librefarray
+- Support IPv6
+- Support LDAP referrals
+- Fix cache issues
+- Better feedback from PAM when offline
+
+* Wed Feb 24 2010 Stephen Gallagehr <sgallagh@redhat.com> - 1.0.5-2
+- Rebuild against new libtevent
+
+* Fri Feb 19 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.5-1
+- Fix licenses in sources and on RPMs
+
+* Mon Jan 25 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.4-1
+- Fix regression on 64-bit platforms
+
+* Fri Jan 22 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.3-1
+- Fixes link error on platforms that do not do implicit linking
+- Fixes double-free segfault in PAM
+- Fixes double-free error in async resolver
+- Fixes support for TCP-based DNS lookups in async resolver
+- Fixes memory alignment issues on ARM processors
+- Manpage fixes
+
+* Thu Jan 14 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.2-1
+- Fixes a bug in the failover code that prevented the SSSD from detecting when it went back online
+- Fixes a bug causing long (sometimes multiple-minute) waits for NSS requests
+- Several segfault bugfixes
+
+* Mon Jan 11 2010 Stephen Gallagher <sgallagh@redhat.com> - 1.0.1-1
+- Fix CVE-2010-0014
+
+* Mon Dec 21 2009 Stephen Gallagher <sgallagh@redhat.com> - 1.0.0-2
+- Patch SSSDConfig API to address
+- https://bugzilla.redhat.com/show_bug.cgi?id=549482
+
+* Fri Dec 18 2009 Stephen Gallagher <sgallagh@redhat.com> - 1.0.0-1
+- New upstream stable release 1.0.0
+
+* Fri Dec 11 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.99.1-1
+- New upstream bugfix release 0.99.1
+
+* Mon Nov 30 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.99.0-1
+- New upstream release 0.99.0
+
+* Tue Oct 27 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.7.1-1
+- Fix segfault in sssd_pam when cache_credentials was enabled
+- Update the sample configuration
+- Fix upgrade issues caused by data provider service removal
+
+* Mon Oct 26 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.7.0-2
+- Fix upgrade issues from old (pre-0.5.0) releases of SSSD
+
+* Fri Oct 23 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.7.0-1
+- New upstream release 0.7.0
+
+* Thu Oct 15 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.6.1-2
+- Fix missing file permissions for sssd-clients
+
+* Tue Oct 13 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.6.1-1
+- Add SSSDConfig API
+- Update polish translation for 0.6.0
+- Fix long timeout on ldap operation
+- Make dp requests more robust
+
+* Tue Sep 29 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.6.0-1
+- Ensure that the configuration upgrade script always writes the config
+  file with 0600 permissions
+- Eliminate an infinite loop in group enumerations
+
+* Mon Sep 28 2009 Sumit Bose <sbose@redhat.com> - 0.6.0-0
+- New upstream release 0.6.0
+
+* Mon Aug 24 2009 Simo Sorce <ssorce@redhat.com> - 0.5.0-0
+- New upstream release 0.5.0
+
+* Wed Jul 29 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.4.1-4
+- Fix for CVE-2009-2410 - Native SSSD users with no password set could log in
+  without a password. (Patch by Stephen Gallagher)
+
+* Sun Jul 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.4.1-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Mon Jun 22 2009 Simo Sorce <ssorce@redhat.com> - 0.4.1-2
+- Fix a couple of segfaults that may happen on reload
+
+* Thu Jun 11 2009 Simo Sorce <ssorce@redhat.com> - 0.4.1-1
+- add missing configure check that broke stopping the daemon
+- also fix default config to add a missing required option
+
+* Mon Jun  8 2009 Simo Sorce <ssorce@redhat.com> - 0.4.1-0
+- latest upstream release.
+- also add a patch that fixes debugging output (potential segfault)
+
+* Mon Apr 20 2009 Simo Sorce <ssorce@redhat.com> - 0.3.2-2
+- release out of the official 0.3.2 tarball
+
+* Mon Apr 20 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.3.2-1
+- bugfix release 0.3.2
+- includes previous release patches
+- change permissions of the /etc/sssd/sssd.conf to 0600
+
+* Tue Apr 14 2009 Simo Sorce <ssorce@redhat.com> - 0.3.1-2
+- Add last minute bug fixes, found in testing the package
+
+* Mon Apr 13 2009 Simo Sorce <ssorce@redhat.com> - 0.3.1-1
+- Version 0.3.1
+- includes previous release patches
+
+* Mon Apr 13 2009 Simo Sorce <ssorce@redhat.com> - 0.3.0-2
+- Try to fix build adding automake as an explicit BuildRequire
+- Add also a couple of last minute patches from upstream
+
+* Mon Apr 13 2009 Simo Sorce <ssorce@redhat.com> - 0.3.0-1
+- Version 0.3.0
+- Provides file based configuration and lots of improvements
+
+* Tue Mar 10 2009 Simo Sorce <ssorce@redhat.com> - 0.2.1-1
+- Version 0.2.1
+
+* Tue Mar 10 2009 Simo Sorce <ssorce@redhat.com> - 0.2.0-1
+- Version 0.2.0
+
+* Sun Mar 08 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.1.0-5.20090309git691c9b3
+- package git snapshot
+
+* Fri Mar 06 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.1.0-4
+- fixed items found during review
+- added initscript
+
+* Thu Mar 05 2009 Sumit Bose <sbose@redhat.com> - 0.1.0-3
+- added sss_client
+
+* Mon Feb 23 2009 Jakub Hrozek <jhrozek@redhat.com> - 0.1.0-2
+- Small cleanup and fixes in the spec file
+
+* Thu Feb 12 2009 Stephen Gallagher <sgallagh@redhat.com> - 0.1.0-1
+- Initial release (based on version 0.1.0 upstream code)